免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1268 | 回复: 0
打印 上一主题 下一主题

转载:ldd3第三章Scull代码解析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-14 01:27 |只看该作者 |倒序浏览
转载:ldd3第三章Scull代码解析
来源:
http://ardam331.blog.163.com/blog/static/5691238220071117561920/
上次看的那个led设备的驱动程序相对来说比较简单些。而且功能也不是很全面。今天打算总结一下书中第3章给出的实例。        从外到内一步一步讲吧!一、初始化和退出模块这个没什么讲的了,就是告诉内核是哪个函数负责这个功能的。
module_init(scull_init_module);module_exit(scull_cleanup_module);
初始化模块的函数
int scull_init_module(void){    int result, i;    dev_t dev = 0;/* * Get a range of minor numbers to work with, asking for a dynamic * major unless directed otherwise at load time. */
//如果有主设备号,那说明就是事先分配好的主设备号。就应该用静态分配设备号,不然就动态分配。    if (scull_major) {        dev = MKDEV(scull_major, scull_minor);        result = register_chrdev_region(dev, scull_nr_devs, "scull");    } else {        result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,                "scull");        scull_major = MAJOR(dev);    }    if (result         printk(KERN_WARNING "scull: can't get major %d ", scull_major);        return result;    }        /*      * allocate the devices -- we can't have them static, as the number     * can be specified at load time     */
//这里为scull_dev设备分配空间一共分配4个scull_dev大小的空间因为有4个scull设备在/dev下。    scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);    if (!scull_devices) {        result = -ENOMEM;        goto fail;  /* Make this more graceful */    }    memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));//初始化每一个设备        /* Initialize each device. */    for (i = 0; i         scull_devices.quantum = scull_quantum;//当前的分配尺寸,是1000        scull_devices.qset = scull_qset;//当前的数组大小,是4000字节        init_MUTEX(&scull_devices.sem);//互斥信号量,这章好像还没用上。        scull_setup_cdev(&scull_devices, i);//字符设备注册    }//其他的相关scull设备初始化和本章无关。        /* At this point call the init function for any friend device */    dev = MKDEV(scull_major, scull_minor + scull_nr_devs);    dev += scull_p_init(dev);    dev += scull_access_init(dev);#ifdef SCULL_DEBUG /* only when debugging */    scull_create_proc();#endif    return 0; /* succeed */  fail:    scull_cleanup_module();    return result;}
注销模块函数
void scull_cleanup_module(void)
{
    int i;
    dev_t devno = MKDEV(scull_major, scull_minor);//得到设备号,如果注册时候有设备号的情况。
    /* Get rid of our char dev entries */
    if (scull_devices) {
        for (i = 0; i //清空设备结构的内容
            cdev_del(&scull_devices.cdev);//删除字符设备
        }
        kfree(scull_devices);//释放字符设备结构占用的空间
    }
#ifdef SCULL_DEBUG /* use proc only if debugging */
    scull_remove_proc();
#endif
    /* cleanup_module is never called if registering failed */
    unregister_chrdev_region(devno, scull_nr_devs);
//删除其他的scull相关设备,也就是前面提到的其他的scull版本
    /* and call the cleanup functions for friend devices */
    scull_p_cleanup();
    scull_access_cleanup();
}
二、open和release函数
int scull_open(struct inode *inode, struct file *filp)
{
    struct scull_dev *dev; /* device information *///首先声明了一个scull_dev设备的指针
    dev = container_of(inode->i_cdev, struct scull_dev, cdev);//通过inode的i_cdev结构也就是cdev结构我们可以得到自己定义的scull_dev结构指针。
    filp->private_data = dev; /* for other methods *///将找到的指针保存到file结构中的private_data字段中,用以备用。
    /* now trim to 0 the length of the device if open was write-only */
    if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
        if (down_interruptible(&dev->sem))
            return -ERESTARTSYS;
        scull_trim(dev); /* ignore errors *///如果以只写方式打开的话对结构清零。
        up(&dev->sem);
    }
    return 0;          /* success */
}
int scull_release(struct inode *inode, struct file *filp)
{
    return 0;
}
三、读写函数
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,                loff_t *f_pos){    struct scull_dev *dev = filp->private_data; //定义一个scull_dev设备类型指针指向在open函数找到的scull_dev设备类型保存在file的private_data中。    struct scull_qset *dptr;    /* the first listitem *///第一个量子集链表项    int quantum = dev->quantum, qset = dev->qset;//量子的大小和数组的大小    int itemsize = quantum * qset; /* how many bytes in the listitem *///每个链表项的总字节数这里是4000*1000    int item, s_pos, q_pos, rest;//第几个量子以及当前量子的第多少个位置    ssize_t retval = 0;    if (down_interruptible(&dev->sem))        return -ERESTARTSYS;    if (*f_pos >= dev->size)//是否偏移量大于了设备结构的尺寸        goto out;    if (*f_pos + count > dev->size)//如果偏移量加读取的数量大于设备结构的尺寸,那么吧读取数量改成只读到设备结构的最后为止。        count = dev->size - *f_pos;//算出偏移量在第几个量子集的什么位置。    /* find listitem, qset index, and offset in the quantum */    item = (long)*f_pos / itemsize;    rest = (long)*f_pos % itemsize;    s_pos = rest / quantum; q_pos = rest % quantum;    /* follow the list up to the right position (defined elsewhere) */    dptr = scull_follow(dev, item);//从链表头一直找到链表的末端,如果中间的位置是NULL那就给它分配空间。    if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])        goto out; /* don't fill holes */    /* read only up to the end of this quantum */
//只读取到当前量子的末端。如果不是count所希望的,那就再次调用read读取下一个量子。    if (count > quantum - q_pos)        count = quantum - q_pos;//把当前量子中从开始一直到量子结束的内容拷贝到用户空间    if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {        retval = -EFAULT;        goto out;    }    *f_pos += 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_pos){    struct scull_dev *dev = filp->private_data;    struct scull_qset *dptr;    int quantum = dev->quantum, qset = dev->qset;    int itemsize = quantum * qset;    int item, s_pos, q_pos, rest;    ssize_t retval = -ENOMEM; /* value used in "goto out" statements */    if (down_interruptible(&dev->sem))        return -ERESTARTSYS;    /* find listitem, qset index and offset in the quantum */    item = (long)*f_pos / itemsize;    rest = (long)*f_pos % itemsize;    s_pos = rest / quantum; q_pos = rest % quantum;    /* follow the list up to the right position */    dptr = scull_follow(dev, item);    if (dptr == NULL)        goto out;
//如果当前的首指针是NULL那就分配一个量子的空间4000字节    if (!dptr->data) {        dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);        if (!dptr->data)            goto out;        memset(dptr->data, 0, qset * sizeof(char *));    }
//如果指向的需要拷贝数据的地方为NULL那就分配1000个数组指针    if (!dptr->data[s_pos]) {        dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);        if (!dptr->data[s_pos])            goto out;    }    /* write only up to the end of this quantum */    if (count > quantum - q_pos)        count = quantum - q_pos;    if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {        retval = -EFAULT;        goto out;    }    *f_pos += count;    retval = count;        /* update the size */    if (dev->size         dev->size = *f_pos;  out:    up(&dev->sem);    return retval;}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/100532/showart_1995189.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP