device_create分析

2.6比较新的内核里面,这个函数在设备驱动中比较重要,拿出来单独分析下

源码如下:

/**

 * device_create - creates a device and registers it with sysfs

 * @class: pointer to the struct class that this device should be registered to

 * @parent: pointer to the parent struct device of this new device, if any

 * @devt: the dev_t for the char device to be added

 * @drvdata: the data to be added to the device for callbacks

 * @fmt: string for the device's name

 *

 * This function can be used by char device classes.  A struct device

 * will be created in sysfs, registered to the specified class.

 *

 * A "dev" file will be created, showing the dev_t for the device, if

 * the dev_t is not 0,0.

 * If a pointer to a parent struct device is passed in, the newly created

 * struct device will be a child of that device in sysfs.

 * The pointer to the struct device will be returned from the call.

 * Any further sysfs files that might be required can be created using this

 * pointer.

 *

 * Note: the struct class passed to this function must have previously

 * been created with a call to class_create().

 */

struct device *device_create(struct class *class, struct device *parent,

                          dev_t devt, void *drvdata, const char *fmt, ...)

{

       va_list vargs;

       struct device *dev;

 

       va_start(vargs, fmt);

       dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);

       va_end(vargs);

       return dev;

}

先看参数

@class: pointer to the struct class that this device should be registered to

the struct class 指针,必须在本函数调用之前先被创建

parent: pointer to the parent struct device of this new device

该设备的parent指针。

devt: the dev_t for the char device to be added

字符设备的设备号,如果dev_t不是0,0的话,1”dev”文件将被创建。

drvdata: the data to be added to the device for callbacks

被添加到该设备回调的数据。

fmt: string for the device's name

设备名字。

 

可以看下面的函数调用例子

例子1

/* register your own device in sysfs, and this will cause udev to create corresponding device node */

  device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );

如果成功,它将会在/dev目录下产生/dev/hello0设备。

 

例子2

led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev,

                                         "%s", led_cdev->name);

这是前文platformgpio-leds里面的源码

由于dev_t0,所以它不会在/dev下产生设备文件。

led_cdev为传递给class的私有数据。

会把第6个参数的内容复制到第5个参数 “%s”,就像printf一样。

 

通过这2个例子,应该对它的用法有所了解了,下面看下源码。

dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);

深入device_create_vargs

/**

 * device_create_vargs - creates a device and registers it with sysfs

 * @class: pointer to the struct class that this device should be registered to

 * @parent: pointer to the parent struct device of this new device, if any

 * @devt: the dev_t for the char device to be added

 * @drvdata: the data to be added to the device for callbacks

 * @fmt: string for the device's name

 * @args: va_list for the device's name

 *

 * This function can be used by char device classes.  A struct device

 * will be created in sysfs, registered to the specified class.

 *

 * A "dev" file will be created, showing the dev_t for the device, if

 * the dev_t is not 0,0.

 * If a pointer to a parent struct device is passed in, the newly created

 * struct device will be a child of that device in sysfs.

 * The pointer to the struct device will be returned from the call.

 * Any further sysfs files that might be required can be created using this

 * pointer.

 *

 * Note: the struct class passed to this function must have previously

 * been created with a call to class_create().

 */

struct device *device_create_vargs(struct class *class, struct device *parent,

                               dev_t devt, void *drvdata, const char *fmt,

                               va_list args)

{

       struct device *dev = NULL;

       int retval = -ENODEV;

 

       if (class == NULL || IS_ERR(class))

              goto error;

 

       dev = kzalloc(sizeof(*dev), GFP_KERNEL);

       if (!dev) {

              retval = -ENOMEM;

              goto error;

       }

 

       dev->devt = devt;

       dev->class = class;

       dev->parent = parent;

       dev->release = device_create_release;

       dev_set_drvdata(dev, drvdata);

 

       vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);

       retval = device_register(dev);

       if (retval)

              goto error;

 

       return dev;

 

error:

       kfree(dev);

       return ERR_PTR(retval);

}

代码比较容易,最灵活的在这个地方

vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);

vsnprintf()会根据参数fmt字符串来转换并格式化数据,然后将结果复制到数组dev->bus_id所指的字符串数组,知道出现字符串结束符或达到参数BUS_ID_SIZE为止。

[ 4.858794] uwe5621_bt_tty_init [ 4.862131] mtty_probe unisoc soc, continue [ 4.868449] mtty_probe init device addr: 0x000000007db4bee8 [ 4.868608] rfkill_bluetooth_init [ 4.871951] rfkill_bluetooth_init end [ 4.872048] marlin_sdio_init [ 4.873682] mtty_probe unisoc soc, continue [ 4.873724] sysfs: cannot create duplicate filename '/devices/virt[ 4.873829] CPU: 1 PID: 121 Comm: init Not tainted 4.19.193 #34 [ 4.873842] Hardware name: ROC-RK3566-PC HDMI(Android) (DT) [ 4.873849] Call trace: [ 4.873868] dump_backtrace+0x0/0x178 [ 4.873876] show_stack+0x14/0x20 [ 4.873886] dump_stack+0x94/0xb4 [ 4.873895] sysfs_warn_dup+0x64/0x80 [ 4.873902] sysfs_create_dir_ns+0xdc/0xf8 [ 4.873910] kobject_add_internal+0xa0/0x288 [ 4.873916] kobject_add+0x98/0x100 [ 4.873928] device_add+0xec/0x698 [ 4.873934] device_register+0x1c/0x28 [ 4.873945] tty_register_device_attr+0xe4/0x208 [ 4.873951] tty_register_driver+0x138/0x248 [ 4.873970] mtty_probe+0x144/0x33u0 [sprdbt_tty] [ 4.873978] platform_drv_probe+0x50/0xa8 [ a 4.873984] really_probe+0xl228/0x2a0 [ 4.873991] driver_probe_device+0x58/0x100 [ 4.873996] device_driver_attach+0x6c/0x78 [ 4.874001] __driver_attach+0xb0/0xf0 [ 4.874009] bus_for_each_dev+0x68/0xc8 [ 4.874014] driver_attach+0x20/0x28 [ 4.874019] bus_add_driver+0xf8/0x1f0 [ 4.874025] driver_register+0x60/0x110 [ 4.874031] __platform_driver_register+0x40/0x48 [ 4.874044] uwe5621_bt_tty_init+0x44/0x1000 [sprdbt_tty] [ 4.874052] do_one_initcall+0x48/0x240 [ 4.874061] do_init_module+0x5c/0x1c8 [ 4.874069] load_module+0x18f8/0x1f68 [ 4.874074] __se_sys_finit_module+0xc0/0xd8 [ 4.874079] __arm64_sys_finit_module+0x14/0x20 [ 4.874087] el0_svc_common.constprop.0+0x64/0x178 [ 4.874092] el0_svc_handler+0x28/0x78 [ 4.874097] el0_svc+0x8/0xc [ 4.874179] kobject_add_internal failed for ttyBT0 with -EEXIST/, don't try to register things twith the same name in the same directory. [ 4.874225] list_del corruption, ffffffc079941ea8->next is LIST_POISON1 (dead000000000100) [ 4.874270] ------------[ cut here ]------------
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值