driverstudio注册码_汽车erp管理系统

(1) 2024-08-04 21:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
driverstudio注册码_汽车erp管理系统,希望能够帮助你!!!。

platform 总线上的驱动注册一般使用module_platform_driver宏,如goldfish设备的注册
module_platform_driver(goldfish_pipe);
这个宏定义在/goldfish/include/linux/platform_device.h文件

/* module_platform_driver() - Helper macro for drivers that don't do * anything special in module init/exit. This eliminates a lot of * boilerplate. Each module may only use this macro once, and * calling it replaces module_init() and module_exit() */ #define module_platform_driver(__platform_driver) \ module_driver(__platform_driver, platform_driver_register, \ platform_driver_unregister) #define module_driver(__driver, __register, __unregister, ...) \ static int __init __driver##_init(void) \ { \ return __register(&(__driver) , ##__VA_ARGS__); \ } \ module_init(__driver##_init); \ static void __exit __driver##_exit(void) \ { \ __unregister(&(__driver) , ##__VA_ARGS__); \ } \ module_exit(__driver##_exit); 

对于platform类型的驱动以goldfish_pipe为例子展开如下

static int __init goldfish_pipe_init(void) { return platform_driver_register(&(goldfish_pipe) ); } module_init(goldfish_pipe_init); static void __exit goldfish_pipe_exit(void) \ { platform_driver_unregister(&(goldfish_pipe) ); } module_exit(goldfish_pipe_exit); 

也就是在.init.setup6段放了连个函数__goldfish_pipe_init和__goldfish_pipe_exit,作用分别是在内核初始化的时候注册该驱动,退出的时候注销该驱动

#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE) /** * __platform_driver_register - register a driver for platform-level devices * @drv: platform driver structure * @owner: owning module/driver */ int __platform_driver_register(struct platform_driver *drv, struct module *owner) { drv->driver.owner = owner; 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); } 

__platform_driver_register的函数设置了一些driver的方法,如probe, remove和shutdown,如果用户没有自己设定该方法,就使用platform框架的,这有些面向对象的思想,子类可以使用父类方法,也可以复写父类方法
这里也设置了driver的bus成员,指向了platform_bus_type,设置了一些platform方法后,调用通用的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) { 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); if (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; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); return ret; } 

1首先检查下设备自己实现的probe,remove,shutdown但是bus也支持probe,remove,shutdown的请款,提示用户升级驱动
2在bus上查找同名drive,如果找到了提示错误(driver_find)
3调用bus_add_driver添加driver到bus上
4 调用driver_add_groups添加到驱动组
5发送uevent add 事件

driver_find函数在drivers/base/driver.c文件下

/** * driver_find - locate driver on a bus by its name. * @name: name of the driver. * @bus: bus to scan for the driver. * * Call kset_find_obj() to iterate over list of drivers on * a bus to find driver by name. Return driver if found. * * This routine provides no locking to prevent the driver it returns * from being unregistered or unloaded while the caller is using it. * The caller is responsible for preventing this. */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); struct driver_private *priv; if (k) { /* Drop reference added by kset_find_obj() */ kobject_put(k); priv = to_driver(k); return priv->driver; } return NULL; } 

在/sys/bus/${bus_name}/drivers对应的kset下查找以驱动为名字的文件

add_driver的实现在drivers/base/bus.c文件

/** * bus_add_driver - Add a driver to the bus. * @drv: driver. */ int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); 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; klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } 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_groups(drv, bus->drv_groups); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_create_groups(%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); } } return 0; out_unregister: kobject_put(&priv->kobj); kfree(drv->p); drv->p = NULL; out_put_bus: bus_put(bus); return error; } 

该函数实现的功能包含如下
1 创建kobj,在bus对应的driver kset下,如platform的/sys/bus/platform/drivers,名称为该驱动的名称
2 添加到bus->p->klist_drivers 链表中
3 driver_attach 进行device绑定
4 module_add_driver
5 driver_create_file
6 driver_add_groups
7 add_bind_files
 
driver_attach 是实现在文件drivers/base/dd.c中,

/** * 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); } 

实现很简单,遍历bus->p->klist_devices链表中的device, 执行__driver_attach
__driver_attach也在文件drivers/base/dd.c中,

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)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); 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; } 

driver_match_device函数主要是调用bus的match函数去匹配设备和驱动。 完成匹配之后就调用driver_probe_device触发driver的探测函数

platform bus匹配驱动和设备的函数在文件drivers/base/platform.c中如下

/** * platform_match - bind platform device to platform driver. * @dev: device. * @drv: driver. * * Platform device IDs are assumed to be encoded like this: * "<name><instance>", where <name> is a short description of the type of * device, like "pci" or "floppy", and <instance> is the enumerated * instance of the device, like '0' or '42'. Driver IDs are simply * "<name>". So, extract the <name> from the platform_device structure, * and compare it against the name of the driver. Return whether they match * or not. */ static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); } 

这部分逻辑可以参考总线驱动设备匹配过程分析这篇文章

