linux嵌入式开发,platform总线形式的驱动,是怎样从应用层调用驱动的呢 可以调用file_ops吗
我只能给一个思路给你,打个比方:你需要在platform平台下注册一个misc设备,那么就要在platform_driver结构中的probe函数中去注册一个misc设备。注意你的Platform_device的name和platform_driver的id_table或者name域相同,这样才会执行Probe函数。其实platform驱动不复杂,只是platform_device中有一些硬件的资源、我们把主要工作都在probe函数中做。
可以参考2.6内核的s3c2440的spi驱动程序,就是用platform形式注册的。
platform device怎么传递i2c client
to_i2c_client(dev) 这个函数返回值是一个指针,这个指针是个struct i2c_client 类型的指针,这个指针指向块内存,内存中存放着 to_i2c_client(dev)这个函数产生的数据。。
驱动程序识别设备时几种方法
驱动程序识别设备时,有以下两种方法:
(1)驱动程序本身带有设备的信息,比如开始地址、中断号等:加载驱动程序时,就可以根据这些信息来识别设备。
(2)驱动程序本身没有设备的信息,但是内核中已经(或以后)根据其他方式确定了很多设备的信息;加载驱动程序时,将驱动程序与这些设备逐个比较,确定两者是否匹配(match)。如果驱动程序与某个设备匹配,就可以通过该驱动程序操作这个设备了。内核常使用第二种方法来识别设备,这可以将各种设备集中在-一个文件中管理,当开发板的配置改变时,便于修改代码。在内核文件includePnuxÔatform _device.h 中,定义了两个数据结构来表示这些设备和驱动程序: platform_ device 结构用来描述设备的名称、ID、所占用的资源(比如内存地址/大小、中断号)等; platform_ driver 结构用来描述各种操作函数, 比如枚举函数、移除设备函数、驱动的名称等。内核启动后,首先构造链表将描述设备的platform_device结构组织起来,得到一一个设备的列表:当加载某个驱动程序的platform_ driver 结构时,使用一.些匹配函数来检查驱动程序能否支持这些设备,常用的检查方法很简单:比较驱动程序和设备的名称。
linux 下platform设备和驱动注册的先后顺序
Linux关于总线、设备、驱动的注册顺序
设备挂接到总线上时,与总线上的所有驱动进行匹配(用bus_type.match进行匹配),
如果匹配成功,则调用bus_type.probe或者driver.probe初始化该设备,挂接到总线上
如果匹配失败,则只是将该设备挂接到总线上。
驱动挂接到总线上时,与总线上的所有设备进行匹配(用bus_type.match进行匹配),
如果匹配成功,则调用bus_type.probe或者driver.probe初始化该设备;挂接到总线上
如果匹配失败,则只是将该驱动挂接到总线上。
需要重点关注的是总线的匹配函数match(),驱动的初始化函数probe()
1. platform_bus_type–总线先被kenrel注册。
2. 系统初始化过程中调用platform_add_devices或者platform_device_register,将平台设备(platform devices)注册到平台总线中(platform_bus_type)
3. 平台驱动(platform driver)与平台设备(platform device)的关联是在platform_driver_register或者driver_register中实现,一般这个函数在驱动的初始化过程调用。
通过这三步,就将平台总线,设备,驱动关联起来。
1. platform bus先被kenrel注册。
——————————————————
do_basic_setup() –》-driver_init() –》-platform_bus_init()–》bus_register()
2. 系统初始化过程中调用platform_add_devices或者platform_device_register,将平台设备(platform devices)注册到平台总线中(platform_bus_type)
——————————————————
系统启动阶段,总线的驱动链表还是空的,所以启动阶段的platform_add_devices()只负责将设备添加到总线的设备链表上。
Linux触摸屏驱动中什么时候会调用suspend这个函数
android系统摁下电源键后会让系统进入休眠以达到节电的目的。内核驱动中和休眠相关的就是suspend和resume函数。
suspend函数用于休眠,resume函数用于唤醒。下面分析驱动中的这两个函数是如何被调用到的。
驱动部分:
首先需要分析驱动的注册过程,较新的内核都是采用DTS方式来取代在内核中直接定义platform_device数据结构的注册方式,本文是基于DTS机制的内核来分析。
product对应的dts文件在编译时被编译为dtb文件,uboot在启动时候会将其地址传给内核,内核在启动过程中会去解析,具体解析是在start_kernel()-》setup_arch() –》 unflatten_device_tree()中具体分析可以参考网上,解析的最终结果会存放在allnodes地址处,这个allnodes随后在machine的init函数
中被使用,init函数中会根据allnodes中的节点数据组合成platform_device数据结构,然后将其注册到platform总线上,下面简要分析一下并重点关注这些初始化过程中和
pm相关的初始化。
我参与的项目中machine的init函数就是via_init_machine函数,在这个函数中就是调用了of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)这个函数来解析allnodes的。of_platform_populate是系统提供的接口。下面分析这个接口的实现:
[html] view plain copy
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path(“/“);
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
root最后就是取到的根节点,然后其作为参数传递给of_platform_bus_create,of_platform_device_create_pdata的实现如下:
[html] view plain copy
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, “compatible“, NULL))) {
pr_debug(“%s() – skipping %s, no compatible prop\n“,
__func__, bus-》full_name);
return 0;
}
auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata-》name;
platform_data = auxdata-》platform_data;
}
if (of_device_is_compatible(bus, “arm,primecell“)) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;
for_each_child_of_node(bus, child) {
pr_debug(“ create child: %s\n“, child-》full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev-》dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
根据传入参数,我们这里直接分析of_platform_device_create_padate函数,如下:
[html] view plain copy
struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;
if (!of_device_is_available(np))
return NULL;
dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;
#if defined(CONFIG_MICROBLAZE)
dev-》archdata.dma_mask = 0xffffffffUL;
#endif
dev-》dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev-》dev.bus = &platform_bus_type;
dev-》dev.platform_data = platform_data;
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
*/
if (of_device_add(dev) != 0) {
platform_device_put(dev);
return NULL;
}
return dev;
}
of_platform_device_create_padate-》of_device_alloc-》platform_device_alloc
便在platform_device_alloc函数中进行进行alloc和初始化了,实现如下:
[html] view plain copy
struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;
pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) {
strcpy(pa-》name, name);
pa-》pdev.name = pa-》name;
pa-》pdev.id = id;
device_initialize(&pa-》pdev.dev);
pa-》pdev.dev.release = platform_device_release;
arch_setup_pdev_archdata(&pa-》pdev);
}
return pa ? &pa-》pdev : NULL;
}
可以看到有个device_initialize,这里面对pdev.dev做一些列的初始化,其中有一个函数就是device_pm_init,这个函数就是我们一直关心的device相关的pm函数,具体实现如下:
[html] view plain copy
void device_pm_init(struct device *dev)
{
dev-》power.is_prepared = false;
dev-》power.is_suspended = false;
init_completion(&dev-》power.completion);
complete_all(&dev-》power.completion);
dev-》power.wakeup = NULL;
spin_lock_init(&dev-》power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev-》power.entry);
dev-》power.power_state = PMSG_INVALID;
}
可以看见它对device和功耗相关的数据做了一些初始化,我们这里先重点关注下dev-》power.entry,初始化一个链表头,所以他/它很有可能会在后面加到某个链表里面去,而那个链表应该是用来保存所有的device用的。系统中所有的platform_device都是通过这种方式注册到系统中的,那么应该所有的platform_device都会初始化一个dev-》power.entry,如果到时候把所有的dev-》power.entry都添加到某个链表上去,那么系统到时候查询的时候只要找到这个list head就可以找到所有的platform_device了。嗯,不过这是我们的猜测。我们接下去分析来验证下。
platform_device通过alloc之后已经初始化好了,那么接下去就可以添加到系统中了,所以我们再回头看of_platform_device_create_pdata的实现。
函数在of_device_alloc之后把dev-》dev.bus赋值给了platform_bus_type,接着就调用了of_device_add函数,在of_device_add函数中最后通过device_add添加到了bus上,但是device_add中有个函数需要我们关系,就是device_pm_add(dev),实现如下:
[html] view plain copy
void device_pm_add(struct device *dev)
{
pr_debug(“PM: Adding info for %s:%s\n“,
dev-》bus ? dev-》bus-》name : “No Bus“, dev_name(dev));
mutex_lock(&dpm_list_mtx);
if (dev-》parent && dev-》parent-》power.is_prepared)
dev_warn(dev, “parent %s should not be sleeping\n“,
dev_name(dev-》parent));
list_add_tail(&dev-》power.entry, &dpm_list);
dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}
可以看到这里list_add_tail(&dev-》power.entry, &dpm_list);这就验证了我们之前的猜测。所有注册到系统中的设备,最终都是会添加到dpm_list这条链表上。
那么系统在休眠的时候是如何通过dmp_list这表链表来suspend设备的呢?接下去就是我们要分析的电源管理部分内容。
系统电源部分:
电源管理相关文件在kernel/power目录下,前面已经分析到。系统中注册的设备都是会添加到dmp_list这条链表上的。那么睡眠的时候系统应该是会查找dmp_list这条链表,
然后通过这条链表依次去查到对应的driver,然后调用driver中的suspend方法。下面我们来验证。
2.在suspend会轮询bus下的driver,然后一次调用到driver-》pm-》suspend方法,然后进入休眠。
3.state_store-》pm_suspend-》enter_state-》suspend_devices_and_enter-》dpm_suspend_start-》dpm_suspend-》device_suspend-》__device_suspend-》pm_op-》(ops-》suspend)
platoform怎么玩
platform的灵魂是:device(设备)driver(驱动)platform_bus(platform总线),其特点是设备,驱动分层动态的管理和加载
其中platform_bus是一个虚拟的总线,当我们将设备和驱动注册到虚拟总线上(内核)时,如果该设备是该驱动的设备,该驱动是该设备的驱动,在他们注册时,会互相寻找
一次对方(只在注册的时候寻找一次,找完了就玩了)。这个找的过程是platform_bus来完成的,我们暂不管他如何让寻找。如果device和driver中的name这个字符串是想相同的话
platform_bus就会调用driver中的.probe函数.这个匹配到调用probe的过程是自动的,有总线自己完成。这个过程从注册开始,从probe结束
设备和驱动的关系是多对一的关系,即多个相同设备可使用一个driver,靠device(设备)中的id号来区别
platform的使用其实就四步:
1)初始化 resource 结构变量
2)初始化 platform_device 结构变量
3)向系统注册设备:platform_device_register。
4)想系统注册驱动:[platform_driver_register()]
登录后复制
drvier和device匹配的方法有3种:
* 当一个设备注册的时候,他会在总线上寻找匹配的driver,platform device一般在系统启动很早的时候就注册了
* 当一个驱动注册[platform_driver_register()]的时候,他会遍历所有总线上的设备来寻找匹配,在启动的过程驱动的注册一般比较晚,或者在模块载入的时候
* 当一个驱动注册[platform_driver_probe()]的时候, 功能上和使用platform_driver_register()是一样的,唯一的区别是它不能被以后其他的device probe了,也就是说这个driver只能和 一个device绑定
eg:定义一个driver
如何通过名称获取platform device设备
而platform_device并不是与字符设备、块设备并列的概念,而是Linux系统提供的一种管理设备的手段,所有SOC系统中集成的独立的外设控制器、挂接在SOC内存空间的外设等都属Platform设备。如ARM S3C6410处理器中,把内部集成的I2C、PTC、SPI、LCD、…
platform device 中的 device怎么构建
1. 在比较新的linux内核中,设备树dts已经取代了传统的machine board device description,dts在内核中以各种device node的形式存在,而这些device node对于大部分的内核驱动模块platform_driver来说,最终需要有对应的platform device来与他匹配才可以完成一次device和driver的probe过程。
所有有必要将dts中需要加载为device的device node转为platform device,而这个过程是交给of_platform_populate来完成的(dts相关的device node tree是在start_kernel的setup_arch-》unflatten_device_tree来加载dtb并解析)。
of_platform_populate的入口一般是处于init_machine中,对于arm架构而言位于board.c中的DT_MACHINE_START()的init_machine中定义,而init_machine的调用是以一个module的形式而存在的,该module被加载后的目的,就是做device的create,在以前旧的board中,会将board.c中定义的相关device info转换为对应的device,以便后面的driver加载时可以match到相应的device。在基于dts的设备管理中,这个功能由of_platform_populate来实现
[cpp] view plain copy
static int __init customize_machine(void)
{
/* customizes platform devices, or adds new ones */
if (machine_desc-》init_machine)
machine_desc-》init_machine();
return 0;
}
arch_initcall(customize_machine);
[cpp] view plain copy
static int __init customize_machine(void)
{
/* customizes platform devices, or adds new ones */
if (machine_desc-》init_machine)
machine_desc-》init_machine();
return 0;
}
arch_initcall(customize_machine);
该module的initcall等级相比内核核心的core module来说是较低的,但一般比device module来的高,所以内核中是先存着device然后再当不同的driver被call加载后,完成一次驱动和设备的probe交互。在dts下这种过程典型的是platform device和driver的形式而存在。
2. of_platform_populate函数做了哪些事情
[cpp] view plain copy
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)//NULL/NULL
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path(“/“);//根节点,可以从非根节点/开始加载
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
[cpp] view plain copy
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)//NULL/NULL
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path(“/“);//根节点,可以从非根节点/开始加载
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
该该函数的功能主要可以总结如下:
a.根据所选择的device node根节点,来递归式的遍历从root node开始以下的所有device node
b.将device node转变为一个platform_device并将其作为device 通过device_add到内核
c.可以判断哪些device node是需要转为device到内核的。
d. 如果传入的root=NULL,则表明从dts的\节点开始逐一的递归处理,否则根据所选择的device node作为root,做递归处理。
e. struct of_device_id *matches,该match table重点是后续节点递归处理时,需要和该table mach后才可以继续递归处理。
需要说明的是dts中定义的各种device node,往往只是用来辅助核心的device node而存在的,也就是说这些node存在并不需要加载为platform device,那么哪些device node是不会在of_platform_populate中被解析为device的呢,具体可以从以下几个方面展开:
[html] view plain copy
static int of_platform_bus_cof_platform_populatereate(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, “compatible“, NULL))) {
pr_debug(“%s() – skipping %s, no compatible prop\n“,
__func__, bus-》full_name);
return 0;
}
auxdata = of_dev_lookup(lookup, bus);//初始设备树解析时lookup为Null
if (auxdata) {
bus_id = auxdata-》name;
platform_data = auxdata-》platform_data;
}
if (of_device_is_compatible(bus, “arm,primecell“)) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);//创建platform device
if (!dev || !of_match_node(matches, bus))//看该bus即父节点是否属于要继续加载子节点
return 0;//matches需要用户的驱动支持of_platform_populate
for_each_child_of_node(bus, child) {//子设备的解析处理
pr_debug(“ create child: %s\n“, child-》full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev-》dev, strict);//父节点下的子设备节点创建
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
[html] view plain copy
static int of_platform_bus_cof_platform_populatereate(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, “compatible“, NULL))) {
pr_debug(“%s() – skipping %s, no compatible prop\n“,
__func__, bus-》full_name);
return 0;
}
auxdata = of_dev_lookup(lookup, bus);//初始设备树解析时lookup为Null
if (auxdata) {
bus_id = auxdata-》name;
platform_data = auxdata-》platform_data;
}
if (of_device_is_compatible(bus, “arm,primecell“)) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);//创建platform device
if (!dev || !of_match_node(matches, bus))//看该bus即父节点是否属于要继续加载子节点
return 0;//matches需要用户的驱动支持of_platform_populate
for_each_child_of_node(bus, child) {//子设备的解析处理
pr_debug(“ create child: %s\n“, child-》full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev-》dev, strict);//父节点下的子设备节点创建
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
可以看到是有一个类似bus的root device node下来逐步展开的,而这个root node可以不是函数重点关注的是:
a. of_get_property(“compatible“),如果这个节点root device属性不存在,则表明其不需要生成为platform device
b. 随着root device node由函数of_platform_device_create_pdata创建为platform device后,需要检查当前节点的compatible是否和match table中定义的table list相互匹配:
[html] view plain copy
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
if (!matches)
return NULL;
while (matches-》name || matches-》type || matches-》compatible) {
int match = 1;
if (matches-》name)
match &= node-》name
&& !strcmp(matches-》name, node-》name);
if (matches-》type)
match &= node-》type
&& !strcmp(matches-》type, node-》type);
if (matches-》compatible)
match &= of_device_is_compatible(node,
matches-》compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
[html] view plain copy
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
if (!matches)
return NULL;
while (matches-》name || matches-》type || matches-》compatible) {
int match = 1;
if (matches-》name)
match &= node-》name
&& !strcmp(matches-》name, node-》name);
if (matches-》type)
match &= node-》type
&& !strcmp(matches-》type, node-》type);
if (matches-》compatible)
match &= of_device_is_compatible(node,
matches-》compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
如果当该device node在被创建为platform device后,就不在和match table相匹配时,其对应的child node就不会再被创建platform device,即无论child node是否定义了“compatible“,其对应的platform device均不会被生成。
c.对于dts中定义的device node,只有其所属的parent node所属的compatible属性和调用of_platform_populate时传入的of_device_id相互匹配,则说明如果当前的device node只要包含有compatible属性就会被创建为platform device。
以一个简单的dts为例:
[html] view plain copy
/{
soc0{
compatible = “my, soc0“;
node1{
compatible = “my, node1“;
node1_1{
compatible = “my, node1_1“;
node1_1_1{
compatible = “my, node1_1_1“;
}
}
}
node2{ }
}
soc1{ compatible = “my, soc1“; }
}
[html] view plain copy
/{
soc0{
compatible = “my, soc0“;
node1{
compatible = “my, node1“;
node1_1{
compatible = “my, node1_1“;
node1_1_1{
compatible = “my, node1_1_1“;
}
}
}
node2{ }
}
soc1{ compatible = “my, soc1“; }
}
a.假设现在在init_machine中调用of_platform_populate()时传入的root node为NULL,且mach id为”my, soc0“,“my,node1“
则最终soc0会被首先作为/ root node的child node被加载为platform device,然后依次是node1,由于其相应的compatible和match id匹配,则其对应的child node允许被继续调用of_platform_bus_create,并且对含有compatible的device node生成为platform device,如本例中的node1。同理对于node1而言会加载node1_1节点,但当node1_1生成为device后,由于无法匹配match id,则其无法再递归的处理其下的子节点,从而使得node1_1_1不会被生成为platform device。而这需要说明的是,这个device虽然不会被自动加载为platform device但在node1_1的device driver实现时,可以将node1_1_1形成一种特定的device,如i2c_client等,只是不会生成platform device。从而解释了为何该device node只是以一个device 的形式存在于内核而不是即是i2c_client和platform device。
而soc0下的node2由于不存在compatible属性,同样不会被生成device,以及其child node下的各级device node也都不会被加载。
b,假设传入的root node为soc1,且mach id为“my,node1“时
这个过程会加载node1,然后是node1_1,同样的node1_1_1不会被生成为platform_device.
3.总结
对于of_platform_populate如何选择性的加载device node为platform device在系统启动阶段,可以只关注该device node所属的parent node的compatible属于match id。
一旦自身包含compatible,则会自动调用of_platform_device_create_pdata生成一个platform device。
嵌入式linux 驱动设备识别过程
驱动程序识别设备时,有以下两种方法:
(1)驱动程序本身带有设备的信息,比如开始地址、中断号等:加载驱动程序时,就可以根据这些信息来识别设备。
(2)驱动程序本身没有设备的信息,但是内核中已经(或以后)根据其他方式确定了很多设备的信息;加载驱动程序时,将驱动程序与这些设备逐个比较,确定两者是否匹配(match)。如果驱动程序与某个设备匹配,就可以通过该驱动程序操作这个设备了。内核常使用第二种方法来识别设备,这可以将各种设备集中在-一个文件中管理,当开发板的配置改变时,便于修改代码。在内核文件includePnuxÔatform _device.h 中,定义了两个数据结构来表示这些设备和驱动程序: platform_ device 结构用来描述设备的名称、ID、所占用的资源(比如内存地址/大小、中断号)等; platform_ driver 结构用来描述各种操作函数, 比如枚举函数、移除设备函数、驱动的名称等。内核启动后,首先构造链表将描述设备的platform_device结构组织起来,得到一一个设备的列表:当加载某个驱动程序的platform_ driver 结构时,使用一.些匹配函数来检查驱动程序能否支持这些设备,常用的检查方法很简单:比较驱动程序和设备的名称。
在Linux中用platform device写的驱动如何区别他是字符设备还是块设备呢
而platform_device并不是与字符设备、块设备并列的概念,而是Linux系统提供的一种管理设备的手段,所有SOC系统中集成的独立的外设控制器、挂接在SOC内存空间的外设等都属Platform设备。如ARM S3C6410处理器中,把内部集成的I2C、PTC、SPI、LCD、看门狗控制器都归纳为Platform设备,而这些设备本身就是字符设备。由此可见Platform中的设备是不分字符设备还是块设备。
字符设备和块设备的区别在于前者只能被顺序读写,后者可以随机访问。大多数设备为字符设备,以字节为单位,实现file_operations结构体。而如磁盘为块设备,以块为单位接受输入和返回输出。实现block_device_operations结构体.