这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮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. UVA 11538 排列组合

    https://vjudge.net/problem/UVA-11538#author=0 将两个不同的皇后放入N*M棋盘中,问使得二者可以相互攻击的方案个数.有可能在同一行,同一列,同一对角线,分开 ...

  2. eclipse启动Tomcat服务输入http://localhost:8080/报404解决方法

    其实如果Tomcat能够正常启动,而就算输入http://localhost:8080时出现404错误,也不会影响Tomcat作为服务器运行.通过eclipse来启动tomcat会碰到“访问http: ...

  3. Ceph配置项动态变更机制浅析

    转自:https://www.ustack.com/blog/ceph%e9%85%8d%e7%bd%ae%e9%a1%b9%e5%8a%a8%e6%80%81%e5%8f%98%e6%9b%b4%e ...

  4. struts中操作request,session

    在Action类中操作request,session 方法一.利用ActionContext.getContext().get("request"); //返回的是Map集合 Ma ...

  5. linux时间管理 之 jiffies

    1.jiffies 又称时钟滴答,是一个全局变量,它的值在系统引导的时候初始化为0,在时钟中断初始化完成后,每次时钟中断发生,在时钟中断处理例程中都会将jiffies的值 +1. jiffies_64 ...

  6. [置顶] Android逆向从未如此简单

    哈,又标题党了..不过我一定竭尽所能,写一篇最亲民的入门文章. 本文仅供学习交流之用,切勿用于非法用途,读者若运用所学知识,进行非法任何商业目的或者非法牟利,一切责任由操作者自行承担,与本人无关.希望 ...

  7. JavaScript test//href

    目录 JavaScript test//href JavaScript test//href href 其实这个问题并不属于这里的.但是呢,由于一天晚上因为这个问题扰我"一夜不能眠" ...

  8. 转载:TCP连接的状态详解以及故障排查

    FROM:http://blog.csdn.net/hguisu/article/details/38700899 该博文的条理清晰,步骤明确,故复制到这个博文中收藏,若文章作者看到且觉得不能装载,麻 ...

  9. 21天学通C++_Day3_Part3

    控制程序流程 0.switch...case...语句中省略了break? break让程序能够退出switch结构,如果没有将继续评估后面的case语句 1.如何退出无限循环? 使用break退出当 ...

  10. loader疑惑

    今天写自己的loader管理类时,发现一个问题,如果证明flash是并发加载资源的呢? var loader:Loader=new Loader; loader.contentLoaderInfo.a ...