三、创建 i2c_adapter 和 i2c_client

// kernel/drivers/i2c/busses/i2c-sc8810.c

/* sc8810_i2c_probe

 *

 * called by the bus driver when a suitabledevice is found

*/

static int sc8810_i2c_probe(struct platform_device *pdev)

{

       struct sc8810_i2c *i2c;

       struct resource *res;

       int irq;

       int ret;

       unsigned int tmp;

 

       i2c = kzalloc(sizeof(struct sc8810_i2c),GFP_KERNEL);

       if (!i2c){

              printk("I2C:kzallocfailed!\n");

              return  -ENOMEM;

       }

 

       res = platform_get_resource(pdev,IORESOURCE_MEM, 0);

       printk("I2C:res->start=%x\n", res->start);

       irq = platform_get_irq(pdev, 0);

       printk("I2C: irq=%d\n", irq);

       if (res == NULL || irq < 0){

              printk("I2C:platform_get_resource&irqfailed!\n");

              ret=-ENODEV;

              goto err_irq;

       }

#if 0

       if (!request_mem_region(res->start,res_len(res), res->name)){

              printk("I2C:request_mem_regionfailed!\n");

              ret=-ENOMEM;

              goto err_irq;

       }

#endif

 

       i2c->membase=res->start;//ioremap(res->start, resource_size(res));

       if (!i2c->membase) {

              printk("I2C:ioremapfailed!\n");

              ret=-EIO;

              goto err_irq;

       }

 

       i2c->irq = irq;     

 

       spin_lock_init(&i2c->lock);

       init_waitqueue_head(&i2c->wait);

 

       snprintf(i2c->adap.name,sizeof(i2c->adap.name),"%s","sc8810-i2c");

       i2c->adap.owner = THIS_MODULE;

       i2c->adap.retries = 4;

      //这一步对i2c的读写很重要,将会在以后的i2c数据结构中详细说明

       i2c->adap.algo = &sc8810_i2c_algorithm;

       i2c->adap.algo_data = i2c;

       i2c->adap.dev.parent =&pdev->dev;

 

       /* initialize the i2c controller */

 

       sc8810_i2c_init(i2c);

      

       ret = request_irq(i2c->irq,sc8810_i2c_irq, IRQF_SHARED,pdev->name,i2c);

       if (ret) {

              printk("I2C:request_irqfailed!\n");

              goto err_irq;

       }

     // adap.nr就是每个platform_device对应的总线号,这在以后会经常用到

       i2c->adap.nr = pdev->id;

 

       ret = i2c_add_numbered_adapter(&i2c->adap);

       if (ret < 0){

              printk("I2C:add_adapterfailed!\n");

              goto err_adap;

       }

 

    sc8810_i2c_ctl[pdev->id] = i2c;

    printk("I2C:sc8810_i2c_ctl[%d]=%x",pdev->id,sc8810_i2c_ctl[pdev->id]);

       platform_set_drvdata(pdev, i2c);

 

       i2c_create_sysfs(pdev);

       return 0;

err_adap:

       free_irq(i2c->irq,i2c);

err_irq:

       kfree(i2c);

 

       return ret;

}

 

 

/**

 * i2c_add_numbered_adapter - declare i2cadapter, use static bus number

 * @adap: the adapter to register (withadap->nr initialized)

 * Context: can sleep

 *

 * This routine is used to declare an I2Cadapter when its bus number

 * matters. For example, use it for I2C adapters from system-on-chip CPUs,

 * or otherwise built in to the system'smainboard, and where i2c_board_info

 * is used to properly configure I2C devices.

 *

 * If no devices have pre-been declared forthis bus, then be sure to

 * register the adapter before any dynamicallyallocated ones.  Otherwise

 * the required bus ID may not be available.

 *

 * When this returns zero, the specifiedadapter became available for

 * clients using the bus number provided inadap->nr.  Also, the table

 * of I2C devices pre-declared usingi2c_register_board_info() is scanned,

 * and the appropriate driver model devicenodes are created.  Otherwise, a

 * negative errno value is returned.

 */

