Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20339
  • 博文数量: 8
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-23 14:34
文章分类
文章存档

2012年(8)

我的朋友
最近访客

分类:

2012-12-01 22:34:03

        参考《Linux设备驱动程序》及其代码,写了一个简单的字符设备驱动,相比作者提供的要简单很多,我在ubuntu10.04的系统上已测试,能运行起来。因水平有限,只实现了open,release,write及read四个基本的接口,且使用测试程序运行时存在明显的bug,望志同道合的朋友一起完善。

头文件部分的定义:

  1. #ifndef __SCULL_H__
  2. #define __SCULL_H__

  3. #ifndef SCULL_MAJOR
  4. #define SCULL_MAJOR 0
  5. #endif

  6. #ifndef SCULL_MINOR
  7. #define SCULL_MINOR 0
  8. #endif

  9. typedef struct _scull_dev_ {
  10.     void **data;     
  11.        int quantum;
  12.        int qset;
  13.        unsigned long size;
  14.        struct semaphore sem;
  15.     struct cdev cdev;

  16. } SCULL_DEV,pSCULL_DEV;

  17. #endif
驱动程序:
  1. /*
  2.  * name:scull.c
  3.  * function:scull character device driver
  4.  * time:2012-2-19
  5.  *
  6.  * author:txgcwm
  7.  * mail:txgcwm@163.com
  8.  * reference:Linux设备驱动程序(第三版)
  9.  */

  10. #ifndef __KERNEL__
  11. # define __KERNEL__
  12. #endif
  13. #ifndef MODULE
  14. # define MODULE
  15. #endif

  16. #include <linux/init.h>
  17. #include <linux/module.h>
  18. #include <linux/cdev.h>
  19. #include <linux/slab.h>
  20. #include <linux/kernel.h> /* printk() */
  21. #include <linux/fs.h> /* everything... */
  22. #include <linux/errno.h> /* error codes */
  23. #include <linux/types.h> /* size_t */
  24. #include <linux/proc_fs.h>
  25. #include <linux/fcntl.h> /* O_ACCMODE */
  26. #include <asm/system.h> /* cli(), *_flags */
  27. #include <asm/uaccess.h>

  28. #include "scull.h" /* local definitions */


  29. int scull_major = SCULL_MAJOR;
  30. int scull_minor    = SCULL_MINOR;
  31. int scull_mn_dev = 1;
  32. int scull_quantum = 4000;    /*每个指针所指向存储单元的大小*/
  33. int scull_qset = 1000;    /*指针数组的大小*/
  34. static pSCULL_DEV *pscull_dev = NULL;


  35. int scull_trim(SCULL_DEV *dev)
  36. {
  37.     int i = 0;
  38.     int qset = dev->qset;

  39.     if (dev->data)
  40.     {
  41.         for(i = 0; i < qset; i++)
  42.         {
  43.             if (dev->data[i])
  44.                 kfree(dev->data[i]);
  45.         }

  46.         kfree(dev->data);
  47.         dev->data=NULL;
  48.     }

  49.     dev->size = 0;
  50.     dev->quantum = scull_quantum;
  51.     dev->qset = scull_qset;
  52.  
  53.     return 0;
  54. }

  55. int scull_open(struct inode *inode, struct file *filp)
  56. {
  57.     SCULL_DEV *dev = NULL;

  58.     dev = container_of(inode->i_cdev,pSCULL_DEV,cdev);
  59.     filp->private_data = dev;
  60.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
  61.     {
  62.         scull_trim(dev);
  63.     }

  64.     return 0;
  65. }

  66. int scull_release(struct inode *inode, struct file *filp)
  67. {
  68.     return 0;
  69. }

  70. ssize_t scull_read(struct file *filp, char *buf, size_t count,loff_t *f_pos)
  71. {
  72.     SCULL_DEV *dev = filp->private_data;
  73.     int quantum = dev->quantum;
  74.     int qset = dev->qset;
  75.     int s_pos, q_pos;
  76.     ssize_t ret = 0;

  77.     if(down_interruptible(&dev->sem))
  78.         return -ERESTARTSYS;
  79.     if(*f_pos >= dev->size)
  80.         goto out;
  81.     if(*f_pos + count > dev->size)
  82.         count = dev->size - *f_pos;
  83.     
  84.     s_pos = (long)*f_pos / quantum;
  85.     q_pos = (long)*f_pos % quantum;

  86.     if(s_pos > qset)
  87.         goto out;
  88.     if(!dev->data)
  89.         goto out;
  90.     if(!dev->data[s_pos])
  91.         goto out;
  92.     
  93.     if(count > quantum - q_pos)
  94.         count = quantum - q_pos;

  95.     if(copy_to_user(buf, dev->data[s_pos]+q_pos, count)) /*将内核空间的数据拷贝到用户空间*/
  96.     {
  97.         ret = -EFAULT;
  98.         goto out;
  99.     }
  100.     *f_pos += count;
  101.     ret = count;

  102.  out:
  103.     up(&dev->sem);
  104.     return ret;    
  105. }

  106. ssize_t scull_write(struct file *filp, const char *buf, size_t count,loff_t *f_pos)
  107. {
  108.     SCULL_DEV *dev = filp->private_data;
  109.     int quantum = dev->quantum;
  110.     int qset = dev->qset;
  111.     int s_pos,q_pos;
  112.     ssize_t ret = -ENOMEM;

  113.     if(down_interruptible(&dev->sem))
  114.         return -ERESTARTSYS;

  115.     s_pos = (long)*f_pos / quantum;
  116.     q_pos = (long)*f_pos % quantum;

  117.     if(!dev->data)
  118.     {
  119.         dev->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
  120.         if (!dev->data)
  121.             goto out;
  122.         memset(dev->data, 0, qset * sizeof(char *));
  123.     }

  124.     if(!dev->data[s_pos])
  125.     {
  126.         dev->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
  127.         if (!dev->data[s_pos])
  128.             goto out;
  129.     }

  130.     if(count > quantum - q_pos)
  131.         count = quantum - q_pos;

  132.     if(copy_from_user(dev->data[s_pos]+q_pos, buf, count))    /*将用户空间的数据拷贝到内核空间*/
  133.     {
  134.         ret = -EFAULT;
  135.         goto out;
  136.     }
  137.     *f_pos += count;
  138.     ret = count;

  139.     if(dev->size < *f_pos)
  140.         dev->size = *f_pos;

  141.   out:
  142.     up(&dev->sem);
  143.     return ret;
  144. }

  145. int scull_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
  146. {
  147.     return 0;
  148. }

  149. loff_t scull_llseek(struct file *filp, loff_t off, int whence)
  150. {
  151.     return 0;
  152. }

  153. struct file_operations scull_fops = {
  154.     .owner     =    THIS_MODULE,
  155.     .llseek    =    scull_llseek,
  156.     .read    =    scull_read,
  157.     .write    =    scull_write,
  158.     .ioctl    =    scull_ioctl,
  159.     .open    =    scull_open,
  160.     .release =    scull_release,
  161. };

  162. static void scull_cleanup_module(void)
  163. {
  164.     dev_t dev;

  165.     dev = MKDEV(scull_major,scull_minor);
  166.     cdev_del(&pscull_dev->cdev);
  167.     unregister_chrdev_region(dev,scull_mn_dev);
  168.     scull_trim(pscull_dev);
  169.     kfree(pscull_dev);
  170.     pscull_dev = NULL;    
  171.     printk(KERN_EMERG"Leave World!\n");

  172.     return;
  173. }

  174. static int scull_init_module(void)
  175. {
  176.     dev_t dev;
  177.     int result = -1;

  178.     pscull_dev = kmalloc(sizeof(SCULL_DEV),GFP_KERNEL);
  179.     if(pscull_dev == NULL)
  180.     {
  181.         printk(KERN_WARNING"scull: can't kmalloc memory\n");
  182.         result = -ENOMEM;
  183.         return result;
  184.     }
  185.     memset(pscull_dev,0,sizeof(SCULL_DEV));
  186.     pscull_dev->data = NULL;
  187.     pscull_dev->quantum = scull_quantum;
  188.     pscull_dev->qset = scull_qset;
  189.     sema_init(&pscull_dev->sem, 1);

  190.     if(scull_major)
  191.     {
  192.         dev = MKDEV(scull_major,scull_minor);    
  193.         result = register_chrdev_region(dev,scull_mn_dev,"scull");
  194.     }
  195.     else
  196.     {
  197.         result = alloc_chrdev_region(&dev,scull_minor,scull_mn_dev,"scull");
  198.         scull_major = MAJOR(dev);
  199.     }

  200.     if(result < 0)
  201.     {
  202.         printk(KERN_WARNING"scull: can't get major %d\n",scull_major);
  203.         return result;
  204.     }

  205.     cdev_init(&pscull_dev->cdev,&scull_fops);
  206.     pscull_dev->cdev.owner = THIS_MODULE;
  207.     pscull_dev->cdev.ops = &scull_fops;
  208.     result = cdev_add(&pscull_dev->cdev,dev,1);
  209.     if(result)
  210.     {
  211.         printk(KERN_NOTICE"Error %d add scull device\n",result);
  212.         goto fail;
  213.     }
  214.     printk(KERN_EMERG"Hello World!\n");
  215.     return 0;

  216.   fail:
  217.     scull_cleanup_module();

  218.     return result;
  219. }



  220. module_init(scull_init_module);
  221. module_exit(scull_cleanup_module);

  222. MODULE_AUTHOR("txgcwm");
  223. MODULE_VERSION("scull_v1.0");
  224. MODULE_LICENSE("GPL");

附件包含了驱动程序,测试程序,启动及卸载脚本。

参考书籍:
       《Linux设备驱动程序第三版》
                                                                            scull.rar  
阅读(1061) | 评论(0) | 转发(0) |
0

上一篇:Linux中的工作队列

下一篇:没有了

给主人留下些什么吧!~~