Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65051
  • 博文数量: 21
  • 博客积分: 290
  • 博客等级: 二等列兵
  • 技术积分: 286
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 16:16
文章分类
文章存档

2019年(3)

2017年(1)

2012年(17)

我的朋友

分类: LINUX

2012-04-02 09:30:07

    看了前面那些文邹邹的文字,看得就不舒服,相信大家也一样。所以今天就把代码贴一下,以供大家更
 
好理解,同时也希望各位大侠多多指点指点,我将不胜感激。
 
    那我们如何验证自己所写的驱动程序功能,那就得看看我们实现了哪些模块了。后面我将为大家演示下
 
面代码在S3C2440开发板的实验结果。
 
   一、源程序,这是一个实验程序而已,以后会慢慢完善其功能。俗话说的好:麻雀虽小,五脏俱全。希
 
望这个小小实验能带给大家兴趣。
 
这是chrdev.h文件

点击(此处)折叠或打开

  1. #ifndef __CHRDEV_H__
  2. #define __CHRDEV_H__

  3. #include <linux/cdev.h>
  4. #include <linux/wait.h>

  5. #ifndef DEV_SIZE
  6. #define DEV_SIZE 4096
  7. #endif

  8. struct own_dev
  9. {
  10.     bool data_flag;
  11.     char *p_cdata;
  12.     size_t size;
  13.     //wait_queue_head_t inq;
  14.     struct cdev cdev;
  15. };

  16. int chr_open(struct inode *inode, struct file *filp);

  17. int chr_release(struct inode *inode, struct file *filp);

  18. ssize_t chr_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);

  19. ssize_t chr_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

  20. #endif
 
这是chrdev.c文件
  

点击(此处)折叠或打开

  1. /******************************************************************************
  2. *
  3. *    Copyright (C), 2012, XXX有限公司 All rights reserved.
  4. *    @file         chrdev.c
  5. *    @brief         实现char devive设备驱动
  6. *    
  7. *    @version       1.0.0
  8. *    @author        cyycyh
  9. *    @date         2012-04-02
  10. *    @section    history
  11. *                \<author\>\<time\>\<version\>\<desc\>
  12. *                @li    cyycyh 20120402 1.0.0 创建
  13. *
  14. ******************************************************************************/
  15. #include <linux/init.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/slab.h>
  19. #include <linux/moduleparam.h>
  20. #include <linux/fcntl.h>
  21. #include <linux/stat.h>
  22. #include <linux/gfp.h>
  23. #include <linux/fs.h>
  24. #include <linux/errno.h>
  25. #include <asm/uaccess.h>
  26. #include <linux/kdev_t.h>
  27. #include <linux/device.h>
  28. #include <linux/sched.h>
  29. #include <linux/version.h>
  30. #include <linux/utsrelease.h>
  31. #include <linux/string.h>

  32. #include "chrdev.h"

  33. #define DRIVE_NAME "chrdev"

  34. struct own_dev *p_chr_dev = NULL;
  35. struct class *p_chr_class = NULL;            // 设备类 /sys/class
  36. struct device *p_chr_device = NULL;            // hello的设备结构
  37. int chr_major = 255;                        // 主设备号变量
  38. int chr_minor     = 0;                            // 次设备号变量

  39. struct file_operations chr_fops =
  40. {
  41.     open: chr_open,
  42.     read: chr_read,
  43.     write: chr_write,
  44.     release: chr_release,
  45. };

  46. /*
  47.  * 模块参数,以供参数输入使用
  48.  */
  49. module_param(chr_major, int, S_IRUGO);
  50. module_param(chr_minor, int, S_IRUGO);

  51. /*
  52.  * @brief            打开设备
  53.  * @param[in]        inode                        文件节点
  54.  * @param[out]        filp                        文件结构
  55.  * @return             @li 0                            
  56.  */
  57. int chr_open(struct inode *inode, struct file *filp)
  58. {
  59.    /**获取自己数据结构**/
  60.    struct own_dev *dev;
  61.    dev = container_of(inode->i_cdev, struct own_dev, cdev);
  62.    filp->private_data = dev;
  63.    
  64.    /**判断文件读取模式**/
  65.    if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
  66.      {
  67.          printk(KERN_ALERT"cyycyh\n");; //...应该做什么操作哦
  68.      }
  69.      //MOD_INC_USE_COUNT; //?为何会报错
  70.    printk(KERN_ALERT"chrdev open\n");
  71.    
  72.      return 0;
  73. }

  74. EXPORT_SYMBOL(chr_open);

  75. /*
  76.  * @brief             释放chrdev设备资源
  77.  * @param[in]         inode                        文件节点
  78.  * @param[out]        filp                        文件结构
  79.  * @return             @li 0                            
  80.  */
  81. int chr_release(struct inode *inode, struct file *filp)
  82. {
  83.     //MOD_DEC_USE_COUNT;
  84.     return 0;
  85. }

  86. /*
  87.  * @brief             读设备
  88.  * @param[in]        filp                        文件结构
  89.  * @param[in]        count                        读数据的字节数    
  90.  * @param[out]        buf                        输出数据的缓冲区
  91.  * @param[in|out]    f_pos                    文件指针的位置
  92.  * @return            读取的数据量    
  93.  *                    @li >= 0                    读取的字节数目
  94.  *                    @li < 0                        错误码
  95.  */
  96. ssize_t chr_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
  97. {
  98.     struct own_dev *dev =(struct own_dev *) filp->private_data;
  99.     ssize_t ret = 0;
  100.     
  101.     /**判断是否读有效**/
  102.   if (*f_pos > dev->size)
  103.     {
  104.         ret = -EFAULT;
  105.         goto read_out;
  106.     }
  107.     if (*f_pos + count > dev->size)
  108.     {
  109.         count = dev->size - *f_pos;
  110.     }
  111.     
  112.      //printk(KERN_ALERT"read : %s \n", dev->p_cdata);
  113.     
  114.     /**读取数据到用户空间**/
  115.     if (NULL == dev->p_cdata)
  116.     {
  117.         printk(KERN_ALERT"no data to read !\n");
  118.         goto read_out;
  119.     }
  120.     /*
  121.     while (!dev->data_flag) //为何用while 而非if
  122.     {
  123.         if (filp->f_flags & O_NONBLOCK)
  124.          return -EAGAIN;
  125.         
  126.     //    wait_event_interruptible(dev->inq, dev->data_flag);
  127.     }
  128.     */

  129.      if (copy_to_user(buf, dev->p_cdata, count))
  130.      {
  131.          ret = -EFAULT;
  132.          goto read_out;
  133.      };
  134.     
  135.      *f_pos += count;
  136.       ret = count;
  137.     
  138.     /*为何要做这样的判断*/
  139.      if (dev->p_cdata[count] == '\0')
  140.      { 
  141.         ret = 0;
  142.      }
  143. read_out :
  144.      printk(KERN_ALERT"read over!\n");
  145.      return ret;    
  146. }

  147. EXPORT_SYMBOL(chr_read);

  148. /*
  149.  * @brief            写chr设备
  150.  * @param[in]        filp                        文件结构
  151.  * @param[in]        count                        读数据的字节数    
  152.  * @param[in]        buf                            输出数据的缓冲区
  153.  * @param[in|out]    f_pos                        文件指针的位置
  154.  * @return            写出结果    
  155.  *                    @li >= 0                    写入的字节数量
  156.  *                    @li < 0                        错误码
  157.  */
  158. ssize_t chr_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
  159. {
  160.     struct own_dev *dev =(struct own_dev *)filp->private_data;
  161.     ssize_t ret = -ENOMEM; //why -ENOMEM
  162.     
  163.     /**判断是否写有效**/
  164.   
  165.   if (*f_pos > dev->size)
  166.   {
  167.       goto write_out;
  168.   }
  169.  /*//为何会无限循环
  170.   if (*f_pos + count >= dev->size)
  171.   {
  172.       count = dev->size - *f_pos;
  173.   }
  174.   */

  175.   /**从用户空间写数据到内核**/ //为何要count + 1呢
  176.   dev->p_cdata = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
  177.   if (NULL == dev->p_cdata)
  178.   {
  179.        printk(KERN_ALERT"no RAM to write\n");
  180.        goto write_out;
  181.   }
  182.   
  183.   dev->size = (count + 1) * sizeof(char);
  184.   if (copy_from_user(dev->p_cdata, buf, count))
  185.   {
  186.       ret = -EFAULT;
  187.      goto write_out;
  188.   };
  189.   dev->p_cdata[count] = '\0'; //记住:结束符
  190.   
  191. // printk(KERN_ALERT"write : %s \n", dev->p_cdata);
  192.   
  193.   *f_pos += count;
  194.    ret = count;
  195.    
  196.   // dev->data_flag = 1;
  197.   // wake_up(&(dev->inq))
  198.   
  199. write_out :
  200.     printk(KERN_ALERT"write over !\n");
  201.     
  202.     return ret;
  203. }

  204. EXPORT_SYMBOL(chr_write);

  205. /*
  206.  * @brief        chr驱动初始化
  207.  */
  208. static int __init chr_init(void)
  209. {
  210.     dev_t dev_no;
  211.     int err = 0;
  212.     
  213. #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
  214.     printk(KERN_ALERT"UTS_RELEASE=%s\n", UTS_RELEASE);
  215. #endif
  216.     printk(KERN_ALERT"Char dev!\n");
  217.     
  218.     // 注册设备号
  219.      if (chr_major != 0)
  220.      {
  221.          dev_no = MKDEV(chr_major, chr_minor);
  222.          err = register_chrdev_region(dev_no, 1, DRIVE_NAME);
  223.      }
  224.      else
  225.      {
  226.          err = alloc_chrdev_region(&dev_no, chr_minor, 1, DRIVE_NAME);
  227.          chr_major = MAJOR(dev_no);
  228.      }
  229.      if (err < 0)
  230.      {
  231.          printk(KERN_WARNING"hello: can't get major %d\n", chr_major);
  232.          goto dev_no_fail;
  233.      }
  234.    /**初始化数据结构**/
  235.     /*
  236.      *1、分配cdev 动态或者静态
  237.      *2、初始化cdev
  238.      *3、注册cdev即通知内核
  239.      */
  240.      p_chr_dev = kmalloc(sizeof(struct own_dev), GFP_KERNEL);    
  241.    if (NULL == p_chr_dev)
  242.    {
  243.        printk(KERN_WARNING"own_dev can't kmalloc \n");
  244.         goto kmalloc_fail;
  245.    }
  246.   // init_waitqueue_head(&(p_chr_dev->inq));
  247.    p_chr_dev->data_flag = 0;
  248.    p_chr_dev->p_cdata = NULL;
  249.    p_chr_dev->size = 0;
  250.    cdev_init(&p_chr_dev->cdev, &chr_fops);
  251.    p_chr_dev->cdev.owner = THIS_MODULE;
  252.    p_chr_dev->cdev.ops = &chr_fops;
  253.    err = cdev_add(&p_chr_dev->cdev, dev_no, 1);
  254.      if (err)
  255.      {
  256.          printk(KERN_WARNING "chr: error %d adding led", err);
  257.          goto cdev_add_fail;
  258.      }
  259.     
  260.      // 创建设备类 /sys/class
  261.     /*
  262.      *创建之后用IS_ERR判断是否有错
  263.      *若错用PTR_ERR获取错误码
  264.      */
  265.      p_chr_class = class_create(THIS_MODULE, DRIVE_NAME);
  266.      if (IS_ERR(p_chr_class))
  267.      {
  268.          printk(KERN_WARNING"chr: can't create class %ld\n", PTR_ERR(p_chr_class));
  269.          goto class_fail;
  270.      }
  271.      p_chr_device = device_create(p_chr_class, NULL, dev_no, NULL, DRIVE_NAME);
  272.      if (IS_ERR(p_chr_device))
  273.      {
  274.       printk(KERN_WARNING "chr: create device fail, error code %ld", PTR_ERR(p_chr_device));
  275.          goto device_fail;
  276.      }
  277.      else
  278.      {
  279.          goto exit_ok;
  280.      }
  281. device_fail:
  282.     class_destroy(p_chr_class);    
  283. class_fail:
  284.     cdev_del(&p_chr_dev->cdev);    
  285. cdev_add_fail:
  286.     kfree(p_chr_dev);
  287. kmalloc_fail:
  288.     unregister_chrdev_region(dev_no, 1);
  289. dev_no_fail:
  290.     
  291. exit_ok:    
  292.     return 0;
  293. }

  294. /*
  295.  * @brief        chr驱动退出
  296.  */
  297. static void __exit chr_exit(void)
  298. {
  299.     dev_t dev_no = MKDEV(chr_major, chr_minor);
  300.     
  301.     printk(KERN_ALERT"Goodbye,chr!\n");
  302.    
  303.     device_destroy(p_chr_class, dev_no);
  304.     class_destroy(p_chr_class);
  305.     cdev_del(&p_chr_dev->cdev);    
  306.     kfree(p_chr_dev->p_cdata);
  307.     kfree(p_chr_dev);
  308.     unregister_chrdev_region(dev_no, 1);
  309. }

  310. module_init(chr_init);
  311. module_exit(chr_exit);
  312. MODULE_LICENSE("Dual BSD/GPL");
  313. MODULE_AUTHOR("cyycyh");
  314. MODULE_DESCRIPTION("This module is char dev");
  315. MODULE_VERSION("v1.0.0");
  316. MODULE_ALIAS("chr_alias");

   二、开发板操作

   1、首先进入我们所要操作的目录:我以 /lib/modules 目录为例

   cd /lib/modules/

   2、下载 xxx.ko (chrdev.ko)文件至开发板

   rz 或者 lrz 或者采用网络服务都可以

   3、加载模块

   insmod chrdev.ko

   4、查看是否加载成功

   lsmod

   若加载成功,则会提醒:chrdev 2023 0 - Live 0xbf000000

   5、前期工作都做好,这下做一些功能性测试

   验证设备号,是否被注册,

   cat /proc/devices

   若注册成功,则有我们所申请的设备号/设备名称:

 Character devices:
  255 chrdev        //这个就是我们所申请的设备号
  1 mem
  4 /dev/vc/0
  4 tty

   6、查看我们所创建的类是否创建成功

   ls /dev/chrdev(这是在/dev 下的类,可以跟下面类名称不同,但一般采用同名称)

   ls /sys/class/chrdev/chrdev/  (这是在虚拟文件系统中的类/sys/class)

   cat /sys/class/chrdev/chrdev/dev (可以获得给设备的主设备号和次设备号)

   7、模块参数检查

   ls /sys/module/chrdev/parameters/    (查看模块参数目录)

   cat /sys/module/chrdev/parameters/参数名称 (获取参数内容)

   8、测试操作方法(struct file_operations)【这是简单测试,一般要写应用程序测试】

   echo "字符串">/dev/chrdev (往设备写)

   cat


阅读(1048) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~