发布时间:2014-09-05 16:56:07作者:知识屋
# Platform Driver 平台驱动
Linux中的所有设备驱动都需要注册到系统平台下,这此操作由platform_device.h中定义的一组函数完成.我们先来看看struct platform_driver这个结构体:
view plaincopy to clipboardprint?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 (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
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 (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
该结构中包含了一组操作函数和一个struct device_driver的对像. 在我们自己的驱动中首先要做的就是定义platform_driver中的函数,并创建这个结构的一个对象实例, 然后在init()函数中调用platform_driver_register()向系统注册我们的驱动.
如kernel-3.0的leds-s3c24xx.c 中的platform_driver的定义为:
view plaincopy to clipboardprint?static struct platform_driver s3c24xx_led_driver = {
.probe = s3c24xx_led_probe,
.remove = s3c24xx_led_remove,
.driver = {
.name = "s3c24xx_led",
.owner = THIS_MODULE,
},
};
static struct platform_driver s3c24xx_led_driver = {
.probe = s3c24xx_led_probe,
.remove = s3c24xx_led_remove,
.driver = {
.name = "s3c24xx_led",
.owner = THIS_MODULE,
},
};
其它中指定了.driver的名字和所有者. 在调用platform_driver_register()注册驱动时,platform首先指定该设备是在系统中platform_bus主总线下,这只是一个虚拟总线驱动.然后platform驱动在调用driver_register(), driver_register在调用bus_add_driver()向系统总线管理器中注册驱动.如果成功会进行设备扫描,在dd.c中的driver_attach()中进行.实际会调用__driver_attach(),该函数又调用driver_probe_device(), driver_probe_device()分别会调用驱动注册时指定的总线probe和驱动自己的probe函数, 即我们上面注册的s3c24xx_led_probe()函数, 总线probe函数由platform_driver_register()中设置, 还设置了默认的Driver的操作函数.
在我们的probe函数中主要是进行设备的探测和初始化,这里2410的led是连接到gpio上的,所以总是存在,但是如果是一些像usb那样的外设,我们就需要先探测对外的外设是否存在.在sc324xx_led_probe中主要做了以下3件事.
1.创建一个私有数据对象, 并调用platform_set_drvdata()来附着到设备对象上.传给probe函数的参数是一个struct platform_device的平台设备对像(在那创建的呢?),
struct platform_device在定义如下:
view plaincopy to clipboardprint?struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
其中有一个struct device对象,这个对象保存了系统中一个具体的设备的相关信息. 其中driver_data一般用于保存和设备具体相关的私有信息,如这里用于保存struct s3c24xx_gpio_led实例,但是我们不要直接操作它,而应该使用platform_set_drvdata()函数.
2. 初始化具体的gpio
3. 调用led_classdev_register向内核注册一个led类驱动
小节: 这这个过程我们可以看到,在一个驱动程序中需要做那些事情,及基本的流程.
1.需要定义一个platform_driver的对象来描述驱动相关信息.
2.实现platform_driver中定义的必要的函数
3.向平台驱动管理器注册驱动.
4.驱动管理器会调用.probe函数来探测设备,需要在这里做设备初始化.
5.内核根据操作请求调用驱动的相应函数,如open, close等.
# Platform Device 平台设备
在platform driver中内核回调用我们注册的.probe函数,参数为一个platform_device的对象指针,但是这个从那来的呢, 以s3c2410 smdk板为例,对应的mach为mach-s3c2410,具体用的那个要看我们在配置内核的时候选择的什么平台和mach了,具体怎么配置或增加mach,不在本文的范围. 现在打开arch/arm/mach-s3c2410/mach-smdk2410.c 在文件的最后有个MACHINE_START的结构体:
view plaincopy to clipboardprint?MACHINE_START(SMDK2410, "SMDK2410")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
MACHINE_START(SMDK2410, "SMDK2410")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
该结构体描述了该mach相关的系统资源,内核在初始化时,根据该结构体的内容,进行初始化操作.找到其中指定的smdk_machine_init函数, 该函数的内容不多,现在我们只关心:
platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
这个调用, 进入platform_add_devices可以看到在该函数中有一个for循环来遍历devs参数中的platform_device,然后调用platform_device_register注册设备.从而生成前面我们的s3c24xx_led_probe收到的platform_device.
那主个devs又是那来的呢,回到上一层,可以看到传入的是一个静态定义的platform_device的数组,这里面就是根据我们的mach定义那的一些设置的配置信息,有点好pc的bios.所以要修改硬件配置就需要从这里开始.
作者“欢迎来到牛棚”
linux一键安装web环境全攻略 在linux系统中怎么一键安装web环境方法
Linux网络基本网络配置方法介绍 如何配置Linux系统的网络方法
Linux下DNS服务器搭建详解 Linux下搭建DNS服务器和配置文件
对Linux进行详细的性能监控的方法 Linux 系统性能监控命令详解
linux系统root密码忘了怎么办 linux忘记root密码后找回密码的方法
Linux基本命令有哪些 Linux系统常用操作命令有哪些
Linux必学的网络操作命令 linux网络操作相关命令汇总
linux系统从入侵到提权的详细过程 linux入侵提权服务器方法技巧
linux系统怎么用命令切换用户登录 Linux切换用户的命令是什么
在linux中添加普通新用户登录 如何在Linux中添加一个新的用户
2012-07-10
CentOS 6.3安装(详细图解教程)
Linux怎么查看网卡驱动?Linux下查看网卡的驱动程序
centos修改主机名命令
Ubuntu或UbuntuKyKin14.04Unity桌面风格与Gnome桌面风格的切换
FEDORA 17中设置TIGERVNC远程访问
StartOS 5.0相关介绍,新型的Linux系统!
解决vSphere Client登录linux版vCenter失败
LINUX最新提权 Exploits Linux Kernel <= 2.6.37
nginx在网站中的7层转发功能