[1] Review
1. The use of
ioctl function ioctl(fd,100,100)
---------------------
unlocked_ioctl(file,cmd,args)
{ printk("cmd D% =, args =% D \ n-", cmd, args); // cmd args = 100 = 100; } command codes via ===> _ IO _IOR _IOW _IORW package 2. automatic device nodes class_create device_create class_destroy device_destroy
[2] The frame of the character device driver
user:
open("the name of the device file", the opening method); write(fd,buf,sizeof(buf));
|
device file name---->ls -i --- -->inode number (file system identification method)
|
------------------------------------- -|-----------------
kernel: |
--------------|
|
struct inode{ //All information in the file is in the inode Recorded umode_t i_mode; //File permission uid_t i_uid; //User id gid_t i_gid; //Group id unsigned long i_ino; //Inode number dev_t i_rdev; //Device number union { struct block_device *i_bdev; //Block device driver struct cdev *i_cdev; //Character device driver }; }
设备号1 设备号2 设备号n
字符设备驱动1 字符设备驱动2 字符设备驱动n
--------- --------- ---------
| | | | | |
| | | | | |
| | | | | |
--------- ---------- ... ----------
1.字符设备驱动的结构体
struct cdev {
const struct file_operations *fops;
//操作方法结构体
struct list_head list;
//内核链表
dev_t dev;
//设备号
unsigned int count;
//同种设备的个数
};
问:在应用程序中read write ioctl close如何通过
fd找到驱动的fops并调用里面对应的函数的?
1.open read write ioctl close函数是在哪里执行的?
在进程中,进程的结构体对象是task_struct
2.既然fd是在进程中产生的,那么它就会在进程
结构体中有记录
struct task_struct {
volatile long state;
//进程的状态
int prio, static_prio, normal_prio;
unsigned int rt_priority;
//进程的优先级
pid_t pid;
//进程号
struct thread_struct thread;
//进程中的线程
struct files_struct *files;
//打开文件时|候产生的各种信息
} |
|
struct file * fd_array[NR_OPEN_DEFAULT];
这是fd的数组,
fd_array[fd]===>struct file *
struct file每打开一次文件,就问产生一个file结构体
对象,将这个file结构体放大fd_array中,这个数组的
下标就是这个文件的文件描述符。这个file结构体就是
描述本次打开文件时候的各种信息的(打开方式,游标等)。
struct file {
const struct file_operations *f_op;
//操作方法结构体是从inode结构体获取的
unsigned int f_flags;
fmode_t f_mode;
loff_t f_pos;
}
通过fd访问到驱动中的read write close的流程如下:
fd-->fd_array[fd]--->file-->fops-->read write close;
编写字符设备驱动的流程?(register_chrdev)
1.定义结构体
struct cdev cdev;
struct cdev *cdev = cdev_alloc();
//使用cdev_alloc在内核空间分配内存
2.结构体成员的初始化
void cdev_init(struct cdev *cdev,
const struct file_operations *fops)
功能:初始化cdev的结构体,没有初始化设备号和设备的个数
参数:
@cdev:刚才分配好的结构体指针
@fops:操作方法结构体
3.申请设备号
1.静态申请(直接指定)
int register_chrdev_region(dev_t from,
unsigned count, const char *name)
功能:静态申请(直接指定)
参数:
@from :设备号的起始值
@count:设备的个数
@name :名字cat /proc/devices
返回值:成功返回0 ,失败返回错误码
2.动态申请(操作系统分配)
int alloc_chrdev_region(dev_t *dev,
unsigned baseminor, unsigned count,
const char *name)
功能:.动态申请(操作系统分配)
参数:
@dev:返回申请到的第一个设备号
@baseminor:次设备号的起始值 3
@count:设备的个数
@name :名字cat /proc/devices
返回值:成功返回0 ,失败返回错误码
4.注册
int cdev_add(struct cdev *p, dev_t dev,
unsigned count)
功能:注册字符设备驱动
参数:
@p:cdev结构体指针
@dev:设备号
@count:设备的个数
返回值:成功返回0 ,失败返回错误码
-----------------------------------------------
void cdev_del(struct cdev *p)
功能:注销字符设备驱动
参数:
@p:cdev的结构体指针
void unregister_chrdev_region(dev_t from, unsigned count)
功能:释放设备号
参数:
@from:设备号的起始的值
@count:设备的个数
void kfree(void *p)
功能:释放cdev_alloc分配的内存
参数:
@p:申请的内存的首地址。
练习:
1.字符设备驱动分步实现流程(20分钟)
[3] What is the difference between a step-by-step character device driver and a character device completed by a function?
Register_chrdev allocates 256 device numbers at a time when registering a character device driver. The
user cannot specify it. If the number of devices required to be allocated in the company is 3 or 500
, this function cannot complete the corresponding function. Based on the above reasons, when the company is doing
character device driver development, the function register_chrdev is generally not used to
complete the registration of character device drivers.
[4] The problem of the device number
1. The range of the major device number is
0-2^12
0-4096
2. Question:
How to store the device number when using cat /proc/devices to view
主设备号采用哈希表的形式存储
主设备号%255 ==作为哈希表数组的下标。
3.问:自动分配设备号的时候为什么每
次分配的都是250 ?
自动分配设备号的时候采用的是倒叙分配,从
254往前查找,直到找到没有被使用过的主设备
号为止,并将这个设备号分配给你。
4.问:自动申请主设备号的范围
自动申请设备号的范围: 1-254
其他的主设备号如何使用,只能采用静
态申请设备号的方式完成
[5] to achieve the following functions
by writing a 1 to the red light myled0
writing 0 to myled0 off red
to a green light myled1 Write
Write 0 to green off myled1
write a bright blue light myled2 to
write to the blue lamp myled2 0
echo 1 >/dev/myled0 红灯亮
echo 0 >/dev/myled0 红灯灭