您的位置:首页 > 其它

驱动之路二----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结构体修改一下,

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驱动就写完了。

大家如果发现什么问题一定要告诉我,大家一起学习了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: