make -C /usr/src/linux-2.6.33 -M /home/kylin/qudong/hello
单独编译一个驱动指令,无须在Makefile中指定KERNEL_DIR
设备文件与普通文件不同,不能使用IO函数建立,需要使用misc_register函数建立设备文件。设备文件位于/dev目录下。
extern int misc_register(struct miscdevice * misc);
extern int misc_deregister(struct miscdevice *misc);
注册设备文件需要声明一个设备文件的结构体来描述相关信息,即miscdevice结构体。
static struct file_operations dev_fops={.owner=THIS_MODULE};
static struct miscdevice misc={.minor=MISC_DYNAMIC_MINOR, .name=DEVICE_NAME,.fops=&dev_fops};
然后在init函数中ret=misx_register(&misc);
驱动中函数用static修饰,会和全局变量一起放在单独的内存中,除非卸载或者关机,这样就不用再进栈、出栈提高了驱动效率。
read函数分析:
ssize dev_write(struct file *file,const char _user *buf,size_t count,loff_tppos)中的const char _user*buf代表不能修改的数据,其中_user宏代表buf的内存区域位于用户空间。
*************************************************************************************************************************************************************
使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行。
原函数:unsigned
int (*poll)(struct file *filp, struct poll_table *wait);
其中:typedef struct poll_table_struct { poll_queue_proc qproc; unsigned long key; } poll_table; 经过以上驱动程序的poll()函数应该返回设备资源的可获取状态,即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏的位"或"结果.每个宏的含义都表示设备的一种状态,如:
常量 | 说明 |
POLLIN | 普通或优先级带数据可读 |
POLLRDNORM | 普通数据可读 |
POLLRDBAND | 优先级带数据可读 |
POLLPRI | 高优先级数据可读 |
POLLOUT | 普通数据可写 |
POLLWRNORM | 普通数据可写 |
POLLWRBAND | 优先级带数据可写 |
POLLERR | 发生错误 |
POLLHUP | 发生挂起 |
POLLNVAL | 描述字不是一个打开的文件 |
韦老师是这样子创建类和创建类的设备:
一、定义
static struct class *firstdrv_class;
static struct class_device *firstdrv_class_dev;
二、入口函数里
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
三、出口函数里
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
而在linux2.6.30.4里,并没有class_device_create和class_device_unregister函数
我是这样子创建类和创建类的设备:
一、定义
static struct class *firstdrv_class;
static struct device *firstdrv_device;
二、入口函数里
/* 创建firstdrv类 */
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
/* 在firstdrv类下创建xxx设备,供应用程序打开设备*/
firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");
三、出口函数里
device_unregister(firstdrv_device); //卸载类下的设备
class_destroy(firstdrv_class); //卸载类
linux2.6.30.4使用device_create函数替代class_device_create函数;
使用device_unregister函数替代class_device_unregister函数。
内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev()。其中,register_chrdev_region()是为提前知道
设备的主次设备号的设备分配设备编号。alloc_chrdev_region() 是动态分配主次设备号。register_chrdev()。是老版本的设备号注册方式,他只分配主设备号。从设备号在mknod的时候指定。
内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里。该散列表中的每一个元素是一个 char_device_struct 结构。只为为一组对应同一个字符设备驱动的设备编号范围定义一个 char_device_struct 结构。
使用cdev_add注册字符设备前应该先调用register_chrdev_region或alloc_chrdev_region分配设备号。register_chrdev_region函数用于指定设备号的情况,alloc_chrdev_region函数用于动态申请设备号,系统自动返回没有占用的设备号
*************************************************************************************