Linux设备驱动开发 - 平台设备驱动

Linux2.6的内核中引入了一种新的设备驱动模型-平台(platform)设备驱动,平台设备驱动分为平台设备(platform_device)和平台驱动(platform_driver),平台设备的引入使得Linux设备驱动更加便于移植。

一、平台设备
平台设备结构体:

 1 struct platform_device {
 2     const char    * name;                      /* 设备名 */
 3     int        id;
 4     struct device    dev;                     /* 设备结构体 */
 5     u32        num_resources;                   /* 设备资源数量 */
 6     struct resource    * resource;              /* 设备资源 */
 7
 8     const struct platform_device_id    *id_entry;
 9
10     /* arch specific additions */
11     struct pdev_archdata    archdata;
12 };

平台设备主要是提供设备资源和平台数据给平台驱动,resource为设备资源数组,类型有IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA、IORESOURCE_DMA。下面是一个网卡芯片DM9000的外设资源:

 1 static struct resource dm9000_resources[] = {
 2     [0] = {
 3         .start        = S3C64XX_PA_DM9000,
 4         .end        = S3C64XX_PA_DM9000 + 3,
 5         .flags        = IORESOURCE_MEM,
 6     },
 7     [1] = {
 8         .start        = S3C64XX_PA_DM9000 + 4,
 9         .end        = S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,
10         .flags        = IORESOURCE_MEM,
11     },
12     [2] = {
13         .start        = IRQ_EINT(7),
14         .end        = IRQ_EINT(7),
15         .flags        = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
16     },
17 };

dm9000_resources里面有三个设备资源,第一个为IORESOURCE_MEM类型,指明了第一个资源内存的起始地址为S3C64XX_PA_DM9000结束地址为S3C64XX_PA_DM9000 + 3,第二个同样为IORESOURCE_MEM类型,指明了第二个资源内存的起始地址为S3C64XX_PA_DM9000 + 4结束地址为S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,第三个为IORESOURCE_IRQ类型,指明了中断号为IRQ_EINT(7)。

 1 struct device {
 2     struct device        *parent;
 3
 4     struct device_private    *p;
 5
 6     struct kobject kobj;
 7     const char        *init_name; /* initial name of the device */
 8     struct device_type    *type;
 9
10     struct mutex        mutex;    /* mutex to synchronize calls to
11                      * its driver.
12                      */
13
14     struct bus_type    *bus;        /* type of bus device is on */
15     struct device_driver *driver;    /* which driver has allocated this
16                        device */
17     void        *platform_data;    /* Platform specific data, device
18                        core doesn‘t touch it */
19     ...
20 };

struct device结构体里面有一个重要成员platform_data,它是平台设备和平台驱动进行数据传递的重要成员。

平台设备注册:

1 int platform_device_register(struct platform_device *pdev);

platform_device_register()会对平台设备进行相应的初始化之后调用platform_device_register()函数把它添加到子系统中。

平台设备注销:

1 void platform_device_unregister(struct platform_device *pdev);

platform_device_unregister()函数释放设备资源之后从子系统中将其移除。

平台设备模板:

 1 static struct resource xxx_resource =
 2 {
 3     [0] =
 4     {
 5         .start = ...,
 6         .end = ...,
 7         .flags = ...,
 8     },
 9     [1] =
10     {
11         ...
12     }
13     ...
14 };
15
16 static struct xxx_plat_data xxx_data =
17 {
18     ...
19 };
20
21 static struct platform_device xxx_platform_device =
22 {
23     .name = NAME,
24     .num_resources = ARRAY_SIZE(xxx_resource),
25     .resource = xxx_resource,
26     .dev =
27     {
28         .platform_data = &xxx_data,
29     }
30 };
31
32 static int __init xxx_device_init(void)
33 {
34     ...
35     /* 注册平台设备 */
36     platform_device_register(&xxx_platform_device);
37     ...
38 }
39
40 static void __exit xxx_device_exit(void)
41 {
42     ...
43     /* 注销平台设备 */
44     platform_device_unregister(&xxx_platform_device);
45     ...
46 }

二、平台驱动
平台驱动结构体:

1 struct platform_driver {
2     int (*probe)(struct platform_device *);
3     int (*remove)(struct platform_device *);
4     void (*shutdown)(struct platform_device *);
5     int (*suspend)(struct platform_device *, pm_message_t state);
6     int (*resume)(struct platform_device *);
7     struct device_driver driver;
8     const struct platform_device_id *id_table;
9 };

平台驱动结构体driver成员里面的name必须与平台设备结构体里面的name成员一致,在系统注册一个设备的时候,会通过设备结构体里面的name成员和平台驱动driver里面的name成员匹配,当匹配成功则调用平台驱动的probe函数,
通常在probe函数中获取平台设备的资源和私有数据并进行设备的初始化。

获取设备资源:

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

platform_get_resource()函数用于获取平台设备的资源,dev为要平台设备,type为平台设备资源类型,num为平台资源号(比如同一个资源有两个则资源号为0,1)。

平台驱动注册:

1 int platform_driver_register(struct platform_driver *drv);

platform_driver_register()函数完成平台驱动的注册,在驱动模块加载时调用。

