当前位置:首页 > 嵌入式 > 嵌入式软件
[导读]从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。

从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。

Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。通过platform机制开发底层设备的流程是申请platform_device,注册platform_device,注册platform_driver

platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在include/linux/platform_device.h中,定义原型如下:

struct platform_device {

const char * name; //定义平台设备的名称

int id;

struct device dev;

u32 num_resources;

struct resource * resource; //定义平台设备的资源。

};

下面来看一下platform_device结构体中最重要的一个成员struct resource * resource。struct resource被定义在include/linux/ioport.h中,定义原型如下:

struct resource {

resource_size_t start; //定义资源的起始地址

resource_size_t end; //定义资源的结束地址

const char *name; //定义资源的名称

unsigned long flags; //定义资源的类型,比如MEM,IO,IRQ,DMA类型

struct resource *parent, *sibling, *child; //资源链表指针

};

通过调用函数platform_add_devices()向系统中添加该设备了,该函数内部调用platform_device_register( )进行设备注册。要注意的是,这里的platform_device设备的注册过程必须在相应设备驱动加载之前被调用,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。

接下来来看platform_driver结构体的原型定义,在include/linux/platform_device.h中,代码如下:

struct platform_driver {

int (*probe)(struct platform_device *);

int (*remove)(struct platform_device *);

void (*shutdown)(struct platform_device *);

int (*suspend)(struct platform_device *, pm_message_t state);

int (*suspend_late)(struct platform_device *, pm_message_t state);

int (*resume_early)(struct platform_device *);

int (*resume)(struct platform_device *);

struct device_driver driver;

};

内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在driver/base/platform.c文件中,具体实现代码如下:

int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;

if (drv->remove)

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)

drv->driver.shutdown = platform_drv_shutdown;

if (drv->suspend)

drv->driver.suspend = platform_drv_suspend;

if (drv->resume)

drv->driver.resume = platform_drv_resume;

return driver_register(&drv->driver);

}

下面举个例子来说明一下:

在kernel/arch/arm/mach-pxa/pxa27x.c定义了

tatic struct resource pxa27x_ohci_resources[] = {

[0] = {

.start = 0x4C000000,

.end = 0x4C00ff6f,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_USBH1,

.end = IRQ_USBH1,

.flags = IORESOURCE_IRQ,

},

};

这里定义了两组resource,它描述了一个usb host设备的资源,第1组描述了这个usb host设备所占用的

总线地址范围,IORESOURCE_MEM表示第1组描述的是内存类型的资源信息,第2组描述了这个usb host设备

的中断号,IORESOURCE_IRQ表示第2组描述的是中断资源信息。设备驱动会根据flags来获取相应的资源信息。

有了resource信息,就可以定义platform_device了:

static struct platform_device ohci_device = {

.name = "pxa27x-ohci",

.id = -1,

.dev = {

.dma_mask = &pxa27x_dmamask,

.coherent_dma_mask = 0xffffffff,

},

.num_resources = ARRAY_SIZE(pxa27x_ohci_resources),

.resource = pxa27x_ohci_resources,

};

有了platform_device就可以调用函数platform_add_devices向系统中添加该设备了,这里的实现是

static int __init pxa27x_init(void)

{

return platform_add_devices(devices, ARRAY_SIZE(devices));

}

这里的pxa27x_init必须在设备驱动加载之前被调用,可以把它放到

subsys_initcall(pxa27x_init);

驱动程序需要实现结构体struct platform_driver,参考kernel/driver/usb/host/ohci-pxa27.c,

static struct platform_driver ohci_hcd_pxa27x_driver = {

.probe = ohci_hcd_pxa27x_drv_probe,

.remove = ohci_hcd_pxa27x_drv_remove,

#ifdef CONFIG_PM

.suspend = ohci_hcd_pxa27x_drv_suspend,

.resume = ohci_hcd_pxa27x_drv_resume,

#endif

.driver = {

.name = "pxa27x-ohci",

},

};

在驱动初始化函数中调用函数platform_driver_register()注册platform_driver,需要注意的是

ohci_device结构中name元素和ohci_hcd_pxa27x_driver结构中driver.name必须是相同的,这样

在platform_driver_register()注册时会对所有已注册的所有platform_device中的name和当前注

册的platform_driver的driver.name进行比较,只有找到相同的名称的platfomr_device才能注册

成功,当注册成功时会调用platform_driver结构元素probe函数指针,这里就是ohci_hcd_pxa27x_drv_probe。

当进入probe函数后,需要获取设备的资源信息,获取资源的函数有:

struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);

根据参数type所指定类型,例如IORESOURCE_MEM,来获取指定的资源。

struct int platform_get_irq(struct platform_device *dev, unsigned int num);

获取资源中的中断号。

struct resource * platform_get_resource_byname(struct platform_device *dev, unsigned int type, char *name);

根据参数name所指定的名称,来获取指定的资源。

int platform_get_irq_byname(struct platform_device *dev, char *name);

根据参数name所指定的名称,来获取资源中的中断号。

 

总结,通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独自的资源(地址总线和IRQs),都可以用platform_driver实现。如:LCD,网卡、USB、UART等,都可以用platfrom_driver写,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

安装Linux操作系统并不复杂,下面是一个大致的步骤指南,以帮助您完成安装。1. 下载Linux发行版:首先,您需要从Linux发行版官方网站下载最新的ISO镜像文件。

关键字: Linux 操作系统 ISO镜像

计算机是由一堆硬件组成的,为了有限的控制这些硬件资源,于是就有了操作系统的产生,操作系统是软件子系统的一部分,是硬件基础上的第一层软件。

关键字: Linux 操作系统 计算机

Linux操作系统是一套免费使用和自由传播的类Unix操作系统,通常被称为GNU/Linux。它是由林纳斯·托瓦兹在1991年首次发布的,并基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。Lin...

关键字: Linux 操作系统

所谓进程间通信就是在不同进程之间传播或交换信息,它是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息;还可以让一个程序能够在同一时间里处理许多用户的需求。

关键字: Linux 进程通信 编程接口

串口通信作为一种最传统的通信方式,在工业自动化、通讯、控制等领域得到广泛使用。

关键字: Linux 串口通信 通讯

2023年11月16日: MikroElektronika(MIKROE) ,作为一家通过提供基于成熟标准的创新式硬软件产品来大幅缩短开发时间的嵌入式解决方案公司,今天宣布推出一款基于单线设备的软硬件开源解决方案Cli...

关键字: 嵌入式 Linux 操作系统

Linux是一种免费使用和自由传播的类Unix操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布。它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CP...

关键字: Linux 操作系统

本文中,小编将对嵌入式予以介绍,如果你想对它的详细情况有所认识,或者想要增进对它的了解程度,不妨请看以下内容哦。

关键字: 嵌入式 Linux

在这篇文章中,小编将为大家带来嵌入式 Linux的相关报道。如果你对本文即将要讲解的内容存在一定兴趣,不妨继续往下阅读哦。

关键字: 嵌入式 Linux
关闭
关闭