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

被折叠的 条评论
为什么被折叠?



