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 图像库PIL详解
PIL详细文档 The most important class in the Python Imaging Library is the Image class, defined in the mo ...
- 遇到不确定的json格式
我们在调用webservice接口,或者http接口时,返回的json数据,有时候会因为情况不同,返回的数据格式也不一样. 比如我在调用增加档案接口时,传入要添加的档案id,如果成功了,success ...
- 跨平台TTS eSpeak Windows开发
转摘请说明出处:http://www.cnblogs.com/luochengor/p/3511165.html以及作者,谢谢. eSpeak是最为流行的开源跨平台的文本转语音程序.这两天进行了简单的 ...
- 完全卸载gitlab
完全卸载删除gitlab 2017年5月29日 wuhao 暂无评论 4,089次浏览 完全卸载删除gitlab 1.停止gitlab 1 gitlab-ctl stop 2.卸载gitlab ...
- MySQL备份与恢复实战案例及生产方案
按天备份 按周备份 mysql的mysqldump备份什么时候能派上用场1,迁移或者升级数据库时2,增加从库的时候3,如果因为硬件或特殊情况,主库或者从库宕机,主从可以互相切换,无需备份4,人为的DD ...
- Qt类型转换
(转自:http://qimo601.iteye.com/blog/1260479) 1.char * 与 const char *的转换 char *ch1="hello11"; ...
- canvas - 圆圈内 hover 高亮 效果
各种计算还挺繁琐的, 关键点在角度的计算, 根据鼠标位置, 利用atan(y/x) 得到反正切值 , 角度 (tan输入的是r和x围成的那个角,输出的是y/x.反tan就是输入y/x输出角.) &l ...
- [JS学习笔记]Event对象
写在前面 学习和总结JS时会伴随性的生成一些dome,其中包含一些动态输出的结果和标注. 之前通过鸡贼的办法实现了在博客中执行JS,但很多时候需要一张干净的页面编写dome,所以尝试通过一些在线的JS ...
- Django之jango框架 及 APP
Django框架 MVC框架和MTV框架 MVC,全名是Model View Controller,是软件工程中的软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器 ...
- 函数及参数http://www.cnblogs.com/Eva-J/p/7125925.html
文件的修改操作.删除操作,with语句 函数: 函数的定义:def 函数名(形参1,形参2....): 函数的调用:函数名(实参1,实参2) 函数的返回值: 定义阶段:return 三种情况:没有返回 ...