当前位置: 首页> 科技> 互联网 > 东莞常平核酸检测点_在线客服人工咨询_青岛seo网站建设公司_阿里云万网域名购买

东莞常平核酸检测点_在线客服人工咨询_青岛seo网站建设公司_阿里云万网域名购买

时间:2025/9/10 9:42:11来源:https://blog.csdn.net/weixin_44586903/article/details/143489133 浏览次数:0次
东莞常平核酸检测点_在线客服人工咨询_青岛seo网站建设公司_阿里云万网域名购买

device_create

主要应用场景是在/dev下创建设备节点;主要是dev_t设备号,引起了device_add的设备节点创建操作

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;
}struct device *device_create_vargs(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt,va_list args)
{return device_create_groups_vargs(class, parent, devt, drvdata, NULL,fmt, args);
}static struct device *
device_create_groups_vargs(struct class *class, struct device *parent,dev_t devt, void *drvdata,const struct attribute_group **groups,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;}device_initialize(dev);dev->devt = devt;dev->class = class;dev->parent = parent;dev->groups = groups;dev->release = device_create_release;dev_set_drvdata(dev, drvdata);retval = kobject_set_name_vargs(&dev->kobj, fmt, args);if (retval)goto error;retval = device_add(dev);if (retval)goto error;return dev;error:put_device(dev);return ERR_PTR(retval);
}

实例

动态申请设备号;申请cdev并赋值ops;添加cdev;创建class;创建设备节点

static int __init led_init(void)
{int ret;dev_t devno;struct cdev *cdev;struct dev *dev;/* 注册设备号 */ret = alloc_chrdev_region(&devno, 0, 1, "led");if (ret < 0) return ret;/* 分配、初始化、注册cdev*/cdev = cdev_alloc();if (IS_ERR(cdev)) {ret = PTR_ERR(cdev);goto out_unregister_devno;}cdev_init(&cdev, &led_fops);cdev.owner = THIS_MODULE;ret = cdev_add(&cdev, devno, 1);    if (ret) goto out_free_cdev;/* 创建设备类 */led_class = class_create(THIS_MODULE, "led_class");if (IS_ERR(led_class)) {ret = PTR_ERR(led_class);goto out_unregister_cdev;} /* 创建设备节点 */dev = device_create(led_class, NULL, devno, NULL, "led");if (IS_ERR(dev)) {ret = PTR_ERR(dev);goto out_del_class;}return 0;
}

device_register

一般用于匹配设备驱动的注册行为,比如platform_device,i2c_client的创建和注册等;所以就只是device_initialize后直接device_add,来添加并注册设备到系统中

int device_register(struct device *dev)
{device_initialize(dev);return device_add(dev);
}

实例1: platform_device_register

int platform_device_register(struct platform_device *pdev)
{device_initialize(&pdev->dev);arch_setup_pdev_archdata(pdev);return platform_device_add(pdev);
}

实例2:i2c_new_device

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;if (!client->irq)client->irq = i2c_dev_irq_from_resources(info->resources,info->num_resources);strlcpy(client->name, info->type, sizeof(client->name));status = i2c_check_addr_validity(client->addr, client->flags);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;}/* Check for address business */status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client));if (status)goto out_err;client->dev.parent = &client->adapter->dev;client->dev.bus = &i2c_bus_type;client->dev.type = &i2c_client_type;client->dev.of_node = info->of_node;client->dev.fwnode = info->fwnode;i2c_dev_set_name(adap, client);if (info->properties) {status = device_add_properties(&client->dev, info->properties);if (status) {dev_err(&adap->dev,"Failed to add properties to client %s: %d\n",client->name, status);goto out_err;}}status = device_register(&client->dev);if (status)goto out_free_props;dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",client->name, dev_name(&client->dev));return client;out_free_props:if (info->properties)device_remove_properties(&client->dev);
out_err:dev_err(&adap->dev,"Failed to register i2c client %s at 0x%02x (%d)\n",client->name, client->addr, status);
out_err_silent:kfree(client);return NULL;
}

