驱动程序设备号
1 驱动程序有主设备号,次设备号之分,主设备号是区分设备属于哪个驱动的标志,次设备号是驱动程序用来区别多个设备的。
2 设备号的内部表示:
typedef unsigned long dev_t;其中搞12位为主设备号,低20位为次设备号。
已知dev_t类型的变量,要想获取主设备号或者次设备号,使用宏:MAJOR(dev_t dev) MINOR(dev_t dev)
已知主次设备号,生成dev_t类型变量,使用宏:MKDEV(int major, int minor);
3 分配主次设备号的方法
一般请求分配设备号的时机应该是在驱动程序的初始化函数中,内核API有:
int register_chrdev_region(dev_t first, unsigned int count, char *name)
静态请求设备号,失败返回负数,dev_t为要申请的主次设备号,count为总共要申请的设备个数,name为驱动的名称
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
动态申请设备号,失败返回负数,dev保存得到的设备号,firstminor为第一个要求申请的次设备号,count为申请的设备个数,name为驱动名称
例子:
1 驱动程序有主设备号,次设备号之分,主设备号是区分设备属于哪个驱动的标志,次设备号是驱动程序用来区别多个设备的。
2 设备号的内部表示:
typedef unsigned long dev_t;其中搞12位为主设备号,低20位为次设备号。
已知dev_t类型的变量,要想获取主设备号或者次设备号,使用宏:MAJOR(dev_t dev) MINOR(dev_t dev)
已知主次设备号,生成dev_t类型变量,使用宏:MKDEV(int major, int minor);
3 分配主次设备号的方法
一般请求分配设备号的时机应该是在驱动程序的初始化函数中,内核API有:
int register_chrdev_region(dev_t first, unsigned int count, char *name)
静态请求设备号,失败返回负数,dev_t为要申请的主次设备号,count为总共要申请的设备个数,name为驱动的名称
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
动态申请设备号,失败返回负数,dev保存得到的设备号,firstminor为第一个要求申请的次设备号,count为申请的设备个数,name为驱动名称
例子:
int scull_major=0;
int scull_minor=0;
if(scull_major)
{
dev=MKDEV(scull_major, scull_minor);
result=register_chrdev_region(dev, scull_nr_devs, "scull");
}
else
{
result=alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
}
if(result<0)
{
printk("cannot get major");
return result;
}
4 释放设备号
unregister_chrdev_region(devno, scull_nr_devs);
int scull_minor=0;
if(scull_major)
{
dev=MKDEV(scull_major, scull_minor);
result=register_chrdev_region(dev, scull_nr_devs, "scull");
}
else
{
result=alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
}
if(result<0)
{
printk("cannot get major");
return result;
}
4 释放设备号
unregister_chrdev_region(devno, scull_nr_devs);
5 创建设备文件
#mknod /dev/scull0 c 252 0
c为字符设备文件
#mknod /dev/scull0 c 252 0
c为字符设备文件
6 注册设备驱动到内核
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&scull_fops;
err=cdev_add(&dev->cdev, devno, 1);
if(err)
printk("add scull fail");
其中cdev_init和下面的两行代码都是初始化各个cdev的字段,cdev_add是将这个设备加入到操作系统字符设备链表中。
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&scull_fops;
err=cdev_add(&dev->cdev, devno, 1);
if(err)
printk("add scull fail");
其中cdev_init和下面的两行代码都是初始化各个cdev的字段,cdev_add是将这个设备加入到操作系统字符设备链表中。
7 注销字符设备
cdev_del(&scull_devices[i].cdev);
cdev_del是将字符设备从字符设备链表中移除。
cdev_del(&scull_devices[i].cdev);
cdev_del是将字符设备从字符设备链表中移除。
8 实现驱动中的重要功能函数
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
// .llseek = no_llseek,
.read = scull_read,
.write = scull_write,
.compat_ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
int scull_open(struct inode *inode, struct file *filp)
用户程序调用open的时候系统会调用驱动的open
int scull_release(struct inode *inode, struct file *filp)
用户调用close的时候一般会调用函数,是当文件表被释放的时候调用的,如果close的时候文件表没有被释放,则不会调用release函数
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
用户调用read的时候,系统会调用驱动中的read函数,filp为文件表指针,buf,count为用户调用时传入的,f_pos为文件表中的f_pos字段
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
loff_t scull_llseek(struct file *filp, loff_t off, int whence)
int scull_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
// .llseek = no_llseek,
.read = scull_read,
.write = scull_write,
.compat_ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
int scull_open(struct inode *inode, struct file *filp)
用户程序调用open的时候系统会调用驱动的open
int scull_release(struct inode *inode, struct file *filp)
用户调用close的时候一般会调用函数,是当文件表被释放的时候调用的,如果close的时候文件表没有被释放,则不会调用release函数
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
用户调用read的时候,系统会调用驱动中的read函数,filp为文件表指针,buf,count为用户调用时传入的,f_pos为文件表中的f_pos字段
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
loff_t scull_llseek(struct file *filp, loff_t off, int whence)
int scull_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)