blob: 7f159f0da001c9bb3a8335a165642bebd9c67abc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * firmware_class.c - Multi purpose firmware loading support
3 *
Markus Rechberger87d37a42007-06-04 18:45:44 +02004 * Copyright (c) 2003 Manuel Estrada Sainz
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
6 * Please see Documentation/firmware_class/ for more information.
7 *
8 */
9
Randy.Dunlapc59ede72006-01-11 12:17:46 -080010#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/device.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/timer.h>
15#include <linux/vmalloc.h>
16#include <linux/interrupt.h>
17#include <linux/bitops.h>
Laura Garciacad1e552006-05-23 23:22:38 +020018#include <linux/mutex.h>
Stephen Boyda36cf842012-03-28 23:31:00 +020019#include <linux/workqueue.h>
David Woodhouse6e03a202009-04-09 22:04:07 -070020#include <linux/highmem.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/firmware.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Stephen Boyda36cf842012-03-28 23:31:00 +020023#include <linux/sched.h>
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -070024#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -070026#define to_dev(obj) container_of(obj, struct device, kobj)
27
Markus Rechberger87d37a42007-06-04 18:45:44 +020028MODULE_AUTHOR("Manuel Estrada Sainz");
Linus Torvalds1da177e2005-04-16 15:20:36 -070029MODULE_DESCRIPTION("Multi purpose firmware loading support");
30MODULE_LICENSE("GPL");
31
Dmitry Torokhovbcb9bd12010-03-13 23:49:18 -080032/* Builtin firmware support */
33
34#ifdef CONFIG_FW_LOADER
35
36extern struct builtin_fw __start_builtin_fw[];
37extern struct builtin_fw __end_builtin_fw[];
38
39static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
40{
41 struct builtin_fw *b_fw;
42
43 for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) {
44 if (strcmp(name, b_fw->name) == 0) {
45 fw->size = b_fw->size;
46 fw->data = b_fw->data;
47 return true;
48 }
49 }
50
51 return false;
52}
53
54static bool fw_is_builtin_firmware(const struct firmware *fw)
55{
56 struct builtin_fw *b_fw;
57
58 for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++)
59 if (fw->data == b_fw->data)
60 return true;
61
62 return false;
63}
64
65#else /* Module case - no builtin firmware support */
66
67static inline bool fw_get_builtin_firmware(struct firmware *fw, const char *name)
68{
69 return false;
70}
71
72static inline bool fw_is_builtin_firmware(const struct firmware *fw)
73{
74 return false;
75}
76#endif
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078enum {
79 FW_STATUS_LOADING,
80 FW_STATUS_DONE,
81 FW_STATUS_ABORT,
Linus Torvalds1da177e2005-04-16 15:20:36 -070082};
83
Dave Jones2f651682007-01-25 15:56:15 -050084static int loading_timeout = 60; /* In seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +020086static inline long firmware_loading_timeout(void)
87{
88 return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
89}
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/* fw_lock could be moved to 'struct firmware_priv' but since it is just
92 * guarding for corner cases a global lock should be OK */
Laura Garciacad1e552006-05-23 23:22:38 +020093static DEFINE_MUTEX(fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95struct firmware_priv {
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 struct completion completion;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 struct firmware *fw;
98 unsigned long status;
David Woodhouse6e03a202009-04-09 22:04:07 -070099 struct page **pages;
100 int nr_pages;
101 int page_array_size;
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700102 phys_addr_t dest_addr;
103 size_t dest_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 struct timer_list timeout;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700105 struct device dev;
Johannes Berge9045f92010-03-29 17:57:20 +0200106 bool nowait;
Dmitry Torokhove1771232010-03-13 23:49:23 -0800107 char fw_id[];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700110static struct firmware_priv *to_firmware_priv(struct device *dev)
111{
112 return container_of(dev, struct firmware_priv, dev);
113}
114
115static void fw_load_abort(struct firmware_priv *fw_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 set_bit(FW_STATUS_ABORT, &fw_priv->status);
118 wmb();
119 complete(&fw_priv->completion);
120}
121
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700122static ssize_t firmware_timeout_show(struct class *class,
123 struct class_attribute *attr,
124 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 return sprintf(buf, "%d\n", loading_timeout);
127}
128
129/**
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800130 * firmware_timeout_store - set number of seconds to wait for firmware
131 * @class: device class pointer
Randy Dunlape59817b2010-03-10 11:47:58 -0800132 * @attr: device attribute pointer
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800133 * @buf: buffer to scan for timeout value
134 * @count: number of bytes in @buf
135 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * Sets the number of seconds to wait for the firmware. Once
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800137 * this expires an error will be returned to the driver and no
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 * firmware will be provided.
139 *
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800140 * Note: zero means 'wait forever'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 **/
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700142static ssize_t firmware_timeout_store(struct class *class,
143 struct class_attribute *attr,
144 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 loading_timeout = simple_strtol(buf, NULL, 10);
Stanislaw W. Gruszkab92eac02005-06-28 20:44:51 -0700147 if (loading_timeout < 0)
148 loading_timeout = 0;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 return count;
151}
152
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800153static struct class_attribute firmware_class_attrs[] = {
154 __ATTR(timeout, S_IWUSR | S_IRUGO,
155 firmware_timeout_show, firmware_timeout_store),
156 __ATTR_NULL
157};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800159static void fw_dev_release(struct device *dev)
160{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700161 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800162 int i;
163
164 for (i = 0; i < fw_priv->nr_pages; i++)
165 __free_page(fw_priv->pages[i]);
166 kfree(fw_priv->pages);
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800167 kfree(fw_priv);
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800168
169 module_put(THIS_MODULE);
170}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Kay Sievers7eff2e72007-08-14 15:15:12 +0200172static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700174 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Kay Sievers7eff2e72007-08-14 15:15:12 +0200176 if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 return -ENOMEM;
Kay Sievers7eff2e72007-08-14 15:15:12 +0200178 if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
kay.sievers@vrfy.org68970892005-04-18 21:57:31 -0700179 return -ENOMEM;
Johannes Berge9045f92010-03-29 17:57:20 +0200180 if (add_uevent_var(env, "ASYNC=%d", fw_priv->nowait))
181 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 return 0;
184}
185
Adrian Bunk1b81d662006-05-20 15:00:16 -0700186static struct class firmware_class = {
187 .name = "firmware",
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800188 .class_attrs = firmware_class_attrs,
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700189 .dev_uevent = firmware_uevent,
190 .dev_release = fw_dev_release,
Adrian Bunk1b81d662006-05-20 15:00:16 -0700191};
192
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700193static ssize_t firmware_loading_show(struct device *dev,
194 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700196 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 return sprintf(buf, "%d\n", loading);
200}
201
David Woodhousedd336c52010-05-02 11:21:21 +0300202static void firmware_free_data(const struct firmware *fw)
203{
204 int i;
205 vunmap(fw->data);
206 if (fw->pages) {
207 for (i = 0; i < PFN_UP(fw->size); i++)
208 __free_page(fw->pages[i]);
209 kfree(fw->pages);
210 }
211}
212
David Woodhouse6e03a202009-04-09 22:04:07 -0700213/* Some architectures don't have PAGE_KERNEL_RO */
214#ifndef PAGE_KERNEL_RO
215#define PAGE_KERNEL_RO PAGE_KERNEL
216#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217/**
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800218 * firmware_loading_store - set value in the 'loading' control file
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700219 * @dev: device pointer
Randy Dunlapaf9997e2006-12-22 01:06:52 -0800220 * @attr: device attribute pointer
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800221 * @buf: buffer to scan for loading control value
222 * @count: number of bytes in @buf
223 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 * The relevant values are:
225 *
226 * 1: Start a load, discarding any previous partial load.
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800227 * 0: Conclude the load and hand the data to the driver code.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 * -1: Conclude the load with an error and discard any written data.
229 **/
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700230static ssize_t firmware_loading_store(struct device *dev,
231 struct device_attribute *attr,
232 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700234 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 int loading = simple_strtol(buf, NULL, 10);
David Woodhouse6e03a202009-04-09 22:04:07 -0700236 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Neil Hormaneea915b2012-01-02 15:31:23 -0500238 mutex_lock(&fw_lock);
239
240 if (!fw_priv->fw)
241 goto out;
242
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 switch (loading) {
244 case 1:
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700245 if (fw_priv->dest_addr) {
246 set_bit(FW_STATUS_LOADING, &fw_priv->status);
247 break;
248 }
David Woodhousedd336c52010-05-02 11:21:21 +0300249 firmware_free_data(fw_priv->fw);
250 memset(fw_priv->fw, 0, sizeof(struct firmware));
251 /* If the pages are not owned by 'struct firmware' */
David Woodhouse6e03a202009-04-09 22:04:07 -0700252 for (i = 0; i < fw_priv->nr_pages; i++)
253 __free_page(fw_priv->pages[i]);
254 kfree(fw_priv->pages);
255 fw_priv->pages = NULL;
256 fw_priv->page_array_size = 0;
257 fw_priv->nr_pages = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 set_bit(FW_STATUS_LOADING, &fw_priv->status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 break;
260 case 0:
261 if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700262 if (fw_priv->dest_addr) {
263 complete(&fw_priv->completion);
264 clear_bit(FW_STATUS_LOADING, &fw_priv->status);
265 break;
266 }
David Woodhousedd336c52010-05-02 11:21:21 +0300267 vunmap(fw_priv->fw->data);
David Woodhouse6e03a202009-04-09 22:04:07 -0700268 fw_priv->fw->data = vmap(fw_priv->pages,
269 fw_priv->nr_pages,
270 0, PAGE_KERNEL_RO);
271 if (!fw_priv->fw->data) {
272 dev_err(dev, "%s: vmap() failed\n", __func__);
273 goto err;
274 }
David Woodhousedd336c52010-05-02 11:21:21 +0300275 /* Pages are now owned by 'struct firmware' */
276 fw_priv->fw->pages = fw_priv->pages;
277 fw_priv->pages = NULL;
278
David Woodhouse6e03a202009-04-09 22:04:07 -0700279 fw_priv->page_array_size = 0;
280 fw_priv->nr_pages = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 complete(&fw_priv->completion);
282 clear_bit(FW_STATUS_LOADING, &fw_priv->status);
283 break;
284 }
285 /* fallthrough */
286 default:
Bjorn Helgaas266a8132008-10-15 22:04:20 -0700287 dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 /* fallthrough */
289 case -1:
David Woodhouse6e03a202009-04-09 22:04:07 -0700290 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 fw_load_abort(fw_priv);
292 break;
293 }
Neil Hormaneea915b2012-01-02 15:31:23 -0500294out:
295 mutex_unlock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 return count;
297}
298
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700299static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700301static int __firmware_data_rw(struct firmware_priv *fw_priv, char *buffer,
302 loff_t *offset, size_t count, int read)
303{
304 u8 __iomem *fw_buf;
305 int retval = count;
306
307 if ((*offset + count) > fw_priv->dest_size) {
308 pr_debug("%s: Failed size check.\n", __func__);
309 retval = -EINVAL;
310 goto out;
311 }
312
313 fw_buf = ioremap(fw_priv->dest_addr + *offset, count);
314 if (!fw_buf) {
315 pr_debug("%s: Failed ioremap.\n", __func__);
316 retval = -ENOMEM;
317 goto out;
318 }
319
320 if (read)
321 memcpy(buffer, fw_buf, count);
322 else
323 memcpy(fw_buf, buffer, count);
324
325 *offset += count;
326 iounmap(fw_buf);
327
328out:
329 return retval;
330}
331
332static ssize_t firmware_direct_read(struct file *filp, struct kobject *kobj,
333 struct bin_attribute *bin_attr,
334 char *buffer, loff_t offset, size_t count)
335{
336 struct device *dev = to_dev(kobj);
337 struct firmware_priv *fw_priv = to_firmware_priv(dev);
338 struct firmware *fw;
339 ssize_t ret_count;
340
341 mutex_lock(&fw_lock);
342 fw = fw_priv->fw;
343
344 if (offset > fw->size) {
345 ret_count = 0;
346 goto out;
347 }
348 if (count > fw->size - offset)
349 count = fw->size - offset;
350
351 if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
352 ret_count = -ENODEV;
353 goto out;
354 }
355
356 ret_count = __firmware_data_rw(fw_priv, buffer, &offset, count, 1);
357out:
358 mutex_unlock(&fw_lock);
359 return ret_count;
360}
361
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700362static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,
363 struct bin_attribute *bin_attr,
364 char *buffer, loff_t offset, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700366 struct device *dev = to_dev(kobj);
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700367 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 struct firmware *fw;
Akinobu Mitaf37e6612008-07-25 01:48:23 -0700369 ssize_t ret_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Laura Garciacad1e552006-05-23 23:22:38 +0200371 mutex_lock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 fw = fw_priv->fw;
Stanislaw W. Gruszkab92eac02005-06-28 20:44:51 -0700373 if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 ret_count = -ENODEV;
375 goto out;
376 }
Jiri Slaby308975f2009-06-21 23:57:31 +0200377 if (offset > fw->size) {
378 ret_count = 0;
379 goto out;
380 }
David Woodhouse6e03a202009-04-09 22:04:07 -0700381 if (count > fw->size - offset)
382 count = fw->size - offset;
383
384 ret_count = count;
385
386 while (count) {
387 void *page_data;
388 int page_nr = offset >> PAGE_SHIFT;
389 int page_ofs = offset & (PAGE_SIZE-1);
390 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
391
392 page_data = kmap(fw_priv->pages[page_nr]);
393
394 memcpy(buffer, page_data + page_ofs, page_cnt);
395
396 kunmap(fw_priv->pages[page_nr]);
397 buffer += page_cnt;
398 offset += page_cnt;
399 count -= page_cnt;
400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401out:
Laura Garciacad1e552006-05-23 23:22:38 +0200402 mutex_unlock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return ret_count;
404}
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800405
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700406static int fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
David Woodhouse6e03a202009-04-09 22:04:07 -0700408 int pages_needed = ALIGN(min_size, PAGE_SIZE) >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
David Woodhouse6e03a202009-04-09 22:04:07 -0700410 /* If the array of pages is too small, grow it... */
411 if (fw_priv->page_array_size < pages_needed) {
412 int new_array_size = max(pages_needed,
413 fw_priv->page_array_size * 2);
414 struct page **new_pages;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
David Woodhouse6e03a202009-04-09 22:04:07 -0700416 new_pages = kmalloc(new_array_size * sizeof(void *),
417 GFP_KERNEL);
418 if (!new_pages) {
419 fw_load_abort(fw_priv);
420 return -ENOMEM;
421 }
422 memcpy(new_pages, fw_priv->pages,
423 fw_priv->page_array_size * sizeof(void *));
424 memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
425 (new_array_size - fw_priv->page_array_size));
426 kfree(fw_priv->pages);
427 fw_priv->pages = new_pages;
428 fw_priv->page_array_size = new_array_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
David Woodhouse6e03a202009-04-09 22:04:07 -0700430
431 while (fw_priv->nr_pages < pages_needed) {
432 fw_priv->pages[fw_priv->nr_pages] =
433 alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
434
435 if (!fw_priv->pages[fw_priv->nr_pages]) {
436 fw_load_abort(fw_priv);
437 return -ENOMEM;
438 }
439 fw_priv->nr_pages++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 return 0;
442}
443
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700444static ssize_t firmware_direct_write(struct file *filp, struct kobject *kobj,
445 struct bin_attribute *bin_attr,
446 char *buffer, loff_t offset, size_t count)
447{
448 struct device *dev = to_dev(kobj);
449 struct firmware_priv *fw_priv = to_firmware_priv(dev);
450 struct firmware *fw;
451 ssize_t retval;
452
453 if (!capable(CAP_SYS_RAWIO))
454 return -EPERM;
455
456 mutex_lock(&fw_lock);
457 fw = fw_priv->fw;
458 if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
459 retval = -ENODEV;
460 goto out;
461 }
462
463 retval = __firmware_data_rw(fw_priv, buffer, &offset, count, 0);
464 if (retval < 0)
465 goto out;
466
467 fw->size = max_t(size_t, offset, fw->size);
468out:
469 mutex_unlock(&fw_lock);
470 return retval;
471}
472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/**
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800474 * firmware_data_write - write method for firmware
Chris Wright2c3c8be2010-05-12 18:28:57 -0700475 * @filp: open sysfs file
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700476 * @kobj: kobject for the device
Randy Dunlap42e61f42007-07-23 21:42:11 -0700477 * @bin_attr: bin_attr structure
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800478 * @buffer: buffer being written
479 * @offset: buffer offset for write in total data store area
480 * @count: buffer size
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 *
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800482 * Data written to the 'data' attribute will be later handed to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 * the driver as a firmware image.
484 **/
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700485static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,
486 struct bin_attribute *bin_attr,
487 char *buffer, loff_t offset, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700489 struct device *dev = to_dev(kobj);
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700490 struct firmware_priv *fw_priv = to_firmware_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 struct firmware *fw;
492 ssize_t retval;
493
494 if (!capable(CAP_SYS_RAWIO))
495 return -EPERM;
Stanislaw W. Gruszkab92eac02005-06-28 20:44:51 -0700496
Laura Garciacad1e552006-05-23 23:22:38 +0200497 mutex_lock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 fw = fw_priv->fw;
Stanislaw W. Gruszkab92eac02005-06-28 20:44:51 -0700499 if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 retval = -ENODEV;
501 goto out;
502 }
503 retval = fw_realloc_buffer(fw_priv, offset + count);
504 if (retval)
505 goto out;
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 retval = count;
David Woodhouse6e03a202009-04-09 22:04:07 -0700508
509 while (count) {
510 void *page_data;
511 int page_nr = offset >> PAGE_SHIFT;
512 int page_ofs = offset & (PAGE_SIZE - 1);
513 int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count);
514
515 page_data = kmap(fw_priv->pages[page_nr]);
516
517 memcpy(page_data + page_ofs, buffer, page_cnt);
518
519 kunmap(fw_priv->pages[page_nr]);
520 buffer += page_cnt;
521 offset += page_cnt;
522 count -= page_cnt;
523 }
524
525 fw->size = max_t(size_t, offset, fw->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526out:
Laura Garciacad1e552006-05-23 23:22:38 +0200527 mutex_unlock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 return retval;
529}
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800530
Dmitry Torokhov0983ca22010-06-04 00:54:37 -0700531static struct bin_attribute firmware_attr_data = {
532 .attr = { .name = "data", .mode = 0644 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 .size = 0,
534 .read = firmware_data_read,
535 .write = firmware_data_write,
536};
537
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700538static struct bin_attribute firmware_direct_attr_data = {
539 .attr = { .name = "data", .mode = 0644 },
540 .size = 0,
541 .read = firmware_direct_read,
542 .write = firmware_direct_write,
543};
544
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700545static void firmware_class_timeout(u_long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 struct firmware_priv *fw_priv = (struct firmware_priv *) data;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 fw_load_abort(fw_priv);
550}
551
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700552static struct firmware_priv *
Stephen Boyddddb5542012-03-28 23:30:43 +0200553fw_create_instance(struct firmware *firmware, const char *fw_name,
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700554 struct device *device, bool uevent, bool nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700556 struct firmware_priv *fw_priv;
557 struct device *f_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700559 fw_priv = kzalloc(sizeof(*fw_priv) + strlen(fw_name) + 1 , GFP_KERNEL);
560 if (!fw_priv) {
Bjorn Helgaas266a8132008-10-15 22:04:20 -0700561 dev_err(device, "%s: kmalloc failed\n", __func__);
Stephen Boyddddb5542012-03-28 23:30:43 +0200562 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
Stephen Boyddddb5542012-03-28 23:30:43 +0200565 fw_priv->fw = firmware;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700566 fw_priv->nowait = nowait;
Dmitry Torokhove1771232010-03-13 23:49:23 -0800567 strcpy(fw_priv->fw_id, fw_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 init_completion(&fw_priv->completion);
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700569 setup_timer(&fw_priv->timeout,
570 firmware_class_timeout, (u_long) fw_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700572 f_dev = &fw_priv->dev;
573
574 device_initialize(f_dev);
Greg Kroah-Hartmanacc0e902009-06-02 15:39:55 -0700575 dev_set_name(f_dev, "%s", dev_name(device));
Greg Kroah-Hartmane55c8792006-09-14 07:30:59 -0700576 f_dev->parent = device;
577 f_dev->class = &firmware_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700579 return fw_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
Stephen Boyddddb5542012-03-28 23:30:43 +0200582static struct firmware_priv *
583_request_firmware_prepare(const struct firmware **firmware_p, const char *name,
584 struct device *device, bool uevent, bool nowait)
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700585{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 struct firmware *firmware;
Stephen Boyddddb5542012-03-28 23:30:43 +0200587 struct firmware_priv *fw_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 if (!firmware_p)
Stephen Boyddddb5542012-03-28 23:30:43 +0200590 return ERR_PTR(-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Jiri Slaby4aed0642005-09-13 01:25:01 -0700592 *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (!firmware) {
Bjorn Helgaas266a8132008-10-15 22:04:20 -0700594 dev_err(device, "%s: kmalloc(struct firmware) failed\n",
595 __func__);
Stephen Boyddddb5542012-03-28 23:30:43 +0200596 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Dmitry Torokhovbcb9bd12010-03-13 23:49:18 -0800599 if (fw_get_builtin_firmware(firmware, name)) {
Rafael J. Wysocki6f18ff92010-02-27 21:43:22 +0100600 dev_dbg(device, "firmware: using built-in firmware %s\n", name);
Stephen Boyddddb5542012-03-28 23:30:43 +0200601 return NULL;
David Woodhouse5658c762008-05-23 13:52:42 +0100602 }
603
Stephen Boyddddb5542012-03-28 23:30:43 +0200604 fw_priv = fw_create_instance(firmware, name, device, uevent, nowait);
605 if (IS_ERR(fw_priv)) {
606 release_firmware(firmware);
607 *firmware_p = NULL;
608 }
609 return fw_priv;
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200610}
611
612static void _request_firmware_cleanup(const struct firmware **firmware_p)
613{
614 release_firmware(*firmware_p);
615 *firmware_p = NULL;
616}
617
Stephen Boyddddb5542012-03-28 23:30:43 +0200618static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
619 long timeout)
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200620{
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200621 int retval = 0;
Stephen Boyddddb5542012-03-28 23:30:43 +0200622 struct device *f_dev = &fw_priv->dev;
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700623 struct bin_attribute *fw_attr_data = fw_priv->dest_addr ?
624 &firmware_direct_attr_data : &firmware_attr_data;
Linus Torvaldscaca9512011-08-24 15:55:30 -0700625
Stephen Boyddddb5542012-03-28 23:30:43 +0200626 dev_set_uevent_suppress(f_dev, true);
David Woodhouse5658c762008-05-23 13:52:42 +0100627
Stephen Boyddddb5542012-03-28 23:30:43 +0200628 /* Need to pin this module until class device is destroyed */
629 __module_get(THIS_MODULE);
630
631 retval = device_add(f_dev);
632 if (retval) {
633 dev_err(f_dev, "%s: device_register failed\n", __func__);
634 goto err_put_dev;
635 }
636
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700637 retval = device_create_bin_file(f_dev, fw_attr_data);
Stephen Boyddddb5542012-03-28 23:30:43 +0200638 if (retval) {
639 dev_err(f_dev, "%s: sysfs_create_bin_file failed\n", __func__);
640 goto err_del_dev;
641 }
642
643 retval = device_create_file(f_dev, &dev_attr_loading);
644 if (retval) {
645 dev_err(f_dev, "%s: device_create_file failed\n", __func__);
646 goto err_del_bin_attr;
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Kay Sievers312c0042005-11-16 09:00:00 +0100649 if (uevent) {
Stephen Boyddddb5542012-03-28 23:30:43 +0200650 dev_set_uevent_suppress(f_dev, false);
651 dev_dbg(f_dev, "firmware: requesting %s\n", fw_priv->fw_id);
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200652 if (timeout != MAX_SCHEDULE_TIMEOUT)
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700653 mod_timer(&fw_priv->timeout,
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200654 round_jiffies_up(jiffies + timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700656 kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
657 }
658
659 wait_for_completion(&fw_priv->completion);
660
661 set_bit(FW_STATUS_DONE, &fw_priv->status);
662 del_timer_sync(&fw_priv->timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Laura Garciacad1e552006-05-23 23:22:38 +0200664 mutex_lock(&fw_lock);
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700665 if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 retval = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 fw_priv->fw = NULL;
Laura Garciacad1e552006-05-23 23:22:38 +0200668 mutex_unlock(&fw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Stephen Boyddddb5542012-03-28 23:30:43 +0200670 device_remove_file(f_dev, &dev_attr_loading);
671err_del_bin_attr:
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700672 device_remove_bin_file(f_dev, fw_attr_data);
Stephen Boyddddb5542012-03-28 23:30:43 +0200673err_del_dev:
674 device_del(f_dev);
675err_put_dev:
676 put_device(f_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 return retval;
678}
679
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700680static int
681__request_firmware(const struct firmware **firmware_p, const char *name,
682 struct device *device, phys_addr_t dest_addr, size_t size)
683{
684 struct firmware_priv *fw_priv;
685 int ret;
686
687 fw_priv = _request_firmware_prepare(firmware_p, name, device, true,
688 false);
689 if (IS_ERR_OR_NULL(fw_priv))
690 return PTR_RET(fw_priv);
691
692 fw_priv->dest_addr = dest_addr;
693 fw_priv->dest_size = size;
694
695 ret = usermodehelper_read_trylock();
696 if (WARN_ON(ret)) {
697 dev_err(device, "firmware: %s will not be loaded\n", name);
698 } else {
699 ret = _request_firmware_load(fw_priv, true,
700 firmware_loading_timeout());
701 usermodehelper_read_unlock();
702 }
703 if (ret)
704 _request_firmware_cleanup(firmware_p);
705
706 return ret;
707}
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709/**
Kay Sievers312c0042005-11-16 09:00:00 +0100710 * request_firmware: - send firmware request and wait for it
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800711 * @firmware_p: pointer to firmware image
712 * @name: name of firmware file
713 * @device: device for which firmware is being loaded
714 *
715 * @firmware_p will be used to return a firmware image by the name
Abhay Salunke6e3eaab2005-09-06 15:17:13 -0700716 * of @name for device @device.
717 *
718 * Should be called from user context where sleeping is allowed.
719 *
Kay Sievers312c0042005-11-16 09:00:00 +0100720 * @name will be used as $FIRMWARE in the uevent environment and
Abhay Salunke6e3eaab2005-09-06 15:17:13 -0700721 * should be distinctive enough not to be confused with any other
722 * firmware image for this or any other device.
723 **/
724int
725request_firmware(const struct firmware **firmware_p, const char *name,
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700726 struct device *device)
Abhay Salunke6e3eaab2005-09-06 15:17:13 -0700727{
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700728 return __request_firmware(firmware_p, name, device, 0, 0);
729}
730
731/**
732 * request_firmware_direct: - send firmware request and wait for it
733 * @name: name of firmware file
734 * @device: device for which firmware is being loaded
735 * @dest_addr: Destination address for the firmware
736 * @dest_size:
737 *
738 * Similar to request_firmware, except takes in a buffer address and
739 * copies firmware data directly to that buffer. Returns the size of
740 * the firmware that was loaded at dest_addr.
741*/
742int request_firmware_direct(const char *name, struct device *device,
743 phys_addr_t dest_addr, size_t dest_size)
744{
745 const struct firmware *fp = NULL;
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200746 int ret;
747
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700748 ret = __request_firmware(&fp, name, device, dest_addr, dest_size);
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200749 if (ret)
Vikram Mulukutlaf5e5aa82013-05-14 11:26:37 -0700750 return ret;
751 ret = fp->size;
752 release_firmware(fp);
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200753 return ret;
Abhay Salunke6e3eaab2005-09-06 15:17:13 -0700754}
755
756/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 * release_firmware: - release the resource associated with a firmware image
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800758 * @fw: firmware resource to release
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 **/
Dmitry Torokhovbcb9bd12010-03-13 23:49:18 -0800760void release_firmware(const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
762 if (fw) {
Dmitry Torokhovbcb9bd12010-03-13 23:49:18 -0800763 if (!fw_is_builtin_firmware(fw))
764 firmware_free_data(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 kfree(fw);
766 }
767}
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769/* Async support */
770struct firmware_work {
771 struct work_struct work;
772 struct module *module;
773 const char *name;
774 struct device *device;
775 void *context;
776 void (*cont)(const struct firmware *fw, void *context);
Bob Liu072fc8f2011-01-26 18:33:32 +0800777 bool uevent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778};
779
Stephen Boyda36cf842012-03-28 23:31:00 +0200780static void request_firmware_work_func(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
Stephen Boyda36cf842012-03-28 23:31:00 +0200782 struct firmware_work *fw_work;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 const struct firmware *fw;
Stephen Boyddddb5542012-03-28 23:30:43 +0200784 struct firmware_priv *fw_priv;
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200785 long timeout;
matthieu castet113fab12005-11-13 16:07:39 -0800786 int ret;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700787
Stephen Boyda36cf842012-03-28 23:31:00 +0200788 fw_work = container_of(work, struct firmware_work, work);
Stephen Boyddddb5542012-03-28 23:30:43 +0200789 fw_priv = _request_firmware_prepare(&fw, fw_work->name, fw_work->device,
790 fw_work->uevent, true);
791 if (IS_ERR_OR_NULL(fw_priv)) {
792 ret = PTR_RET(fw_priv);
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200793 goto out;
Stephen Boyddddb5542012-03-28 23:30:43 +0200794 }
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200795
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200796 timeout = usermodehelper_read_lock_wait(firmware_loading_timeout());
797 if (timeout) {
Stephen Boyddddb5542012-03-28 23:30:43 +0200798 ret = _request_firmware_load(fw_priv, fw_work->uevent, timeout);
Rafael J. Wysocki9b78c1d2012-03-28 23:30:02 +0200799 usermodehelper_read_unlock();
800 } else {
801 dev_dbg(fw_work->device, "firmware: %s loading timed out\n",
802 fw_work->name);
803 ret = -EAGAIN;
804 }
Rafael J. Wysocki811fa402012-03-28 23:29:55 +0200805 if (ret)
806 _request_firmware_cleanup(&fw);
807
808 out:
Johannes Berg9ebfbd42009-10-29 12:36:02 +0100809 fw_work->cont(fw, fw_work->context);
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 module_put(fw_work->module);
812 kfree(fw_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813}
814
815/**
Ben Hutchings3c31f072010-02-14 14:18:53 +0000816 * request_firmware_nowait - asynchronous version of request_firmware
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800817 * @module: module requesting the firmware
Kay Sievers312c0042005-11-16 09:00:00 +0100818 * @uevent: sends uevent to copy the firmware image if this flag
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800819 * is non-zero else the firmware copy must be done manually.
820 * @name: name of firmware file
821 * @device: device for which firmware is being loaded
Johannes Berg9ebfbd42009-10-29 12:36:02 +0100822 * @gfp: allocation flags
Randy Dunlapeb8e3172005-10-30 15:03:01 -0800823 * @context: will be passed over to @cont, and
824 * @fw may be %NULL if firmware request fails.
825 * @cont: function will be called asynchronously when the firmware
826 * request is over.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 *
Ming Lei7fcab092009-05-29 11:33:19 +0800828 * Asynchronous variant of request_firmware() for user contexts where
829 * it is not possible to sleep for long time. It can't be called
830 * in atomic contexts.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 **/
832int
833request_firmware_nowait(
Bob Liu072fc8f2011-01-26 18:33:32 +0800834 struct module *module, bool uevent,
Johannes Berg9ebfbd42009-10-29 12:36:02 +0100835 const char *name, struct device *device, gfp_t gfp, void *context,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 void (*cont)(const struct firmware *fw, void *context))
837{
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700838 struct firmware_work *fw_work;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700840 fw_work = kzalloc(sizeof (struct firmware_work), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (!fw_work)
842 return -ENOMEM;
Dmitry Torokhovf8a4bd32010-06-04 00:54:43 -0700843
844 fw_work->module = module;
845 fw_work->name = name;
846 fw_work->device = device;
847 fw_work->context = context;
848 fw_work->cont = cont;
849 fw_work->uevent = uevent;
850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (!try_module_get(module)) {
852 kfree(fw_work);
853 return -EFAULT;
854 }
855
Stephen Boyda36cf842012-03-28 23:31:00 +0200856 INIT_WORK(&fw_work->work, request_firmware_work_func);
857 schedule_work(&fw_work->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return 0;
859}
860
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800861static int __init firmware_class_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800863 return class_register(&firmware_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
Dmitry Torokhov673fae92010-03-13 23:49:13 -0800865
866static void __exit firmware_class_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 class_unregister(&firmware_class);
869}
870
Shaohua Lia30a6a22006-09-27 01:50:52 -0700871fs_initcall(firmware_class_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872module_exit(firmware_class_exit);
873
874EXPORT_SYMBOL(release_firmware);
875EXPORT_SYMBOL(request_firmware);
876EXPORT_SYMBOL(request_firmware_nowait);