diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2017-05-02 05:02:41 -0400 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2017-05-02 05:02:41 -0400 | 
| commit | 4d6ca227c768b50b05cf183974b40abe444e9d0c (patch) | |
| tree | bf953d8e895281053548b9967a2c4b58d641df00 /lib/test_firmware.c | |
| parent | 800f3eef8ebc1264e9c135bfa892c8ae41fa4792 (diff) | |
| parent | af22a610bc38508d5ea760507d31be6b6983dfa8 (diff) | |
Merge branch 'for-4.12/asus' into for-linus
Diffstat (limited to 'lib/test_firmware.c')
| -rw-r--r-- | lib/test_firmware.c | 92 | 
1 files changed, 62 insertions, 30 deletions
| diff --git a/lib/test_firmware.c b/lib/test_firmware.c index a3e8ec3fb1c5..09371b0a9baf 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c | |||
| @@ -42,12 +42,6 @@ static const struct file_operations test_fw_fops = { | |||
| 42 | .read = test_fw_misc_read, | 42 | .read = test_fw_misc_read, | 
| 43 | }; | 43 | }; | 
| 44 | 44 | ||
| 45 | static struct miscdevice test_fw_misc_device = { | ||
| 46 | .minor = MISC_DYNAMIC_MINOR, | ||
| 47 | .name = "test_firmware", | ||
| 48 | .fops = &test_fw_fops, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static ssize_t trigger_request_store(struct device *dev, | 45 | static ssize_t trigger_request_store(struct device *dev, | 
| 52 | struct device_attribute *attr, | 46 | struct device_attribute *attr, | 
| 53 | const char *buf, size_t count) | 47 | const char *buf, size_t count) | 
| @@ -132,39 +126,81 @@ out: | |||
| 132 | } | 126 | } | 
| 133 | static DEVICE_ATTR_WO(trigger_async_request); | 127 | static DEVICE_ATTR_WO(trigger_async_request); | 
| 134 | 128 | ||
| 135 | static int __init test_firmware_init(void) | 129 | static ssize_t trigger_custom_fallback_store(struct device *dev, | 
| 130 | struct device_attribute *attr, | ||
| 131 | const char *buf, size_t count) | ||
| 136 | { | 132 | { | 
| 137 | int rc; | 133 | int rc; | 
| 134 | char *name; | ||
| 138 | 135 | ||
| 139 | rc = misc_register(&test_fw_misc_device); | 136 | name = kstrndup(buf, count, GFP_KERNEL); | 
| 137 | if (!name) | ||
| 138 | return -ENOSPC; | ||
| 139 | |||
| 140 | pr_info("loading '%s' using custom fallback mechanism\n", name); | ||
| 141 | |||
| 142 | mutex_lock(&test_fw_mutex); | ||
| 143 | release_firmware(test_firmware); | ||
| 144 | test_firmware = NULL; | ||
| 145 | rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, name, | ||
| 146 | dev, GFP_KERNEL, NULL, | ||
| 147 | trigger_async_request_cb); | ||
| 140 | if (rc) { | 148 | if (rc) { | 
| 141 | pr_err("could not register misc device: %d\n", rc); | 149 | pr_info("async load of '%s' failed: %d\n", name, rc); | 
| 142 | return rc; | 150 | kfree(name); | 
| 151 | goto out; | ||
| 143 | } | 152 | } | 
| 144 | rc = device_create_file(test_fw_misc_device.this_device, | 153 | /* Free 'name' ASAP, to test for race conditions */ | 
| 145 | &dev_attr_trigger_request); | 154 | kfree(name); | 
| 146 | if (rc) { | 155 | |
| 147 | pr_err("could not create sysfs interface: %d\n", rc); | 156 | wait_for_completion(&async_fw_done); | 
| 148 | goto dereg; | 157 | |
| 158 | if (test_firmware) { | ||
| 159 | pr_info("loaded: %zu\n", test_firmware->size); | ||
| 160 | rc = count; | ||
| 161 | } else { | ||
| 162 | pr_err("failed to async load firmware\n"); | ||
| 163 | rc = -ENODEV; | ||
| 149 | } | 164 | } | 
| 150 | 165 | ||
| 151 | rc = device_create_file(test_fw_misc_device.this_device, | 166 | out: | 
| 152 | &dev_attr_trigger_async_request); | 167 | mutex_unlock(&test_fw_mutex); | 
| 168 | |||
| 169 | return rc; | ||
| 170 | } | ||
| 171 | static DEVICE_ATTR_WO(trigger_custom_fallback); | ||
| 172 | |||
| 173 | #define TEST_FW_DEV_ATTR(name) &dev_attr_##name.attr | ||
| 174 | |||
| 175 | static struct attribute *test_dev_attrs[] = { | ||
| 176 | TEST_FW_DEV_ATTR(trigger_request), | ||
| 177 | TEST_FW_DEV_ATTR(trigger_async_request), | ||
| 178 | TEST_FW_DEV_ATTR(trigger_custom_fallback), | ||
| 179 | NULL, | ||
| 180 | }; | ||
| 181 | |||
| 182 | ATTRIBUTE_GROUPS(test_dev); | ||
| 183 | |||
| 184 | static struct miscdevice test_fw_misc_device = { | ||
| 185 | .minor = MISC_DYNAMIC_MINOR, | ||
| 186 | .name = "test_firmware", | ||
| 187 | .fops = &test_fw_fops, | ||
| 188 | .groups = test_dev_groups, | ||
| 189 | }; | ||
| 190 | |||
| 191 | static int __init test_firmware_init(void) | ||
| 192 | { | ||
| 193 | int rc; | ||
| 194 | |||
| 195 | rc = misc_register(&test_fw_misc_device); | ||
| 153 | if (rc) { | 196 | if (rc) { | 
| 154 | pr_err("could not create async sysfs interface: %d\n", rc); | 197 | pr_err("could not register misc device: %d\n", rc); | 
| 155 | goto remove_file; | 198 | return rc; | 
| 156 | } | 199 | } | 
| 157 | 200 | ||
| 158 | pr_warn("interface ready\n"); | 201 | pr_warn("interface ready\n"); | 
| 159 | 202 | ||
| 160 | return 0; | 203 | return 0; | 
| 161 | |||
| 162 | remove_file: | ||
| 163 | device_remove_file(test_fw_misc_device.this_device, | ||
| 164 | &dev_attr_trigger_async_request); | ||
| 165 | dereg: | ||
| 166 | misc_deregister(&test_fw_misc_device); | ||
| 167 | return rc; | ||
| 168 | } | 204 | } | 
| 169 | 205 | ||
| 170 | module_init(test_firmware_init); | 206 | module_init(test_firmware_init); | 
| @@ -172,10 +208,6 @@ module_init(test_firmware_init); | |||
| 172 | static void __exit test_firmware_exit(void) | 208 | static void __exit test_firmware_exit(void) | 
| 173 | { | 209 | { | 
| 174 | release_firmware(test_firmware); | 210 | release_firmware(test_firmware); | 
| 175 | device_remove_file(test_fw_misc_device.this_device, | ||
| 176 | &dev_attr_trigger_async_request); | ||
| 177 | device_remove_file(test_fw_misc_device.this_device, | ||
| 178 | &dev_attr_trigger_request); | ||
| 179 | misc_deregister(&test_fw_misc_device); | 211 | misc_deregister(&test_fw_misc_device); | 
| 180 | pr_warn("removed interface\n"); | 212 | pr_warn("removed interface\n"); | 
| 181 | } | 213 | } | 
