1、Linux字符设备驱动 实验二:Linux字符设备驱动一字符设备驱动实现的方法包括Write, Read, Poll, Icotl, Mmap, Llseek等。二字符设备驱动的主要内容:并发控制,阻塞与非阻塞,异步通知。三字符设备驱动的主要文件:globalfifo.c Makefile globalfifo_test,globalfifo.c。四.驱动程序如下:#include #include #include #include #include #include #include #include #include #include #include #include #include
2、 /* device_create()*/#define GLOBALFIFO_SIZE 24 /*全局fifo最大4K字节*/#define FIFO_CLEAR 0x1 /*清0全局内存的长度*/#define GLOBALFIFO_MAJOR 249 /*预设的globalfifo的主设备号*/static int globalfifo_major = GLOBALFIFO_MAJOR;/*globalfifo设备结构体*/struct globalfifo_dev struct cdev cdev; /*cdev结构体*/ unsigned int current_len; /*fif
3、o有效数据长度*/ unsigned char memGLOBALFIFO_SIZE; /*全局内存*/ struct semaphore sem; /*并发控制用的信号量*/ wait_queue_head_t r_wait; /*阻塞读用的等待队列头*/ wait_queue_head_t w_wait; /*阻塞写用的等待队列头*/;struct globalfifo_dev *globalfifo_devp; /*设备结构体指针*/*文件打开函数*/int globalfifo_open(struct inode *inode, struct file *filp) /*将设备结构体指
4、针赋值给文件私有数据指针*/ filp-private_data = globalfifo_devp; return 0;/*文件释放函数*/int globalfifo_release(struct inode *inode, struct file *filp) return 0;/* ioctl设备控制函数 */static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) struct globalfifo_dev *dev = filp-
5、private_data;/*获得设备结构体指针*/ switch (cmd) case FIFO_CLEAR: down(&dev-sem); /* 获得信号量 */ dev-current_len = 0; memset(dev-mem,0,GLOBALFIFO_SIZE);up(&dev-sem); /* 释放信号量 */printk(KERN_INFO globalfifo is set to zeron); break; default: return - EINVAL; return 0;static unsigned int globalfifo_poll(struct file
6、 *filp, poll_table *wait) unsigned int mask = 0; struct globalfifo_dev *dev = filp-private_data; /*获得设备结构体指针*/ down(&dev-sem); poll_wait(filp, &dev-r_wait, wait);/*把读等待队列添加到poll_table*/ poll_wait(filp, &dev-w_wait, wait);/*把写等待队列添加到poll_table*/ /*fifo非空 表示可读*/ if (dev-current_len != 0) mask |= POLLI
7、N | POLLRDNORM; /*标示数据可获得*/ /*fifo非满 表示可写*/ if (dev-current_len != GLOBALFIFO_SIZE) mask |= POLLOUT | POLLWRNORM; /*标示数据可写入*/ up(&dev-sem); return mask;/*globalfifo读函数*/static ssize_t globalfifo_read(struct file *filp, char _user *buf, size_t count, loff_t *ppos) int ret; struct globalfifo_dev *dev
8、= filp-private_data;DECLARE_WAITQUEUE(wait, current); down(&dev-sem); /* 获得信号量 */ add_wait_queue(&dev-r_wait, &wait); /* 进入读等待队列头 */ /* 等待FIFO非空 */ if (dev-current_len = 0) if (filp-f_flags &O_NONBLOCK) ret = - EAGAIN; goto out; _set_current_state(TASK_INTERRUPTIBLE); /* 改变进程状态为睡眠 */ up(&dev-sem); s
9、chedule(); /* 调度其他进程执行 */ if (signal_pending(current) /* 如果是因为信号唤醒 */ ret = - ERESTARTSYS; goto out2; down(&dev-sem); /* 拷贝到用户空间 */ if (count dev-current_len) count = dev-current_len; if (copy_to_user(buf, dev-mem, count) ret = - EFAULT; goto out; else memcpy(dev-mem, dev-mem + count, dev-current_le
10、n - count); /* fifo数据前移 */dev-current_len -= count; /* 有效数据长度减少 */ printk(KERN_INFO read %d bytes(s),current_len:%dn, count, dev-current_len);wake_up_interruptible(&dev-w_wait); /* 唤醒写等待队列 */ ret = count; out: up(&dev-sem); /* 释放信号量 */out2: remove_wait_queue(&dev-w_wait, &wait); /* 从附属的等待队列头移除 */set
11、_current_state(TASK_RUNNING); return ret;/*globalfifo写操作*/static ssize_t globalfifo_write(struct file *filp, const char _user *buf,size_t count, loff_t *ppos) struct globalfifo_dev *dev = filp-private_data;int ret; DECLARE_WAITQUEUE(wait, current);down(&dev-sem);add_wait_queue(&dev-w_wait, &wait);/*
12、 等待FIFO非满 */if (dev-current_len = GLOBALFIFO_SIZE) if (filp-f_flags &O_NONBLOCK) ret = - EAGAIN;goto out; _set_current_state(TASK_INTERRUPTIBLE); /* 改变进程状态为睡眠 */ up(&dev-sem);schedule(); /* 调度其他进程执行 */if (signal_pending(current) /* 如果是因为信号唤醒 */ret = - ERESTARTSYS;goto out2; down(&dev-sem); /* 获得信号量
13、*/*从用户空间拷贝到内核空间*/if (count GLOBALFIFO_SIZE - dev-current_len) count = GLOBALFIFO_SIZE - dev-current_len;if (copy_from_user(dev-mem + dev-current_len, buf, count)ret = - EFAULT;goto out; else dev-current_len += count;printk(KERN_INFO written %d bytes(s),current_len:%dn, count, dev-current_len);wake_u
14、p_interruptible(&dev-r_wait); /* 唤醒读等待队列 */ret = count;out:up(&dev-sem); /* 释放信号量 */out2:remove_wait_queue(&dev-w_wait, &wait); /* 从附属的等待队列头移除 */ set_current_state(TASK_RUNNING);return ret;static int memdev_mmap(struct file *filp, struct vm_area_struct *vma)struct mem_dev *dev = filp-private_data; /
15、*获得设备结构体指针*/ vma-vm_flags |= VM_IO;vma-vm_flags |= VM_RESERVED if (remap_pfn_range(vma,vma-vm_start,virt_to_phys(dev-data)PAGE_SHIFT, vma-vm_end - vma-vm_start, vma-vm_page_prot)return -EAGAIN; return 0;/*文件操作结构体*/static const struct file_operations globalfifo_fops = .owner = THIS_MODULE,.read = glo
16、balfifo_read, .write = globalfifo_write, .ioctl = globalfifo_ioctl, .poll = globalfifo_poll, .open = globalfifo_open, .release = globalfifo_release, .mmap=memdev_mmap,;/*初始化并注册cdev*/static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)int err, devno = MKDEV(globalfifo_major, index
17、); cdev_init(&dev-cdev, &globalfifo_fops); dev-cdev.owner = THIS_MODULE; err = cdev_add(&dev-cdev, devno, 1); if (err) printk(KERN_NOTICE Error %d adding LED%d, err, index);/*设备驱动模块加载函数*/int globalfifo_init(void) struct class *myclass; int ret; dev_t devno = MKDEV(globalfifo_major, 0); /* 申请设备号*/ if
18、 (globalfifo_major) ret = register_chrdev_region(devno, 1, globalfifo); else /* 动态申请设备号 */ ret = alloc_chrdev_region(&devno, 0, 1, globalfifo); globalfifo_major = MAJOR(devno); if (ret sem); /*初始化信号量*/ init_waitqueue_head(&globalfifo_devp-r_wait); /*初始化读等待队列头*/ init_waitqueue_head(&globalfifo_devp-w
19、_wait); /*初始化写等待队列头*/ return 0;fail_malloc: unregister_chrdev_region(devno, 1); return ret;/*模块卸载函数*/void globalfifo_exit(void) cdev_del(&globalfifo_devp-cdev); /*注销cdev*/ kfree(globalfifo_devp); /*释放设备结构体内存*/ unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*释放设备号*/MODULE_AUTHOR(Song Baohu
20、a);MODULE_LICENSE(Dual BSD/GPL);module_param(globalfifo_major, int, S_IRUGO);module_init(globalfifo_init);module_exit(globalfifo_exit);五.(1)驱动程序的Makefile:obj-$(CONFIG_GLOBALFIFO) +=GLOBALFIFO.o(2)驱动程序的Kconfig为:config GLOBALFIFO tristate zifushebeiqudong(3)进入控制界面如图:(4)驱动模块的产生:总结:通过对字符设备驱动的操作,在实验过程中,遇到了很多困难,感觉有好多知识很生疏,学到的知识也不能很好的运用到实践中,在编写字符设备驱动程序时,比如在测试写阻塞,就会遇见写阻塞通过不了的问题,经过老师的讲解。才知道对于内存分配不合理,在其他地方也会出现很多错误,但是,经过慢慢摸索,我也学到了很多知道,加强了这方面的一些不足,感觉自己在字符设备驱动方面有了很大提高。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1