分类: LINUX
2014-08-02 16:35:20
学驱动一个星期,中个思路还有些不适应,觉得内核重定义的类型略多,对于高手来说这样比较能够防错,但是初学略吃力,所以在总结头放上一些必要的基本只是出来。
框架:
大体上就是你注册的时候用到module_init调用初始化,注销时候module_exit调用注销函数。
初始化分三部分:1、申请设备号 2、注册 3、初始化硬件
然后其余的功能函数比如read、write、open、release、llseek都是自己实现然后存放在file_operation中供初始化注册和调用。
unsigned int 类型,32位(这个是通用32位机的,不一定所有都是),用于在驱动程序中定义设备编号,高12位为主设备号,低20位为次设备号 你在/dev目录下,用命令ll就可以看到那些设备文件的主次设备号. 在程序中用宏MAJOR(dev_t dev)可以解析出主设备号,用宏MINOR(dev_t dev)可以解析出次设备号,但是更加推荐用iminor(inode)和 imajor(inode)来代替这两个。 后面又建议把从的cdev设备定义到自定义的结构体中,用container_of来直接访问整个结构体来获得设备号。 又: 关于设备号,是在mknod时添加进去存放在inode结构体中的,一个设备实体添加一次节点,也就是说应用层的如果打开两个设备应该是打开 两个不同节点的。 file_operation: file_operation就是把系统调用和驱动程序关联起来的关键数据结构。这个结构的每一个成员都对应着一个系统调用。读取file_operation中 相应的函数指针,接着把控制权转交给函数,从而完成了Linux备驱动程序的工作。也就是,把函数挂在过去调用啦。 inode: 马书原话“内核用inode结构在内部表示文件”。其中dev_t i_rdev包含真正的设备编号,他是mknod时注册进去的。 struct cdev *i_cdev,当inode指向一个字符设备文件时,该字段包含了指向struct cdev结构的指针。 file: 表示打开的文件描述符,open时产生close时关闭。 重要的成员: loff_t f_pos:(long long)当前的读写位置。read/write会直接对f_pos进行位置操作,而不直接对filp->f_pos进行操作。 例外的是llseek,因为他本身就是为了修改文件位置来着。 void *private_data: open调用时会将它清NULL,驱动程序可将他任意使用。我现在用他做: filp->private_data = container_of(inode->i_cdev, struct Mdev, cdev);//会根据不同的mknod地址有不同的inode就 有不同的设备号哦 这里,filp->private_data存的就是一个mem_dev的地址来存储一个结构体。 调试打印用: printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);//打印绝对路径, 函数名, 行号的方法 最后对犯的错误总结: 1、要有几个次设备就要open几次的,这时的设备节点是不一样的,也就是说,你要几个次设备就应该mknod几次,/dev/名字, 其中名字当然是不一样的^_^ 2、要把应用层函数和驱动函数结合起来理解,参数的由来, 是注册来的还是应用层传来的, 另:新学理解应用层函数与驱动关系, 关系就是没有个关系啊,其实人家只是在读dev设备端口而已,所以千万不要用错应用层函数啊(某抽了用fread了,打死打死)。 3、2.4内核使用老的注册方法注册的 int register_chrdev(unsigned int major, const char *name, struct file_operations *fops) 2.6以后用的现在的方法。 几个版本的代码晚些附上,以上是自己整理的,有过有理解上的错误还请指正^_^!
青丘凤九2014-09-16 01:01:46
demon_feng:看了一遍,发现我没看懂。。。。。驱动是用来指挥硬件工作的,可是我怎么就看不出来,他是如何让硬件工作的。。
咦,我以前为什么就没有发现你还给我回复过,好神奇,恩,我决定继续写下去
回复 | 举报