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

什么是分离分层的概念?

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


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


总线驱动设备模型:

6410之驱动程序的分层分离,总线设备驱动模型_第1张图片

该模型有三个结构体:

struct bus_type,struct device和struct device_driver。详细的设备模型内容可以参考http://blog.csdn.net/longshan_2009/article/details/10098573

如上图所示:

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的时候出现下面现象:

6410之驱动程序的分层分离,总线设备驱动模型_第2张图片


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;
}


你可能感兴趣的:(bus_driver_dev)