zoukankan      html  css  js  c++  java
  • [Linux驱动]字符设备驱动学习笔记(二)———实例

    一,注册字符设备

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #define GLOBALMEM_MAJOR 256  
    2. #define GLOBALMEM_SIZE 0X1000 //4k  
    3. static int char_major=GLOBALMEM_MAJOR;//主设备号  
    4. struct chartest_dev  
    5. {  
    6.    struct cdev cdev;  
    7.    unsigned char mem[GLOBALMEM_SIZE];  
    8. };  
    9. struct chartest_dev glob_char_dev;//全局设备结构  
    10. static struct class *char_class=NULL;  
    11. static struct class_device *char_class_dev=NULL;  
    12. //-------------------------------------设备打开函数,匹配上层函数调用  
    13. static int char_open(struct inode *inode, struct file *filp)  
    14. {  
    15.   filp->private_data = &glob_char_dev;  
    16.   return 0;  
    17. }  
    18. //-------------------------------------从内核往用户空间拷贝读取数据  
    19. static  ssize_t  char_read(struct file* filp,char __user *buf,size_t count,loff_t *ppos)  
    20. {  
    21.         unsigned long p=*ppos;  
    22.         int ret=0;  
    23.         struct chartest_dev *char_dev=filp->private_data;  
    24.         if(p>GLOBALMEM_SIZE)//作越界检查  
    25.         return 0;  
    26.     if(count>GLOBALMEM_SIZE-p)// 读取数据较多  
    27.         count=GLOBALMEM_SIZE-p;  
    28.     if(copy_to_user(buf,(void*)(char_dev->mem+p),count))  
    29.             ret=-EFAULT;  
    30.         else  
    31.     {  
    32.         *ppos=*ppos+count;  
    33.                 ret=count;  
    34.                 printk(KERN_INFO "READ %d BYTES(S) FROM %d",count,p);  
    35.     }  
    36.         return ret;  
    37. }  
    38. //-------------------------------------从用户控件往内核写数据  
    39. static ssize_t  char_write(struct file* filp,const char __user *buf,size_t count,loff_t *ppos)  
    40. {  
    41.         unsigned long p=*ppos;  
    42.         int ret=0;  
    43.     struct chartest_dev *char_dev=filp->private_data;  
    44.         if(p>GLOBALMEM_SIZE)  
    45.         return 0;  
    46.     if(count>GLOBALMEM_SIZE-p)  
    47.         count=GLOBALMEM_SIZE-p;  
    48.     if(copy_from_user(char_dev->mem+p,buf,count))  
    49.         ret=-EFAULT;  
    50.     else  
    51.     {  
    52.         *ppos=*ppos+count;  
    53.                 ret=count;  
    54.                 printk(KERN_INFO "WRITTEN %d BYTES(S) FROM %d",count,p);  
    55.     }  
    56.         return ret;  
    57. }  
    58. static loff_t char_llseek(struct file *filp, loff_t offset, int orig)  
    59. {  
    60.   loff_t ret = 0;  
    61.   switch (orig)  
    62.   {  
    63.     case 0:     
    64.       if (offset < 0)  
    65.       {  
    66.         ret =  - EINVAL;  
    67.         break;  
    68.       }  
    69.       if ((unsigned int)offset > GLOBALMEM_SIZE)  
    70.       {  
    71.         ret =  - EINVAL;  
    72.         break;  
    73.       }  
    74.       filp->f_pos = (unsigned int)offset;  
    75.       ret = filp->f_pos;  
    76.       break;  
    77.     case 1:    
    78.       if ((filp->f_pos + offset) > GLOBALMEM_SIZE)  
    79.       {  
    80.         ret =  - EINVAL;  
    81.         break;  
    82.       }  
    83.       if ((filp->f_pos + offset) < 0)  
    84.       {  
    85.         ret =  - EINVAL;  
    86.         break;  
    87.       }  
    88.       filp->f_pos += offset;  
    89.       ret = filp->f_pos;  
    90.       break;  
    91.     default:  
    92.       ret =  - EINVAL;  
    93.       break;  
    94.   }  
    95.   return ret;  
    96. }  
    97. static const struct file_operations char_fops = {  
    98.     .owner      = THIS_MODULE,  
    99.     .llseek     =char_llseek,  
    100.     .open       = char_open,  
    101.     .read       = char_read,  
    102.     .write      = char_write,  
    103.     };  
    104.   
    105. static void chartest_setup_cdev()  
    106. {  
    107.     int err,devno=MKDEV(char_major,0);  
    108.     cdev_init(&glob_char_dev.cdev,&char_fops);/*初始化*/  
    109.     glob_char_dev.cdev.owner=THIS_MODULE;  
    110.     err=cdev_add(&glob_char_dev.cdev,devno,1);  
    111.     if(err<0)  
    112.     printk(KERN_NOTICE "ERROR %d ADDING chartest",err);  
    113.     char_class=class_create(THIS_MODULE,"chartest");  
    114.     char_class_dev=device_create(char_class,NULL,devno,NULL,"chartest",0);  
    115. }  
    116. static int  char_init(void)  
    117. {  
    118.  int result;  
    119.  unsigned long char_dev_no=MKDEV(char_major,0);  
    120.  if(char_major){  
    121.     result=register_chrdev_region(char_dev_no,1,"chartest");  
    122.   }  
    123.   else{  
    124.         result=alloc_chrdev_region(&char_dev_no,0,1,"chartest");  
    125.     char_major=MAJOR(char_dev_no);  
    126.   }  
    127.  printk(KERN_ALERT "Hello,,We succeed ");  
    128.  if(result<0)  
    129.     return result;  
    130.   chartest_setup_cdev();  
    131.   printk(KERN_ALERT "Hello,,We succeed ");  
    132.   return 0;  
    133. }  
    134. static void  char_exit(void)  
    135. {  
    136.     cdev_del(&glob_char_dev.cdev);  
    137.     unregister_chrdev_region( MKDEV(char_major,0),1);//ZHU XIAO  
    138.     device_unregister(char_class_dev);  
    139.     class_destroy(char_class);  
    140.     printk(KERN_ALERT "720 unregister success ");  
    141. }  
    142. MODULE_LICENSE("Dual BSD/GPL");  
    143. module_init(char_init);  

    二,注意点:

    read和write函数的参数 buff是用户空间的指针,因此内核代码不能直接引用其中的内容,主要原因如下:
    1,在内核模式运行时,用户空间的指针可能是无效的
    2,用户空间是分页的,涉及的内容可能不在RAM中,对用户空间的内存直接引用可能导致页错误
    3.指针是用户空间提供的,可能存在缺陷。

    copy_to_user()和copy_from_user()两个函数除了在内核空间和用户空间进行数据拷贝,还会检查用户空间的指针是否有效,如果指针无效则不拷贝,如果拷贝过程中遇到无效地址,则仅仅会复制部分数据,,在这两种情况下返回值是还需要拷贝内存数量的值。

  • 相关阅读:
    Cocos游戏引擎,让小保安成就大梦想
    Android 高仿QQ5.2双向側滑菜单DrawerLayout实现源代码
    Java中字符串相等与大小比較
    Android四大基本组件之 Activity
    C++基础学习教程(五)
    HAWQ技术解析(八) —— 大表分区
    Jenkins 安装与使用--实例
    Android多点触控技术,实现对图片的放大缩小平移,惯性滑动等功能
    Mycat(4):消息表mysql数据库分表实践
    谋哥:《App自推广》开篇之回到远古人类
  • 原文地址:https://www.cnblogs.com/zhiliao112/p/4237233.html
Copyright © 2011-2022 走看看