首先了解几个结构。
struct kobject {
//容器的名称。
const char * k_name;
char name[KOBJ_NAME_LEN];
//容器的引用计数。
struct kref kref;
//
struct list_head entry;
//父kobject.
struct kobject * parent;
//所属的kset
struct kset * kset;
//容器的类型。
struct kobj_type * ktype;
//在sys文件系统的目录项。
struct dentry * dentry;
};
struct kset {
//所属的子系统。
struct subsystem * subsys;
//kset的类型,被所有kobject共亨。
struct kobj_type * ktype;
//包函所有kobject的链表头。
struct list_head list;
spinlock_t list_lock;
//嵌入的kobject
struct kobject kobj;
struct kset_hotplug_ops * hotplug_ops;
};
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
};
linux用sys文件系统来组织所有驱动、设备、总线,以上三个结构就是sys文件系统的最基本原素,object可以代表一个驱动或一个设备,
kset是同类 object的集合,subsystem又是多个kset的集合,要理解kset可以是kset的集合。
再看下面的结构:
struct device_driver {
//驱动名。
const char * name;
//所属的总线。
struct bus_type * bus;
struct completion unloaded;
struct kobject kobj;
//所有使用当前驱动的设备。
struct klist klist_devices;
//总线里驱动的一员。
struct klist_node knode_bus;
struct module * owner;
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);
int (*suspend) (struct device * dev, pm_message_t state, u32 level);
int (*resume) (struct device * dev, u32 level);
};
struct device {
//所有子设备的头
struct klist klist_children;
//所属的父设备、驱动、总线。
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device * parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type * bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
void *firmware_data; /* Firmware specific data (e.g. ACPI,
BIOS data),reserved for device core*/
struct dev_pm_info power;
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
void (*release)(struct device * dev);
};
struct bus_type {
//总线的名称。
const char * name;
//代表总线的子系统。
struct subsystem subsys;
//驱动程序集和。
struct kset drivers;
//设备集和。
struct kset devices;
//链接所有属于当前总线的驱动和设备。
struct klist klist_devices;
struct klist klist_drivers;
//总线、设备、驱动属性
struct bus_attribute * bus_attrs;
struct device_attribute * dev_attrs;
struct driver_attribute * drv_attrs;
int (*match)(struct device * dev, struct device_driver * drv);
int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
int (*suspend)(struct device * dev, pm_message_t state);
int (*resume)(struct device * dev);
};
基本布局是总线上有驱动和和设备,每当一个驱动注册到总线或总线发现一个设备时就调用mach,查看是否有匹配的,如果有那么相应驱动的
probe就会被调用。
sys文件系统的初始化过程(也就是linux设备驱动模型的初始化)
//这个在init进程里调用。
void __init driver_init(void)
{
printk("\n\n#driver_init***********************************************************\n");
/* These are the core pieces */
//sys/device
devices_init();
//sys/bus
buses_init();
//sys/class
classes_init();
//sys/firmware
firmware_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
//sys/device/platform
//sys/bus/platform
platform_bus_init();
//sys/device/system
system_bus_init();
cpu_dev_init();
attribute_container_init();
printk("\n#driver_init***********************************************************\n\n");
}
下面应是函数执行后sys的结构:
ls -l /sys
drwxr-xr-x 6 0 0 0 Jan 1 00:00 bus
drwxr-xr-x 18 0 0 0 Jan 1 00:00 class
drwxr-xr-x 4 0 0 0 Jan 1 00:00 devices
drwxr-xr-x 2 0 0 0 Jan 1 00:00 firmware
ls -l /sys/device
drwxr-xr-x 11 0 0 0 Jan 1 00:00 platform
drwxr-xr-x 5 0 0 0 Jan 1 00:00 system
ls -l /sys/bus
drwxr-xr-x 4 0 0 0 Jan 1 00:00 platform
一个SOC里的所有设备都是以平台设备身份出现的,也就是平台设备和平台驱动都属于上面创建的平台总线,初始化时先把所有设备注册到平
台总线。等到驱动注册时会认领。最后的图如下:
# pwd
/sys/devices/platform
# ls -l
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-i2c
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-iis
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-lcd
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-nand.1
drwxr-xr-x 3 0 0 0 Jan 1 00:00 s3c2410-ohci
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-uart.0
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-uart.1
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-uart.2
drwxr-xr-x 2 0 0 0 Jan 1 00:00 s3c2410-wdt
实现过程:
在setup_arch->smdk2410_map_io
把所有平台设备的I/O空间进行了映射,初始化所有平台设备的struct device结构。
//平台IO设备初始化。
static void __init smdk2410_map_io(void)
{
//IO空间映射。
s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
//设置时钟。
s3c24xx_init_clocks(0);
//初始化串口
s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
//注册平台上的USB、LCD、WDT、I2C、IIS、NAND驱动并注册相应的时钟。
s3c24xx_set_board(&smdk2410_board);
//设置LCD驱动的平台私有数据。
set_s3c2410fb_info(&smdk2410_lcdcfg); /* add by gjl */
//设备USB的私有数据。
usb_sbc2410_init(); /* by gjl */
}
//这个函数就把所有平台设备都挂到平台总线上。
static int __init s3c_arch_init(void)
{
int ret;
// do the correct init for cpu
printk("[s3c_arch_init(cpu.c)]\n");
if (cpu == NULL)
panic("s3c_arch_init: NULL cpu\n");
ret = (cpu->init)();
if (ret != 0)
return ret;
if (board != NULL) {
struct platform_device **ptr = board->devices;
int i;
for (i = 0; i < board->devices_count; i++, ptr++) {
ret = platform_device_register(*ptr);
if (ret) {
printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret,
*ptr);
}
}
/* mask any error, we may not need all these board
* devices */
ret = 0;
}
return ret;
}
几个关键函数:
//设备注册
int device_register(struct device *dev)
{
#if CONFIG_QL_DEBUG
printk("#--------注册设备[%s]-",dev->bus_id);
printk("父设备为");
if(dev->parent)
printk("[%s]",dev->parent->bus_id);
else
printk("NULL");
printk("-属于总线");
if(dev->bus)
printk("[%s]\n",dev->bus->name);
else
printk("NULL\n");
#endif
device_initialize(dev);
return device_add(dev);
}
void device_initialize(struct device *dev)
{
//属于devices_subsys子系统。
kobj_set_kset_s(dev, devices_subsys);
kobject_init(&dev->kobj);
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
int error = -EINVAL;
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id))
goto Error;
parent = get_device(dev->parent);
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
//设置kobject名子。
/* first, register with generic layer. */
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
//设置父kobject
if (parent)
dev->kobj.parent = &parent->kobj;
//增加到sysfs
if ((error = kobject_add(&dev->kobj)))
goto Error;
kobject_hotplug(&dev->kobj, KOBJ_ADD);
if ((error = device_pm_add(dev)))
goto PMError;
//增加的总线。
if ((error = bus_add_device(dev)))
goto BusError;
//增加到父设备。
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
Done:
put_device(dev);
return error;
BusError:
device_pm_remove(dev);
PMError:
kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
if (parent)
put_device(parent);
goto Done;
}
//在总线上加设备。
int bus_add_device(struct device * dev)
{
struct bus_type * bus = get_bus(dev->bus);
int error = 0;
if (bus) {
#if CONFIG_QL_DEBUG
printk("#--------总线[%s]增加设备[%s]\n", bus->name, dev->bus_id);
#endif
//偿试与驱动结合
device_attach(dev);
//把设备链到总线。
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
error = device_add_attrs(bus, dev);
if (!error) {
//在相应总线上创建符号链接。
sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
}
}
return error;
}
int device_attach(struct device * dev)
{
int ret = 0;
down(&dev->sem);
//如果指定驱动,直接结合。
if (dev->driver) {
device_bind_driver(dev);
ret = 1;
} else
//试着与总线上的每一个驱动结合。
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
up(&dev->sem);
return ret;
}
//驱动注册
int driver_register(struct device_driver * drv)
{
#if CONFIG_QL_DEBUG
printk("\n#--------驱动[%s]注册-属于总线",drv->name);
if(drv->bus)
printk("[%s]\n",drv->bus->name);
else
printk("NULL\n");
#endif
//把驱动的设备列表初始化为空。
klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
init_completion(&drv->unloaded);
return bus_add_driver(drv);
}
int bus_add_driver(struct device_driver * drv)
{
struct bus_type * bus = get_bus(drv->bus);
int error = 0;
if (bus) {
error = kobject_set_name(&drv->kobj, "%s", drv->name);
if (error) {
put_bus(bus);
return error;
}
drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj))) {
put_bus(bus);
return error;
}
driver_attach(drv);
//链接到总线的驱动列表。
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
driver_add_attrs(bus, drv);
//创建文件。
driver_create_file(drv, &driver_attr_unbind);
driver_create_file(drv, &driver_attr_bind);
}
return error;
}
//总线注册
int bus_register(struct bus_type * bus)
{
int retval;
retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
if (retval)
goto out;
//做为bus_subsys的子集。
subsys_set_kset(bus, bus_subsys);
//注册当前总线。
retval = subsystem_register(&bus->subsys);
if (retval)
goto out;
//设备总线设备集合的名子,并注册。
kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.subsys = &bus->subsys;
retval = kset_register(&bus->devices);
if (retval)
goto bus_devices_fail;
//设备总线驱动集合的名子,并注册。
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.subsys = &bus->subsys;
bus->drivers.ktype = &ktype_driver;
retval = kset_register(&bus->drivers);
if (retval)
goto bus_drivers_fail;
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);
bus_add_attrs(bus);
pr_debug("bus type '%s' registered\n", bus->name);
return 0;
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
subsystem_unregister(&bus->subsys);
out:
return retval;
}