这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮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. activity启动模式之singleTask

    activity启动模式之singleTask 一.简介 如果另外一个应用调用了C2,C2在栈底,如果这个程序里面再嗲用C1,C3,C2,那么这个C2就是调用onNewIntant的,C1和C3都被销 ...

  2. MFC,ATL,CLR简介

    MFC.ATL和CLR是VC2005内置的3大库,涵盖了windows的各种开发方法和开发应用.当然关于 C++ 开发的库不止这3个,不过这3个是微软推荐.从编程所处层次而言,WIN32为最底层,其次 ...

  3. 解决tomcat中jdk1.5运行日志相差8小时问题

    tomcat运行日志时间与电脑中的时间相差8小时,原因是因为jdk1.5的原因: 解决办法是在jdk运行的时候加上默认参数: Window->Preferences->Java->I ...

  4. IOS-HTTP协议

    网络由下往上分为 物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用层, 三者从本质上来说没有可 ...

  5. 转:大数据架构:flume-ng+Kafka+Storm+HDFS 实时系统组合

    虽然比较久,但是这套架构已经很成熟了,记录一下 一般数据流向,从“数据采集--数据接入--流失计算--数据输出/存储”<ignore_js_op> 1).数据采集 负责从各节点上实时采集数 ...

  6. ubuntu下安装交叉编译工具链

    /usr/localmkdir arm 将文件file1复制成文件file2 cp file1 file2 /cp /mnt/hgfs/UbuntuGX/arm-2008q3-linux.tar.gz ...

  7. jsp和servlet学习总结

    一.Jsp与servlet的区别: jsp是java代码嵌入html中,用java代码控制来html. Servlet完全是JAVA程序代码构成,用来流程控制和事务处理 jsp更擅长表现于页面显示,s ...

  8. 深入解析Glide源码

    Glide 是 Google的开源项目, Glide具有获取.解码和展示视频剧照.图片.动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里.创建Glide的主 ...

  9. mono developer 无法启动 可以试试如下插件包.

    http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.22.msi 我以前装的旧版unity 再装了新的版本以后 mono ...

  10. I-O流概念认知升级

    在文件操作基础入门中,我们提到了流的 概念,这篇我们将更多的介绍流这个东西,以及C的I/O相关知识 现在,我们从C程序员最熟悉的printf函数开始学习I/O流. 我们对printf函数一直是很喜爱的 ...