platform Bus Driver

Posted by Gestahr on Tue, 02 Jul 2019 20:47:36 +0200

In the last LED driver, the device and driver are attached to the bus through the macth on the bus.( Linux When adding devices or drivers to the system bus, the matching function corresponding to each bus is called to judge whether the driver and the device match or not) to match the device with the driver. In this paper, we learn another bus, platform, platform bus, and a virtual bus, which separates the board code from the driver code, and makes the driver more scalable. Sex and cross-platform.


The corresponding device of platform bus is called platform_device, and the driver is platform_driver.

What we want to achieve is the registration and matching of device and driver. After the matching is successful, we call the probe function, which completes the final work of driver registration, resources, interrupt the calling function and other related work.


Next, let's analyze our specific code.

1. Definition of Platform Device and Driver

  1. static struct platform_device s3c_led_device = {  
  2.      .name    = "s3c_led",  
  3.      .id      = 1,  
  4.      .dev     =  
  5.      {  
  6.          .platform_data = &s3c_led_data,  
  7.          .release = platform_led_release,  
  8.      },  
  9.  };  

  1. static struct platform_driver s3c_led_driver = {  
  2.      .probe      = s3c_led_probe,  
  3.      .remove     = s3c_led_remove,  
  4.      .driver     = {  
  5.          .name       = "s3c_led",  
  6.          .owner      = THIS_MODULE,  
  7.      },  
  8.  };  

Here you can see that our. name is the same, so that we can match successfully and bind together.

2. Registration of Platform Platform Devices and Drivers

  1. static int __init s3c_led_init(void)  
  2.  {  
  3.     int       ret = 0;  
  4.    
  5.     ret = platform_device_register(&s3c_led_device);     //Registered Platform Equipment  
  6.     if(ret)  
  7.     {  
  8.          printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, ret);  
  9.          goto fail_reg_plat_dev;  
  10.     }  
  11.     dbg_print("Regist S3C LED Platform Device successfully.\n");  
  12.    
  13.     ret = platform_driver_register(&s3c_led_driver);     //Register Platform Driver  
  14.     if(ret)  
  15.     {  
  16.         printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, ret);  
  17.         goto fail_reg_plat_drv;  
  18.     }  
  19.     dbg_print("Regist S3C LED Platform Driver successfully.\n");  
  20.    
  21.     return 0;  
  22.   
  23.  fail_reg_plat_drv:  
  24.     platform_driver_unregister(&s3c_led_driver);  
  25.  fail_reg_plat_dev:  
  26.     return ret;  
  27.  }  

Registration is done by init, i.e. registration is done as soon as it is started. We can see that when registering platform devices and platform drivers, we take the values of sc3_led_device and s3c_led_driver structures respectively, that is, the platform devices and driver structures we just defined.

3. When the driver matches the device's. name successfully, it's time for our probe to come out as a matchmaker.

  1. static int s3c_led_probe(struct platform_device *dev)  
  2.  {  
  3.      struct s3c_led_platform_data *pdata = dev->dev.platform_data;  
  4.      int result = 0;  
  5.      int i;  
  6.      dev_t devno;  
  7.       
  8.     /* Initialize the LED status Initialization of LED state*/  
  9.      for(i=0; i<pdata->nleds; i++)  
  10.      {  
  11.           s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);  
  12.           if(ON == pdata->leds[i].status)  
  13.           {  
  14.              s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);  //Exist the output value in active_level  
  15.           }  
  16.           else  
  17.           {  
  18.              s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
  19.           }  
  20.      }  
  21.        
  22.       
  23.     /*  Alloc the device for driver Application for Equipment Number*/  
  24.      if (0 != dev_major)  
  25.      {  
  26.          devno = MKDEV(dev_major, dev_minor);  
  27.          result = register_chrdev_region(devno, 1, DEV_NAME);  
  28.      }  
  29.      else  
  30.      {  
  31.          result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);  
  32.          dev_major = MAJOR(devno);  
  33.      }  
  34.    
  35.    
  36.      /* Alloc for device major failure */  
  37.      if (result < 0)  
  38.      {  
  39.          printk("%s driver can't get major %d\n", DEV_NAME, dev_major);  
  40.          return result;  
  41.      }  
  42.   
  43.        
  44.     /* Initialize button structure and register cdev*/  
  45.      memset(&led_device, 0, sizeof(led_device));         //memset function initializes memory  
  46.      led_device.data = dev->dev.platform_data;  
  47.      cdev_init (&(led_device.cdev), &led_fops);        //Initialize character device cdev  
  48.      led_device.cdev.owner  = THIS_MODULE;  
  49.    
  50.      result = cdev_add (&(led_device.cdev), devno , 1);       //Registered Character Device cdev  
  51.      if (result)  
  52.      {  
  53.          printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);  
  54.          goto ERROR;  
  55.      }  
  56.   
  57.     led_device.dev_class = class_create(THIS_MODULE, DEV_NAME);      //Define a class to automatically create device nodes, so we don't have to create our own when testing programs.  
  58.      if(IS_ERR(led_device.dev_class))  
  59.      {  
  60.          printk("%s driver create class failture\n",DEV_NAME);  
  61.          result =  -ENOMEM;  
  62.          goto ERROR;  
  63.      }  
  64.    
  65.  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)       
  66.      device_create(led_device.dev_class, NULL, devno, NULL, DEV_NAME);  
  67.  #else  
  68.      device_create (led_device.dev_class, NULL, devno, DEV_NAME);  
  69.  #endif  
  70.   
  71.      /*  Initial the LED blink timer Initialize the flicker time. This timer function is described below.*/  
  72.      init_timer(&(led_device.blink_timer));  
  73.      led_device.blink_timer.function = led_timer_handler;  
  74.      led_device.blink_timer.data = (unsigned long)pdata;  
  75.      led_device.blink_timer.expires  = jiffies + TIMER_TIMEOUT;  
  76.      add_timer(&(led_device.blink_timer));  
  77.    
  78.      printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);  
  79.    
  80.      return 0;  
  81.    
  82.    
  83.  ERROR:  
  84.      printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);  
  85.      cdev_del(&(led_device.cdev));  
  86.    
  87.      unregister_chrdev_region(devno, 1);  
  88.      return result;  
  89.    
  90.  }  

The probe function mainly completes the application of device number, initializes and registers character device cdev, and reads out hardware resources from cdev.


4. Important structures:

  1. static struct file_operations led_fops = {  
  2.      .owner = THIS_MODULE,  
  3.      .open = led_open,  
  4.      .release = led_release,  
  5.      .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/  
  6.  };  

This structure illustrates some of the function calls that we need to use, and our read and write operations can only be implemented here.

