ldd3 chapter3 字符驱动简单记录
2016-06-19 17:43
369 查看
动态分配节点号:
删除节点号:
动态分配cdev:
将cdev和节点号绑定:
删除cdev:
代码:
Makfile:
测试:
[root@FriendlyARM /nfs]# insmod scull.ko
major = 253,minor = 0
[root@FriendlyARM /nfs]# mknod /dev/scull0 c 253 0
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
删除节点号:
void unregister_chrdev_region(dev_t from, unsigned count)
动态分配cdev:
struct cdev *cdev_alloc(void)初始化cdev,并绑定file_operations:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
将cdev和节点号绑定:
int cdev_add(struct cdev *, dev_t, unsigned);
删除cdev:
void cdev_del(struct cdev *p)
代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/list.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/errno.h> #include <asm/uaccess.h> #include <linux/semaphore.h> loff_t scull_llseek(struct file *filp, loff_t f_ops, int flag); ssize_t scull_read(struct file *filp, char __user * buf, size_t count, loff_t *f_ops); ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops); int scull_ioctl(struct inode *p_inode, struct file *filp, unsigned int cmd, unsigned long args); int scull_open(struct inode *p_inode, struct file *filp); int scull_release(struct inode *p_inode, struct file *filp); struct file_operations scull_fops = { .owner = THIS_MODULE, .llseek = scull_llseek, .read = scull_read, .write = scull_write, .ioctl = scull_ioctl, .open = scull_open, .release = scull_release, }; struct scull_qset { struct list_head qset_node; void **data; }; struct scull_dev { struct list_head qset_head; int quantum; int qset; unsigned long size; dev_t dev_t; struct cdev cdev; struct semaphore sem; }; struct scull_dev g_scull_dev; //根据index 返回p_qset结构,如果没有就创建一个 struct scull_qset *scull_follow(struct scull_dev* dev, int index) { int i = 0; struct list_head * p_qset_node; struct scull_qset *p_qset; list_for_each(p_qset_node, &dev->qset_head) { if((i++) == index) { return container_of(p_qset_node, struct scull_qset, qset_node); } } p_qset = (struct scull_qset *)kmalloc(sizeof(struct scull_qset), GFP_KERNEL); if (p_qset == NULL) return NULL; memset(p_qset, 0, sizeof(struct scull_qset)); p_qset->data = kmalloc(dev->qset * sizeof(char *), GFP_KERNEL); if (p_qset->data == NULL) { kfree(p_qset); return NULL; } memset(p_qset->data, 0, dev->qset * sizeof(char *)); list_add_tail(&p_qset->qset_node, &dev->qset_head); return p_qset; } int scull_trim(struct scull_dev *dev) { struct list_head *p_qset_node = NULL; struct scull_qset *p_qset; int i; while(!list_empty(&dev->qset_head)) { p_qset_node = dev->qset_head.next; p_qset = container_of(p_qset_node, struct scull_qset, qset_node); for (i = 0; i < dev->qset; i++) { kfree(p_qset->data[i]); } list_del(p_qset_node); kfree(p_qset); } dev->size = 0; return 0; } loff_t scull_llseek(struct file *filp, loff_t f_ops, int flag) { printk(KERN_ERR"llseek\n"); return 0; } ssize_t scull_read(struct file *filp, char __user * buf, size_t count, loff_t *f_ops) { struct scull_dev *dev = filp->private_data; struct scull_qset *p_qset; int qset_size = dev->quantum * dev->qset; int qset_index,qset_rest; int quan_index,quan_rest; ssize_t retval = 0; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; qset_index = (long)*f_ops / qset_size; qset_rest = (long)*f_ops % qset_size; quan_index = qset_rest / dev->quantum; quan_rest = qset_rest % dev->quantum; if (*f_ops > dev->size) goto out; if ((*f_ops + count) > dev->size) { count = dev->size - *f_ops; } p_qset = scull_follow(dev, qset_index); if (p_qset == NULL || p_qset->data == NULL || p_qset->data[quan_index] == NULL) { goto out; } if (count > (dev->quantum - quan_rest)) { count = dev->quantum - quan_rest; } if (copy_to_user(buf, p_qset->data[quan_index] + quan_rest, count)) { retval = -EFAULT; goto out; } *f_ops += count; retval = count; out: up(&dev->sem); return retval; } ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops) { struct scull_dev *dev = filp->private_data; struct scull_qset *p_qset = NULL; int qset_size = dev->quantum * dev->qset; int qset_index,qset_rest; int quan_index,quan_rest; ssize_t retval = -ENOMEM; if(down_interruptible(&dev->sem)) return -ERESTARTSYS; qset_index = (long)*f_ops / qset_size; qset_rest = (long)*f_ops % qset_size; quan_index = qset_rest / dev->quantum; quan_rest = qset_rest % dev->quantum; p_qset = scull_follow(dev, qset_index); if (p_qset == NULL) goto out; if (p_qset->data[quan_index] == NULL) { p_qset->data[quan_index] = kmalloc(dev->quantum, GFP_KERNEL); if (p_qset->data[quan_index] == NULL) goto out; } if (count > (dev->quantum - quan_rest)) { count = dev->quantum - quan_rest; } if (copy_from_user(p_qset->data[quan_index] + quan_rest, buf, count)) { retval = -EFAULT; goto out; } *f_ops += count; retval = count; if (dev->size < *f_ops) dev->size = *f_ops; out: up(&dev->sem); return retval; } int scull_ioctl(struct inode *p_inode, struct file *filp, unsigned int cmd, unsigned long args) { printk(KERN_ERR"ioctl\n"); return 0; } int scull_open(struct inode *p_inode, struct file *filp) { struct scull_dev *dev = NULL; dev = container_of(p_inode->i_cdev, struct scull_dev, cdev); filp->private_data = dev; //如果以append模式打开,则文件指针指向末尾 if (filp->f_flags & O_APPEND) { filp->f_pos = p_inode->i_size; } //如果以trunc模式打开,则将dev内容清除 if (filp->f_flags & O_TRUNC) { scull_trim(dev); p_inode->i_size = dev->size; } printk(KERN_ERR"file size = %ld\n",dev->size); return 0; } int scull_release(struct inode *p_inode, struct file *filp) { struct scull_dev *dev = filp->private_data; if(down_interruptible(&dev->sem)) return -ERESTARTSYS; //更新文件大小 p_inode->i_size = dev->size; up(&dev->sem); return 0; } static int scull_init(void) { int result = 0; //分配节点号 if ((result = alloc_chrdev_region(&g_scull_dev.dev_t, 0, 4, "scull")) < 0) { printk(KERN_ERR"alloc_chrdev_region error!\n"); return result; } //初始化cdev结构,并绑定file_operations和节点号 cdev_init(&g_scull_dev.cdev, &scull_fops); cdev_add(&g_scull_dev.cdev, g_scull_dev.dev_t, 4); printk(KERN_ERR"major = %d,minor = %d\n",MAJOR(g_scull_dev.dev_t),MINOR(g_scull_dev.dev_t)); //初始化设备结构体 g_scull_dev.qset = 4096; g_scull_dev.quantum = 4096; INIT_LIST_HEAD(&g_scull_dev.qset_head); sema_init(&g_scull_dev.sem, 1); return 0; } static void scull_exit(void) { cdev_del(&g_scull_dev.cdev); unregister_chrdev_region(g_scull_dev.dev_t, 1); scull_trim(&g_scull_dev); return; } module_init(scull_init); module_exit(scull_exit); MODULE_LICENSE("Dual BSD/GPL");
Makfile:
obj-m += scull.o KDIR := /home/linux-2.6.32.2 PWD = $(shell pwd) all: make -C $(KDIR) M=$(PWD) modules clean: rm -rf *.o
测试:
[root@FriendlyARM /nfs]# insmod scull.ko
major = 253,minor = 0
[root@FriendlyARM /nfs]# mknod /dev/scull0 c 253 0
相关文章推荐
- 转 字符设备驱动与块设备驱动的区别
- 块设备和字符设备区别
- linux驱动的动态加载和编译内核的方式加载
- JiamiJiemi
- Linux_ARM_字符串设备_按键中断驱动
- Linux驱动编程--字符设备文件注册
- linux驱动编程--几个重要函数及概念
- 基于MCP2515的Linux CAN总线驱动程序设计(二)
- 基于MCP2515的Linux CAN总线驱动程序设计(三)
- linux 内核编程之字符设备驱动
- linux中的字符设备与块设备
- 通用i2c驱动
- 字符设备驱动内核框架小结(一)
- 第一个字符设备驱动
- 字符设备驱动程序内核机制
- 字符设备打开操作的过程详解
- [快速上手Linux设备驱动]之我看字符设备驱动
- linux 驱动分类
- LINUX之设备驱动开发概述
- Linux内核模块编程-字符设备驱动