平台总线、设备、驱动的学习
2016-08-17 21:39
176 查看
设备和驱动的绑定是通过总线实现的。总线通过查找总线下的设备列表和驱动列表,名字相同的进行匹配。
总线代码的实现:
struct bus_type {
constchar *name; //总线名字
structbus_attribute *bus_attrs; //总线属性
structdevice_attribute *dev_attrs; //设备属性
structdriver_attribute *drv_attrs; //驱动属性
int(*match)(struct device *dev, struct device_driver *drv); //匹配总线下的dev(设备)和drv(驱动)
int(*uevent)(struct device *dev, struct kobj_uevent_env *env);//用于总线环境变量添加
int(*probe)(struct device *dev); //回调函数,总线和驱动匹配成功就会调用此函数。
int(*remove)(struct device *dev);
void(*shutdown)(struct device *dev);
int(*suspend)(struct device *dev, pm_message_t state);
int(*resume)(struct device *dev);
conststruct dev_pm_ops *pm; 电源管理
structbus_type_private *p; 这个指针将bus同其他类型联系起来。将bus、device、sysfs三者联系起来。 Bus的一些私有成员、数据
};
structbus_type_private {
structkset subsys;
structkset *drivers_kset; 表示总线目录下的驱动的子目录
structkset *devices_kset; 表示总线目录下的设备的子目录
structklist klist_devices; 表示总线下的设备的链表
structklist klist_drivers; 表示总线下的驱动的链表(总线通过链表查找驱动和设备)
structblocking_notifier_head bus_notifier;
unsignedint drivers_autoprobe:1;
structbus_type *bus;
};
设备启动时候初始化过程:(main.c(init))
1、 kernel_init() 2、do_basic_setup ()3、driver_init() 4、devices_init 5、buses_init 。。。
在driver_init()中驱动没有注册。驱动的注册时在驱动函数中的moudle_init中注册。在do_initcalls() 中才开始加载module_init。
分析总线的注册:
1、平台总线如何注册?
Uboot-----加载linux内核----从main.c(init)中执行start_kernel----rest_init()一些复位初始化; 开始创建kernel_init线程(kernel_thread(kernel_init,NULL,…)-------然后do_basic_setup基本安装-----driver_init()----先后执行buses_init和platform_bus_init
2、buses_init()进一步分析:
3、platform_bus_init()
error = bus_register(&platform_bus_type); 进行platform总线的注册。
在bus_register(&platform_bus_type);中:
kobject_set_name(&priv->subsys.kobj,"%s", bus->name); 设置bus的名字。
priv->subsys.kobj.kset = bus_kset; 此处理解为bus_kset指向platform上一层的目录,
因为在buses_init中,bus_kset = kset_create_and_add("bus", &bus_uevent_ops,NULL);
所以bus_kset指向了bus目录,所以platform目录是在bus目录下创建的。
priv->drivers_autoprobe = 1;设置标志位,后面会用到,当驱动注册时,会自动匹配设备,初始化probe函数。
retval =kset_register(&priv->subsys); 注册kset,创建目录。在此处platform_bus_init()
是创建一个platform目录。
bus_create_file(bus, &bus_attr_uevent);在当前总线(此处对应platform总线)目录下生成bus_attr_uevent属性,包括读写操作。
kset_create_and_add("devices",NULL,&priv->subsys.kobj);创建devices链表。
kset_create_and_add("drivers",NULL,&priv->subsys.kobj);创建驱动链表。
平台设备的注册(platform_devices)
1、 平台设备是如何注册?如何实现?
如果在devices/platform/创建了设备,那么它在平台总线上肯定有对应的、一样的设备。用为我们的平台设备总是挂载到平台总线上的。如图:
系统初始化的时候会调用mini2440_machine_init会调用platform_add_devices()将mini2440_devices这些设备注册到linux系统里面。
staticstruct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_rtc,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_usbgadget,
};
在platfrom_add_devices中:
1、platform_device_register()
第一步device_initialize(&pdev->dev); //初始化。
其中dev->kobj.kset = devices_kset;中的devices_kset来自于devices_init 函数中
第二步:return platform_device_add(pdev);
Platform_device 结构体
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
struct platform_device_id *id_entry;
struct pdev_archdata archdata;
};
部分device结构的成员:
struct device{
struct device *parent; //设备的父设备,该设备所属的设备,通常是某种总线或者其他宿主控制器
struct device_private *p;
struct kobject kobj;
const char *init_name; 设备名字
struct bus_type *bus; 标识该设备连接在何种总线上
struct device_driver *driver; 管理该设备的驱动
void *platform_data;
void (*release)(struct device*dev);
};
在platform_device_add(structplatform_device *pdev)中首先进行一些初始化
(1) pdev->dev.parent =&platform_bus; 设置设备的父节点
(2) pdev->dev.bus =&platform_bus_type;设置设备挂载的总线类型
(3) dev_set_name(&pdev->dev,"%s.%d", pdev->name, pdev->id);设置设备的名字
(4) 设置设备的资源。
(5) ret =device_add(&pdev->dev);在这里才是真的开始添加设备,之前都是一些结构体的初始化
平台驱动的注册(platform_driver):
platform_device_resigter设备注册和platform_driver_resigter驱动注册的区别?
USB设备和USB驱动的注册过程:
1、 USB设备插进电脑中,开始运行我的USB驱动程序,安装USB驱动时候就会开始“遍历”USB总线上的所有设备与驱动匹配。(设备先注册,驱动后注册)。
2、 U盘的驱动程序先安装好,每次U盘设备插到电脑,设备被识别。在这里(先注册驱动,设备去找驱动)
3、 驱动注册和设备注册没有绝对的先后顺序。
平台驱动的注册过程(以声卡s3c24xx-uda134x)
Uboot—do_initcall—module_init()—platform_driver_resigter()
进入platform_driver_resigter()中对device_driver 结构体的初始化:
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;
struct platform_device_id *id_table;
};
struct device_driver {
const char *name; //名字
struct bus_type *bus; //所挂的总线
struct module *owner;
const char *mod_name;
bool suppress_bind_attrs;
int (*probe) (struct device *dev);
int (*remove) (s
acdc
truct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev,pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
}
进入driver_register(&drv->driver):
other = driver_find(drv->name,drv->bus); 驱动在/sys/bus/platform/drivers列表查找或者遍历是否有相同驱动名字,如果有,就不会注册这个驱动。
ret =bus_add_driver(drv); 添加驱动
在bus_add_driver中:
其中drv->bus->p->drivers_autoprobe的赋值在总线注册.的时候就赋值为1 。
然后进入driver_attach中进行驱动绑定。
在bus_for_each_dev中,执行error = fn(dev, data);将dev,data的值传递给函数driver_attach;
static int__driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
if (!driver_match_device(drv, dev)) //在平台总线下是调用platform_match通过名字进行匹配
return 0;
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev); //因为设备中没有probe函数所以调用驱动里的probe函数
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
总线代码的实现:
struct bus_type {
constchar *name; //总线名字
structbus_attribute *bus_attrs; //总线属性
structdevice_attribute *dev_attrs; //设备属性
structdriver_attribute *drv_attrs; //驱动属性
int(*match)(struct device *dev, struct device_driver *drv); //匹配总线下的dev(设备)和drv(驱动)
int(*uevent)(struct device *dev, struct kobj_uevent_env *env);//用于总线环境变量添加
int(*probe)(struct device *dev); //回调函数,总线和驱动匹配成功就会调用此函数。
int(*remove)(struct device *dev);
void(*shutdown)(struct device *dev);
int(*suspend)(struct device *dev, pm_message_t state);
int(*resume)(struct device *dev);
conststruct dev_pm_ops *pm; 电源管理
structbus_type_private *p; 这个指针将bus同其他类型联系起来。将bus、device、sysfs三者联系起来。 Bus的一些私有成员、数据
};
structbus_type_private {
structkset subsys;
structkset *drivers_kset; 表示总线目录下的驱动的子目录
structkset *devices_kset; 表示总线目录下的设备的子目录
structklist klist_devices; 表示总线下的设备的链表
structklist klist_drivers; 表示总线下的驱动的链表(总线通过链表查找驱动和设备)
structblocking_notifier_head bus_notifier;
unsignedint drivers_autoprobe:1;
structbus_type *bus;
};
设备启动时候初始化过程:(main.c(init))
1、 kernel_init() 2、do_basic_setup ()3、driver_init() 4、devices_init 5、buses_init 。。。
在driver_init()中驱动没有注册。驱动的注册时在驱动函数中的moudle_init中注册。在do_initcalls() 中才开始加载module_init。
分析总线的注册:
1、平台总线如何注册?
Uboot-----加载linux内核----从main.c(init)中执行start_kernel----rest_init()一些复位初始化; 开始创建kernel_init线程(kernel_thread(kernel_init,NULL,…)-------然后do_basic_setup基本安装-----driver_init()----先后执行buses_init和platform_bus_init
2、buses_init()进一步分析:
3、platform_bus_init()
error = bus_register(&platform_bus_type); 进行platform总线的注册。
在bus_register(&platform_bus_type);中:
kobject_set_name(&priv->subsys.kobj,"%s", bus->name); 设置bus的名字。
priv->subsys.kobj.kset = bus_kset; 此处理解为bus_kset指向platform上一层的目录,
因为在buses_init中,bus_kset = kset_create_and_add("bus", &bus_uevent_ops,NULL);
所以bus_kset指向了bus目录,所以platform目录是在bus目录下创建的。
priv->drivers_autoprobe = 1;设置标志位,后面会用到,当驱动注册时,会自动匹配设备,初始化probe函数。
retval =kset_register(&priv->subsys); 注册kset,创建目录。在此处platform_bus_init()
是创建一个platform目录。
bus_create_file(bus, &bus_attr_uevent);在当前总线(此处对应platform总线)目录下生成bus_attr_uevent属性,包括读写操作。
kset_create_and_add("devices",NULL,&priv->subsys.kobj);创建devices链表。
kset_create_and_add("drivers",NULL,&priv->subsys.kobj);创建驱动链表。
平台设备的注册(platform_devices)
1、 平台设备是如何注册?如何实现?
如果在devices/platform/创建了设备,那么它在平台总线上肯定有对应的、一样的设备。用为我们的平台设备总是挂载到平台总线上的。如图:
系统初始化的时候会调用mini2440_machine_init会调用platform_add_devices()将mini2440_devices这些设备注册到linux系统里面。
staticstruct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_rtc,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_usbgadget,
};
在platfrom_add_devices中:
1、platform_device_register()
第一步device_initialize(&pdev->dev); //初始化。
其中dev->kobj.kset = devices_kset;中的devices_kset来自于devices_init 函数中
第二步:return platform_device_add(pdev);
Platform_device 结构体
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
struct platform_device_id *id_entry;
struct pdev_archdata archdata;
};
部分device结构的成员:
struct device{
struct device *parent; //设备的父设备,该设备所属的设备,通常是某种总线或者其他宿主控制器
struct device_private *p;
struct kobject kobj;
const char *init_name; 设备名字
struct bus_type *bus; 标识该设备连接在何种总线上
struct device_driver *driver; 管理该设备的驱动
void *platform_data;
void (*release)(struct device*dev);
};
在platform_device_add(structplatform_device *pdev)中首先进行一些初始化
(1) pdev->dev.parent =&platform_bus; 设置设备的父节点
(2) pdev->dev.bus =&platform_bus_type;设置设备挂载的总线类型
(3) dev_set_name(&pdev->dev,"%s.%d", pdev->name, pdev->id);设置设备的名字
(4) 设置设备的资源。
(5) ret =device_add(&pdev->dev);在这里才是真的开始添加设备,之前都是一些结构体的初始化
平台驱动的注册(platform_driver):
platform_device_resigter设备注册和platform_driver_resigter驱动注册的区别?
USB设备和USB驱动的注册过程:
1、 USB设备插进电脑中,开始运行我的USB驱动程序,安装USB驱动时候就会开始“遍历”USB总线上的所有设备与驱动匹配。(设备先注册,驱动后注册)。
2、 U盘的驱动程序先安装好,每次U盘设备插到电脑,设备被识别。在这里(先注册驱动,设备去找驱动)
3、 驱动注册和设备注册没有绝对的先后顺序。
平台驱动的注册过程(以声卡s3c24xx-uda134x)
Uboot—do_initcall—module_init()—platform_driver_resigter()
进入platform_driver_resigter()中对device_driver 结构体的初始化:
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;
struct platform_device_id *id_table;
};
struct device_driver {
const char *name; //名字
struct bus_type *bus; //所挂的总线
struct module *owner;
const char *mod_name;
bool suppress_bind_attrs;
int (*probe) (struct device *dev);
int (*remove) (s
acdc
truct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev,pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
}
进入driver_register(&drv->driver):
other = driver_find(drv->name,drv->bus); 驱动在/sys/bus/platform/drivers列表查找或者遍历是否有相同驱动名字,如果有,就不会注册这个驱动。
ret =bus_add_driver(drv); 添加驱动
在bus_add_driver中:
其中drv->bus->p->drivers_autoprobe的赋值在总线注册.的时候就赋值为1 。
然后进入driver_attach中进行驱动绑定。
在bus_for_each_dev中,执行error = fn(dev, data);将dev,data的值传递给函数driver_attach;
static int__driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
if (!driver_match_device(drv, dev)) //在平台总线下是调用platform_match通过名字进行匹配
return 0;
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev); //因为设备中没有probe函数所以调用驱动里的probe函数
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
相关文章推荐
- 嵌入式学习-驱动开发-lesson5-总线设备驱动模型及平台总线驱动
- Linux学习:platform平台总线、平台设备、平台驱动
- 平台总线设备驱动模型——代码分析
- 平台总线设备驱动详解
- linux驱动platform平台设备总线
- linux平台总线驱动设备模型之点亮LED
- Linux设备驱动程式学习(13)-Linux设备模型(总线、设备、驱动程式和类)
- 平台总线 设备 驱动相关调用与简介
- linux内核学习之总线、驱动、设备、kset、kobject
- Linux平台总线驱动设备模型
- 16.总线设备驱动模型学习
- ok6410学习笔记(15.platform平台总线驱动模型之混杂设备驱动led)
- linux平台设备驱动学习笔记
- Linux平台总线驱动设备模型
- 平台总线设备驱动模型——基础知识
- 木其工作室(专业程序代写服务)[原]ok6410学习笔记(15.platform平台总线驱动模型之混杂设备驱动led)
- linux平台总线驱动设备模型之点亮LED
- Linux平台总线驱动设备模型
- Linux平台总线驱动设备模型
- Linux平台总线驱动设备模型