Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112614
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2013-09-03 16:50:46

一. 一个简洁的scull_ch3
在看的第三章 字符设备驱动程序时,发现源码中没有比较简洁的scull,(类似于helloworld,只包含所讲的内容的代码).
下面就整一个scull_ch3,
         a. 只包含所讲的内容,文件操作接口只有 open read write release
         b. 删去了 proc pipe等以后章节讲的代码
         c. 增加了自动创建设备节点,省去了手动mknod的麻烦.
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/kernel.h>    /* printk() */
  4. #include <linux/slab.h>      /* kmalloc() */
  5. #include <linux/fs.h>        /* everything... */
  6. #include <linux/errno.h>     /* error codes */
  7. #include <linux/types.h>     /* size_t */
  8. #include <linux/seq_file.h>
  9. #include <linux/cdev.h>
  10. #include <linux/device.h>    /*class device*/

  11. #include <asm/uaccess.h>     /*copy_from_user*/

  12. #define SCULL_MAJOR 0        /* dynamic major by default */
  13. #define SCULL_NR_DEVS 4      /* scull0 through scull3 */
  14. #define SCULL_QUANTUM 4000
  15. #define SCULL_QSET 1000

  16. int scull_major = SCULL_MAJOR;
  17. int scull_minor = 0;
  18. int scull_nr_devs = SCULL_NR_DEVS;    /* number of bare scull devices */
  19. int scull_quantum = SCULL_QUANTUM;
  20. int scull_qset = SCULL_QSET;

  21. struct scull_qset {
  22.     void **data;
  23.     struct scull_qset *next;
  24. };

  25. struct scull_dev {
  26.     struct scull_qset *data;     /* Pointer to first quantum set */
  27.     int quantum;                 /* the current quantum size */
  28.     int qset;                    /* the current array size */
  29.     unsigned long size;          /* amount of data stored here */
  30.     struct cdev cdev;            /* Char device structure        */
  31.     struct class *cls;
  32. };
  33. struct scull_dev *scull_devices;

  34. int scull_trim(struct scull_dev *dev)
  35. {
  36.     struct scull_qset *next, *dptr;
  37.     int qset = dev->qset;      /* "dev" is not-null */
  38.     int i;
  39.     /* all the list items */
  40.     for (dptr = dev->data; dptr; dptr = next) {
  41.         if (dptr->data) {
  42.             for (i = 0; i < qset; i++)
  43.                 kfree(dptr->data[i]);
  44.             kfree(dptr->data);
  45.             dptr->data = NULL;
  46.         }
  47.         next = dptr->next;
  48.         kfree(dptr);
  49.     }
  50.     dev->size = 0;
  51.     dev->quantum = scull_quantum;
  52.     dev->qset = scull_qset;
  53.     dev->data = NULL;
  54.     return 0;
  55. }
  56. static int scull_open(struct inode* node, struct file *filp)
  57. {
  58.     struct scull_dev *dev; /* device information */

  59.     dev = container_of(node->i_cdev, struct scull_dev, cdev);
  60.     filp->private_data = dev;
  61.     return 0; /* success */
  62. }

  63. struct scull_qset *scull_follow(struct scull_dev *dev, int n)
  64. {
  65.     struct scull_qset *qs = dev->data;

  66.     /* Allocate first qset explicitly if need be */
  67.     if (! qs) {
  68.         qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
  69.         if (qs == NULL)
  70.             return NULL; /* Never mind */
  71.         memset(qs, 0, sizeof(struct scull_qset));
  72.     }

  73.     /* Then follow the list */
  74.     while (n--) {
  75.         if (!qs->next) {
  76.             qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
  77.             if (qs->next == NULL)
  78.                 return NULL; /* Never mind */
  79.             memset(qs->next, 0, sizeof(struct scull_qset));
  80.         }
  81.         qs = qs->next;
  82.         continue;
  83.     }
  84.     return qs;
  85. }


  86. static ssize_t scull_read(struct file* filp, char __user *buf, size_t count, loff_t *f_pos)
  87. {
  88.     struct scull_dev *dev = filp->private_data;
  89.     struct scull_qset *dptr;    /* the first listitem */
  90.     int quantum = dev->quantum, qset = dev->qset;
  91.     int itemsize = quantum * qset; /* how many bytes in the listitem */
  92.     int item, s_pos, q_pos, rest;
  93.     ssize_t retval = 0;

  94.     if (*f_pos >= dev->size)
  95.         goto out;
  96.     if (*f_pos + count > dev->size)
  97.         count = dev->size - *f_pos;

  98.     /* find listitem, qset index, and offset in the quantum */
  99.     item = (long)*f_pos / itemsize;
  100.     rest = (long)*f_pos % itemsize;
  101.     s_pos = rest / quantum; q_pos = rest % quantum;

  102.     /* follow the list up to the right position (defined elsewhere) */
  103.     dptr = scull_follow(dev, item);

  104.     if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])
  105.         goto out; /* don't fill holes */

  106.     /* read only up to the end of this quantum */
  107.     if (count > quantum - q_pos)
  108.         count = quantum - q_pos;

  109.     if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
  110.         retval = -EFAULT;
  111.         goto out;
  112.     }
  113.     *f_pos += count;
  114.     retval = count;

  115.   out:
  116.     return retval;
  117. }

  118. static ssize_t scull_write(struct file* filp, const char __user *buf, size_t count, loff_t *f_pos)
  119. {
  120.     struct scull_dev *dev = filp->private_data;
  121.     struct scull_qset *dptr;
  122.     int quantum = dev->quantum, qset = dev->qset;
  123.     int itemsize = quantum * qset;
  124.     int item, s_pos, q_pos, rest;
  125.     ssize_t retval = -ENOMEM; /* value used in "goto out" statements */


  126.     /* find listitem, qset index and offset in the quantum */
  127.     item = (long)*f_pos / itemsize;
  128.     rest = (long)*f_pos % itemsize;
  129.     s_pos = rest / quantum; q_pos = rest % quantum;

  130.     /* follow the list up to the right position */
  131.     dptr = scull_follow(dev, item);
  132.     if (dptr == NULL)
  133.         goto out;
  134.     if (!dptr->data) {
  135.         dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
  136.         if (!dptr->data)
  137.             goto out;
  138.         memset(dptr->data, 0, qset * sizeof(char *));
  139.     }
  140.     if (!dptr->data[s_pos]) {
  141.         dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
  142.         if (!dptr->data[s_pos])
  143.             goto out;
  144.     }
  145.     /* write only up to the end of this quantum */
  146.     if (count > quantum - q_pos)
  147.         count = quantum - q_pos;

  148.     if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
  149.         retval = -EFAULT;
  150.         goto out;
  151.     }
  152.     *f_pos += count;
  153.     retval = count;

  154.         /* update the size */
  155.     if (dev->size < *f_pos)
  156.         dev->size = *f_pos;

  157.   out:
  158.     return retval;
  159. }

  160. static int scull_release(struct inode *node, struct file* filp)
  161. {
  162.     printk(KERN_ALERT "scull release!\n");
  163.     return 0;
  164. }
  165. static const struct file_operations scull_fops =
  166. {
  167.     .owner = THIS_MODULE,
  168.     .open = scull_open,
  169.     .read = scull_read,
  170.     .write = scull_write,
  171.     .release = scull_release,
  172. };

  173. static void __exit scull_exit(void)
  174. {
  175.     int i;
  176.     dev_t devno = MKDEV(scull_major, scull_minor);

  177.     printk(KERN_ALERT "goodbye scull dirver\n");
  178.     /* Get rid of our char dev entries */
  179.     if (scull_devices) {
  180.         for (i = 0; i < scull_nr_devs; i++) {
  181.             scull_trim(scull_devices + i);
  182.             cdev_del(&scull_devices[i].cdev);
  183.             //以下去掉增加自动创建的设备结点
  184.             device_destroy(scull_devices[i].cls, MKDEV(scull_major, i));
  185.             class_destroy(scull_devices[i].cls);
  186.         }
  187.         kfree(scull_devices);
  188.     }
  189.     unregister_chrdev_region(devno, scull_nr_devs);
  190.     return ;
  191. }

  192. static void scull_setup_cdev(struct scull_dev *dev, int index)
  193. {
  194.     int err, devno = MKDEV(scull_major, scull_minor + index);
  195.     char buf[128];
  196.     memset(buf, 0, sizeof(buf));

  197.     cdev_init(&dev->cdev, &scull_fops);
  198.     dev->cdev.owner = THIS_MODULE;
  199.     dev->cdev.ops = &scull_fops;
  200.     err = cdev_add (&dev->cdev, devno, 1);
  201.     if (err)
  202.         printk(KERN_NOTICE "Error %d adding scull%d", err, index);
  203.     //以下增加自动创建设备结点
  204.     sprintf(buf, "scull_class%d", index);
  205.     dev->cls = class_create(THIS_MODULE, buf);
  206.     if(IS_ERR(dev->cls))
  207.         printk(KERN_ALERT "class create error!\n");

  208.     device_create(dev->cls, NULL, devno, NULL, buf);
  209. }

  210. static int __init scull_init(void)
  211. {
  212.     int result, i;
  213.     dev_t dev = 0;
  214.     printk(KERN_NOTICE "scull_init\n");
  215.     if (scull_major) {
  216.         dev = MKDEV(scull_major, scull_minor);
  217.         result = register_chrdev_region(dev, scull_nr_devs, "scull");
  218.     } else {
  219.         result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
  220.         scull_major = MAJOR(dev);
  221.     }
  222.     if (result < 0) {
  223.         printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
  224.         goto fail;
  225.     }

  226.     /* allocate the devices -- we can't have them static, as the number
  227.      * can be specified at load time */
  228.     scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
  229.     if (!scull_devices) {
  230.         result = -ENOMEM;
  231.         goto fail;    /* Make this more graceful */
  232.     }
  233.     memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));

  234.         /* Initialize each device. */
  235.     for (i = 0; i < scull_nr_devs; i++) {
  236.         scull_devices[i].quantum = scull_quantum;
  237.         scull_devices[i].qset = scull_qset;
  238.         scull_setup_cdev(&scull_devices[i], i);
  239.     }
  240.     return 0;
  241. fail:
  242.   scull_exit();
  243.   return result;
  244. }

  245. MODULE_LICENSE("GPL");
  246. MODULE_AUTHOR("wangcong02345");
  247. module_init(scull_init);
  248. module_exit(scull_exit);






附代码下载:
ch3_scull.rar 
下载后改名: ch3_scull.tar.gz
阅读(1858) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~