// kernel/drivers/i2c/i2c-core.c

inti2c_add_numbered_adapter(structi2c_adapter *adap)

{

       int   id;

       int   status;

 

       if (adap->nr & ~MAX_ID_MASK)

              return -EINVAL;

 

retry:

       if (idr_pre_get(&i2c_adapter_idr,GFP_KERNEL) == 0)

              return -ENOMEM;

       mutex_lock(&core_lock);

       /* "above" here means"above or equal to", sigh;

        *we need the "equal to" result to force the result

        */

       status =idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);

       if (status == 0 && id !=adap->nr) {

              status = -EBUSY;

              idr_remove(&i2c_adapter_idr,id);

       }

       mutex_unlock(&core_lock);

       if (status == -EAGAIN)

              goto retry;

 

       if (status == 0)

              status = i2c_register_adapter(adap);

       return status;

}

 

 

 

// kernel/drivers/i2c/i2c-core.c

static int i2c_register_adapter(struct i2c_adapter *adap)

{

       int res = 0, dummy;

 

       /* Can't register until after drivermodel init */

       if (unlikely(WARN_ON(!i2c_bus_type.p))) {

              res = -EAGAIN;

              goto out_list;

       }

 

       rt_mutex_init(&adap->bus_lock);

       INIT_LIST_HEAD(&adap->userspace_clients);

 

       /* Set default timeout to 1 second if notalready set */

       if (adap->timeout == 0)

              adap->timeout = HZ;

   

   //i2c_adapter的名字,分别为:i2c-0i2c-1i2c-2i2c-3

       dev_set_name(&adap->dev,"i2c-%d", adap->nr);

       adap->dev.bus = &i2c_bus_type;

       adap->dev.type =&i2c_adapter_type;

   //注册i2c_adapter,文件节点在sys/devices/platform/sc8810-i2c.ID/i2c-ID

       res = device_register(&adap->dev);

       if (res)

              goto out_list;

 

       dev_dbg(&adap->dev, "adapter[%s] registered\n", adap->name);

 

#ifdefCONFIG_I2C_COMPAT

       res =class_compat_create_link(i2c_adapter_compat_class, &adap->dev,

                                   adap->dev.parent);

       if (res)

              dev_warn(&adap->dev,

                      "Failed to create compatibility classlink\n");

#endif

 

       /* create pre-declared device nodes */

   //在“”中的i2c_register_board_info()函数中可知,__i2c_first_dynamic_bus_num的值为3。因此只会创建挂在i2c-0i2c-1、i2c-2上的clientI2c-3不会进入此函数

       if (adap->nr <__i2c_first_dynamic_bus_num)

              i2c_scan_static_board_info(adap);

 

       /* Notify drivers */

       mutex_lock(&core_lock);

       dummy =bus_for_each_drv(&i2c_bus_type, NULL, adap,

                             __process_new_adapter);

       mutex_unlock(&core_lock);

 

       return 0;

 

out_list:

       mutex_lock(&core_lock);

       idr_remove(&i2c_adapter_idr,adap->nr);

       mutex_unlock(&core_lock);

       return res;

}


 

// kernel/drivers/i2c/i2c-core.c

static void i2c_scan_static_board_info(struct i2c_adapter *adapter)

{

       struct i2c_devinfo      *devinfo;

 

       down_read(&__i2c_board_lock);

  list_for_each_entry(devinfo,&__i2c_board_list, list) {

            //遍历全局__i2c_board_list链表,分别为挂在i2c-0i2c-1i2c-2下的设备创建i2c_client

              if (devinfo->busnum== adapter->nr   &&   !i2c_new_device(adapter,   &devinfo->board_info))

                     dev_err(&adapter->dev,

                            "Can't createdevice at 0x%02x\n",

                            devinfo->board_info.addr);

       }

       up_read(&__i2c_board_lock);

}

 


