linux移植wifi sd8688.bin 最新固件,[ZZ]浅析firmware完整生存和使用流程
/class/firmware
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);//創建/class/firmware/mmc1:0001:1/目錄
if (error)
goto Error;
if (platform_notify)
platform_notify(dev);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE,
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_add_class_symlinks(dev);
if (error)
goto
SymlinkError;
error = device_add_attrs(dev);
if (error)
goto
AttrsError;
error = dpm_sysfs_add(dev);
if (error)
goto PMError;
device_pm_add(dev);
error = bus_add_device(dev);
if (error)
goto BusError;
kobject_uevent(&dev->kobj,
KOBJ_ADD);//向用戶空間發送uevent事件,如果kset和class
bus_attach_device(dev);
if (parent)
klist_add_tail(&dev->knode_parent,
&parent->klist_children);
if (dev->class) {
down(&dev->class->sem);
list_add_tail(&dev->node, &dev->class->devices);
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
put_device(dev);
return error;
BusError:
device_pm_remove(dev);
PMError:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DEL_DEVICE,
dev);
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
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);
goto Done;
}
int
kobject_uevent(struct
kobject *kobj, enum kobject_action action)
{
return
kobject_uevent_env(kobj, action, NULL);//發布uevent事件
}
int
kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp_ext[])
{
struct kobj_uevent_env
*env;
const char *action_string = kobject_actions[action];
const char *devpath = NULL;
const char *subsystem;
struct kobject
*top_kobj;
struct kset *kset;
struct kset_uevent_ops
*uevent_ops;
u64 seq;
int i = 0;
int retval = 0;
pr_debug("kobject: '%s' (%p):
%s\n",
kobject_name(kobj), kobj, __FUNCTION__);
top_kobj =
kobj;
while (!top_kobj->kset && top_kobj->parent)
top_kobj =
top_kobj->parent;
if (!top_kobj->kset) {
pr_debug("kobject: '%s' (%p): %s: attempted to send
uevent "
"without
kset!\n",
kobject_name(kobj), kobj,
__FUNCTION__);
return -EINVAL;
}
//對于device_register(),
//kset =
devices_kset;
//uevent_ops =
device_uevent_ops;[luther.gliethttp]
kset =
top_kobj->kset;
uevent_ops =
kset->uevent_ops;
if (uevent_ops &&
uevent_ops->filter)
if (!uevent_ops->filter(kset, kobj)) {
//該uevent是否被過濾了,
//對于device_register(),如果dev->uevent_suppress
= 1;
//那么表示用戶希望過濾掉該uevent,所以在這里直接返回即可.
//對于上面request_firmware中fw_register_device的
//retval =
device_register(f_dev);在執行之前,調用了f_dev->uevent_suppress
= 1;
//就表示在這里將直接返回,它不希望產生uevent事件到用戶空間,它會自己選擇時機
//調用kobject_uevent()來讓uevent事件發送給用戶空間[luther.gliethttp].
pr_debug("kobject: '%s' (%p): %s: filter function
"
"caused the event to
drop!\n",
kobject_name(kobj), kobj, __FUNCTION__);
return 0;
}
if (uevent_ops &&
uevent_ops->name)
subsystem =
uevent_ops->name(kset, kobj);
else
subsystem =
kobject_name(&kset->kobj);
if (!subsystem) {
pr_debug("kobject: '%s' (%p): %s: unset subsystem
caused the "
"event to
drop!\n",
kobject_name(kobj), kobj,
__FUNCTION__);
return 0;
}
env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
if (!env)
return -ENOMEM;
devpath =
kobject_get_path(kobj, GFP_KERNEL);
if (!devpath) {
retval = -ENOENT;
goto exit;
}
retval =
add_uevent_var(env, "ACTION=%s", action_string);
if (retval)
goto exit;
retval =
add_uevent_var(env, "DEVPATH=%s", devpath);
if (retval)
goto exit;
retval =
add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
if (retval)
goto exit;
if (envp_ext) {
for (i = 0; envp_ext[i]; i++) {
retval =
add_uevent_var(env, envp_ext[i]);
if (retval)
goto exit;
}
}
if (uevent_ops &&
uevent_ops->uevent) {
//對于device_register()來說,就是對于f_dev這個kobj來說,
//就是調用dev_uevent添加major和minor等操作[luther.gliethttp]
retval =
uevent_ops->uevent(kset, kobj, env);
if (retval) {
pr_debug("kobject: '%s' (%p): %s: uevent() returned
"
"%d\n", kobject_name(kobj), kobj,
__FUNCTION__, retval);
goto exit;
}
}
...
}
int __init
devices_init(void)
{
devices_kset =
kset_create_and_add("devices", &device_uevent_ops,
NULL);
//在sysfs文件系統的根目錄下建立deviecs這個kset可視文件,比如/sys/devices
//該kset的uevent處理函數為device_uevent_ops
if (!devices_kset)
return -ENOMEM;
return 0;
}
static struct kset_uevent_ops
device_uevent_ops =
{
.filter = dev_uevent_filter,
.name = dev_uevent_name,
.uevent = dev_uevent,
};
static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type
*ktype = get_ktype(kobj);
if (ktype == &device_ktype)
{
//為默認的device_ktype管理
//在device_register=>device_initialize=>kobject_init(&dev->kobj,
&device_ktype);
struct device *dev = to_dev(kobj);
if (dev->uevent_suppress)//調用device_register()函數的驅動不希望dev的uevent發布到用戶空間
return 0;
if (dev->bus)
return 1;
if (dev->class)
return 1;
}
return 0;
}
static int dev_uevent(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env
*env)
{
struct device *dev = to_dev(kobj);
int retval = 0;
if (MAJOR(dev->devt)) {//填充major和minor設備號,以便接收uevent事件的init進程,能夠mknod來創建相應的節點文件在/dev目錄下[luther.gliethttp].
add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
if (dev->type && dev->type->name)
add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
add_uevent_var(env, "DRIVER=%s", dev->driver->name);
#ifdef CONFIG_SYSFS_DEPRECATED
if (dev->class) {
struct device *parent = dev->parent;
while (parent && !parent->bus)
parent =
parent->parent;
if (parent && parent->bus) {
const char *path;
path =
kobject_get_path(&parent->kobj, GFP_KERNEL);
if (path) {
add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
if (parent->driver)
add_uevent_var(env, "PHYSDEVDRIVER=%s",
parent->driver->name);
}
} else if (dev->bus) {
add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
add_uevent_var(env, "PHYSDEVDRIVER=%s",
dev->driver->name);
}
#endif
if (dev->bus && dev->bus->uevent) {
retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: bus uevent() returned
%d\n",
dev->bus_id, __FUNCTION__, retval);
}
if (dev->class && dev->class->dev_uevent) {
retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: class uevent()
"
"returned
%d\n",
dev->bus_id,
__FUNCTION__, retval);
}
if (dev->type && dev->type->uevent) {
retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("device: '%s': %s: dev_type uevent()
"
"returned
%d\n",
dev->bus_id,
__FUNCTION__, retval);
}
return retval;
}
static int fw_setup_device(struct firmware *fw, struct device **dev_p,
const char *fw_name, struct device *device,
int uevent)
{
struct device *f_dev;
struct firmware_priv
*fw_priv;
int retval;
*dev_p = NULL;
retval =
fw_register_device(&f_dev, fw_name, device);
if (retval)
goto out;
__module_get(THIS_MODULE);
fw_priv =
dev_get_drvdata(f_dev);
fw_priv->fw = fw;
retval =
sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
//在sysfs中創建bin類型文件,即:firmware_attr_data_tmpl
//sysfs_create_bin_file
//直接向sysfs的'內存磁盤'創建'磁盤文件'-firmware_attr_data_tmpl
if (retval) {
printk(KERN_ERR
"%s: sysfs_create_bin_file
failed\n",
__FUNCTION__);
goto
error_unreg;
}
//device_create_file=>sysfs_create_file
//直接向sysfs的'內存磁盤'創建'磁盤文件'-dev_attr_loading
retval =
device_create_file(f_dev, &dev_attr_loading);//firmware處理狀態提示文件
if (retval) {
printk(KERN_ERR
"%s: device_create_file
failed\n",
__FUNCTION__);
goto
error_unreg;
}
if (uevent)
//如果希望該request_firmware發送uevent到用戶空間,那么f_dev->uevent_suppress清0[luther.gliethttp]
f_dev->uevent_suppress
= 0;
*dev_p = f_dev;
goto out;
error_unreg:
device_unregister(f_dev);
out:
return retval;
}
static int
_request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device, int uevent)
{
struct device *f_dev;
struct firmware_priv
*fw_priv;
struct firmware
*firmware;
int retval;
if (!firmware_p)
return -EINVAL;
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR
"%s: kmalloc(struct firmware)
failed\n",
__FUNCTION__);
retval = -ENOMEM;
goto out;
}
retval =
fw_setup_device(firmware, &f_dev, name, device, uevent);
if (retval)
goto
error_kfree_fw;
fw_priv =
dev_get_drvdata(f_dev);
if (uevent) {
if (loading_timeout > 0) {
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
add_timer(&fw_priv->timeout);
}
//因為上面device_register時,dev->uevent_suppress
= 1;
//所以device_register將uevent過濾掉了,沒有將uevent發送到用戶空間,
//后來dev->uevent_suppress =
0;所以所以經過上面亂七八糟的設置之后,現在它認為可以安全
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的linux移植wifi sd8688.bin 最新固件,[ZZ]浅析firmware完整生存和使用流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下安装树梅派系统,优麒麟树莓派
- 下一篇: linux nginx 代理iis,ng