这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮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. javascript练习题(2):变量作用域

    1. 外层变量在内部可以找到,反之找不到 以下看个案例: var a=10; function aaa(){ alert(a); } function bbb(){ var a=20; aaa(); ...

  2. grep 查询包含内容的文件

    加入到 ~/.bashrc 或者 ~/.bash_profile bash export GREPF_FILES=/mnt/d/Developer:/mnt/e/Developer function ...

  3. 【Python】生成器和迭代器

    l=[1,2,3,4] for n in l: print n 在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象.那么for 语句是怎么来遍历列表l的呢?要回答这 ...

  4. 【scala】应用程序和App特性

    一.应用程序 要运行一个Scala对象,必须提供一个独立对象的名称.这个独立对象需要包含一个main方法,该方法接受一个Array[String]作为参数,结果类型为Unit. import Chec ...

  5. ASM9260T开发板使用

    ifconfig eth0 192.168.1.66 netmask 255.255.255.0 up   //设备iproute add default gw 192.168.1.1   //添加网 ...

  6. Node net模块与http模块一些研究

    这周遇到一个有意思的需求,端上同学希望通过 socket 传送表单数据(包含文件内容)到 node 端,根据表单里的文件名.手机号等信息将文件数据保存下来.于是我这样写了一下--socket_serv ...

  7. Android界面View及ViewGroup学习 《转载》

    View及ViewGroup类关系 Android View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的. View ...

  8. cannot be read or is not a valid ZIP file

    在eclipse下创建 maven 项目,运行 flowable 6.1.2 配置maven之后,下载相应的依赖库. 发现报错: Archive for required library: '/Use ...

  9. Android(Lollipop/5.0) Material Design(一) 简介

    官网地址:https://developer.android.com/intl/zh-tw/design/material/index.html 使用Material Design 需要api21,即 ...

  10. MySql 批量创建、导入实例

    1.创建sql(例如,taobao,dangdang): DROP DATABASE IF EXISTS taobao; CREATE DATABASE taobao CHARSET=utf8; US ...