diff options
Diffstat (limited to 'drivers/base/firmware_class.c')
| -rw-r--r-- | drivers/base/firmware_class.c | 135 | 
1 files changed, 62 insertions, 73 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 72c644b191a..ae00a2fd280 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -440,21 +440,19 @@ static void firmware_class_timeout(u_long data)  }  static struct firmware_priv * -fw_create_instance(const struct firmware *firmware, const char *fw_name, +fw_create_instance(struct firmware *firmware, const char *fw_name,  		   struct device *device, bool uevent, bool nowait)  {  	struct firmware_priv *fw_priv;  	struct device *f_dev; -	int error;  	fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);  	if (!fw_priv) {  		dev_err(device, "%s: kmalloc failed\n", __func__); -		error = -ENOMEM; -		goto err_out; +		return ERR_PTR(-ENOMEM);  	} -	fw_priv->fw = (struct firmware *)firmware; +	fw_priv->fw = firmware;  	fw_priv->nowait = nowait;  	strcpy(fw_priv->fw_id, fw_name);  	init_completion(&fw_priv->completion); @@ -468,74 +466,37 @@ fw_create_instance(const struct firmware *firmware, const char *fw_name,  	f_dev->parent = device;  	f_dev->class = &firmware_class; -	dev_set_uevent_suppress(f_dev, true); - -	/* Need to pin this module until class device is destroyed */ -	__module_get(THIS_MODULE); - -	error = device_add(f_dev); -	if (error) { -		dev_err(device, "%s: device_register failed\n", __func__); -		goto err_put_dev; -	} - -	error = device_create_bin_file(f_dev, &firmware_attr_data); -	if (error) { -		dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__); -		goto err_del_dev; -	} - -	error = device_create_file(f_dev, &dev_attr_loading); -	if (error) { -		dev_err(device, "%s: device_create_file failed\n", __func__); -		goto err_del_bin_attr; -	} - -	if (uevent) -		dev_set_uevent_suppress(f_dev, false); -  	return fw_priv; - -err_del_bin_attr: -	device_remove_bin_file(f_dev, &firmware_attr_data); -err_del_dev: -	device_del(f_dev); -err_put_dev: -	put_device(f_dev); -err_out: -	return ERR_PTR(error); -} - -static void fw_destroy_instance(struct firmware_priv *fw_priv) -{ -	struct device *f_dev = &fw_priv->dev; - -	device_remove_file(f_dev, &dev_attr_loading); -	device_remove_bin_file(f_dev, &firmware_attr_data); -	device_unregister(f_dev);  } -static int _request_firmware_prepare(const struct firmware **firmware_p, -				     const char *name, struct device *device) +static struct firmware_priv * +_request_firmware_prepare(const struct firmware **firmware_p, const char *name, +			  struct device *device, bool uevent, bool nowait)  {  	struct firmware *firmware; +	struct firmware_priv *fw_priv;  	if (!firmware_p) -		return -EINVAL; +		return ERR_PTR(-EINVAL);  	*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);  	if (!firmware) {  		dev_err(device, "%s: kmalloc(struct firmware) failed\n",  			__func__); -		return -ENOMEM; +		return ERR_PTR(-ENOMEM);  	}  	if (fw_get_builtin_firmware(firmware, name)) {  		dev_dbg(device, "firmware: using built-in firmware %s\n", name); -		return 0; +		return NULL;  	} -	return 1; +	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); +	if (IS_ERR(fw_priv)) { +		release_firmware(firmware); +		*firmware_p = NULL; +	} +	return fw_priv;  }  static void _request_firmware_cleanup(const struct firmware **firmware_p) @@ -544,21 +505,38 @@ static void _request_firmware_cleanup(const struct firmware **firmware_p)  	*firmware_p = NULL;  } -static int _request_firmware(const struct firmware *firmware, -			     const char *name, struct device *device, -			     bool uevent, bool nowait, long timeout) +static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, +				  long timeout)  { -	struct firmware_priv *fw_priv;  	int retval = 0; +	struct device *f_dev = &fw_priv->dev; + +	dev_set_uevent_suppress(f_dev, true); -	if (uevent) -		dev_dbg(device, "firmware: requesting %s\n", name); +	/* Need to pin this module until class device is destroyed */ +	__module_get(THIS_MODULE); -	fw_priv = fw_create_instance(firmware, name, device, uevent, nowait); -	if (IS_ERR(fw_priv)) -		return PTR_ERR(fw_priv); +	retval = device_add(f_dev); +	if (retval) { +		dev_err(f_dev, "%s: device_register failed\n", __func__); +		goto err_put_dev; +	} + +	retval = device_create_bin_file(f_dev, &firmware_attr_data); +	if (retval) { +		dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__); +		goto err_del_dev; +	} + +	retval = device_create_file(f_dev, &dev_attr_loading); +	if (retval) { +		dev_err(f_dev, "%s: device_create_file failed\n", __func__); +		goto err_del_bin_attr; +	}  	if (uevent) { +		dev_set_uevent_suppress(f_dev, false); +		dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);  		if (timeout != MAX_SCHEDULE_TIMEOUT)  			mod_timer(&fw_priv->timeout,  				  round_jiffies_up(jiffies + timeout)); @@ -577,7 +555,13 @@ static int _request_firmware(const struct firmware *firmware,  	fw_priv->fw = NULL;  	mutex_unlock(&fw_lock); -	fw_destroy_instance(fw_priv); +	device_remove_file(f_dev, &dev_attr_loading); +err_del_bin_attr: +	device_remove_bin_file(f_dev, &firmware_attr_data); +err_del_dev: +	device_del(f_dev); +err_put_dev: +	put_device(f_dev);  	return retval;  } @@ -600,17 +584,19 @@ int  request_firmware(const struct firmware **firmware_p, const char *name,                   struct device *device)  { +	struct firmware_priv *fw_priv;  	int ret; -	ret = _request_firmware_prepare(firmware_p, name, device); -	if (ret <= 0) -		return ret; +	fw_priv = _request_firmware_prepare(firmware_p, name, device, true, +					    false); +	if (IS_ERR_OR_NULL(fw_priv)) +		return PTR_RET(fw_priv);  	ret = usermodehelper_read_trylock();  	if (WARN_ON(ret)) {  		dev_err(device, "firmware: %s will not be loaded\n", name);  	} else { -		ret = _request_firmware(*firmware_p, name, device, true, false, +		ret = _request_firmware_load(fw_priv, true,  					firmware_loading_timeout());  		usermodehelper_read_unlock();  	} @@ -648,6 +634,7 @@ static int request_firmware_work_func(void *arg)  {  	struct firmware_work *fw_work = arg;  	const struct firmware *fw; +	struct firmware_priv *fw_priv;  	long timeout;  	int ret; @@ -656,14 +643,16 @@ static int request_firmware_work_func(void *arg)  		return 0;  	} -	ret = _request_firmware_prepare(&fw, fw_work->name, fw_work->device); -	if (ret <= 0) +	fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device, +			fw_work->uevent, true); +	if (IS_ERR_OR_NULL(fw_priv)) { +		ret = PTR_RET(fw_priv);  		goto out; +	}  	timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());  	if (timeout) { -		ret = _request_firmware(fw, fw_work->name, fw_work->device, -					fw_work->uevent, true, timeout); +		ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);  		usermodehelper_read_unlock();  	} else {  		dev_dbg(fw_work->device, "firmware: %s loading timed out\n",  |