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;  
原文地址:https://www.cnblogs.com/wanghuaijun/p/7563478.html