zoukankan      html  css  js  c++  java
  • linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)

    一.驱动框架

    初始化:insmod 加载

         1.确定主设备号:

                分为静态和动态分配,其中LED_GPIO_SIZE 表示支持的次设备号数目,一般默认为1. 相关实现代码如下:

    1.    int result;  
    2. dev_t dev;  
    3.   
    4.    /*分配主设备号*/  
    5.    if (scull_major)   /*静态分配一个主设备号*/  
    6.    {  
    7.     dev = MKDEV(scull_major,0);  
    8.     result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);   
    9.    }  
    10. else               /*动态分配一个主设备号*/  
    11. {  
    12.     result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);  
    13.     scull_major = MAJOR(dev);  
    14. }  
    15. if(result <0)  
    16. {  
    17.     printk("LED:can not get major:%d ",scull_major);  
    18.     return result;  
    19. }  


        2.构造 file_operations 结构:结构成员对应相应的处理函数:

    1. static struct file_operations mini2440_leds_fops = {  
    2.     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */  
    3.     .open   =   mini2440_leds_open,              
    4.     .write  =   mini2440_leds_write,         
    5. };  


     3.将相关操作告诉内核:

         内核用cdev结构来表示字符设备,cev_init()将文件操作和cdev关联。cdev_add()将之前生成的主次设备号和cdev连接在一起,

    1. led_class = class_create(THIS_MODULE,DEVICE_NAME);    
    2.    cdev_init(&led_gpio_cdev, &mini2440_leds_fops);  
    3. result = cdev_add(&led_gpio_cdev, dev, 1);  
    4. if(result <0)  
    5. {  
    6.     printk("LED:cdev_add error ");  
    7.     return result;  
    8. }  
    9.   
    10. device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");  


    卸载驱动 rmmod 卸载 代码实现如下:

    1. dev_t dev_id = MKDEV(scull_major, 0);  
    2.   
    3. /*卸载主设备号*/  
    4. unregister_chrdev_region(dev_id, LED_GPIO_SIZE);  
    5.   
    6. device_destroy(led_class,MKDEV(scull_major, 0));  
    7. cdev_del(&led_gpio_cdev);  
    8.   
    9. class_destroy(led_class);  

    最后附上一个较为完整的驱动框架,其中创建了主设备号和次设备号,驱动代码如下:

    1. #include <linux/module.h>  
    2. #include <linux/kernel.h>  
    3. #include <linux/fs.h>  
    4. #include <linux/init.h>  
    5. #include <linux/delay.h>  
    6. #include <asm/uaccess.h>  
    7. #include <asm/irq.h>  
    8. #include <mach/io.h>  
    9. #include <mach/regs-gpio.h>  
    10. #include <mach/hardware.h>  
    11. #include <linux/device.h>  
    12.   
    13. #include <linux/cdev.h>  
    14.   
    15.   
    16. #define DEVICE_NAME "led_1"  
    17. #define LED_GPIO_SIZE 4  
    18.   
    19. static int scull_major = 0;  
    20.   
    21. static struct class *led_class;  
    22. static struct cdev led_gpio_cdev[LED_GPIO_SIZE];  
    23.   
    24. static int mini2440_leds_open(struct inode *inode, struct file *file)  
    25. {  
    26.   
    27.     int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);  
    28.     printk("/dev/led%d has opened ",minor);  
    29.     return 0;  
    30. }  
    31.   
    32.   
    33. static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)  
    34. {  
    35.     char val;  
    36.     int minor = MINOR(filp->f_dentry->d_inode->i_rdev);  
    37.     copy_from_user(&val, buf, 1);  
    38.   
    39.     printk("/dev/led%d write the val = %d ",minor,val);  
    40.     return 0;  
    41. }  
    42.   
    43. static struct file_operations mini2440_leds_fops = {  
    44.     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */  
    45.     .open   =   mini2440_leds_open,              
    46.     .write  =   mini2440_leds_write,         
    47. };  
    48.   
    49. /* 
    50.  * 执行insmod命令时就会调用这个函数  
    51.  */  
    52.   
    53. static int mini2440_leds_init(void)  
    54. {  
    55.   
    56.     int result,i;  
    57.     dev_t dev;  
    58.   
    59.     /*分配主设备号*/  
    60.     if (scull_major)   /*静态分配一个主设备号*/  
    61.     {  
    62.         dev = MKDEV(scull_major,0);  
    63.         result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);   
    64.     }  
    65.     else               /*动态分配一个主设备号*/  
    66.     {  
    67.         result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);  
    68.         scull_major = MAJOR(dev);  
    69.     }  
    70.     if(result <0)  
    71.     {  
    72.         printk("LED:can not get major:%d ",scull_major);  
    73.         return result;  
    74.     }  
    75.   
    76.     led_class = class_create(THIS_MODULE,DEVICE_NAME);    
    77.     if (IS_ERR(led_class)) {  
    78.         return PTR_ERR(led_class);  
    79.     }  
    80.       
    81.     for (i=0; i<LED_GPIO_SIZE;i++)  
    82.     {  
    83.         cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops);  
    84.         result = cdev_add(&led_gpio_cdev[i], (dev+i), 1);  
    85.         if(result <0)  
    86.         {  
    87.             printk("LED:cdev_add error ");  
    88.             return result;  
    89.         }  
    90.         device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i);  
    91.     }  
    92.   
    93.     return 0;  
    94. }  
    95.   
    96. /* 
    97.  * 执行rmmod命令时就会调用这个函数  
    98.  */  
    99. static void mini2440_leds_exit(void)  
    100. {  
    101.     int i;  
    102.     dev_t dev_id = MKDEV(scull_major, 0);  
    103.   
    104.     /*卸载主设备号*/  
    105.     unregister_chrdev_region(dev_id, LED_GPIO_SIZE);  
    106.   
    107.     for(i=0;i<LED_GPIO_SIZE;i++)  
    108.     {  
    109.         device_destroy(led_class,MKDEV(scull_major, i));  
    110.         cdev_del(&led_gpio_cdev[i]);  
    111.     }  
    112.     class_destroy(led_class);  
    113.   
    114. }  
    115.   
    116.   
    117. /* 这两行指定驱动程序的初始化函数和卸载函数 */  
    118. module_init(mini2440_leds_init);  
    119. module_exit(mini2440_leds_exit);  
    120.   
    121. /* 描述驱动程序的一些信息,不是必须的 */  
    122.   
    123. MODULE_LICENSE("GPL");  


    linux 测试代码:

      1. #include <sys/types.h>  
      2. #include <sys/stat.h>  
      3. #include <fcntl.h>  
      4. #include <stdio.h>  
      5.   
      6.   
      7. /* 
      8.   *  ledtest <dev> <on|off> 
      9.   */  
      10.   
      11. void print_usage(char *file)  
      12. {  
      13.     printf("Usage: ");  
      14.     printf("%s <dev> <on|off> ",file);  
      15.     printf("eg.  ");  
      16.     printf("%s /dev/led0 a ", file);  
      17.     printf("%s /dev/led1 b ", file);  
      18.     printf("%s /dev/led2 c ", file);  
      19.     printf("%s /dev/led3 d ", file);  
      20. }  
      21.   
      22. int main(int argc, char **argv)  
      23. {  
      24.     int fd;  
      25.     char* filename;  
      26.     char val;  
      27.   
      28.     if (argc != 3)  
      29.     {  
      30.         print_usage(argv[0]);  
      31.         return 0;  
      32.     }  
      33.   
      34.     filename = argv[1];  
      35.   
      36.     fd = open(filename, O_RDWR);  
      37.     if (fd < 0)  
      38.     {  
      39.         printf("error, can't open %s ", filename);  
      40.         return 0;  
      41.     }  
      42.   
      43.     if (!strcmp("a", argv[2]))  
      44.     {  
      45.         val = 10;  
      46.         write(fd, &val, 1);  
      47.     }  
      48.     else if (!strcmp("b", argv[2]))  
      49.     {  
      50.         val = 11;  
      51.         write(fd, &val, 1);  
      52.     }  
      53.     else if (!strcmp("c", argv[2]))  
      54.     {  
      55.         val = 12;  
      56.         write(fd, &val, 1);  
      57.     }  
      58.     else if (!strcmp("d", argv[2]))  
      59.     {  
      60.     
      61.         val = 13;  
      62.         write(fd, &val, 1);  
      63.     }  
      64.   
      65.       
      66.       
      67.     return 0;  
  • 相关阅读:
    React源码 Suspense 和 ReactLazy
    React源码 ReactContext
    BZOJ 3456: 城市规划 与 多项式求逆算法介绍(多项式求逆, dp)
    LOJ #6436. 「PKUSC2018」神仙的游戏(字符串+NTT)
    LOJ #6433. 「PKUSC2018」最大前缀和(状压dp)
    LOJ #6432. 「PKUSC2018」真实排名(组合数)
    LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp + FMT)
    LOJ #2541. 「PKUWC 2018」猎人杀(容斥 , 期望dp , NTT优化)
    LOJ #2540. 「PKUWC 2018」随机算法(概率dp)
    LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/7563478.html
Copyright © 2011-2022 走看看