:字符设备驱动

Posted Ven_J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:字符设备驱动相关的知识,希望对你有一定的参考价值。

编写驱动程序的第一步就是:定义驱动程序为用户程序提供的功能(机制)
1、主设备号和次设备号       对字符设备的访问是通过文件系统内的设备名称进行的。那些名称被称为特殊文件、设备文件、或者简单称之为文件系统树的节点,他们通常位于/dev目录下。     一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。     在内核中,dev_t类型用来保存设备号——包括主设备号和次设备号。
    dev_t是一个32位的数,前12位用来表示主设备号,后20位用来表示次设备号。如果要获得dev_t的主设备号和次设备号,应该使用下面的宏:
   
  1. #define MINORBITS 20
  2. #define MINORMASK ((1U << MINORBITS) - 1)
  3. #define MAJOR(dev) ((unsigned int)((dev) >> MINORBITS)
  4. #define MINOR(dev) ((unsigned int)((dev) & MINORMASK)
MAJOR宏获得主设备号,MINOR宏获得次设备号。     相反,如果需要将主设备号和次设备号转换成dev_t类型则使用下面的宏:
   
  1. #define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi))
2、分配和释放设备编号          在建立一个字符设备之前,我们的驱动程序 首先要获得一个或多个设备号。完成该工作的函数是:
   
  1. #include <linux/fs.h>
  2. int register_chrdev_region(dev_t first, unsigned int count, char *name)
其中,first是要分配的设备编号范围的起始值。first的次设备号经常被置为0。 count是所请求的连续设备编号的个数。如果count非常大,则所请求的范围可能与下一个主设 备号重叠,但是只要我们所请求的编号范围时可用的,那就没有问题。 name是和该编号范围关联的设备名称,它将出现在/proc/devices和sysfs中。     register_chrdev_region的返回值在成功的时候返回0。在错误的情况下,返回一个负的错误码,并且不能使用所请求的编号区域。

  动态分配所需的主设备号:
   
  1. int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
dev是仅用于输出的参数,在成功完成调用后将保存已分配范围的第一个编号。firstminor是要使用的被请求的第一个次设备号,它通常是0。count和name跟上面的是一样的意思。
释放设备号
   
  1. void unregister_chrdev_region(dev_t first, unsigned int count)
first表示要释放的设备号,count表示从first开始要释放的设备号个数。 通常在模块的清除函数中调用unregister_chrdev_region函数。
分配主设备号的最佳方式是:默认采用动态分配,同时保留在加载甚至是在编译时指定主设备号的余地。
   
  1. if (scull_major)
  2. dev = MKDEV(scull_major, scull_minor);
  3. result = register_chrdev_region(dev, scull_nr_devs, "scull");
  4. else
  5. result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
  6. scull_major = MAJOR(dev);
  7. if (result < 0)
  8. printk(KERN_WARNING "scull: cannot get major %d\\n", scull_major);
  9. return result;
3、重要的数据结构          大部分的驱动程序操作涉及到三个重要的内核数据结构,分别是file_operations、file、inode

文件操作          file_opreations结构就是用来将驱动程序操作连接到我们保留的设备编号上的。
   
  1. struct file_operations
  2. struct module *owner;//拥有该结构的模块的指针,一般为THIS_MODULES
  3. loff_t (*llseek) (struct file *, loff_t, int);//用来修改文件当前的读写位置
  4. ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//从设备中同步读取数据
  5. ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//向设备发送数据
  6. ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的读取操作
  7. ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一个异步的写入操作
  8. int (*readdir) (struct file *, void *, filldir_t);//仅用于读取目录,对于设备文件,该字段为NULL
  9. unsigned int (*poll) (struct file *, struct poll_table_struct *); //轮询函数,判断目前是否可以进行非阻塞的读写或写入
  10. int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //执行设备I/O控制命令
  11. long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系统,将使用此种函数指针代替ioctl
  12. long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系统上,32位的ioctl调用将使用此函数指针代替
  13. int (*mmap) (struct file *, struct vm_area_struct *); //用于请求将设备内存映射到进程地址空间
  14. int (*open) (struct inode *, struct file *); //打开
  15. int (*flush) (struct file *, fl_owner_t id);
  16. int (*release) (struct inode *, struct file *); //关闭
  17. int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待处理的数据
  18. int (*aio_fsync) (struct kiocb *, int datasync); //异步刷新待处理的数据
  19. int (*fasync) (int, struct file *, int); //通知设备FASYNC标志发生变化
  20. int (*lock) (struct file *, int, struct file_lock *);
  21. ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
  22. unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
  23. int (*check_flags)(int);
  24. int (*flock) (struct file *, int, struct file_lock *);
  25. ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
  26. ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
  27. int (*setlease)(struct file *, long, struct file_lock **);
  28. ;
inode问题之No space left on device!

df -i和df -h

ext3_dx_add_entry: Directory index full!

Linux-标准字符设备

Linux-标准字符设备

linux中啥是块设备和字符设备?