平台驱动注销:

1 void platform_driver_unregister(struct platform_driver *drv);

platform_driver_unregister()函数完成平台驱动的注销,在驱动模块卸载时调用。

平台驱动模板:

 1 static int __devinit xxx_probe(struct platform_device *pdev)
 2 {
 3     struct xxx_plat_data *pdata = pdev->dev.platform_data;    /* 获取私有数据 */
 4     platform_get_resource(pdev,xxx,x);                        /* 获取设备资源 */
 5     ...
 6 }
 7
 8 static struct platform_driver xxx_platform_driver =
 9 {
10     .probe = xxx_probe,
11     .remove = __devexit_p(xxx_remove),
12     .driver =
13     {
14         .name = NAME,    /* 跟平台设备名一致 */
15         ...
16     },
17     ...
18 };
19
20 static int __init xxx_driver_init(void)
21 {
22     ...
23     /* 驱动注册 */
24     platform_driver_register(&xxx_platform_driver);
25     ...
26 }
27
28 static void __exit xxx_driver_exit(void)
29 {
30     ...
31     /* 驱动注销 */
32     platform_driver_unregister(&xxx_platform_driver);
33     ...
34 }
时间: 2024-10-10 07:46:30

Linux设备驱动开发 - 平台设备驱动的相关文章

Linux 设备驱动开发 —— platform设备驱动应用实例解析

前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 -- platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platform模型驱动编程,platform 驱动只是在字符设备驱动外套一层platform_driver 的外壳. 在一般情况下,2.6内核中已经初始化并挂载了一条platform总线在sysfs文件系统中.那么我们编写platform模型驱动时,需要完成两个工作: a -- 实现platform驱动 架构就

字符设备驱动、平台设备驱动、设备驱动模型、sysfs的关系

Linux驱动开发的童鞋们来膜拜吧:-)  学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关联的分析.对于开发者而言,能够熟悉某一点并分享出来已很难得,但对于专注传授技术和经验给

[kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术.对于初学者来说会非常困惑,甚至对Linux有一定基础的工程师而言,能够较好理解这些相关技术也相对不错了.要深刻理解其中的原理需要非常熟悉设备驱动相关的框架和模型代码.网络上有关这些技术的文章不少,但多是对其中的某一点进行阐述,很难找到对这些技术进行比较和关

驱动开发之 设备读写方式:直接方式

上一节介绍了缓冲区方式读写,这一节咱们来看看直接方式读写设备. 1. 直接方式读写设备,操作系统会将用户模式下的缓冲区锁住,然后操作系统将这段缓冲区在内核模式地址再次映射一遍.这样,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存.无论操作系统如何切换进程,内核模式地址都保持不变. 创建好设备IoCreateDevice后,需要设置DO_DIRECT_IO,  pDevObj->Flags |= DO_DIRECT_IO. 2. 这里涉及到内存描述符表(MDL) MDL结构的声明如下

Linux驱动之平台设备

<平台设备设备驱动> a:背景: 平台总线是Linux2.6的设备驱动模型中,关心总线,设备和驱动这3个实体.一个现实的Linux设备和驱动通常需要挂接在一种总线上(比如本身依附于PCI,USB,IIC,SPI等设备而言).但是在嵌入式系统里面,SoC系统即集成的独立外设控制器,挂接在SoC内存空间的外设却没有这样的总线依附,为了和Linux设备驱动模型理论相互统一,Linux系统开发了Platform_bus这种虚拟总线,相应的设备叫做platform_device ,相应的驱动叫platf

Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)

Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了. 对于整个设备总线驱动模型的样子,如下图.简单来说,bus 负责维护注册进来的devcie 与 driver,每注册进来一个device 或者 driver 都会调用 Bus->match 函数

13 Linux驱动之平台设备

一 platform子系统 1.对平台设备描述 struct platform_device { const char * name; //设备名字 int id; // -1 struct device dev; //通用设备描述 u32 num_resources; //资源的个数 struct resource * resource;//资源 //如果是在driver的id_table中匹配成功,id_entry就会记录id_table匹配的项 const struct platform_

linux嵌入式开发平台网卡驱动解决办法

最近用了下树莓派和inter Edison,本来打算使用一下网卡,可是发现树莓派和Edison竟然都编译不了官方的驱动,报错缺少 /kenerl/bulid 目录,查了下资料,原来是这些嵌入式平台都为了节省空间,都没有搭载源码,而在网卡的驱动程序中有需要调用系统的接口,但是没有源码,这些接口也就没有了,编译的时候就找不到接口,so,报错了. 一编译驱动 解决办法有两个: 第一 安装source-devel source-devel也就是源码库,你所用的内核的接口该有的它都有. 1. 首先,查看内

Linux USB 驱动开发—— USB 鼠标驱动注解及测试

参考2.6.14版本中的driver/usb/input/usbmouse.c.鼠标驱动可分为几个部分:驱动加载部分.probe部分.open部分.urb回调函数处理部分. 一.驱动加载部分 static int __init usb_mouse_init(void) { int retval = usb_register(&usb_mouse_driver);//注册鼠标驱动 if (retval == 0) info(DRIVER_VERSION ":" DRIVER_DE