匹配成功则代表设备和驱动都存在了,所以就可以进行下一步操作,绑定设备和驱动,是通过函数driver_probe_device完成的
drivers/base/dd.c

/** * 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 * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock 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; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); return ret; } 

1 首先调用device_is_registered确保设备已经注册
2 pm_runtime_barrier防止设备掉电
3 really_probe 真正的探测函数

static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; int local_trigger_count = atomic_read(&deferred_trigger_count); 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 using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) goto probe_failed; 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); 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("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; dev_set_drvdata(dev, NULL); if (ret == -EPROBE_DEFER) { /* Driver requested deferred probing */ dev_info(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add(dev); /* Did a trigger occur while probing? Need to re-trigger if yes */ if (local_trigger_count != atomic_read(&deferred_trigger_count)) driver_deferred_probe_trigger(); } else 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); } else { pr_debug("%s: probe of %s rejects match %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; } 

1 绑定针脚控制器(pinctrl_bind_pins)
2 创建dev设备的sysfs对应目录
3 如果bus存在probe函数调用bus的,否则driver存在probe函数则调用
driver的,由此可见bus的优先级比较高
4 给driver绑定device
5 通知probe_waitqueue

struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }; 

platform_bus_type并没有实现自己的probe函数,另外如果driver实现了probe函数,则会被替换为platform_drv_probe函数,所以这里基本上调用的都是platform_drv_probe(除非driver不需要执行probe函数)

static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); int ret; ret = of_clk_set_defaults(_dev->of_node, false); if (ret < 0) return ret; ret = dev_pm_domain_attach(_dev, true); if (ret != -EPROBE_DEFER) { ret = drv->probe(dev); if (ret) dev_pm_domain_detach(_dev, true); } if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); ret = -ENXIO; } return ret; } 

1 of_clk_set_defaults 用于设置时钟信息
2 dev_pm_domain_attach用于附加到电源管理域上
3 调用driver自己实现的prob函数

我们以goldfish_pipe为例子看下是如何实现的probe函数
drivers/platform/goldfish/goldfish_pipe.c

static int goldfish_pipe_probe(struct platform_device *pdev) { DPRINT("%s: call. platform_device=0x%lx\n", __FUNCTION__, pdev); int err; struct resource *r; struct goldfish_pipe_dev *dev = pipe_dev; /* not thread safe, but this should not happen */ WARN_ON(dev->base != NULL); spin_lock_init(&dev->lock); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL || resource_size(r) < PAGE_SIZE) { dev_err(&pdev->dev, "can't allocate i/o page\n"); return -EINVAL; } dev->base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); if (dev->base == NULL) { dev_err(&pdev->dev, "ioremap failed\n"); return -EINVAL; } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (r == NULL) { err = -EINVAL; goto error; } dev->irq = r->start; err = devm_request_irq(&pdev->dev, dev->irq, goldfish_pipe_interrupt, IRQF_SHARED, "goldfish_pipe", dev); if (err) { dev_err(&pdev->dev, "unable to allocate IRQ\n"); goto error; } err = misc_register(&goldfish_pipe_device); if (err) { dev_err(&pdev->dev, "unable to register device\n"); goto error; } setup_access_params_addr(pdev, dev); /* Although the pipe device in the classic Android emulator does not * recognize the 'version' register, it won't treat this as an error * either and will simply return 0, which is fine. */ dev->version = readl(dev->base + PIPE_REG_VERSION); return 0; error: dev->base = NULL; return err; } 

1 获取设备=io地址空间(物理地址)
2 使用ioremap映射到一块虚拟地址
3 获取irq信息,注册irq处理函数 goldfish_pipe_interrupt
4 注册为设备goldfish_pipe_device

driver和device匹配到后就会执行module_add_driver, 这部分主要创建/sys/module下的kobject目录,注册irq处理函数

void module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; int no_warn; struct module_kobject *mk = NULL; if (!drv) return; if (mod) mk = &mod->mkobj; else if (drv->mod_name) { struct kobject *mkobj; /* Lookup built-in module entry in /sys/modules */ mkobj = kset_find_obj(module_kset, drv->mod_name); if (mkobj) { mk = container_of(mkobj, struct module_kobject, kobj); /* remember our module structure */ drv->p->mkobj = mk; /* kset_find_obj took a reference */ kobject_put(mkobj); } } if (!mk) return; /* Don't check return codes; these calls are idempotent */ no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); if (driver_name) { module_create_drivers_dir(mk); no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); kfree(driver_name); } } 

创建不创建对应的module模块还要看mk参数是否为空,不为空的情况下会把/sys/module/${driver_module} 目录符号链接到/sys/bus/${bus_name}/drivers/${driver_name}/module目录,给用户提供一个视角, 并在/sys/module下创建driver相关文件夹,下面的文件也是从/sys/bus/${bus_name}/drivers/${driver_name}链接过来的

driver_create_file 创建uevent文件,用于发送uevent事件
driver_add_groups 创建这个组

int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups) { return sysfs_create_groups(&drv->p->kobj, groups); } 
/** * 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 * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock 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; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); return ret; } 

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复