1. 程式人生 > >linux驅動摸索 --驅動框架初始化(結合韋東山視頻教程)

linux驅動摸索 --驅動框架初始化(結合韋東山視頻教程)

boa kernel cde targe 一個 自動 comm argv ops

一.驅動框架

初始化:insmod 加載

1.確定主設備號:

分為靜態和動態分配,其中LED_GPIO_SIZE 表示支持的次設備號數目,一般默認為1. 相關實現代碼如下:

[cpp] view plain copy
  1. int result;
  2. dev_t dev;
  3. /*分配主設備號*/
  4. if (scull_major) /*靜態分配一個主設備號*/
  5. {
  6. dev = MKDEV(scull_major,0);
  7. result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
  8. }
  9. else /*動態分配一個主設備號*/
  10. {
  11. result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
  12. scull_major = MAJOR(dev);
  13. }
  14. if(result <0)
  15. {
  16. printk("LED:can not get major:%d\n",scull_major);
  17. return result;
  18. }


2.構造 file_operations 結構:結構成員對應相應的處理函數:

[cpp] view plain copy
  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連接在一起,

[cpp] view plain copy
  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\n");
  7. return result;
  8. }
  9. device_create(led_class, NULL, MKDEV(scull_major, 0), NULL, "led0");


卸載驅動 rmmod 卸載 代碼實現如下:

[cpp] view plain copy
  1. dev_t dev_id = MKDEV(scull_major, 0);
  2. /*卸載主設備號*/
  3. unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
  4. device_destroy(led_class,MKDEV(scull_major, 0));
  5. cdev_del(&led_gpio_cdev);
  6. class_destroy(led_class);

最後附上一個較為完整的驅動框架,其中創建了主設備號和次設備號,驅動代碼如下:

[cpp] view plain copy
  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. #include <linux/cdev.h>
  13. #define DEVICE_NAME "led_1"
  14. #define LED_GPIO_SIZE 4
  15. static int scull_major = 0;
  16. static struct class *led_class;
  17. static struct cdev led_gpio_cdev[LED_GPIO_SIZE];
  18. static int mini2440_leds_open(struct inode *inode, struct file *file)
  19. {
  20. int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
  21. printk("/dev/led%d has opened\n",minor);
  22. return 0;
  23. }
  24. static ssize_t mini2440_leds_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
  25. {
  26. char val;
  27. int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
  28. copy_from_user(&val, buf, 1);
  29. printk("/dev/led%d write the val = %d\n",minor,val);
  30. return 0;
  31. }
  32. static struct file_operations mini2440_leds_fops = {
  33. .owner = THIS_MODULE, /* 這是一個宏,推向編譯模塊時自動創建的__this_module變量 */
  34. .open = mini2440_leds_open,
  35. .write = mini2440_leds_write,
  36. };
  37. /*
  38. * 執行insmod命令時就會調用這個函數
  39. */
  40. static int mini2440_leds_init(void)
  41. {
  42. int result,i;
  43. dev_t dev;
  44. /*分配主設備號*/
  45. if (scull_major) /*靜態分配一個主設備號*/
  46. {
  47. dev = MKDEV(scull_major,0);
  48. result = register_chrdev_region(dev,LED_GPIO_SIZE,DEVICE_NAME);
  49. }
  50. else /*動態分配一個主設備號*/
  51. {
  52. result = alloc_chrdev_region(&dev,0,LED_GPIO_SIZE,DEVICE_NAME);
  53. scull_major = MAJOR(dev);
  54. }
  55. if(result <0)
  56. {
  57. printk("LED:can not get major:%d\n",scull_major);
  58. return result;
  59. }
  60. led_class = class_create(THIS_MODULE,DEVICE_NAME);
  61. if (IS_ERR(led_class)) {
  62. return PTR_ERR(led_class);
  63. }
  64. for (i=0; i<LED_GPIO_SIZE;i++)
  65. {
  66. cdev_init(&led_gpio_cdev[i], &mini2440_leds_fops);
  67. result = cdev_add(&led_gpio_cdev[i], (dev+i), 1);
  68. if(result <0)
  69. {
  70. printk("LED:cdev_add error\n");
  71. return result;
  72. }
  73. device_create(led_class, NULL, MKDEV(scull_major, i), NULL, "led%d",i);
  74. }
  75. return 0;
  76. }
  77. /*
  78. * 執行rmmod命令時就會調用這個函數
  79. */
  80. static void mini2440_leds_exit(void)
  81. {
  82. int i;
  83. dev_t dev_id = MKDEV(scull_major, 0);
  84. /*卸載主設備號*/
  85. unregister_chrdev_region(dev_id, LED_GPIO_SIZE);
  86. for(i=0;i<LED_GPIO_SIZE;i++)
  87. {
  88. device_destroy(led_class,MKDEV(scull_major, i));
  89. cdev_del(&led_gpio_cdev[i]);
  90. }
  91. class_destroy(led_class);
  92. }
  93. /* 這兩行指定驅動程序的初始化函數和卸載函數 */
  94. module_init(mini2440_leds_init);
  95. module_exit(mini2440_leds_exit);
  96. /* 描述驅動程序的一些信息,不是必須的 */
  97. MODULE_LICENSE("GPL");


linux 測試代碼:

[cpp] view plain copy
    1. #include <sys/types.h>
    2. #include <sys/stat.h>
    3. #include <fcntl.h>
    4. #include <stdio.h>
    5. /*
    6. * ledtest <dev> <on|off>
    7. */
    8. void print_usage(char *file)
    9. {
    10. printf("Usage:\n");
    11. printf("%s <dev> <on|off>\n",file);
    12. printf("eg. \n");
    13. printf("%s /dev/led0 a\n", file);
    14. printf("%s /dev/led1 b\n", file);
    15. printf("%s /dev/led2 c\n", file);
    16. printf("%s /dev/led3 d\n", file);
    17. }
    18. int main(int argc, char **argv)
    19. {
    20. int fd;
    21. char* filename;
    22. char val;
    23. if (argc != 3)
    24. {
    25. print_usage(argv[0]);
    26. return 0;
    27. }
    28. filename = argv[1];
    29. fd = open(filename, O_RDWR);
    30. if (fd < 0)
    31. {
    32. printf("error, can‘t open %s\n", filename);
    33. return 0;
    34. }
    35. if (!strcmp("a", argv[2]))
    36. {
    37. val = 10;
    38. write(fd, &val, 1);
    39. }
    40. else if (!strcmp("b", argv[2]))
    41. {
    42. val = 11;
    43. write(fd, &val, 1);
    44. }
    45. else if (!strcmp("c", argv[2]))
    46. {
    47. val = 12;
    48. write(fd, &val, 1);
    49. }
    50. else if (!strcmp("d", argv[2]))
    51. {
    52. val = 13;
    53. write(fd, &val, 1);
    54. }
    55. return 0;
    56. }

linux驅動摸索 --驅動框架初始化(結合韋東山視頻教程)