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 ...
随机推荐
- ubuntu16.04 添加中文ibus输入法
ubuntu版本 16.04 在terminal 输入命令 sudo apt-get install ibus-pinyin sudo apt-get ibus-setup 设置 选择拼音,添加选择 ...
- python面向对象编程学习
python面向对象编程 基本概念理解 面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...
- 一 web爬虫,requests请求
requests请求,就是用python的requests模块模拟浏览器请求,返回html源码 模拟浏览器请求有两种,一种是不需要用户登录或者验证的请求,一种是需要用户登录或者验证的请求 一.不需要用 ...
- Oracle Package
(转自:http://blog.csdn.net/bbliutao/article/details/9016947) 一.概述包可将一些有联系的对象放在其内部.任何能在块定义部分出现的对象都可以在包中 ...
- Visual Studio 调试技巧:10 篇热文汇总
本文精选了 DotNet 2017年11月份的10篇热门文章.其中有技术分享.技术资源. 注:以下文章,点击标题即可阅读 <Visual Studio的调试技巧 > 调试技巧是衡量程序员 ...
- 将从mysql数据库查询的信息,遍历到List<>以及一些随机数的生成
将从mysql数据库查询的信息,遍历到List<>以及一些随机数的生成. 代码比较乱,但是方法还是对的,大家又需要的选择看,希望对博友 有帮助,欢迎留言分享! public class s ...
- java网络编程TCP传输—流操作—服务端反馈与客户端接收
在读取完流后,服务端会向客户端返回一些数据,告诉客户端,已经写完了. 在这里和”流操作—拿到源后的写入动作“差不多,客户端同样以byte与Buffered两种缓冲读取作为例子,同时,.也是希望大家给补 ...
- linux ls-al 指令详解
ls -al 具体说明请自行找男人(man 中了鸟哥的毒 =.=).
- SGU 505 Prefixes and suffixes
题解 现将字符串排序: 那么某前缀在字符串中出现肯定是连续的:写几个案例就知道了:这是记录每个字符在以前缀排名的rank : 然后将字符串反序: 再排序:依照前缀,可以知道相同名字的后缀也会出现在 ...
- 深入了解ZooKeeper(一)
在上篇博客ZooKeeper初探之安装和配置中已经对Zookeeper这个“服务协调者”有了初步的认识和了解,一个字“美”,接下来开始深入的交往,开始了解其内心世界! 1. 内容思维导图 2. 分布式 ...