linux平台总线驱动设备模型之点亮LED
这一节里,我们来使用平台驱动设备这一套架构来实现我们之前使用简单的字符设备驱动点亮LED,这里并无实际意义,只是告诉大家如果编写平台总线驱动设备。
问:如何编写平台总线驱动设备这一套架构的设备驱动?
答:分为两个.c文件,一个是drv.c,另一个是dev.c;前者实现平台驱动,后者实现平台设备,平台总线不用我们自己实现。
问:编写平台驱动的核心内容有哪些?
答:分配、设置、注册一个platform_driver
问:如何注册平台驱动?
答:使用platform_driver_register(struct platform_driver *drv)函数,该函数的参数为platform_driver
问:如何定义platform_driver?
答:简单示例
plain?
- static struct platform_driver led_driver = {
- .probe = led_probe,
- .remove = led_remove,
- .driver = {
- .name = "myled",
- .owner = THIS_MODULE,
- }
- };
问:probe函数什么时候被调用?
答:当系统中有同名的平台设备和平台驱动时,就会调用probe函数。
问:probe函数有什么作用?
答:该函数可以做什么由你决定,你可以只打印一条语句,也可以做很复杂的事情。例如,led_probe函数就做了获取资源,映射IO,注册字符设备。
led_drv.c源码参考:
plain?
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/fs.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <linux/sched.h>
- #include <linux/pm.h>
- #include <linux/sysctl.h>
- #include <linux/proc_fs.h>
- #include <linux/delay.h>
- #include <linux/platform_device.h>
- #include <linux/input.h>
- #include <linux/gpio_keys.h>
- #include <asm/uaccess.h> // copy_from_user
- #include <asm/io.h> // ioremap
- static struct class *led_cls;
- static volatile unsigned long *gpio_con;
- static volatile unsigned long *gpio_dat;
- static int pin;
- static int major;
- static int led_open(struct inode * inode, struct file * filp)
- {
- *gpio_con &= ~(0x3<<(pin*2));
- *gpio_con |= (0x1<<(pin*2));
- return 0;
- }
- static ssize_t
- led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
- {
- int val;
- copy_from_user(&val, buf, count);
- if(val == 1)
- {
- /* 点灯 */
- *gpio_dat &= ~(1<<pin);
- }
- else
- {
- /* 灭灯 */
- *gpio_dat |= (1<<pin);
- }
- return 0;
- }
- /* File operations struct for character device */
- static const struct file_operations led_fops = {
- .owner = THIS_MODULE,
- .open = led_open,
- .write = led_write,
- };
- static int __devinit led_probe(struct platform_device *pdev)
- {
- struct resource *res;
- printk("led_probe, found led\n");
- /* 根据platform_device的资源进行ioremap */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- gpio_con = ioremap(res->start, res->end - res->start + 1);
- gpio_dat = gpio_con + 1;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- pin = res->start;
- /* 注册字符设备 */
- major = register_chrdev(0, "myled", &led_fops);
- led_cls = class_create(THIS_MODULE,"myled");
- device_create(led_cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
- return 0;
- }
- static int __devexit led_remove(struct platform_device *pdev)
- {
- printk("led_remove, remove led\n");
- device_destroy(led_cls, MKDEV(major, 0));
- class_destroy(led_cls);
- unregister_chrdev(major, "myled");
- iounmap(gpio_con);
- return 0;
- }
- static struct platform_driver led_driver = {
- .probe = led_probe,
- .remove = led_remove,
- .driver = {
- .name = "myled",
- .owner = THIS_MODULE,
- }
- };
- /* 分配/设置/注册一个platform_driver */
- static int led_drv_init(void)
- {
- return platform_driver_register(&led_driver);
- }
- static void led_drv_exit(void)
- {
- platform_driver_unregister(&led_driver);
- }
- module_init(led_drv_init);
- module_exit(led_drv_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("LWJ");
- MODULE_DESCRIPTION("Just for Demo");
问:编写平台设备驱动的核心内容有哪些?
答:分配、设置、注册一个platform_device
问:如何注册平台设备?
答:使用platform_device_register(struct platform_device *pdev)函数,该函数的参数为platform_device
问:如何定义platform_device?
答:简单示例:led_device
plain?
- static struct platform_device led_device = {
- .id = -1,
- .name = "myled", /* 与led_driver的name一致 */
- .resource = led_resources,
- .num_resources = ARRAY_SIZE(led_resources),
- .dev ={
- .release = led_release,
- },
- };
问:如何定义resource?
答:简单示例:
plain?
- static struct resource led_resources[] = {
- [0] = {
- .start = 0x56000010, /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
- .end = 0x56000010 + 8 -1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 5, /* LED1 */
- .end = 5,
- .flags = IORESOURCE_IRQ,
- },
- };
led_dev.c源码参考:
plain?
- #include <linux/module.h>
- #include <linux/version.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/interrupt.h>
- #include <linux/list.h>
- #include <linux/timer.h>
- #include <linux/init.h>
- #include <linux/serial_core.h>
- #include <linux/platform_device.h>
- static struct resource led_resources[] = {
- [0] = {
//寄存器的起始地址 - .start = 0x56000010, /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
- .end = 0x56000010 + 8 -1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
//寄存器的哪一个引脚,以后可以修改这儿来操作让哪个led点亮 - .start = 5, /* LED1 */
- .end = 5,
- .flags = IORESOURCE_IRQ,
- },
- };
- static void led_release(struct device * dev)
- {
- }
- static struct platform_device led_device = {
- .id = -1,
- .name = "myled", /* 与led_driver的name一致 */
- .resource = led_resources,
- .num_resources = ARRAY_SIZE(led_resources),
- .dev ={
- .release = led_release,
- },
- };
- /* 分配/设置/注册一个platform_device */
- static int led_dev_init(void)
- {
- return platform_device_register(&led_device);
- }
- static void led_dev_exit(void)
- {
- platform_device_unregister(&led_device);
- }
- module_init(led_dev_init);
- module_exit(led_dev_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("LWJ");
- MODULE_DESCRIPTION("Just for Demo");
应用测试程序源码:
plain?
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- /* 9th_led_test on
- * 9th_led_test off
- */
- int main(int argc, char **argv)
- {
- int fd;
- int val = 1;
- fd = open("/dev/led", O_RDWR);
- if (fd < 0)
- {
- printf("can't open!\n");
- }
- if (argc != 2)
- {
- printf("Usage :\n");
- printf("%s <on|off>\n", argv[0]);
- return 0;
- }
- if (strcmp(argv[1], "on") == 0)
- {
- val = 1;
- }
- else
- {
- val = 0;
- }
- write(fd, &val, 4);
- return 0;
- }
测试步骤:
plain?
- 9th_led_test first_drv.ko sddisk
- Qt first_test second_drv.ko
- TQLedtest fourth_drv.ko second_test
- app_test fourth_test sixth_drv.ko
- bin home sixth_test
- busybox led_dev.ko sixthdrvtest
- buttons_all_drv.ko led_drv.ko sys
- buttons_all_test lib third_drv.ko
- buttons_input.ko linuxrc third_test
- dev mnt tmp
- driver_test opt udisk
- etc proc usr
- fifth_drv.ko root var
- fifth_test sbin web
- [WJ2440]# insmod led_drv.ko
- [WJ2440]# insmod led_dev.ko
- led_probe, found led
- [WJ2440]# rmmod led_dev
- led_remove, remove led
- rmmod: module 'led_dev' not found
- [WJ2440]# lsmod
- led_drv 2800 0 - Live 0xbf003000
- [WJ2440]# insmod led_dev.ko
- led_probe, found led
- [WJ2440]# lsmod
- led_dev 1444 0 - Live 0xbf009000
- led_drv 2800 0 - Live 0xbf003000
- [WJ2440]# ls /dev/led -l
- crw-rw---- 1 root root 252, 0 Jan 2 07:44 /dev/led
- [WJ2440]# ./9th_led_test
- Usage :
- ./9th_led_test <on|off>
- [WJ2440]# ./9th_led_test off
- [WJ2440]# ./9th_led_test on
当执行./9th_led_test off时,led1被熄灭;当执行./9th_led_test on时 led1被点亮。如果你需要点亮led2,那么只需要修改led_dev的led_resources改为:
plain?
- static struct resource led_resources[] = {
- [0] = {
- .start = 0x56000010, /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */
- .end = 0x56000010 + 8 -1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 6, /* LED2 */
- .end = 6,
- .flags = IORESOURCE_IRQ,
- },
- };
这样,应用程序不用更改,即可点亮led2,这样一来就实现了,稳定部分不用修改,只需要修改硬件易变部分,并且应用程序不需要任何更改。
linux平台总线驱动设备模型之点亮LED的更多相关文章
- Linux平台总线驱动设备模型
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...
- 驱动程序分层分离概念_总线驱动设备模型_P
分层概念: 驱动程序向上注册的原理: 比如:输入子程序一个input.c作为一层,下层为Dev.c和Dir.c,分别编写Dev.c和Dir.c向上Input.c注册:如图所示 分离概念: 分离概念主要 ...
- Linux平台总线设备驱动
1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...
- 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...
- 驱动04.平台总线驱动模型——点亮LED灯
1 平台总线的简介 平台总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的 ...
- Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化
我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...
- linux usb总线驱动(一)
目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...
- Linux平台下裸设备的绑定:
Linux平台下裸设备的绑定: 运用RAW绑定 方法一 raw的配置(1) [root@qs-dmm-rh2 mapper]# cat /etc/rc.local #!/bin/sh # # This ...
随机推荐
- python学习笔记(virtualenv下载安装)
之前博客评论中有人建议我面对多个python版本的情况.可以使用virtualenv这个python虚拟沙盒 首页是利用pip下载.关于pip如何下载安装前面的博客中已经提到就不细说 cmd直接进入p ...
- selenium学习笔记(加入unittest)
利用firefox浏览器的selenium IDE可以直接生成webdriver+unittest的python脚本 当然博主是要为了自己编写脚本.对用例内容进行了修改,把元素校验功能也放入了用例中 ...
- angular指令详解--自定义指令
自定义指令 directive()这个方法是用来定义指令的: angular.module('myApp', []) .directive('myDirective', function ($time ...
- Node.js权威指南学习记录
学习nodeJS权威指南的学习记录 导航: 1.console模块 2.全局变量 3.Buffer对象 4.事件对象 5.网络请求 6.文件操作对象 一. COMMON.js的学习.(commonJS ...
- 使用Jenkins自动编译我的 java 项目 git maven jenkins
之前的项目已经将jenkins部署好,现在添加maven项目 准备工作 安装插件 Git plugin Publish Over SSH 全局设置 key: 是 linux服务器的私钥 Global ...
- [置顶]
kubernetes1.7新特性:新增StorageOS卷插件和Local持久存储
背景介绍 在Kubernetes中卷的作用在于提供给POD存储,这些存储可以挂载到POD中的容器上,进而给容器提供存储. 从图中可以看到结构体PodSpec有个属性是Volumes,通过这个Volum ...
- [置顶]
Android开发百科全书
友情提示根据目录 快速查找问题 %1$s %1$d Android string 1.整型,比如"我今年23岁了",这个23是整型的.在string.xml中可以这样写,<s ...
- apply 无循环拼接数组
apply()第二个参数只能是数组,这个数组将作为参数传给原函数的参数列表arguments. 其实在实际开发中,JS 继承的方法并不止这一种,使用原型链继承是更加常用的方式,此外还有构造函数继承,这 ...
- Beego的controller怎么用嵌入实现继承问题
Go Lang是无继承层次的轻量级面向对象编程范式.Go Lang中的接口与实现之间完全是非侵入式的.这种接口实现方式很值得称赞.不但如此,在Go Lang中只有类型嵌入而没有类型继承.这规避了很多与 ...
- (效果三)js实现选项卡切换
开发了很久的小程序,在接到一个h5移动端页面的时候,很多原生的东西都忘了,虽然说我们随着工作经验的增加,处理业务逻辑的能力在提高,但是基础的东西如果长时间不用,也会逐渐忘记.所以以后会经常总结原生的一 ...