这节我们开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的。个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门。
  不能再扯了,涉及到linux的驱动开发知识面灰常广,再扯文章会变得灰常长。首先还是回到led驱动的本身上,自从linux被移植到arm上后,做驱动开发的硬件知识要求有所降低,很多都回归到了软件上,这是系统编程的一大特点,当然 ,也不排除有很多设备的驱动需要我们从头做起。
  led的驱动虽然看似很简单,但是要描述清楚估计上万字都不一定够用,本篇文章从初学者的角度出发,重点关注在整个软件的开发的流程和思想,而不过多局限与细节的分析,初学者应该首先把握某一类编程的流程和思想,这样才能入门快,进步迅速。作为一个初学者我一直觉得这样入门效率高。
  下面我们进入主题led驱动的书写:
  既然是在linux系统下设备驱动开发,不同于以往我们单片机下设置一个高电平而了事,在linux系统下开发的驱动程序要想在linux正常工作,一定要符合linux系统的规范,linux下设备被分为三个类型字符设备/块设备/网络设备。上述的三种设备不可能面面俱到,因此还提出了一个杂设备作为补充,看了下网上大部分人都把led的驱动设备归到了杂设备,这是为什么呢?原来是友善之臂的手册上把它归为了杂设备,哈哈,所以杂设备这种版本比较流行,木有追求的人们啊! 那我们把它归为那种设备呢?当然是杂设备了,嘿嘿。。。。。。
  既然对led我们准备把它作为一个杂设备加入系统,是不是应该有一个名字吧,还应该有个操作符号吧。。。。。。
  stop,停止你的YY,关于这个设备的标准形式大神已经帮你定义好了,具体它存在于系统的include下,里面有一个miscdivice.h。
  1 struct miscdevice  {
  2         int minor;
  3         const char *name;
  4         const struct file_operations *fops;
  5         struct list_head list;
  6         struct device *parent;
  7         struct device *this_device;
  8         const char *nodename;
  9         mode_t mode;
  10 };
  好吧,原来为了统一规范,我们只需按照标准来填充内容可以啦!要想正确的使用这个描述设备的结构体,必须清楚的了解到其中的每个成员。天空飘来四个字 f u c k
  好,让我们平复一下心情,继续了解它。查了下minor这个单词是次要的,在这里是次设备号的意思。这是因为杂设备为了节约主设备号,采用共用主设备号的方式,次设备号加以区分的方式来描述设备,因此来看这个minor是要必须填写啦!不愧是过了四级的人,第二个直接看懂啦!欧耶~
  之前做过一个了解,这第三个在linux驱动中非常的重要,可以称之为核心,我们很大的工作 都要围绕这个file_operations来操作,因此必须要隆重的研究下这个file_operatios这个结构体。
  file_operations这个结构体的存在是linux中将所有设备看做文件的基础,这是为什么呢?因为通俗的说是这个结构体是文件操作和驱动操作的一个关系映射,对于系统的操作函数(诸如read/write)在这个结构体里都有与之对应的对硬件进行操作的函数。wow这个函数居然如此之酷!这样以来,我们还弄清楚了另外一个问题,是为什么我们不能直接越过操作系统来操作硬件,都是因为有它啊!可见这个结构体在内核中的地位,以及在linux操作系统中的地位。哈哈下面的几个成员,先不分析啦!我们这次也用不上,感觉在linux下开发驱动真是个力气活啊!
  见过file_operations的厉害之后,我们自然知道 现在只要把这个结构体弄清楚可以敲代码写驱动啦!so,let‘s go!
  首先在系统目录include/linux/fs.h中找到这个牛逼的结构体:

 

1 struct file_operations {
2         struct module *owner;
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);
9         unsigned int (*poll) (struct file *, struct poll_table_struct *);
10         int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
11         long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
12         long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
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);
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 };

  当我知道有这么多成员的时候,当时我尿了,不过,还好我们只需要实现本次驱动需要的东东!查看了一下手册上的驱动,欧耶~这次我们只需要研究两个成员ower和ioctl。上面可以看出ower是一个结构体成员是是那个模块,而ioctl是个函数。