驱动之路二----LED(MISC设备)
2013-11-17 00:08
197 查看
驱动开始之路------LED驱动
在上面的这篇博客中,我写的LED驱动是将LED作为字符设备写的,大家可能也发现了,在写驱动文件时特别冗长,这样是不利于程序员们写驱动的,Linux内核(2.6版内核之后的)添加了设备分类的概念,注意与设备模型概念的区分。
设备模型:(三要素)总线、驱动、设备
优点:电源管理(设计的初衷)
热插拔
增强驱动的可移植性
Linux 内核将所有的设备分为三大类:字符设备、块设备、网络设备、
要记住,Linux 内核只是给出了这种分类,并没有明确给出哪种设备是属于哪一类,这根据程序员自己的经验来判定,什么样的设备拿什么样类来写;
字符设备:是设备种类最多的一类,基本常见的设备都可以拿字符设备来写
块设备:很容易看出,主要是存储类的,SD卡,NAND,硬盘等
网络设备:常见的就是网卡了
但是在这三大类的基础上,是可以写了,但是还是会有诸多不便,2.6版本以后的内核又加上了设备分类
设备分类:实际将字符设备进一步分类了
输入设备
fb设备
sound设备
....
tty设备
....
misc
当然也可以自己创建类,通过函数class_create创建一个类
了解完了基本概念,我们现在将led作为misc设备重写,
基本的宏定义我就不重写了,都与本文开始提到的博客中的头文件相同,只是将led_info结构体修改一下,
为了体现完整性,我将驱动文件完全的写以下:
作为misc设备的LED驱动就写完了。
大家如果发现什么问题一定要告诉我,大家一起学习了。
在上面的这篇博客中,我写的LED驱动是将LED作为字符设备写的,大家可能也发现了,在写驱动文件时特别冗长,这样是不利于程序员们写驱动的,Linux内核(2.6版内核之后的)添加了设备分类的概念,注意与设备模型概念的区分。
设备模型:(三要素)总线、驱动、设备
优点:电源管理(设计的初衷)
热插拔
增强驱动的可移植性
Linux 内核将所有的设备分为三大类:字符设备、块设备、网络设备、
要记住,Linux 内核只是给出了这种分类,并没有明确给出哪种设备是属于哪一类,这根据程序员自己的经验来判定,什么样的设备拿什么样类来写;
字符设备:是设备种类最多的一类,基本常见的设备都可以拿字符设备来写
块设备:很容易看出,主要是存储类的,SD卡,NAND,硬盘等
网络设备:常见的就是网卡了
但是在这三大类的基础上,是可以写了,但是还是会有诸多不便,2.6版本以后的内核又加上了设备分类
设备分类:实际将字符设备进一步分类了
输入设备
fb设备
sound设备
....
tty设备
....
misc
当然也可以自己创建类,通过函数class_create创建一个类
了解完了基本概念,我们现在将led作为misc设备重写,
基本的宏定义我就不重写了,都与本文开始提到的博客中的头文件相同,只是将led_info结构体修改一下,
struct led_info { void __iomem *v; int status; int user; dev_t no; struct miscdevice dev;//misc设备的结构体 void (*on)(struct led_info *l, int no); void (*off)(struct led_info *l, int no); };对于设备文件基本就不需要改了,对于一个相同的设备,设备文件基本不动
为了体现完整性,我将驱动文件完全的写以下:
#include <linux/init.h> #include <linux/module.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/fs.h> #include "s3c_led.h" void s3c_led_on(struct led_info *l, int no) { u32 tmp; tmp = readl(l->v + GPMDAT); tmp &= GPM_LOW(no); writel(tmp, l->v + GPMDAT); } void s3c_led_off(struct led_info *l, int no) { u32 tmp; tmp = readl(l->v + GPMDAT); tmp |= GPM_HIGH(no); writel(tmp, l->v + GPMDAT); } void s3c_led_init(struct led_info *l) { u32 tmp; tmp = readl(l->v + GPMCON); tmp &= GPM0_3_MASK; tmp |= GPM0_3_OUT; writel(tmp, l->v + GPMCON); tmp = readl(l->v + GPMDAT); tmp |= GPM0_3_HIGH; writel(tmp, l->v + GPMDAT); l->on = s3c_led_on; l->off = s3c_led_off; } void s3c_led_exit(struct led_info *l) { u32 tmp; tmp = readl(l->v + GPMDAT); tmp |= GPM0_3_HIGH; writel(tmp, l->v + GPMDAT); } //-----------------------------------------------------------以下是与硬件无关的,模式比较固定 struct led_info *led; ssize_t led_read(struct file *fp, char __user *buffer, size_t count, loff_t *off) { char buf[64]; int ret = 0; ret += sprintf(buf, "State:%x\n", led->status); if(copy_to_user(buffer, buf, ret)) return -EFAULT; return ret; } ssize_t led_write(struct file *fp, const char __user *buffer, size_t count, loff_t *off) { if(buffer[1] == '1'){ led->on(led, buffer[0] - '0'); led->status |= S_LED_ON(buffer[0] - '0'); }else if(buffer[1] == '0'){ led->off(led, buffer[0] - '0'); led->status &= S_LED_OFF(buffer[0] - '0'); }else{ return -EPERM; } return count; } int led_open(struct inode *no, struct file *fp) { if(!led->user) led->user++; else return -EBUSY; return 0; } int led_release(struct inode *no, struct file *fp) { if(led->user) led->user--; else return -ENODEV; return 0; } struct file_operations led_ops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .read = led_read, .write = led_write, }; int led_probe(struct platform_device *pdev) { struct resource *led_res; int ret; led_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if(!led_res) return -EBUSY; led = kzalloc(sizeof(struct led_info), GFP_KERNEL); if(!led) return -ENOMEM; led->v = ioremap(led_res->start, led_res->end - led_res->start + 1); if(!led->v){ ret = -ENOMEM; goto remap_v_error; } //可以看出,此处的代码比使用字符设备要少很多 led->dev.name = pdev->name; led->dev.minor = MISC_DYNAMIC_MINOR;//动态分配次设备号,misc设备的主设备号固定是10 led->dev.fops = &led_ops; ret = misc_register(&led->dev);/这里注册的是misc设备,就不是字符设备了 if(ret) goto misc_register_error; s3c_led_init(led); led->status = S_LED_OFF_ALL; return 0; misc_register_error: iounmap(led->v); remap_v_error: kfree(led); return ret; } int led_remove(struct platform_device *pdev) { s3c_led_exit(led); misc_deregister(&led->dev); iounmap(led->v); kfree(led); return 0; } struct platform_driver drv = { .probe = led_probe, .remove = led_remove, .driver = { .name = "s3c-led", }, }; static __init int module_test_init(void) { return platform_driver_register(&drv); } static __exit void module_test_exit(void) { platform_driver_unregister(&drv); } module_init(module_test_init); module_exit(module_test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Musesea"); MODULE_VERSION("1.0"); MODULE_DESCRIPTION("Test for module");
作为misc设备的LED驱动就写完了。
大家如果发现什么问题一定要告诉我,大家一起学习了。
相关文章推荐
- linux驱动开发之路(一)--LED驱动(misc设备)
- linux的misc设备led--6410---学习笔记
- 字符设备驱动之LED-混杂设备驱动(misc)
- platform设备驱动之LED(misc设备)
- 字符设备驱动第十五课-----LED点灯
- tiny6410 linux混杂设备 led驱动
- Tiny6410_LED驱动程序_自动分配主设备号+手动创建设备节点
- 一个纯字符的(最原始版本)led驱动(有有助于加深对字符设备的理解)
- s3c2440基于linux的gpio led字符设备驱动实践
- linux设备驱动--LED驱动
- 字符设备驱动程序--LED驱动
- Linux输入子系统(6):设备驱动层之LED驱动
- 嵌入式Linux字符设备驱动LED驱动编写
- misc设备
- 字符设备驱动程序之LED驱动程序__韦老师linux视频源码
- miscdevice混杂设备驱动
- 基于platform总线的mini2440的led设备驱动例子
- 第七章 驱动开发_第一个字符型设备(LED)驱动
- 字符设备编程(四)之可爱的 misc
- MISC 设备动态次设备号分析