以611_I2C为例 跟踪Platform架构驱动——驱动注册篇

来源:互联网 发布:java pem space 编辑:程序博客网 时间:2024/04/28 04:26

//*************************************************
//         下面是驱动的注册
//*************************************************

//
static struct platform_driver sep0611_i2c_driver = {
   .probe     =   sep0611_i2c_probe,
 .remove    =   sep0611_i2c_remove,
 //.resume    =   sep0611_i2c_resume,
 .driver    =   {
        .owner =  THIS_MODULE,
        .name  =  "sep0611-i2c",
 },
};


truct bus_type platform_bus_type = {
 .name  = "platform",
 .dev_attrs = platform_dev_attrs,
 .match  = platform_match,
 .uevent  = platform_uevent,
 .pm  = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

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;

 return driver_register(&drv->driver);      //这是核心,产生sys文件系统的关联,运行probe函数
}
EXPORT_SYMBOL_GPL(platform_driver_register);


tatic int platform_drv_probe(struct device *_dev)
{
 struct platform_driver *drv = to_platform_driver(_dev->driver);
 struct platform_device *dev = to_platform_device(_dev);

 return drv->probe(dev);      //这里的probe已经初始化为用户的probe函数
}

int driver_register(struct device_driver *drv)
{
 int ret;
 struct device_driver *other;

 BUG_ON(!drv->bus->p);

 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);

 other = driver_find(drv->name, drv->bus);       //检查是否已经注册,通过在kset链表中查找
 if (other) {
  put_driver(other);
  printk(KERN_ERR "Error: Driver '%s' is already registered, "
   "aborting...\n", drv->name);
  return -EBUSY;
 }

 ret = bus_add_driver(drv);              //如果没有,则进行注册,这个函数嵌套比较深
 if (ret)
  return ret;
 ret = driver_add_groups(drv, drv->groups);
 if (ret)
  bus_remove_driver(drv);
 return ret;
}
EXPORT_SYMBOL_GPL(driver_register);

int bus_add_driver(struct device_driver *drv)
{
 struct bus_type *bus;
 struct driver_private *priv;
 int error = 0;

 bus = bus_get(drv->bus);   //在启动时,device初始化时已经初始化部分
 if (!bus)
  return -EINVAL;

 pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 if (!priv) {
  error = -ENOMEM;
  goto out_put_bus;
 }
 klist_init(&priv->klist_devices, NULL, NULL);
 priv->driver = drv;
 drv->p = priv;
 priv->kobj.kset = bus->p->drivers_kset;
 error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
         "%s", drv->name);
 if (error)
  goto out_unregister;

 if (drv->bus->p->drivers_autoprobe) {
  error = driver_attach(drv);      //关联设备的函数
  if (error)
   goto out_unregister;
 }
 klist_add_tail(&priv->knode_bus, &bus->p->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",
   __func__, 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",
   __func__, drv->name);
 }

 if (!drv->suppress_bind_attrs) {
  error = add_bind_files(drv);
  if (error) {
   /* Ditto */
   printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
    __func__, drv->name);
  }
 }

 kobject_uevent(&priv->kobj, KOBJ_ADD);
 return 0;

out_unregister:
 kfree(drv->p);
 drv->p = NULL;
 kobject_put(&priv->kobj);
out_put_bus:
 bus_put(bus);
 return error;
}

int driver_attach(struct device_driver *drv)    //函数回调,传入函数指针__driver_attach,然后运行
{
 return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);

 

int bus_for_each_dev(struct bus_type *bus, struct device *start,
       void *data, int (*fn)(struct device *, void *))
{
 struct klist_iter i;
 struct device *dev;
 int error = 0;

 if (!bus)
  return -EINVAL;

 klist_iter_init_node(&bus->p->klist_devices, &i,
        (start ? &start->p->knode_bus : NULL));
 while ((dev = next_device(&i)) && !error)
  error = fn(dev, data);          //回调函数的调用,这是核心
 klist_iter_exit(&i);
 return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);

 


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.
  */

 if (!driver_match_device(drv, dev))   //这个函数调用总线的match函数,而总线为platform_bus_type,所以最终会调用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);   //这里才是真正的探测调用
 up(&dev->sem);
 if (dev->parent)
  up(&dev->parent->sem);

 return 0;
}

static inline int driver_match_device(struct device_driver *drv,
          struct device *dev)
{
 return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

int driver_probe_device(struct device_driver *drv, struct device *dev)       //其实probe函数真正的作用可以理解为申请资源以及将驱动和设备关联
{
 int ret = 0;

 if (!device_is_registered(dev))
  return -ENODEV;

 pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
   drv->bus->name, __func__, dev_name(dev), drv->name);

 pm_runtime_get_noresume(dev);
 pm_runtime_barrier(dev);
 ret = really_probe(dev, drv);    //核心
 pm_runtime_put_sync(dev);

 return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
 int ret = 0;