device_add

device_add一般也是跟device_initialize一起配合使用的;只是跟device_register的区别在于这样的灵活性高:

1. 根据不同设备驱动模块的不同特性,针对device的parent,class,name等信息初始化2. 在device_initialize和device_add之间,也可以加入不同模块的的不同初始化操作

以下代码和注释是device_add的详细分析

int device_add(struct device *dev)  dev = get_device(dev);//增加该设备的引用计数  if (!dev->p) {  error = device_private_init(dev);//初始化设备的私有成员p  if (error)  goto done;  }  if (dev->init_name) {  dev_set_name(dev, "%s", dev->init_name);//初始化设备内部的kobject的名字  dev->init_name = NULL;  }  if (!dev_name(dev) && dev->bus && dev->bus->dev_name)  dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);//使用bus以及设备id来初始化设备内部kobject名字  if (!dev_name(dev)) {//获得设备的名字  error = -EINVAL;  goto name_error;  }  parent = get_device(dev->parent);增加设备父设备并增加父设备引用计数  kobj = get_device_parent(dev, parent);  if (kobj)  dev->kobj.parent = kobj;//在kobject层实现设备父子关系  if (parent)  set_dev_node(dev, dev_to_node(parent));  error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//将设备加入到kobject模型中,创建sys相关目录  /* notify platform of device entry */  if (platform_notify)  platform_notify(dev);  error = device_create_file(dev, &uevent_attr);//创建sys目录下设备的uevent属性文件,通过它可以查看设备的uevent事件  if (MAJOR(dev->devt)) {  error = device_create_file(dev, &devt_attr);//创建sys目录下设备的设备号属性,即major和minor  error = device_create_sys_dev_entry(dev);  devtmpfs_create_node(dev); //在/dev下创建设备节点文件}  error = device_add_class_symlinks(dev);  error = device_add_attrs(dev);//创建sys目录下设备其他属性文件  error = bus_add_device(dev);//将设备加入到管理它的bus总线的设备连表上  error = dpm_sysfs_add(dev);//电源管理相关  device_pm_add(dev);  /* Notify clients of device addition.  This call must come * after dpm_sysfs_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);//产生一个内核uevent事件,该事件可以被内核以及应用层捕获,属于linux设备模型中热插拔机制  bus_probe_device(dev);//------------开始寻找设备所对应的驱动------------  if (parent)  klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children);
//建立设备与总线间的父子关系  if (dev->class) {//如果设备的属于某个设备类,比如Mass storage,HID等等  mutex_lock(&dev->class->p->mutex);  /* tie the class to the device */  klist_add_tail(&dev->knode_class,&dev->class->p->klist_devices);//将设备挂接在其设备类上面  /* notify any interfaces that the device is here */  list_for_each_entry(class_intf,&dev->class->p->interfaces, node)  if (class_intf->add_dev)  class_intf->add_dev(dev, class_intf);//通知有新设备加入  mutex_unlock(&dev->class->p->mutex);  

实例1

设备树节点生成platform_device的时候

 

在之间加初始化操作init和add之间加bus和platform_data信息

static struct platform_device *of_platform_device_create_pdata(struct device_node *np,const char *bus_id,void *platform_data,struct device *parent)
{struct platform_device *dev;if (!of_device_is_available(np) ||of_node_test_and_set_flag(np, OF_POPULATED))return NULL;dev = of_device_alloc(np, bus_id, parent);if (!dev)goto err_clear_flag;dev->dev.bus = &platform_bus_type;dev->dev.platform_data = platform_data;of_msi_configure(&dev->dev, dev->dev.of_node);if (of_device_add(dev) != 0) {platform_device_put(dev);goto err_clear_flag;}return dev;err_clear_flag:of_node_clear_flag(np, OF_POPULATED);return NULL;
}

 