5.led_timer_handler function

  1. void led_timer_handler(unsigned long data)  
  2.  {  
  3.      int  i;  
  4.      struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;  
  5.    
  6.      for(i=0; i<pdata->nleds; i++)  
  7.      {  
  8.          if(ON == pdata->leds[i].status)  
  9.          {  
  10.                s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);  
  11.          }  
  12.          else  
  13.          {  
  14.                s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);  
  15.          }  
  16.    
  17.          if(ENABLE == pdata->leds[i].blink )  /* LED should blink */  
  18.          {  
  19.              /* Switch status between 0 and 1 to turn LED ON or off */  
  20.              pdata->leds[i].status = pdata->leds[i].status ^ 0x01;  
  21.          }<pre class="cpp" name="code">         mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);  //If there is blink, the flicker property, the state is changed once per cycle.  
  22.      }  
  23.  }  
  24. </pre><br>  
  25. <pre></pre>  
  26. <p>This function reads each of them regularly LED The pin status is saved to active_level Medium.</p>  
  27. <p></p>  
  28. <p>Well, several main functions have been analyzed, and there are some function calls and definitions of the structure. Let's give a complete driver code.</p>  
  29. <pre class="cpp" name="code">/********************************************************************************* 
  30.  *      Copyright:  (C) 2017 Tang Yanjun<519656780@qq.com>   
  31.  *                  All rights reserved. 
  32.  * 
  33.  *       Filename:  s3c_led.c 
  34.  *    Description:  This is the common LED driver runs on S3C24XX. 
  35.  *                  
  36.  *        Version:  1.0.0(10/27/2011~) 
  37.  *         Author:  Tang Yanjun <519656780@qq.com> 
  38.  *      ChangeLog:  1, Release initial version on "23/4/2017 11:39:10 AM" 
  39.  *                  
  40.  ********************************************************************************/  
  41. #include "s3c_driver.h"  
  42.   
  43. #define DRV_AUTHOR                "Tang Yanjun <519656780@qq.com>"  
  44. #define DRV_DESC                  "S3C24XX LED driver"  
  45.   
  46. /* Driver version*/  
  47. #define DRV_MAJOR_VER             1  
  48. #define DRV_MINOR_VER             0  
  49. #define DRV_REVER_VER             0  
  50.   
  51. #define DEV_NAME                  DEV_LED_NAME  
  52.   
  53. #define DEV_MAJOR                 DEV_LED_MAJOR  
  54. #ifndef DEV_MAJOR  
  55. #define DEV_MAJOR                 0 /*  dynamic major by default */   
  56. #endif  
  57.   
  58. #define TIMER_TIMEOUT             40  
  59.   
  60. static int debug = DISABLE;  
  61. static int dev_major = DEV_MAJOR;  
  62. static int dev_minor = 0;  
  63.   
  64.   
  65. /* ============================ Platform Device part ===============================*/  
  66. /*  LED hardware informtation structure*/  
  67. struct s3c_led_info  
  68. {  
  69.     unsigned char           num;              /* The LED number  */  
  70.     unsigned int            gpio;             /* Which GPIO the LED used */    
  71.     unsigned char           active_level;     /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off  */  
  72.     unsigned char           status;           /* Current LED status: OFF/ON */  
  73.     unsigned char           blink;            /* Blink or not */             
  74. };  
  75.   
  76. /*  The LED platform device private data structure */  
  77. struct s3c_led_platform_data  
  78. {  
  79.     struct s3c_led_info    *leds;  
  80.     int                     nleds;  
  81. };  
  82.   
  83.   
  84. /*  LED hardware informtation data*/   
  85. static struct s3c_led_info  s3c_leds[] = {  
  86.     [0] = {  
  87.         .num = 1,  
  88.         .gpio = S3C2410_GPB(5),  
  89.         .active_level = LOWLEVEL,  
  90.         .status = OFF,  
  91.         .blink = ENABLE,  
  92.     },  
  93.     [1] = {  
  94.         .num = 2,  
  95.         .gpio = S3C2410_GPB(6),  
  96.         .active_level = LOWLEVEL,  
  97.         .status = OFF,  
  98.         .blink = DISABLE,  
  99.     },  
  100.     [2] = {  
  101.         .num = 3,  
  102.         .gpio = S3C2410_GPB(8),  
  103.         .active_level = LOWLEVEL,  
  104.         .status = OFF,  
  105.         .blink = DISABLE,  
  106.     },  
  107.     [3] = {   
  108.         .num = 4,  
  109.         .gpio = S3C2410_GPB(10),  
  110.         .active_level = LOWLEVEL,  
  111.         .status = OFF,  
  112.         .blink = DISABLE,  
  113.     },   
  114. };  
  115.   
  116. /*  The LED platform device private data */  
  117. static struct s3c_led_platform_data s3c_led_data = {  
  118.     .leds = s3c_leds,  
  119.     .nleds = ARRAY_SIZE(s3c_leds),  
  120. };  
  121.   
  122. struct led_device  
  123. {  
  124.     struct s3c_led_platform_data    *data;  
  125.     struct cdev                     cdev;  
  126.     struct class                    *dev_class;  
  127.     struct timer_list               blink_timer;  
  128. } led_device;  
  129.   
  130. static void platform_led_release(struct device * dev)  
  131. {  
  132.     int i;  
  133.     struct s3c_led_platform_data *pdata = dev->platform_data;   
  134.   
  135.     dbg_print("%s():%d\n", __FUNCTION__,__LINE__);  
  136.   
  137.     /* Turn all LED off */  
  138.     for(i=0; i<pdata->nleds; i++)  
  139.     {  
  140.          s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
  141.     }  
  142. }  
  143.   
  144. static struct platform_device s3c_led_device = {  
  145.     .name    = "s3c_led",  
  146.     .id      = 1,  
  147.     .dev     =   
  148.     {  
  149.         .platform_data = &s3c_led_data,   
  150.         .release = platform_led_release,  
  151.     },  
  152. };  
  153.   
  154.   
  155.   
  156. /* ===================== led device driver part ===========================*/  
  157.   
  158. void led_timer_handler(unsigned long data)  
  159. {   
  160.     int  i;   
  161.     struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;  
  162.   
  163.     for(i=0; i<pdata->nleds; i++)   
  164.     {   
  165.         if(ON == pdata->leds[i].status)  
  166.         {  
  167.               s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);   
  168.         }  
  169.         else  
  170.         {  
  171.               s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
  172.         }  
  173.   
  174.         if(ENABLE == pdata->leds[i].blink )  /* LED should blink */  
  175.         {  
  176.             /* Switch status between 0 and 1 to turn LED ON or off */  
  177.             pdata->leds[i].status = pdata->leds[i].status ^ 0x01;    
  178.         }  
  179.   
  180.         mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);  
  181.     }  
  182. }  
  183.   
  184.   
  185. static int led_open(struct inode *inode, struct file *file)  
  186. {   
  187.     struct led_device *pdev ;  
  188.     struct s3c_led_platform_data *pdata;  
  189.   
  190.     pdev = container_of(inode->i_cdev,struct led_device, cdev);  
  191.     pdata = pdev->data;  
  192.   
  193.     file->private_data = pdata;  
  194.   
  195.     return 0;  
  196. }  
  197.   
  198.   
  199. static int led_release(struct inode *inode, struct file *file)  
  200. {   
  201.     return 0;  
  202. }  
  203.   
  204. static void print_led_help(void)  
  205. {  
  206.     printk("Follow is the ioctl() command for LED driver:\n");  
  207.     printk("Enable Driver debug command: %u\n", SET_DRV_DEBUG);  
  208.     printk("Get Driver verion  command : %u\n", GET_DRV_VER);  
  209.     printk("Turn LED on command        : %u\n", LED_ON);  
  210.     printk("Turn LED off command       : %u\n", LED_OFF);  
  211.     printk("Turn LED blink command     : %u\n", LED_BLINK);  
  212. }  
  213.   
  214. /* compatible with kernel version >=2.6.38*/  
  215. static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  216. {   
  217.     struct s3c_led_platform_data *pdata = file->private_data;  
  218.   
  219.     switch (cmd)  
  220.     {  
  221.         case SET_DRV_DEBUG:  
  222.             dbg_print("%s driver debug now.\n", DISABLE == arg ? "Disable" : "Enable");  
  223.             debug = (0==arg) ? DISABLE : ENABLE;  
  224.             break;  
  225.         case GET_DRV_VER:  
  226.             print_version(DRV_VERSION);  
  227.             return DRV_VERSION;  
  228.   
  229.         case LED_OFF:  
  230.             if(pdata->nleds <= arg)  
  231.             {  
  232.                printk("LED%ld doesn't exist\n", arg);    
  233.                return -ENOTTY;  
  234.             }  
  235.             pdata->leds[arg].status = OFF;  
  236.             pdata->leds[arg].blink = DISABLE;  
  237.             break;  
  238.   
  239.         case LED_ON:  
  240.             if(pdata->nleds <= arg)  
  241.             {  
  242.                printk("LED%ld doesn't exist\n", arg);    
  243.                return -ENOTTY;  
  244.             }  
  245.             pdata->leds[arg].status = ON;  
  246.             pdata->leds[arg].blink = DISABLE;  
  247.             break;  
  248.   
  249.         case LED_BLINK:  
  250.             if(pdata->nleds <= arg)  
  251.             {  
  252.                printk("LED%ld doesn't exist\n", arg);    
  253.                return -ENOTTY;  
  254.             }  
  255.             pdata->leds[arg].blink = ENABLE;  
  256.             pdata->leds[arg].status = ON;  
  257.             break;  
  258.   
  259.         default:   
  260.             dbg_print("%s driver don't support ioctl command=%d\n", DEV_NAME, cmd);   
  261.             print_led_help();  
  262.             return -EINVAL;  
  263.   
  264.     }  
  265.     return 0;  
  266. }  
  267.   
  268.   
  269. static struct file_operations led_fops = {   
  270.     .owner = THIS_MODULE,   
  271.     .open = led_open,   
  272.     .release = led_release,   
  273.     .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/  
  274. };  
  275.   
  276.   
  277. static int s3c_led_probe(struct platform_device *dev)  
  278. {  
  279.     struct s3c_led_platform_data *pdata = dev->dev.platform_data;   
  280.     int result = 0;  
  281.     int i;  
  282.     dev_t devno;  
  283.   
  284.     /* Initialize the LED status */  
  285.     for(i=0; i<pdata->nleds; i++)  
  286.     {  
  287.          s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);  
  288.          if(ON == pdata->leds[i].status)  
  289.          {  
  290.             s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);   
  291.          }  
  292.          else  
  293.          {  
  294.             s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);   
  295.          }  
  296.     }  
  297.   
  298.     /*  Alloc the device for driver */  
  299.     if (0 != dev_major)   
  300.     {   
  301.         devno = MKDEV(dev_major, dev_minor);   
  302.         result = register_chrdev_region(devno, 1, DEV_NAME);   
  303.     }   
  304.     else   
  305.     {   
  306.         result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);   
  307.         dev_major = MAJOR(devno);   
  308.     }  
  309.   
  310.     /* Alloc for device major failure */   
  311.     if (result < 0)   
  312.     {   
  313.         printk("%s driver can't get major %d\n", DEV_NAME, dev_major);   
  314.         return result;   
  315.     }  
  316.   
  317.     /* Initialize button structure and register cdev*/  
  318.     memset(&led_device, 0, sizeof(led_device));  
  319.     led_device.data = dev->dev.platform_data;  
  320.     cdev_init (&(led_device.cdev), &led_fops);  
  321.     led_device.cdev.owner  = THIS_MODULE;  
  322.   
  323.     result = cdev_add (&(led_device.cdev), devno , 1);   
  324.     if (result)   
  325.     {   
  326.         printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);   
  327.         goto ERROR;   
  328.     }   
  329.       
  330.     led_device.dev_class = class_create(THIS_MODULE, DEV_NAME);   
  331.     if(IS_ERR(led_device.dev_class))   
  332.     {   
  333.         printk("%s driver create class failture\n",DEV_NAME);   
  334.         result =  -ENOMEM;   
  335.         goto ERROR;   
  336.     }  
  337.   
  338. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)       
  339.     device_create(led_device.dev_class, NULL, devno, NULL, DEV_NAME);  
  340. #else  
  341.     device_create (led_device.dev_class, NULL, devno, DEV_NAME);  
  342. #endif  
  343.   
  344.     /*  Initial the LED blink timer */  
  345.     init_timer(&(led_device.blink_timer));  
  346.     led_device.blink_timer.function = led_timer_handler;  
  347.     led_device.blink_timer.data = (unsigned long)pdata;  
  348.     led_device.blink_timer.expires  = jiffies + TIMER_TIMEOUT;  
  349.     add_timer(&(led_device.blink_timer));   
  350.   
  351.     printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);   
  352.   
  353.     return 0;  
  354.                  
  355.   
  356. ERROR:   
  357.     printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);   
  358.     cdev_del(&(led_device.cdev));   
  359.   
  360.     unregister_chrdev_region(devno, 1);   
  361.     return result;  
  362.   
  363. }  
  364.   
  365. static int s3c_led_remove(struct platform_device *dev)  
  366. {  
  367.     dev_t devno = MKDEV(dev_major, dev_minor);  
  368.   
  369.     del_timer(&(led_device.blink_timer));  
  370.   
  371.     cdev_del(&(led_device.cdev));   
  372.     device_destroy(led_device.dev_class, devno);   
  373.     class_destroy(led_device.dev_class);   
  374.       
  375.     unregister_chrdev_region(devno, 1);   
  376.     printk("S3C %s driver removed\n", DEV_NAME);  
  377.   
  378.     return 0;  
  379. }  
  380.   
  381.   
  382. static struct platform_driver s3c_led_driver = {   
  383.     .probe      = s3c_led_probe,   
  384.     .remove     = s3c_led_remove,   
  385.     .driver     = {   
  386.         .name       = "s3c_led",   
  387.         .owner      = THIS_MODULE,   
  388.     },  
  389. };  
  390.   
  391.   
  392. static int __init s3c_led_init(void)  
  393. {  
  394.    int       ret = 0;  
  395.   
  396.    ret = platform_device_register(&s3c_led_device);  
  397.    if(ret)  
  398.    {  
  399.         printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, ret);   
  400.         goto fail_reg_plat_dev;  
  401.    }  
  402.    dbg_print("Regist S3C LED Platform Device successfully.\n");  
  403.   
  404.    ret = platform_driver_register(&s3c_led_driver);  
  405.    if(ret)  
  406.    {  
  407.         printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, ret);   
  408.         goto fail_reg_plat_drv;  
  409.    }  
  410.    dbg_print("Regist S3C LED Platform Driver successfully.\n");  
  411.   
  412.    return 0;  
  413.   
  414. fail_reg_plat_drv:  
  415.    platform_driver_unregister(&s3c_led_driver);  
  416. fail_reg_plat_dev:  
  417.    return ret;  
  418. }  
  419.   
  420.   
  421. static void s3c_led_exit(void)  
  422. {  
  423.     dbg_print("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__);  
  424.     platform_driver_unregister(&s3c_led_driver);  
  425.     dbg_print("%s():%d remove LED platform device\n", __FUNCTION__,__LINE__);  
  426.     platform_device_unregister(&s3c_led_device);  
  427. }  
  428.   
  429. module_init(s3c_led_init);  
  430. module_exit(s3c_led_exit);  
  431.   
  432. module_param(debug, int, S_IRUGO);  
  433. module_param(dev_major, int, S_IRUGO);  
  434. module_param(dev_minor, int, S_IRUGO);  
  435.   
  436. MODULE_AUTHOR(DRV_AUTHOR);  
  437. MODULE_DESCRIPTION(DRV_DESC);  
  438. MODULE_LICENSE("GPL");  
  439. MODULE_ALIAS("platform:S3C24XX_led");</pre>  
  440. <div><br>  
  441. </div>  
  442. <div><br>  
  443. </div>  
  444. <div>Learning platform Bus driver, and LED After driving, there are all kinds of routines, all kinds of applications, all kinds of registration, and finally matching. platform More than ordinary led More than one probe To match the character device with the driver device, and then there is the automatic creation of the node, as well as the definition. led The next article gives a test code test.</div>  
  445. <div><br>  
  446. </div>  
  447. <div>---It's a long way to go, and our driving journey has just begun. In addition, please point out that I don't understand the right place and correct it. I hope you can help me learn where I don't understand enough.</div>  
  448. <p><br>  
  449. </p>  
  450. <pre></pre>  
  451.      


Topics: Linux