/**

 * i2c_new_device - instantiate an i2c device

 * @adap: the adapter managing the device

 * @info: describes one I2C device; bus_num isignored

 * Context: can sleep

 *

 * Create an i2c device. Binding is handledthrough driver model

 * probe()/remove() methods.  A driver may be bound to this device when we

 * return from this function, or any latermoment (e.g. maybe hotplugging will

 * load the driver module).  This call is not appropriate for use bymainboard

 * initialization logic, which usually runsduring an arch_initcall() long

 * before any i2c_adapter could exist.

 *

 * This returns the new i2c client, which maybe saved for later use with

 * i2c_unregister_device(); or NULL to indicatean error.

 */

//i2c 动态注册直接调用该函数,把相应的i2c_adapteri2c_board_info传进去

// kernel/drivers/i2c/i2c-core.c

struct i2c_client* i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const*info)

{

       struct i2c_client  *client;

       int                 status;

 

       client = kzalloc(sizeof *client,GFP_KERNEL);

       if (!client)

              return NULL;

 

       client->adapter = adap;

       client->dev.platform_data =info->platform_data;

 

       if (info->archdata)

              client->dev.archdata =*info->archdata;

 

       client->flags = info->flags;

       client->addr = info->addr;

       client->irq = info->irq;

 

       strlcpy(client->name, info->type,sizeof(client->name));

 

       /* Check for address validity */

       status =i2c_check_client_addr_validity(client);

       if (status) {

              dev_err(&adap->dev,"Invalid %d-bit I2C address 0x%02hx\n",

                     client->flags &I2C_CLIENT_TEN ? 10 : 7, client->addr);

              // goto out_err_silent;

        status = 0;

       }

 

       /* Check for address business */

   //防止同一条 i2c总线上出现多个地址相同的 I2C设备

       status = i2c_check_addr_busy(adap, client->addr);

       if (status)

              goto out_err;

 

       client->dev.parent =&client->adapter->dev;

       client->dev.bus = &i2c_bus_type;

       client->dev.type =&i2c_client_type;

#ifdef CONFIG_OF

       client->dev.of_node =info->of_node;

#endif

    //i2c_client的命名规范

       dev_set_name(&client->dev,"%d-%04x", i2c_adapter_id(adap), client->addr);

 //将设备client->dev注册进内核,文件节点在sys/devices/platform/sc8810-i2c.ID /i2c-ID/ID-ADDR(%04x)

       status = device_register(&client->dev);

       if (status)

              goto out_err;

 

       dev_dbg(&adap->dev, "client[%s] registered with bus id %s\n",

              client->name,dev_name(&client->dev));

 

       return client;

 

out_err:

       dev_err(&adap->dev, "Failedto register i2c client %s at 0x%02x "

              "(%d)\n",client->name, client->addr, status);

out_err_silent:

       kfree(client);

       return NULL;

}

 

 

/**

 * device_register - register a device with thesystem.

 * @dev: pointer to the device structure

 *

 * This happens in two clean steps - initializethe device

 * and add it to the system. The two steps canbe called

 * separately, but this is the easiest and mostcommon.

 * I.e. you should only call the two helpersseparately if

 * have a clearly defined need to use andrefcount the device

 * before it is added to the hierarchy.

 * NOTE: _Never_ directly free @dev aftercalling this function, even

 * if it returned an error! Always useput_device() to give up the

 * reference initialized in this function instead.

 */

// kernel/drivers/base/core.c

int device_register(struct device *dev)

{

       device_initialize(dev);

       return device_add(dev);

}



/**

 * device_add - add device to device hierarchy.

 * @dev: device.

 *

 * This is part 2 of device_register(), though maybe called

 * separately _iff_ device_initialize() hasbeen called separately.

 *

 * This adds @dev to the kobject hierarchy viakobject_add(), adds it

 * to the global and sibling lists for thedevice, then

 * adds it to the other relevant subsystems ofthe driver model.

 *

 * NOTE: _Never_ directly free @dev aftercalling this function, even

 * if it returned an error! Always useput_device() to give up your

 * reference instead.

 */

