Linux驱动总结3
return kobject_name(&dev-> 上面的命令解析宏可以快速的确定。 /*检查类型,幻数是否正确*/ if(_IOC_TYPE(cmd)!=MAGIC_NUM) return -EINVAL; /*检测命令序号是否大于允许的最大序号*/ if(_IOC_NR(cmd)> MEM_MAX_CMD) return -EINVAL; 2、主要是指针参数的检测。指针参数主要是因为内核空间和用户空间的差异性导致的,因此需要来自用户空间指针的有效性。使用copy_from_user,copy_to_user,get_user,put_user之类的函数时,由于函数会实现指针参量的检测,因此可以省略,但是采用__get_user(),__put_user()之类的函数时一定要进行检测。具体的检测方法如下所示: if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE,(void *)args,_IOC_SIZE(cmd)); else if(_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ,(void *)args,_IOC_SIZE(cmd)); if(err)/*返回错误*/ return -EFAULT; 当方向是读时,说明是从设备读数据到用户空间,因此要检测用户空间的指针是否可写,采用VERIFY_WRITE,而当方向是写时,说明是往设备中写数据,因此需要检测用户空间中的指针的可读性VERIFY_READ。检查通常采用access_ok()实现检测,第一个参数为读写,第二个为检测的指针,第三个为数据的大小。 3、命名的控制: 命令的控制主要是采用switch和case相结合实现的,这于window编程中的检测各种消息的实现方式是相同的。 /*根据命令执行相应的操作*/ switch(cmd) { case MEMDEV_PRINTF: printk("<--------CMD MEMDEV_PRINTF Done------------>"); ... break; case MEMDEV_READ: ioarg = &mem_devp->data; ... ret = __put_user(ioarg,(int *)args); ioarg = 0; ... break; case MEMDEV_WRITE: ... ret = __get_user(ioarg,(int *)args); printk("<--------CMD MEMDEV_WRITE Done ioarg = %d--------->",ioarg); ioarg = 0; ... break; default: ret = -EINVAL; printk("<-------INVAL CMD--------->"); break; } 这只是基本的框架结构,实际中根据具体的情况进行修改。这样就实现了基本的命令控制。 文件操作支持的集合如下: /*添加该模块的基本文件操作支持*/ static const struct file_operations mem_fops = { /*结尾不是分号,注意其中的差别*/ .owner = THIS_MODULE, .llseek = mem_llseek, .read = mem_read, .write = mem_write, .open = mem_open, .release = mem_release, /*添加新的操作支持*/ .unlocked_ioctl = mem_ioctl, }; 需要注意不是ioctl,而是unlocked_ioctl。 二、设备的堵塞读写方式实现,通常采用等待队列。 设备的堵塞读写方式,默认情况下的读写操作都是堵塞型的,具体的就是如果需要读数据,当设备中没有数据可读的时候应该等待设备中有设备再读,当往设备中写数据时,如果上一次的数据还没有被读完成,则不应该写入数据,就会导致进程的堵塞,等待数据可读写。但是在应用程序中也可以采用非堵塞型的方式进行读写。只要在打开文件的时候添加一个O_NONBLOCK,这样在不能读写的时候就会直接返回,而不会等待。 因此我们在实际设计驱动设备的同时需要考虑读写操作的堵塞方式。堵塞方式的设计主要是通过等待队列实现,通常是将等待队列(实质就是一个链表)的头作为设备数据结构的一部分。在设备初始化过程中初始化等待队列的头。最后在设备读写操作的实现添加相应的等待队列节点,并进行相应的控制。 等待队列的操作基本如下: 1、等待队列的头定义并初始化的过程如下: 方法一: struct wait_queue_head_t mywaitqueue; init_waitqueue_head(&mywaitqueue); 方法二: DECLARE_WAIT_QUEUE_HEAD(mywaitqueue); 以上的两种都能实现定义和初始化等待队列头。 2、创建、移除一个等待队列的节点,并添加、移除相应的队列。 定义一个等待队列的节点:DECLARE_WAITQUEUE(wait,tsk) 其中tsk表示一个进程,可以采用current当前的进程。 添加到定义好的等待队列头中。 add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait); 即:add_wait_queue(&mywaitqueue,&wait); 移除等待节点 remove_wait_queue(wait_queue_head_t *q,wait_queue_t *wait); 即:remove_wait_queue(&mywaitqueue,&wait); 3、等待事件 wait_event(queue,
Linux驱动总 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)