实例2

先mmc_alloc_host申请host结构,并device_initialize初始化host结构的device成员;后面的mmc_add_host调用device_add,将device添加到系统

static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
{struct mmc_omap_slot *slot = NULL;struct mmc_host *mmc;int r;mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev);if (mmc == NULL)return -ENOMEM;slot = mmc_priv(mmc);slot->host = host;slot->mmc = mmc;slot->id = id;slot->power_mode = MMC_POWER_UNDEFINED;slot->pdata = &host->pdata->slots[id];host->slots[id] = slot;mmc->caps = 0;if (host->pdata->slots[id].wires >= 4)mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE;mmc->ops = &mmc_omap_ops;mmc->f_min = 400000;if (mmc_omap2())mmc->f_max = 48000000;elsemmc->f_max = 24000000;if (host->pdata->max_freq)mmc->f_max = min(host->pdata->max_freq, mmc->f_max);mmc->ocr_avail = slot->pdata->ocr_mask;/* Use scatterlist DMA to reduce per-transfer costs.* NOTE max_seg_size assumption that small blocks aren't* normally used (except e.g. for reading SD registers).*/mmc->max_segs = 32;mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;mmc->max_seg_size = mmc->max_req_size;if (slot->pdata->get_cover_state != NULL) {setup_timer(&slot->cover_timer, mmc_omap_cover_timer,(unsigned long)slot);tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,(unsigned long)slot);}r = mmc_add_host(mmc);if (r < 0)goto err_remove_host;if (slot->pdata->name != NULL) {r = device_create_file(&mmc->class_dev,&dev_attr_slot_name);if (r < 0)goto err_remove_host;}if (slot->pdata->get_cover_state != NULL) {r = device_create_file(&mmc->class_dev,&dev_attr_cover_switch);if (r < 0)goto err_remove_slot_name;tasklet_schedule(&slot->cover_tasklet);}return 0;err_remove_slot_name:if (slot->pdata->name != NULL)device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
err_remove_host:mmc_remove_host(mmc);mmc_free_host(mmc);return r;
}

mmc_alloc_host会在device_initialize后先一些初始化(device_enable_async_suspend);以及判断操作来决定是否device_add

struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{int err;struct mmc_host *host;host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);if (!host)return NULL;/* scanning will be enabled when we're ready */host->rescan_disable = 1;err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL);if (err < 0) {kfree(host);return NULL;}host->index = err;dev_set_name(&host->class_dev, "mmc%d", host->index);host->parent = dev;host->class_dev.parent = dev;host->class_dev.class = &mmc_host_class;device_initialize(&host->class_dev);device_enable_async_suspend(&host->class_dev);if (mmc_gpio_alloc(host)) {put_device(&host->class_dev);ida_simple_remove(&mmc_host_ida, host->index);kfree(host);return NULL;}spin_lock_init(&host->lock);init_waitqueue_head(&host->wq);INIT_DELAYED_WORK(&host->detect, mmc_rescan);INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);/** By default, hosts do not support SGIO or large requests.* They have to set these according to their abilities.*/host->max_segs = 1;host->max_seg_size = PAGE_SIZE;host->max_req_size = PAGE_SIZE;host->max_blk_size = 512;host->max_blk_count = PAGE_SIZE / 512;return host;
}

mmc_add_host调用device_add将mmc主机设备添加到系统

int mmc_add_host(struct mmc_host *host)
{int err;WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&!host->ops->enable_sdio_irq);err = device_add(&host->class_dev);if (err)return err;led_trigger_register_simple(dev_name(&host->class_dev), &host->led);#ifdef CONFIG_DEBUG_FSmmc_add_host_debugfs(host);
#endifmmc_start_host(host);mmc_register_pm_notifier(host);return 0;
}

关键字:东莞常平核酸检测点_在线客服人工咨询_青岛seo网站建设公司_阿里云万网域名购买

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: