ldd3 chapter3 字符驱动简单记录

来源:互联网 发布:淘宝网能用货到付款 编辑:程序博客网 时间:2024/06/07 03:06

动态分配节点号:

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.oKDIR := /home/linux-2.6.32.2PWD = $(shell pwd)all:make -C $(KDIR) M=$(PWD) modulesclean:rm -rf *.o

测试:

[root@FriendlyARM /nfs]# insmod scull.ko
major = 253,minor = 0
[root@FriendlyARM /nfs]# mknod /dev/scull0 c 253 0


0 0
原创粉丝点击