Chinaunix首页 | 论坛 | 博客
  • 博客访问: 869186
  • 博文数量: 189
  • 博客积分: 4310
  • 博客等级: 上校
  • 技术积分: 1925
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-27 08:56
文章分类

全部博文(189)

文章存档

2015年(1)

2013年(2)

2012年(1)

2011年(39)

2010年(98)

2009年(48)

分类: LINUX

2010-04-04 16:21:21

Platform总线是linux2.6内核加入的一种虚拟总线,由两部分组成Platform_device和Platform_driver组成(注:虚拟总线一般由bus,device和device_driver组成的,然而Platform的bus内核已经有了,所以这里所讲的Platform由两部分组成是省掉了bus),通过Platform机制开发底层设备驱动的流程为:
1.定义Platform_device
2.注册Platform_device
3.定义Platform_driver
4.注册Platform_driver
其中platform_device的原型为
struct platform_device {
 const char * name;
 int  id;
 struct device dev;
 u32  num_resources;
 struct resource * resource;
};
其中platform_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 (*suspend_late)(struct platform_device *, pm_message_t state);
 int (*resume_early)(struct platform_device *);
 int (*resume)(struct platform_device *);
 struct device_driver driver;
};
然而很多的硬件的Platform_device系统已经Devs.c中定义了,或你自己可以在那加如:
/* NAND Controller */
static struct resource s3c_nand_resource[] = {
 [0] = {
  .start = S3C2410_PA_NAND,
  .end   = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1,
  .flags = IORESOURCE_MEM,
 }
};
struct platform_device s3c_device_nand = {
 .name    = "s3c2410-nand",
 .id    = -1,
 .num_resources   = ARRAY_SIZE(s3c_nand_resource),
 .resource   = s3c_nand_resource,
};
 
其实很多硬件的设备已经在系统初始化时被注册。
 
 
下面分析Platform_driver_register的过程
/**
 * platform_driver_register
 * @drv: platform driver structure
 */
int platform_driver_register(struct platform_driver *drv)
{
 drv->driver.bus = &platform_bus_type;
 if (drv->probe)
  drv->driver.probe = platform_drv_probe;
 if (drv->remove)
  drv->driver.remove = platform_drv_remove;
 if (drv->shutdown)
  drv->driver.shutdown = platform_drv_shutdown;
 if (drv->suspend)
  drv->driver.suspend = platform_drv_suspend;
 if (drv->resume)
  drv->driver.resume = platform_drv_resume;
 return driver_register(&drv->driver);
}
进入driver_register
/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver * drv)
{
 if ((drv->bus->probe && drv->probe) ||
     (drv->bus->remove && drv->remove) ||
     (drv->bus->shutdown && drv->shutdown)) {
  printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
 }
 klist_init(&drv->klist_devices, NULL, NULL);
 return bus_add_driver(drv);
}
进入bus_add_driver
/**
 * bus_add_driver - Add a driver to the bus.
 * @drv: driver.
 *
 */
int bus_add_driver(struct device_driver *drv)
{
 struct bus_type * bus = bus_get(drv->bus);
 int error = 0;
 if (!bus)
  return -EINVAL;
 pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
 error = kobject_set_name(&drv->kobj, "%s", drv->name);
 if (error)
  goto out_put_bus;
 drv->kobj.kset = &bus->drivers;
 error = kobject_register(&drv->kobj);
 if (error)
  goto out_put_bus;
 if (drv->bus->drivers_autoprobe) {
  error = driver_attach(drv);
  if (error)
   goto out_unregister;
 }
 klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 module_add_driver(drv->owner, drv);
 error = driver_create_file(drv, &driver_attr_uevent);
 if (error) {
  printk(KERN_ERR "%s: uevent attr (%s) failed\n",
   __FUNCTION__, drv->name);
 }
 error = driver_add_attrs(bus, drv);
 if (error) {
  /* How the hell do we get out of this pickle? Give up */
  printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
   __FUNCTION__, drv->name);
 }
 error = add_bind_files(drv);
 if (error) {
  /* Ditto */
  printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
   __FUNCTION__, drv->name);
 }
 return error;
out_unregister:
 kobject_unregister(&drv->kobj);
out_put_bus:
 bus_put(bus);
 return error;
}
进入 driver_attach
/**
 * driver_attach - try to bind driver to devices.
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver * drv)
{
 return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
进入__driver_attach
static int __driver_attach(struct device * dev, void * data)
{
 struct device_driver * drv = data;
 /*
  * Lock device and try to bind to it. We drop the error
  * here and always return 0, because we need to keep trying
  * to bind to devices and some drivers will return an error
  * simply if it didn't support the device.
  *
  * driver_probe_device() will spit a warning if there
  * is an error.
  */
//2.6.29的内核这边还有一句if (drv->bus->match && !drv->bus->match(dev, drv))return 0;
 if (dev->parent) /* Needed for USB */
  down(&dev->parent->sem);
 down(&dev->sem);
 if (!dev->driver)
  driver_probe_device(drv, dev);
 up(&dev->sem);
 if (dev->parent)
  up(&dev->parent->sem);
 return 0;
}
进入driver_probe_device
/**
 * driver_probe_device - attempt to bind device & driver together
 * @drv: driver to bind a device to
 * @dev: device to try to bind to the driver
 *
 * First, we call the bus's match function, if one present, which should
 * compare the device IDs the driver supports with the device IDs of the
 * device. Note we don't do this ourselves because we don't know the
 * format of the ID structures, nor what is to be considered a match and
 * what is not.
 *
 * This function returns 1 if a match is found, -ENODEV if the device is
 * not registered, and 0 otherwise.
 *
 * This function must be called with @dev->sem held.  When called for a
 * USB interface, @dev->parent->sem must be held as well.
 */
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
 int ret = 0;
 if (!device_is_registered(dev))
  return -ENODEV;
 if (drv->bus->match && !drv->bus->match(dev, drv))
  goto done;
 pr_debug("%s: Matched Device %s with Driver %s\n",
   drv->bus->name, dev->bus_id, drv->name);
 ret = really_probe(dev, drv);
done:
 return ret;
}
其中这句 if (drv->bus->match && !drv->bus->match(dev, drv))
  goto done;为匹配设备和驱动的过程,若不匹配则退出。
进入really_probe
static int really_probe(struct device *dev, struct device_driver *drv)
{
 int ret = 0;
 atomic_inc(&probe_count);
 pr_debug("%s: Probing driver %s with device %s\n",
   drv->bus->name, drv->name, dev->bus_id);
 WARN_ON(!list_empty(&dev->devres_head));
 dev->driver = drv;
 if (driver_sysfs_add(dev)) {
  printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
   __FUNCTION__, dev->bus_id);
  goto probe_failed;
 }
 if (dev->bus->probe) {
  ret = dev->bus->probe(dev);
  if (ret)
   goto probe_failed;
 } else if (drv->probe) {
  ret = drv->probe(dev);
  if (ret)
   goto probe_failed;
 }
 driver_bound(dev);
 ret = 1;
 pr_debug("%s: Bound Device %s to Driver %s\n",
   drv->bus->name, dev->bus_id, drv->name);
 goto done;
probe_failed:
 devres_release_all(dev);
 driver_sysfs_remove(dev);
 dev->driver = NULL;
 if (ret != -ENODEV && ret != -ENXIO) {
  /* driver matched but the probe failed */
  printk(KERN_WARNING
         "%s: probe of %
阅读(1496) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~