您的位置:首页 > 其它

6410之驱动程序的分层分离,总线设备驱动模型

2013-08-20 11:33 387 查看
什么是分离分层的概念?

如前面的input子系统所述,分离分层概念可以如下图所示:



input.c和buttons.c,evdev.c形成分层的概念,buttons.c和evdev.c形成分离的概念,一边是硬件相关的代码由编写驱动的人员编写,一边是纯软件是由linux内核所提供的。

总线驱动设备模型:



该模型有三个结构体:

struct bus_type,struct device和struct device_driver。详细的设备模型内容可以参考/article/10646599.html

如上图所示:

device_add的作用:

1.把device放入bus的dev链表中

2.从bus的drv链表中取出每一个drv,再使用bus上的match函数判断drv是否支持dev

3.若可以支持,则调用drv的probe函数

driver_register的作用:

1.将driver放入到bus的drv链表中。

2.从bus上的devices链表中取出每一个dev,再使用bus上的match函数判断drv是否支持dev

3.若可以支持,则调用drv的probe函数

综上所述:总线,设备,驱动模型只是一个driver和dev建立链接的一种机制而已。

当一个文件夹中有多个模块文件,就需要将Makefile修改:

obj-m += led_dev.o

obj-m += led_drv.o

led_dev.c

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>

static struct resource s3c_led_resource[] = {
[0] = {
.start = 0x7F008830,
.end   = 0x7F008830 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 1,
.end   = 1,
.flags = IORESOURCE_IRQ,//表示led灯接到寄存器的第几个引脚
}
};

void led_release(struct device *dev)
{

}

struct platform_device led_dev = {
.name         = "s3c-led",
.id           = -1,
.num_resources    = ARRAY_SIZE(s3c_led_resource),
.resource     = s3c_led_resource,
.dev 		  = {
.release = led_release,//这个函数在rmmod led_dev的时候会使用到,最终调用到led_remove
}
};

static int led_devices_init(void)
{
platform_device_register(&led_dev);
return 0;
}

static void led_devices_exit(void)
{
platform_device_unregister(&led_dev);
}

module_init(led_devices_init);
module_exit(led_devices_exit);
MODULE_LICENSE("GPL");


如果不加release函数的话,在rmmod led_dev的时候出现下面现象:



led_drv.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>

static int led_probe(struct platform_device *pdev)
{
printk("Led probe !!!\n");
return 0;
}

static int led_remove(struct platform_device *dev)
{
printk("Led remove !!!\n");
return 0;
}

struct platform_driver led_driver = {
.probe	= led_probe,
.remove	= led_remove,
.driver	= {
.name	= "s3c-led",
.owner  = THIS_MODULE,
},
};

static int led_driver_init(void)
{
platform_driver_register(&led_driver);
return 0;
}

static void led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}

module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");


具体操作led:

只需要修改led_drv.c即可:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/fs.h>

struct class *led_dev_class;
struct device *led_dev;
int major;
static int pin;
static volatile unsigned long *gpiocon;
static volatile unsigned long *gpiodat;

static int led_drv_open(struct inode *inode, struct file *file)
{
//设置gpio为输出引脚
*gpiocon &= ~(0x3 << (pin*4));        //pin为从led_dev.c获取到的resource
*gpiocon |= (0x1 << (pin*4));

return 0;
}

ssize_t led_drv_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
int val;

copy_from_user(&val,buf,len);

if(val == 1){
//点灯
*gpiodat &= ~(1 << pin );
}else if(val == 0){
//灭灯
*gpiodat |= (1 << pin );
}

return sizeof(buf);
}

static struct file_operations led_drv_fops = {
.owner   =   THIS_MODULE,
.open    =   led_drv_open,
.write   =   led_drv_write,
};

static int led_probe(struct platform_device *pdev)
{
printk("Led probe !!!\n");

struct resource *res ;
res = platform_get_resource(pdev,IORESOURCE_MEM,0);  //获取到标志为IORESORCE_MEM的res

gpiocon = ioremap(res->start,res->end - res->start + 1);
gpiodat = gpiocon + 1;

res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
pin = res->start;

major = register_chrdev(0,"led_drv",&led_drv_fops);
led_dev_class = class_create(THIS_MODULE,"led_class");
led_dev = device_create(led_dev_class,NULL,MKDEV(major,0),NULL,"led");
return 0;
}

static int led_remove(struct platform_device *dev)
{
printk("Led remove !!!\n");

device_destroy(led_dev_class,MKDEV(major,0));
class_destroy(led_dev_class);
unregister_chrdev(major,"led_drv");
iounmap(gpiocon);

return 0;
}

struct platform_driver led_driver = {
.probe	= led_probe,
.remove	= led_remove,
.driver	= {
.name	= "s3c-led",
.owner  = THIS_MODULE,
},
};

static int led_driver_init(void)
{
platform_driver_register(&led_driver);
return 0;
}

static void led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}

module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");


测试程序:

#include <stdio.h>
#include <fcntl.h>

int main(int argc , char **argv)
{
int fd ;
int val;

if(argc < 2){
printf("Usage : %s <on/off> \n",argv[0]);
return -1;
}

if(!strcmp(argv[1],"on")){
val = 1;
}else if(!strcmp(argv[1],"off")){
val = 0;
}
fd = open("/dev/led",O_RDWR); //打开设备节点/dev/led
if(fd < 0){
printf("Can not open devices\n");
return -1;
}

write(fd,&val,4);//向设备节点做写操作
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: