Chinaunix首页 | 论坛 | 博客
  • 博客访问: 74625
  • 博文数量: 22
  • 博客积分: 1475
  • 博客等级: 上尉
  • 技术积分: 260
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 23:39
文章分类

全部博文(22)

文章存档

2013年(1)

2011年(6)

2010年(15)

我的朋友

分类: LINUX

2010-05-17 16:49:38

首先了解几个结构。
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;
}
阅读(1089) | 评论(0) | 转发(0) |
0

上一篇:(5)linux文件系统

下一篇:(7)linux字符设备

给主人留下些什么吧!~~