 atomic_inc(&probe_count);
 pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
   drv->bus->name, __func__, drv->name, dev_name(dev));
 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",
   __func__, dev_name(dev));
  goto probe_failed;
 }

 if (dev->bus->probe) {
  ret = dev->bus->probe(dev);//如果这里platform总线以对probe函数传值,则调用,但由上platform_bus_type可知没有,其实也可以加个回调
  if (ret)
   goto probe_failed;
 } else if (drv->probe) {       //如果总线没有,则调用device_driver->probe的,由上可知,已经初始化为用户的probe函数
  ret = drv->probe(dev);
  if (ret)
   goto probe_failed;
 }

 driver_bound(dev);  
 ret = 1;
 pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
   drv->bus->name, __func__, dev_name(dev), 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 %s failed with error %d\n",
         drv->name, dev_name(dev), ret);
 }
 /*
  * Ignore errors returned by ->probe so that the next driver can try
  * its luck.
  */
 ret = 0;
done:
 atomic_dec(&probe_count);
 wake_up(&probe_waitqueue);
 return ret;
}

static int sep0611_i2c_probe(struct platform_device *pdev)  //经过一系列的跳转 ,进入用户的probe函数
{
   struct sep0611_i2c *i2c;
   struct i2c_adapter *adap;
   struct resource *mem, *ioarea;
   int irq,ret;

   mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  //本身的resoure已经在boardc.c中定义,通过pdev传过来
   if(!mem){
     dev_err(&pdev->dev, "no mem resource!\n");
     return -EINVAL;
       }

   irq = platform_get_irq(pdev, 0);
   if (irq < 0) {
  dev_err(&pdev->dev, "no irq resource!\n");
  return irq; /* -ENXIO */
 }

   ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);  //芯片设计好后,各个模块有自己的物理地址,这已在board.c中给出,这是
 if (!ioarea) {
  dev_err(&pdev->dev, "I2C region already claimed\n");
  return -EBUSY;
 }

   i2c = kzalloc(sizeof(struct sep0611_i2c), GFP_KERNEL);
 if (!i2c) {
  ret = -ENOMEM;
  goto err_release_region;
 }

   init_completion(&i2c->cmd_complete);
 mutex_init(&i2c->lock);
 i2c->dev = get_device(&pdev->dev);
 i2c->irq = irq;
 platform_set_drvdata(pdev, i2c);
/*
   i2c->clk = clk_get(&pdev->dev, NULL);
 if (IS_ERR(i2c->clk)) {
  ret = -ENODEV;
  goto err_free_mem;
 }
 clk_enable(i2c->clk);
*/
   i2c->base = ioremap(mem->start, resource_size(mem));   //映射虚拟地址后就可在用户空间使用
 if (i2c->base == NULL) {
  dev_err(&pdev->dev, "failure mapping io resources\n");
  ret = -EBUSY;
  goto err_unuse_clocks;
 }
}

 

struct resource *platform_get_resource(struct platform_device *dev,
           unsigned int type, unsigned int num)
{
 int i;

 for (i = 0; i < dev->num_resources; i++) {
  struct resource *r = &dev->resource[i];

  if (type == resource_type(r) && num-- == 0)
   return r;
 }
 return NULL;
}
EXPORT_SYMBOL_GPL(platform_get_resource);

int platform_get_irq(struct platform_device *dev, unsigned int num)
{
 struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);

 return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq);

#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
#

static inline resource_size_t resource_size(struct resource *res)
{
 return res->end - res->start + 1;
}

struct resource * __request_region(struct resource *parent,
       resource_size_t start, resource_size_t n,
       const char *name, int flags)
{
 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);

 if (!res)
  return NULL;

 res->name = name;
 res->start = start;
 res->end = start + n - 1;
 res->flags = IORESOURCE_BUSY;
 res->flags |= flags;

 write_lock(&resource_lock);

 for (;;) {
  struct resource *conflict;

  conflict = __request_resource(parent, res);      //核心
  if (!conflict)
   break;
  if (conflict != parent) {
   parent = conflict;
   if (!(conflict->flags & IORESOURCE_BUSY))
    continue;
  }

  /* Uhhuh, that didn't work out.. */
  kfree(res);
  res = NULL;
  break;
 }
 write_unlock(&resource_lock);
 return res;
}
EXPORT_SYMBOL(__request_region);


static struct resource * __request_resource(struct resource *root, struct resource *new)
{
 resource_size_t start = new->start;
 resource_size_t end = new->end;
 struct resource *tmp, **p;

 if (end < start)
  return root;
 if (start < root->start)
  return root;
 if (end > root->end)
  return root;
 p = &root->child;
 for (;;) {
  tmp = *p;
  if (!tmp || tmp->start > end) {
   new->sibling = tmp;
   *p = new;
   new->parent = root;
   return NULL;
  }
  p = &tmp->sibling;
  if (tmp->end < start)
   continue;
  return tmp;
 }
}

 

原创粉丝点击