驱动程序之_1_字符设备_10_分离分层概念_总线驱动设备机制

本文深入探讨了驱动程序设计中的关键概念——分离分层,特别是总线驱动设备机制。通过LED驱动程序实例,详细解释了如何将硬件(device)与软件(driver)分离,以及如何在多个驱动程序中抽象出通用机制,实现代码的复用和模块化。文章还提供了具体的代码示例,展示了device层和driver层的实现细节。

驱动程序之_1_字符设备_10_分离分层概念_总线驱动设备机制

一个好的驱动框架往往会使用到分离分层的概念,分离是横向的,分层是纵向的,分离出来的东西是平行的,分层出来的东西,是不平行的,可以认为分层出来的东西有的是抽象的、有的是具体的。关于分离分层一个很好的例子就是总线驱动设备框架,后面LCD驱动程序的文章也使用到了分离分层概念

使用的硬件不同,硬件相关的代码也不同,但软件相关的代码可以相同,分离就是将硬件、软件分开,在移植过程中只需要修改硬件相关的代码即可,软件代码保持稳定;而分层,则可以在多个驱动程序中抽象出一种机制,这种机制单独作为一层,提供为多个驱动程序使用,这样使得众多驱动程序形式上趋同

总线驱动设备机制就是使用了分层概念抽象出来的一套机制,它仅仅是一种机制,是抽象的,它需要融入实际的驱动程序才具有意义,而众多驱动程序都可以使用这套机制
在总线驱动设备机制中,使用了分离的概念,将一个驱动分为了硬件(device)部分、软件(driver)部分,这里作为例子,将以前写过的LED驱动程序使用总线驱动设备机制将其拆分为两块,驱动程序中只给定了一个LED设备,当我们需要更换LED设备(点亮其他灯),只需要修改驱动程序device层的参数即可,而不需要修改driver层(这里只是举个例子,在驱动程序中控制3个LED设备是可以做到的)

device层:
1、声明、定义platform_device(要指定设备名、可用资源信息)
2、在入口函数注册platform_device
3、在出口函数销毁platform_device

driver层:
1、声明、定义platform_driver(指定probe、remove函数、设备名)、file_operations
2、在入口函数注册platform_driver
3、在出口函数销毁platform_driver
4、实现probe、remove函数,完成文件结构体的注册和销毁操作,实现open、write等函数

在注册device、driver时,会将相应的结构体添加到总线的链表中,并且根据名字检测是否有匹配的driver、device(如果是注册device,就匹配driver,如果是注册driver,就匹配device),如果匹配到,就调用driver的probe函数,因此probe可以看作驱动程序的真正入口;同样地,当销毁device、driver时,将相应结构体移出总线链表,根据名字检测是否有匹配地driver、device,如果有,就调用driver地remove函数,同样remove也可以看作是驱动程序的真正出口

附上驱动程序和测试用的应用程序代码

驱动程序的device层

#include <linux/device.h>
#include <linux/module.h>
#include <linux/version.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/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>


void led_release (struct device * dev)  {}

static struct resource led_resource[] = {
	[0] = {
		.start = 0x56000050,
		.end   = 0x56000050 + 8 - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = 4,
		.end   = 4,
		.flags = IORESOURCE_IO,
	},
};

static struct platform_device led_dev = {
	.name     	 	  = "led",
	.id       	   	  = -1,
    .num_resources    = ARRAY_SIZE(led_resource),
	.resource 		  = led_resource,
	.dev      		  = {
		.release 	  = led_release,
	},
};

static int platform_dev_init(void)
{
	platform_device_register(&led_dev);

	return 0;
}

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

module_init(platform_dev_init);
module_exit(platform_dev_exit);
MODULE_LICENSE("GPL");

驱动程序的driver层

#include <linux/module.h>
#include <linux/version.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/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>

static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;
static unsigned int pin;

static int led_open(struct inode *inode, struct file *file)
{
	*gpfcon &= ~(0x3<<(pin*2));
	*gpfcon |= (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;
	int error;
	
	error = copy_from_user(&val,buf,count);
	
	if(val)
		*gpfdat &= ~(1<<pin);
	else
		*gpfdat |= 1<<pin;		

	
	return 0;
}


static struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open  = led_open,
	.write = led_write,
};


static int 					 major;
static struct class 		*led_class;
static struct class_device  *led_class_dev;

static int led_probe(struct platform_device *pdev)
{
	struct resource * res;
	
	res = platform_get_resource(pdev,IORESOURCE_MEM,0);
	if(!res)
		printk("get_resource error\r\n");
	else
	{
		gpfcon = ioremap(res->start,res->end - res->start + 1);
		gpfdat = gpfcon + 1;
	}
	
	res = platform_get_resource(pdev,IORESOURCE_IO,0);
	if(!res)
		printk("get_resource error\r\n");
	else
		pin = res->start;

	major = register_chrdev(0,"led",&led_fops);
	led_class = class_create(THIS_MODULE,"led_class");
	led_class_dev = class_device_create(led_class,0,MKDEV(major,0),0,"led");

	return 0;
}

static int led_remove(struct platform_device *pdev)
{
	class_device_destroy(led_class,MKDEV(major,0));
	class_unregister(led_class);
	unregister_chrdev(major,"led");

	iounmap(gpfcon);

	return 0;
}

static struct platform_driver led_drv = {
	.probe  = led_probe,
	.remove = led_remove,
	.driver = {
		.name = "led",
	},
};

static int platform_drv_init(void)
{
	platform_driver_register(&led_drv);

	return 0;
}

static void platform_drv_exit(void)
{
	platform_driver_unregister(&led_drv);
}

module_init(platform_drv_init);
module_exit(platform_drv_exit);
MODULE_LICENSE("GPL");

应用程序

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(int argv,char *argc[])
{
	int fd;
	int error;
	int stat = 0;;
	
	if(argv != 2)
	{
		printf("Usage : ./filename <on | off>\r\n");
		return -1;
	}
	
	if(error = strcmp("on",argc[1]))
	{
		if(error = strcmp("off",argc[1]))
		{
			printf("Usage : ./filename <on | off>\r\n");
			return -2;
		}
	
}	
	else
	{
		stat = 1;	
	}

	fd = open("/dev/led",O_RDWR);
	if(fd < 0)
	{
		printf("open error\r\n");
		return -2;
	}
	error = write(fd,&stat,sizeof(stat));
	
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值