这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮LED,这里并无实际意义,只是告诉大家如果编写平台总线驱动设备。

问:如何编写平台总线驱动设备这一套架构的设备驱动?

答:分为两个.c文件,一个是drv.c,另一个是dev.c;前者实现平台驱动,后者实现平台设备,平台总线不用我们自己实现。

问:编写平台驱动的核心内容有哪些?

答:分配、设置、注册一个platform_driver

问:如何注册平台驱动?

答:使用platform_driver_register(struct platform_driver *drv)函数,该函数的参数为platform_driver

问:如何定义platform_driver?

答:简单示例

[cpp] view
plain
?
  1. static struct platform_driver led_driver = {
  2. .probe      = led_probe,
  3. .remove     = led_remove,
  4. .driver     = {
  5. .name   = "myled",
  6. .owner  = THIS_MODULE,
  7. }
  8. };

问:probe函数什么时候被调用?

答:当系统中有同名的平台设备和平台驱动时,就会调用probe函数。

问:probe函数有什么作用?

答:该函数可以做什么由你决定,你可以只打印一条语句,也可以做很复杂的事情。例如,led_probe函数就做了获取资源,映射IO,注册字符设备。

led_drv.c源码参考:

[cpp] view
plain
?
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/fs.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/irq.h>
  6. #include <linux/sched.h>
  7. #include <linux/pm.h>
  8. #include <linux/sysctl.h>
  9. #include <linux/proc_fs.h>
  10. #include <linux/delay.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/input.h>
  13. #include <linux/gpio_keys.h>
  14. #include <asm/uaccess.h>   // copy_from_user
  15. #include <asm/io.h>  // ioremap
  16. static struct class *led_cls;
  17. static volatile unsigned long *gpio_con;
  18. static volatile unsigned long *gpio_dat;
  19. static int pin;
  20. static int major;
  21. static int led_open(struct inode * inode, struct file * filp)
  22. {
  23. *gpio_con &= ~(0x3<<(pin*2));
  24. *gpio_con |= (0x1<<(pin*2));
  25. return 0;
  26. }
  27. static ssize_t
  28. led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  29. {
  30. int val;
  31. copy_from_user(&val, buf, count);
  32. if(val == 1)
  33. {
  34. /* 点灯 */
  35. *gpio_dat  &= ~(1<<pin);
  36. }
  37. else
  38. {
  39. /* 灭灯 */
  40. *gpio_dat  |= (1<<pin);
  41. }
  42. return 0;
  43. }
  44. /* File operations struct for character device */
  45. static const struct file_operations led_fops = {
  46. .owner      = THIS_MODULE,
  47. .open       = led_open,
  48. .write      = led_write,
  49. };
  50. static int __devinit led_probe(struct platform_device *pdev)
  51. {
  52. struct resource *res;
  53. printk("led_probe, found led\n");
  54. /* 根据platform_device的资源进行ioremap */
  55. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  56. gpio_con =  ioremap(res->start, res->end - res->start + 1);
  57. gpio_dat = gpio_con + 1;
  58. res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  59. pin =  res->start;
  60. /* 注册字符设备 */
  61. major = register_chrdev(0, "myled", &led_fops);
  62. led_cls = class_create(THIS_MODULE,"myled");
  63. device_create(led_cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
  64. return 0;
  65. }
  66. static int __devexit led_remove(struct platform_device *pdev)
  67. {
  68. printk("led_remove, remove led\n");
  69. device_destroy(led_cls, MKDEV(major, 0));
  70. class_destroy(led_cls);
  71. unregister_chrdev(major, "myled");
  72. iounmap(gpio_con);
  73. return 0;
  74. }
  75. static struct platform_driver led_driver = {
  76. .probe      = led_probe,
  77. .remove     = led_remove,
  78. .driver     = {
  79. .name   = "myled",
  80. .owner  = THIS_MODULE,
  81. }
  82. };
  83. /* 分配/设置/注册一个platform_driver */
  84. static int led_drv_init(void)
  85. {
  86. return platform_driver_register(&led_driver);
  87. }
  88. static void led_drv_exit(void)
  89. {
  90. platform_driver_unregister(&led_driver);
  91. }
  92. module_init(led_drv_init);
  93. module_exit(led_drv_exit);
  94. MODULE_LICENSE("GPL");
  95. MODULE_AUTHOR("LWJ");
  96. MODULE_DESCRIPTION("Just for Demo");

问:编写平台设备驱动的核心内容有哪些?

答:分配、设置、注册一个platform_device

问:如何注册平台设备?

答:使用platform_device_register(struct platform_device *pdev)函数,该函数的参数为platform_device

问:如何定义platform_device?

答:简单示例:led_device

[cpp] view
plain
?
  1. static struct platform_device led_device = {
  2. .id         = -1,
  3. .name       = "myled",  /* 与led_driver的name一致 */
  4. .resource       = led_resources,
  5. .num_resources  = ARRAY_SIZE(led_resources),
  6. .dev            ={
  7. .release    = led_release,
  8. },
  9. };

问:如何定义resource?

答:简单示例:

[cpp] view
plain
?
  1. static struct resource led_resources[] = {
  2. [0] = {
  3. .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
  4. .end    = 0x56000010 + 8 -1,
  5. .flags  = IORESOURCE_MEM,
  6. },
  7. [1] = {
  8. .start  = 5,        /* LED1 */
  9. .end    = 5,
  10. .flags  = IORESOURCE_IRQ,
  11. },
  12. };

led_dev.c源码参考:

[cpp] view
plain
?
  1. #include <linux/module.h>
  2. #include <linux/version.h>
  3. #include <linux/init.h>
  4. #include <linux/kernel.h>
  5. #include <linux/types.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/list.h>
  8. #include <linux/timer.h>
  9. #include <linux/init.h>
  10. #include <linux/serial_core.h>
  11. #include <linux/platform_device.h>
  12. static struct resource led_resources[] = {
  13. [0] = {  
    //寄存器的起始地址
  14. .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
  15. .end    = 0x56000010 + 8 -1,
  16. .flags  = IORESOURCE_MEM,
  17. },
  18. [1] = {  
    //寄存器的哪一个引脚,以后可以修改这儿来操作让哪个led点亮
  19. .start  = 5,        /* LED1 */
  20. .end    = 5,
  21. .flags  = IORESOURCE_IRQ,
  22. },
  23. };
  24. static void led_release(struct device * dev)
  25. {
  26. }
  27. static struct platform_device led_device = {
  28. .id         = -1,
  29. .name       = "myled",  /* 与led_driver的name一致 */
  30. .resource       = led_resources,
  31. .num_resources  = ARRAY_SIZE(led_resources),
  32. .dev            ={
  33. .release    = led_release,
  34. },
  35. };
  36. /* 分配/设置/注册一个platform_device */
  37. static int led_dev_init(void)
  38. {
  39. return platform_device_register(&led_device);
  40. }
  41. static void led_dev_exit(void)
  42. {
  43. platform_device_unregister(&led_device);
  44. }
  45. module_init(led_dev_init);
  46. module_exit(led_dev_exit);
  47. MODULE_LICENSE("GPL");
  48. MODULE_AUTHOR("LWJ");
  49. MODULE_DESCRIPTION("Just for Demo");

应用测试程序源码:

[cpp] view
plain
?
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. /* 9th_led_test on
  6. * 9th_led_test off
  7. */
  8. int main(int argc, char **argv)
  9. {
  10. int fd;
  11. int val = 1;
  12. fd = open("/dev/led", O_RDWR);
  13. if (fd < 0)
  14. {
  15. printf("can't open!\n");
  16. }
  17. if (argc != 2)
  18. {
  19. printf("Usage :\n");
  20. printf("%s <on|off>\n", argv[0]);
  21. return 0;
  22. }
  23. if (strcmp(argv[1], "on") == 0)
  24. {
  25. val  = 1;
  26. }
  27. else
  28. {
  29. val = 0;
  30. }
  31. write(fd, &val, 4);
  32. return 0;
  33. }

测试步骤:

[cpp] view
plain
?
  1. 9th_led_test        first_drv.ko        sddisk
  2. Qt                  first_test          second_drv.ko
  3. TQLedtest           fourth_drv.ko       second_test
  4. app_test            fourth_test         sixth_drv.ko
  5. bin                 home                sixth_test
  6. busybox             led_dev.ko          sixthdrvtest
  7. buttons_all_drv.ko  led_drv.ko          sys
  8. buttons_all_test    lib                 third_drv.ko
  9. buttons_input.ko    linuxrc             third_test
  10. dev                 mnt                 tmp
  11. driver_test         opt                 udisk
  12. etc                 proc                usr
  13. fifth_drv.ko        root                var
  14. fifth_test          sbin                web
  15. [WJ2440]# insmod led_drv.ko
  16. [WJ2440]# insmod led_dev.ko
  17. led_probe, found led
  18. [WJ2440]# rmmod led_dev
  19. led_remove, remove led
  20. rmmod: module 'led_dev' not found
  21. [WJ2440]# lsmod
  22. led_drv 2800 0 - Live 0xbf003000
  23. [WJ2440]# insmod led_dev.ko
  24. led_probe, found led
  25. [WJ2440]# lsmod
  26. led_dev 1444 0 - Live 0xbf009000
  27. led_drv 2800 0 - Live 0xbf003000
  28. [WJ2440]# ls /dev/led -l
  29. crw-rw----    1 root     root      252,   0 Jan  2 07:44 /dev/led
  30. [WJ2440]# ./9th_led_test
  31. Usage :
  32. ./9th_led_test <on|off>
  33. [WJ2440]# ./9th_led_test off
  34. [WJ2440]# ./9th_led_test on

当执行./9th_led_test off时,led1被熄灭;当执行./9th_led_test on时 led1被点亮。如果你需要点亮led2,那么只需要修改led_dev的led_resources改为:

[cpp] view
plain
?
  1. static struct resource led_resources[] = {
  2. [0] = {
  3. .start  = 0x56000010,      /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
  4. .end    = 0x56000010 + 8 -1,
  5. .flags  = IORESOURCE_MEM,
  6. },
  7. [1] = {
  8. .start  = 6,        /* LED2 */
  9. .end    = 6,
  10. .flags  = IORESOURCE_IRQ,
  11. },
  12. };

这样,应用程序不用更改,即可点亮led2,这样一来就实现了,稳定部分不用修改,只需要修改硬件易变部分,并且应用程序不需要任何更改。

linux平台总线驱动设备模型之点亮LED的更多相关文章

  1. Linux平台总线驱动设备模型

    platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...

  2. 驱动程序分层分离概念_总线驱动设备模型_P

    分层概念: 驱动程序向上注册的原理: 比如:输入子程序一个input.c作为一层,下层为Dev.c和Dir.c,分别编写Dev.c和Dir.c向上Input.c注册:如图所示 分离概念: 分离概念主要 ...

  3. Linux平台总线设备驱动

    1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...

  4. 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...

  5. Linux SPI总线和设备驱动架构之三:SPI控制器驱动

    通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...

  6. 驱动04.平台总线驱动模型——点亮LED灯

    1 平台总线的简介 平台总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的 ...

  7. Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化

    我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...

  8. linux usb总线驱动(一)

    目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...

  9. Linux平台下裸设备的绑定:

    Linux平台下裸设备的绑定: 运用RAW绑定 方法一 raw的配置(1) [root@qs-dmm-rh2 mapper]# cat /etc/rc.local #!/bin/sh # # This ...

随机推荐

  1. spring3: helloword

    借助:eclipse,mavn,spring-tool-sitedchapter2.helloworld 项目搭建好了,让我们来开发接口,此处我们只需实现打印“Hello World!”,所以我们定义 ...

  2. phalcon: 独立的映射,字段名名别名

    class ProductsController extends \Phalcon\Mvc\Controller { public function saveAction() { //Obtain t ...

  3. CentOS下安装mysql及配置使用

    最近一直使用的是CentOS,平时用的最多的数据库是Sql Server,对于mysql还停留在上学的时候,早已忘得一干二净,写这篇内容目的是,重新学习如何安装使用mysql. 一.安装mysql 操 ...

  4. Appium 自动化测试(2)--环境安装:安装Android模拟器

    一.安装java 环境-JDK 略,自行百度安装. 二.安装Android SDK Android SDK提供给我们API库和开发工具构建,测试和调试应用程序,Android.简单来讲,Android ...

  5. MySQL 5.6 二进制包安装配置多实例方法

    MySQL支持一台机器上启动多个实例,如果你的机器性能很好的话,启动多个实例将最大化利用你的服务器硬件资源. MySQL多实例一般有两种配置方法: 1.官方推荐的mysqld_multi方式,多个实例 ...

  6. 【MAVEN】笔记

    引言 Maven是Java项目开发中的重要组成部分,了解它学习它是我们的必修课. Maven是什么? Maven是一个项目管理和综合工具.Maven是标准化的产物,使用标准的目录结构和默认构建生命周期 ...

  7. 下载并安装Prism5.0库 Download and Setup Prism Library 5.0 for WPF(英汉对照版)

    Learn what’s included in Prism 5.0 including the documentation, WPF code samples, and libraries. Add ...

  8. Database项目中关于Procedure sp_refreshsqlmodule_internal的错误

    最近项目中发现一怪问题,使用DB项目发布数据库时,总提示 “(110,1): SQL72014: .Net SqlClient Data Provider: Msg 1222, Level 16, S ...

  9. SWF文件加密、混淆

    简单说下SWF文件的混淆原理,(已经明白的请跳过本段):我们的AS源代码被编译完成后,SWF内部会形成一个字符串映射表,包含源码里出现的所有字符串(类名,包名,成员变量名,常量等).一个数字(相当于地 ...

  10. Django 使用 内置 content-type

    django内置的content-type组件, 记录了项目中所有model元数据的表 可以通过一个ContentType表的id和一个具体表中的id找到任何记录,及先通过ContenType表的id ...