// kernel/drivers/base/core.c

int device_add(struct device *dev)

{

       struct device *parent = NULL;

       struct class_interface *class_intf;

       int error = -EINVAL;

 

       dev = get_device(dev);

       if (!dev)

              goto done;

 

       if (!dev->p) {

              error = device_private_init(dev);

              if (error)

                     goto done;

       }

 


       /*

        *for statically allocated devices, which should all be converted

        *some day, we need to initialize the name. We prevent reading back

        *the name, and force the use of dev_name()

        */

       if (dev->init_name) {

              dev_set_name(dev, "%s",dev->init_name);

              dev->init_name = NULL;

       }

 

       if (!dev_name(dev)) {

              error = -EINVAL;

              goto name_error;

       }

 

       pr_debug("device: '%s': %s\n",dev_name(dev), __func__);

 

       parent = get_device(dev->parent);

       setup_parent(dev, parent);

 

       /* use parent numa_node */

       if (parent)

              set_dev_node(dev, dev_to_node(parent));

 

       /* first, register with generic layer. */

       /* we require the name to be set before,and pass NULL */

       error = kobject_add(&dev->kobj,dev->kobj.parent, NULL);

       if (error)

              goto Error;

 

       /* notify platform of device entry */

       if (platform_notify)

              platform_notify(dev);

 

       error = device_create_file(dev,&uevent_attr);

       if (error)

              goto attrError;

 

       if (MAJOR(dev->devt)) {

              error = device_create_file(dev,&devt_attr);

              if (error)

                     goto ueventattrError;

 

              error =device_create_sys_dev_entry(dev);

              if (error)

                     goto devtattrError;

 

              devtmpfs_create_node(dev);

       }

 

       error = device_add_class_symlinks(dev);

       if (error)

              goto SymlinkError;

       error = device_add_attrs(dev);

       if (error)

              goto AttrsError;

       error = bus_add_device(dev);

       if (error)

              goto BusError;

       error = dpm_sysfs_add(dev);

       if (error)

              goto DPMError;

       device_pm_add(dev);

 

       /* Notify clients of deviceaddition.  This call must come

        *after dpm_sysf_add() and before kobject_uevent().

        */

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

                                        BUS_NOTIFY_ADD_DEVICE, dev);

 

       kobject_uevent(&dev->kobj,KOBJ_ADD);

       bus_probe_device(dev);

       if (parent)

              klist_add_tail(&dev->p->knode_parent,

                            &parent->p->klist_children);

 

       if (dev->class) {

              mutex_lock(&dev->class->p->class_mutex);

              /* tie the class to the device */

              klist_add_tail(&dev->knode_class,

                           &dev->class->p->class_devices);

 

              /* notify any interfaces that thedevice is here */

              list_for_each_entry(class_intf,

                               &dev->class->p->class_interfaces, node)

                     if (class_intf->add_dev)

                            class_intf->add_dev(dev,class_intf);

              mutex_unlock(&dev->class->p->class_mutex);

       }

done:

       put_device(dev);

       return error;

 DPMError:

       bus_remove_device(dev);

 BusError:

       device_remove_attrs(dev);

 AttrsError:

       device_remove_class_symlinks(dev);

 SymlinkError:

       if (MAJOR(dev->devt))

              devtmpfs_delete_node(dev);

       if (MAJOR(dev->devt))

              device_remove_sys_dev_entry(dev);

 devtattrError:

       if (MAJOR(dev->devt))

              device_remove_file(dev,&devt_attr);

 ueventattrError:

       device_remove_file(dev,&uevent_attr);

 attrError:

       kobject_uevent(&dev->kobj,KOBJ_REMOVE);

       kobject_del(&dev->kobj);

 Error:

       cleanup_device_parent(dev);

       if (parent)

              put_device(parent);

name_error:

       kfree(dev->p);

       dev->p = NULL;

       goto done;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值