platform_led驱动

本文介绍了一种基于S3C24XX芯片的LED驱动程序设计,包括驱动结构、设备注册流程及应用程序控制LED的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主机: centos 6.7

开发板: FL2440

系统内核版本:Linux 3.0

编译器: arm-Linux-gcc-4.5.4

芯片: Samsung S3C2400

驱动程序:

[hongfuhao@centos6 platform_led]$ ls

plat_led.

[hongfuhao@centos6 platform_led]$ vim plat_led.c

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /********************************************************************************* 
  2.  *      Copyright:  (C) 2011 Guo Wenxue<guowenxue@gmail.com> 
  3.  *                  All rights reserved. 
  4.  * 
  5.  *       Filename:  s3c_led.c 
  6.  *    Description:  This is the common LED driver runs on S3C24XX. 
  7.  * 
  8.  *        Version:  1.0.0(10/27/2011~) 
  9.  *         Author:  Guo Wenxue <guowenxue@gmail.com> 
  10.  *      ChangeLog:  1, Release initial version on "10/27/2011 11:39:10 AM" 
  11.  * 
  12.  ********************************************************************************/  
  13. #include "s3c_driver.h"  
  14.    
  15. #define DRV_AUTHOR                "Guo Wenxue <guowenxue@gmail.com>"  
  16. #define DRV_DESC                  "S3C24XX LED driver"  
  17.    
  18. /* Driver version*/  
  19. #define DRV_MAJOR_VER             1  
  20. #define DRV_MINOR_VER             0  
  21. #define DRV_REVER_VER             0  
  22.    
  23. #define DEV_NAME                  DEV_LED_NAME  
  24.    
  25. //#define DEV_MAJOR                 DEV_LED_MAJOR  
  26. #ifndef DEV_MAJOR  
  27. #define DEV_MAJOR                 0 /*  dynamic major by default */  
  28. #endif  
  29.    
  30. #define TIMER_TIMEOUT             40  
  31.    
  32. static int debug = DISABLE;  
  33. static int dev_major = DEV_MAJOR;  
  34. static int dev_minor = 0;  
  35.    
  36.    
  37. /* ============================ Platform Device part ===============================*/  
  38. /*  LED hardware informtation structure*/  
  39. struct s3c_led_info   //LED结构体的定义  
  40. {  
  41.     unsigned char           num;              /* The LED number  */  
  42.     unsigned int            gpio;             /* Which GPIO the LED used */  
  43.     unsigned char           active_level;     /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off  */  
  44.     unsigned char           status;           /* Current LED status: OFF/ON */  
  45.     unsigned char           blink;            /* Blink or not */  
  46. };  
  47.    
  48. /*  The LED platform device private data structure */  
  49. struct s3c_led_platform_data  //总线的定义  
  50. {  
  51.     struct s3c_led_info    *leds;  
  52.     int                     nleds;  
  53. };  
  54.    
  55.    
  56. /*  LED hardware informtation data*/  
  57. static struct s3c_led_info  s3c_leds[] = { //LED灯的信息  
  58.     [0] = {  
  59.         .num = 1,  
  60.         .gpio = S3C2410_GPB(5),  
  61.         .active_level = LOWLEVEL,  
  62.         .status = OFF,                                                                                                            
  63.         .blink = ENABLE,  
  64.     },  
  65.     [1] = {  
  66.         .num = 2,  
  67.         .gpio = S3C2410_GPB(6),  
  68.         .active_level = LOWLEVEL,  
  69.         .status = OFF,  
  70.         .blink = DISABLE,  
  71.     },  
  72.     [2] = {  
  73.         .num = 3,  
  74.         .gpio = S3C2410_GPB(8),  
  75.         .active_level = LOWLEVEL,  
  76.         .status = OFF,  
  77.         .blink = DISABLE,  
  78.     },  
  79.     [3] = {  
  80.         .num = 4,  
  81.         .gpio = S3C2410_GPB(10),  
  82.         .active_level = LOWLEVEL,  
  83.         .status = OFF,  
  84.         .blink = DISABLE,  
  85.     },  
  86. };  
  87.    
  88. /*  The LED platform device private data */  
  89. static struct s3c_led_platform_data s3c_led_data = {//定义LED灯的结构体信息  
  90.     .leds = s3c_leds,//LED灯的每条信息  
  91.     .nleds = ARRAY_SIZE(s3c_leds),//灯数  
  92. };  
  93.    
  94. struct led_device//定义led_device的结构体  
  95. {  
  96.     struct s3c_led_platform_data    *data;  
  97.     struct cdev                     cdev;  
  98.     struct class                    *dev_class;  
  99.     struct timer_list               blink_timer;  
  100. } led_device;  
  101.    
  102. static void platform_led_release(struct device * dev)//撤销LED灯的函数  
  103. {  
  104.     int i;  
  105.     struct s3c_led_platform_data *pdata = dev->platform_data;  
  106.   dbg_print("%s():%d\n", __FUNCTION__,__LINE__);  
  107.    
  108.     /* Turn all LED off */  
  109.     for(i=0; i<pdata->nleds; i++)  
  110.     {  
  111.          s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);  
  112.     }  
  113. }  
  114.    
  115. static struct platform_device s3c_led_device = {//定义设备结构体  
  116.     .name    = "s3c_led",  
  117.     .id      = 1,  
  118.     .dev     =  
  119.     {  
  120.         .platform_data = &s3c_led_data,  
  121.         .release = platform_led_release,  
  122.     },  
  123. };  
  124.    
  125.    
  126.    
  127. /* ===================== led device driver part ===========================*/  
  128.    
  129. void led_timer_handler(unsigned long data)//实现LED灯的状态  
  130. {  
  131.     int  i;  
  132.     struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;  
  133.    
  134.     for(i=0; i<pdata->nleds; i++)  
  135.     {  
  136.         if(ON == pdata->leds[i].status)//判断LED灯的亮灭  
  137.         {  
  138.               s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);  
  139.         }  
  140.         else  
  141.         {  
  142.               s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);  
  143.         }                                             
  144.         if(ENABLE == pdata->leds[i].blink )  /* LED should blink */           //LED灯闪  
  145.         {  
  146.             /* Switch status between 0 and 1 to turn LED ON or off */  
  147.             pdata->leds[i].status = pdata->leds[i].status ^ 0x01;  
  148.         }  
  149.    
  150.         mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);//计时器更新,jiffies是全局变量,在头文件  
  151.     }  
  152. }  
  153.    
  154.    
  155. static int led_open(struct inode *inode, struct file *file)//LED开启函数  
  156. {  
  157.     struct led_device *pdev ;  
  158.     struct s3c_led_platform_data *pdata;  
  159.   /*container_of 在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针, 
  160. 就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址*/  
  161.     pdev = container_of(inode->i_cdev,struct led_device, cdev);  
  162.     pdata = pdev->data;  
  163.    
  164.     file->private_data = pdata;  
  165.    
  166.     return 0;  
  167. }  
  168.    
  169.    
  170. static int led_release(struct inode *inode, struct file *file)//LED关闭函数{  
  171.     return 0;  
  172. }  
  173.    
  174. static void print_led_help(void)//帮助信息  
  175. {  
  176.     printk("Follow is the ioctl() command for LED driver:\n");  
  177.     printk("Enable Driver debug command: %u\n", SET_DRV_DEBUG);  
  178.     printk("Get Driver verion  command : %u\n", GET_DRV_VER);  
  179.     printk("Turn LED on command        : %u\n", LED_ON);  
  180.     printk("Turn LED off command       : %u\n", LED_OFF);  
  181.     printk("Turn LED blink command     : %u\n", LED_BLINK);  
  182. }  
  183.    
  184. /* compatible with kernel version >=2.6.38*/  
  185. static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  186. {  
  187.     struct s3c_led_platform_data *pdata = file->private_data;  
  188.    
  189.     switch (cmd)  
  190.     {  
  191.         case SET_DRV_DEBUG:  
  192.             dbg_print("%s driver debug now.\n", DISABLE == arg ? "Disable" : "Enable");  
  193.             debug = (0==arg) ? DISABLE : ENABLE;  
  194.             break;  
  195.         case GET_DRV_VER:  
  196.             print_version(DRV_VERSION);  
  197.             return DRV_VERSION;  
  198.    
  199.         case LED_OFF:  
  200.             if(pdata->nleds <= arg)  
  201.             {  
  202.                printk("LED%ld doesn't exist\n", arg);  
  203.                return -ENOTTY;  
  204.             }  
  205.             pdata->leds[arg].status = OFF;  
  206.             pdata->leds[arg].blink = DISABLE;  
  207.             break;  
  208.    
  209.         case LED_ON:  
  210.             if(pdata->nleds <= arg)  
  211.             {  
  212.                printk("LED%ld doesn't exist\n", arg);  
  213.                return -ENOTTY;  
  214.             }  
  215.             pdata->leds[arg].status = ON;  
  216.             pdata->leds[arg].blink = DISABLE;  
  217.             break;  
  218.    
  219.         case LED_BLINK:  
  220.             if(pdata->nleds <= arg)  
  221.             {  
  222.                printk("LED%ld doesn't exist\n", arg);  
  223.                return -ENOTTY;  
  224.             }  
  225.             pdata->leds[arg].blink = ENABLE;  
  226.              pdata->leds[arg].status = ON;  
  227.             break;  
  228.    
  229.         default:  
  230.             dbg_print("%s driver don't support ioctl command=%d\n", DEV_NAME, cmd);  
  231.             print_led_help();  
  232.             return -EINVAL;  
  233.    
  234.     }  
  235.     return 0;  
  236. }  
  237.    
  238.    
  239. static struct file_operations led_fops = {  
  240.     .owner = THIS_MODULE,  
  241.     .open = led_open,  
  242.     .release = led_release,  
  243.     .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/  
  244. };  
  245.    
  246.    
  247. static int s3c_led_probe(struct platform_device *dev)//设备和驱动相互识别是调用从由内核把platform_device传到probe函数  
  248. {  
  249.     struct s3c_led_platform_data *pdata = dev->dev.platform_data;  
  250.     int result = 0;  
  251.     int i;  
  252.     dev_t devno;  
  253.    
  254.     /* Initialize the LED status */  
  255.     for(i=0; i<pdata->nleds; i++)  
  256.     {  
  257.          s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);  
  258.          if(ON == pdata->leds[i].status)//LED管脚亮  
  259.          {  
  260.             s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level);  
  261.          }  
  262.          Else//LED管脚灭  
  263.          {  
  264.             s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);  
  265.          }  
  266.     }  
  267.    
  268.     /*  Alloc the device for driver */  
  269. if (0 != dev_major)  
  270.  {  
  271.         devno = MKDEV(dev_major, dev_minor);  
  272.         result = register_chrdev_region(devno, 1, DEV_NAME);  
  273.     }  
  274.     else  
  275.     {//动态分配主次设备号  
  276.         result = alloc_chrdev_region(&devno, dev_minor, 1, DEV_NAME);  
  277.         dev_major = MAJOR(devno);  
  278.     }  
  279.    
  280.     /* Alloc for device major failure */  
  281.     if (result < 0)  
  282.     {//分配失败打印信息  
  283.         printk("%s driver can't get major %d\n", DEV_NAME, dev_major);  
  284.         return result;  
  285.     }  
  286.    
  287.     /* Initialize button structure and register cdev*/  
  288.     memset(&led_device, 0, sizeof(led_device));  
  289.     led_device.data = dev->dev.platform_data;  
  290.     cdev_init (&(led_device.cdev), &led_fops);  
  291.     led_device.cdev.owner  = THIS_MODULE;  
  292.    
  293.     result = cdev_add (&(led_device.cdev), devno , 1);  
  294.     if (result)  
  295.     {  
  296.         printk (KERN_NOTICE "error %d add %s device", result, DEV_NAME);  
  297.         goto ERROR;  
  298.     }  
  299.    
  300.     led_device.dev_class = class_create(THIS_MODULE, DEV_NAME);  
  301.     if(IS_ERR(led_device.dev_class))  
  302.     {  
  303.         printk("%s driver create class failture\n",DEV_NAME);  
  304.         result =  -ENOMEM;  
  305.         goto ERROR;  
  306.     }  
  307.    
  308. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)  
  309.     device_create(led_device.dev_class, NULL, devno, NULL, DEV_NAME);  
  310. #else  
  311.     device_create (led_device.dev_class, NULL, devno, DEV_NAME);  
  312. #endif  
  313.       
  314.     /*  Initial the LED blink timer */  
  315.     init_timer(&(led_device.blink_timer));//初始化闪烁定时器  
  316.     led_device.blink_timer.function = led_timer_handler;//时间到了执行函数  
  317.     led_device.blink_timer.data = (unsigned long)pdata;//函数传参  
  318.     led_device.blink_timer.expires  = jiffies + TIMER_TIMEOUT;//时间间隔  
  319.     add_timer(&(led_device.blink_timer));  
  320.    
  321.     printk("S3C %s driver version %d.%d.%d initiliazed.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);  
  322.    
  323.     return 0;  
  324.    
  325.    
  326. ERROR:  
  327.     printk("S3C %s driver version %d.%d.%d install failure.\n", DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER, DRV_REVER_VER);  
  328.     cdev_del(&(led_device.cdev));  
  329.    
  330.     unregister_chrdev_region(devno, 1);  
  331.     return result;  
  332.    
  333. }  
  334.    
  335. static int s3c_led_remove(struct platform_device *dev)//释放主次设备号给Linux内核  
  336. {  
  337.     dev_t devno = MKDEV(dev_major, dev_minor);  
  338.    
  339.     del_timer(&(led_device.blink_timer));  
  340.    
  341.     cdev_del(&(led_device.cdev));  
  342.     device_destroy(led_device.dev_class, devno);  
  343.     class_destroy(led_device.dev_class);  
  344.    
  345.     unregister_chrdev_region(devno, 1);  
  346.     printk("S3C %s driver removed\n", DEV_NAME);  
  347.    
  348.     return 0;  
  349. }  
  350.    
  351.    
  352. static struct platform_driver s3c_led_driver = {//定义总线驱动结构体  
  353.     .probe      = s3c_led_probe,//注册设备主次设备号  
  354.     .remove     = s3c_led_remove,  
  355.     .driver     = {  
  356.           .name       = "s3c_led",  
  357.         .owner      = THIS_MODULE,  
  358.     },  
  359. };  
  360.    
  361.    
  362. static int __init s3c_led_init(void)//LED初始化  
  363. {  
  364.    int       ret = 0;  
  365.    
  366.    ret = platform_device_register(&s3c_led_device);  
  367.    if(ret)  
  368.    {  
  369.         printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, ret);  
  370.         goto fail_reg_plat_dev;  
  371.    }  
  372.    dbg_print("Regist S3C LED Platform Device successfully.\n");  
  373.    
  374.    ret = platform_driver_register(&s3c_led_driver);  
  375.    if(ret)  
  376.    {  
  377.         printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, ret);  
  378.         goto fail_reg_plat_drv;  
  379.    }  
  380.    dbg_print("Regist S3C LED Platform Driver successfully.\n");  
  381.    
  382.    return 0;  
  383.    
  384. fail_reg_plat_drv:  
  385.    platform_driver_unregister(&s3c_led_driver);  
  386. fail_reg_plat_dev:  
  387.    return ret;  
  388. }  
  389.    
  390.    
  391. static void s3c_led_exit(void)//LED撤销  
  392. {  
  393.     dbg_print("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__);  
  394.     platform_driver_unregister(&s3c_led_driver);  
  395.     dbg_print("%s():%d remove LED platform device\n", __FUNCTION__,__LINE__);  
  396.     platform_device_unregister(&s3c_led_device);  
  397. }  
  398.    
  399. module_init(s3c_led_init);  
  400. module_exit(s3c_led_exit);  
  401.    
  402. module_param(debug, int, S_IRUGO);  
  403. module_param(dev_major, int, S_IRUGO);  
  404. module_param(dev_minor, int, S_IRUGO);  
  405.    
  406. MODULE_AUTHOR(DRV_AUTHOR);  
  407. MODULE_DESCRIPTION(DRV_DESC);  
  408. MODULE_LICENSE("GPL");  
  409. MODULE_ALIAS("platform:S3C24XX_led");  
[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. </pre><p><strong>[leiyuxing@centos6 platform_led]$ vim Makefile</strong></p><p></p><pre code_snippet_id="1822395" snippet_file_name="blog_20160811_2_2241077" name="code" class="html">   
  2. obj-m:=plat_led.c  
  3. C=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc  
  4. KDIR?=/home/leiyuxing/fl2440/kernel/linux-3.0  
  5. obj-m:=plat_led.o  
  6.    
  7. default:  
  8.         $(MAKE) -C $(KDIR) M=`pwd` modules  
  9.         make clean  
  10.    
  11. clean:  
  12.         rm -f *.o *mod.c *.order *.symvers  
  13.    

应用程序:

[hongfuhao@centos6 platform_led]$ vim plat_ioctl.c

[html]  view plain  copy
 print ?
  1. *********************************************************************************  
  2.  *     Copyright:  (C) 2016 hongfuhao <70786774@qq.com>  
  3.  *                  All rights reserved.  
  4.  *  
  5.  *       Filename:  plat_icotl.c  
  6.  *    Description:  This file  
  7.  *  
  8.  *        Version:  1.0.0(07/27/2016)  
  9.  *         Author:  hongfuhao <70786774@qq.com>  
  10.  *      ChangeLog:  1, Release initial version on "07/27/2016 10:24:30 AM"  
  11.  *  
  12.  ********************************************************************************/  
  13. #include <stdio.h>  
  14. #include <stdarg.h>  
  15. #include <fcntl.h>  
  16. #include <sys/types.h>  
  17. #include <errno.h>  
  18. #include <sys/ioctl.h>  
  19. #include <sys/stat.h>  
  20. #include <unistd.h>  
  21. #include <stdlib.h>  
  22. #define PLATDRV_MAGIC             0x60  
  23. #define LED_OFF                   _IO (PLATDRV_MAGIC, 0x18)  
  24. #define LED_ON                    _IO (PLATDRV_MAGIC, 0x19)  
  25. #define LED_BLINK                 _IO (PLATDRV_MAGIC, 0x1A)  
  26. #define  DEVNAMELEN 10  
  27. int main (int argc,char **argv)  
  28. {  
  29.         int fd;  
  30.         fd=open("dev/led",O_RDWR);  
  31.         ioctl(fd,LED_ON,0);  
  32.         ioctl(fd,LED_ON,1);  
  33.         ioctl(fd,LED_ON,2);  
  34.         ioctl(fd,LED_BLINK,3);  
  35.         close(fd);  
  36.         return 0;  
  37. }  

[hongfuhao@centos6platform_led_test]$ /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc plat_ioctl.c
[hongfuhao@centos6 platform_led_test]$ ls
a.out  plat_ioctl.c


在开发板上的操作:

>: tftp -gr plat_led.ko 192.168.1.2

plat_led.ko          100% |*******************************|  8827   0:00:00 ETA

>: tftp -gr a.out 192.168.1.2

>:insmod   plat_led.ko 

>: chmod 777 a.out

>: ./a.out

此时你就会看到led0,led1,led2是稳定红灯,lled3是一闪一闪的红灯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

煮雨小哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值