aboutsummaryrefslogtreecommitdiff
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r--util-linux/mdev.c249
1 files changed, 180 insertions, 69 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 0a34122b4..79871d30e 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -92,7 +92,9 @@
92//usage: "\n" 92//usage: "\n"
93//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n" 93//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n"
94//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n" 94//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n"
95//usage: "To activate this feature, create empty /dev/mdev.seq at boot." 95//usage: "To activate this feature, create empty /dev/mdev.seq at boot.\n"
96//usage: "\n"
97//usage: "If /dev/mdev.log file exists, debug log will be appended to it."
96 98
97#include "libbb.h" 99#include "libbb.h"
98#include "xregex.h" 100#include "xregex.h"
@@ -139,10 +141,101 @@
139 * This happens regardless of /sys/class/.../dev existence. 141 * This happens regardless of /sys/class/.../dev existence.
140 */ 142 */
141 143
144/* Kernel's hotplug environment constantly changes.
145 * Here are new cases I observed on 3.1.0:
146 *
147 * Case with $DEVNAME and $DEVICE, not just $DEVPATH:
148 * ACTION=add
149 * BUSNUM=001
150 * DEVICE=/proc/bus/usb/001/003
151 * DEVNAME=bus/usb/001/003
152 * DEVNUM=003
153 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5
154 * DEVTYPE=usb_device
155 * MAJOR=189
156 * MINOR=2
157 * PRODUCT=18d1/4e12/227
158 * SUBSYSTEM=usb
159 * TYPE=0/0/0
160 *
161 * Case with $DEVICE, but no $DEVNAME - apparenty, usb iface notification?
162 * "Please load me a module" thing?
163 * ACTION=add
164 * DEVICE=/proc/bus/usb/001/003
165 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0
166 * DEVTYPE=usb_interface
167 * INTERFACE=8/6/80
168 * MODALIAS=usb:v18D1p4E12d0227dc00dsc00dp00ic08isc06ip50
169 * PRODUCT=18d1/4e12/227
170 * SUBSYSTEM=usb
171 * TYPE=0/0/0
172 *
173 * ACTION=add
174 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5
175 * DEVTYPE=scsi_host
176 * SUBSYSTEM=scsi
177 *
178 * ACTION=add
179 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/scsi_host/host5
180 * SUBSYSTEM=scsi_host
181 *
182 * ACTION=add
183 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0
184 * DEVTYPE=scsi_target
185 * SUBSYSTEM=scsi
186 *
187 * Case with strange $MODALIAS:
188 * ACTION=add
189 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0
190 * DEVTYPE=scsi_device
191 * MODALIAS=scsi:t-0x00
192 * SUBSYSTEM=scsi
193 *
194 * ACTION=add
195 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0
196 * SUBSYSTEM=scsi_disk
197 *
198 * ACTION=add
199 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_device/5:0:0:0
200 * SUBSYSTEM=scsi_device
201 *
202 * Case with explicit $MAJOR/$MINOR (no need to read /sys/$DEVPATH/dev?):
203 * ACTION=add
204 * DEVNAME=bsg/5:0:0:0
205 * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/bsg/5:0:0:0
206 * MAJOR=253
207 * MINOR=1
208 * SUBSYSTEM=bsg
209 *
210 * ACTION=add
211 * DEVPATH=/devices/virtual/bdi/8:16
212 * SUBSYSTEM=bdi
213 *
214 * ACTION=add
215 * DEVNAME=sdb
216 * DEVPATH=/block/sdb
217 * DEVTYPE=disk
218 * MAJOR=8
219 * MINOR=16
220 * SUBSYSTEM=block
221 *
222 * Case with ACTION=change:
223 * ACTION=change
224 * DEVNAME=sdb
225 * DEVPATH=/block/sdb
226 * DEVTYPE=disk
227 * DISK_MEDIA_CHANGE=1
228 * MAJOR=8
229 * MINOR=16
230 * SUBSYSTEM=block
231 */
232
233static const char keywords[] ALIGN1 = "add\0remove\0change\0";
234enum { OP_add, OP_remove };
235
142struct rule { 236struct rule {
143 bool keep_matching; 237 bool keep_matching;
144 bool regex_compiled; 238 bool regex_compiled;
145 bool regex_has_slash;
146 mode_t mode; 239 mode_t mode;
147 int maj, min0, min1; 240 int maj, min0, min1;
148 struct bb_uidgid_t ugid; 241 struct bb_uidgid_t ugid;
@@ -154,6 +247,7 @@ struct rule {
154 247
155struct globals { 248struct globals {
156 int root_major, root_minor; 249 int root_major, root_minor;
250 smallint verbose;
157 char *subsystem; 251 char *subsystem;
158#if ENABLE_FEATURE_MDEV_CONF 252#if ENABLE_FEATURE_MDEV_CONF
159 const char *filename; 253 const char *filename;
@@ -245,7 +339,6 @@ static void parse_next_rule(void)
245 } 339 }
246 xregcomp(&G.cur_rule.match, val, REG_EXTENDED); 340 xregcomp(&G.cur_rule.match, val, REG_EXTENDED);
247 G.cur_rule.regex_compiled = 1; 341 G.cur_rule.regex_compiled = 1;
248 G.cur_rule.regex_has_slash = (strchr(val, '/') != NULL);
249 } 342 }
250 343
251 /* 2nd field: uid:gid - device ownership */ 344 /* 2nd field: uid:gid - device ownership */
@@ -366,13 +459,16 @@ static char *build_alias(char *alias, const char *device_name)
366 * after NUL, but we promise to not mangle (IOW: to restore if needed) 459 * after NUL, but we promise to not mangle (IOW: to restore if needed)
367 * path string. 460 * path string.
368 * NB2: "mdev -s" may call us many times, do not leak memory/fds! 461 * NB2: "mdev -s" may call us many times, do not leak memory/fds!
462 *
463 * device_name = $DEVNAME (may be NULL)
464 * path = /sys/$DEVPATH
369 */ 465 */
370static void make_device(char *path, int delete) 466static void make_device(char *device_name, char *path, int operation)
371{ 467{
372 char *device_name, *subsystem_slash_devname;
373 int major, minor, type, len; 468 int major, minor, type, len;
374 469
375 dbg("%s('%s', delete:%d)", __func__, path, delete); 470 if (G.verbose)
471 bb_error_msg("device: %s, %s", device_name, path);
376 472
377 /* Try to read major/minor string. Note that the kernel puts \n after 473 /* Try to read major/minor string. Note that the kernel puts \n after
378 * the data, so we don't need to worry about null terminating the string 474 * the data, so we don't need to worry about null terminating the string
@@ -380,7 +476,7 @@ static void make_device(char *path, int delete)
380 * We also depend on path having writeable space after it. 476 * We also depend on path having writeable space after it.
381 */ 477 */
382 major = -1; 478 major = -1;
383 if (!delete) { 479 if (operation == OP_add) {
384 char *dev_maj_min = path + strlen(path); 480 char *dev_maj_min = path + strlen(path);
385 481
386 strcpy(dev_maj_min, "/dev"); 482 strcpy(dev_maj_min, "/dev");
@@ -391,40 +487,27 @@ static void make_device(char *path, int delete)
391 return; 487 return;
392 /* no "dev" file, but we can still run scripts 488 /* no "dev" file, but we can still run scripts
393 * based on device name */ 489 * based on device name */
394 } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) { 490 } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) {
491 if (G.verbose)
492 bb_error_msg("maj,min: %u,%u", major, minor);
493 } else {
395 major = -1; 494 major = -1;
396 } 495 }
397 } 496 }
398 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ 497 /* else: for delete, -1 still deletes the node, but < -1 suppresses that */
399 498
400 /* Determine device name, type, major and minor */ 499 /* Determine device name, type, major and minor */
401 device_name = (char*) bb_basename(path); 500 if (!device_name)
501 device_name = (char*) bb_basename(path);
402 /* http://kernel.org/doc/pending/hotplug.txt says that only 502 /* http://kernel.org/doc/pending/hotplug.txt says that only
403 * "/sys/block/..." is for block devices. "/sys/bus" etc is not. 503 * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
404 * But since 2.6.25 block devices are also in /sys/class/block. 504 * But since 2.6.25 block devices are also in /sys/class/block.
405 * We use strstr("/block/") to forestall future surprises. */ 505 * We use strstr("/block/") to forestall future surprises.
506 */
406 type = S_IFCHR; 507 type = S_IFCHR;
407 if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0)) 508 if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0))
408 type = S_IFBLK; 509 type = S_IFBLK;
409 510
410 /* Make path point to "subsystem/device_name" */
411 subsystem_slash_devname = NULL;
412 /* Check for coldplug invocations first */
413 if (strncmp(path, "/sys/block/", 11) == 0) /* legacy case */
414 path += sizeof("/sys/") - 1;
415 else if (strncmp(path, "/sys/class/", 11) == 0)
416 path += sizeof("/sys/class/") - 1;
417 else {
418 /* Example of a hotplug invocation:
419 * SUBSYSTEM="block"
420 * DEVPATH="/sys" + "/devices/virtual/mtd/mtd3/mtdblock3"
421 * ("/sys" is added by mdev_main)
422 * - path does not contain subsystem
423 */
424 subsystem_slash_devname = concat_path_file(G.subsystem, device_name);
425 path = subsystem_slash_devname;
426 }
427
428#if ENABLE_FEATURE_MDEV_CONF 511#if ENABLE_FEATURE_MDEV_CONF
429 G.rule_idx = 0; /* restart from the beginning (think mdev -s) */ 512 G.rule_idx = 0; /* restart from the beginning (think mdev -s) */
430#endif 513#endif
@@ -434,10 +517,10 @@ static void make_device(char *path, int delete)
434 char *command; 517 char *command;
435 char *alias; 518 char *alias;
436 char aliaslink = aliaslink; /* for compiler */ 519 char aliaslink = aliaslink; /* for compiler */
437 const char *node_name; 520 char *node_name;
438 const struct rule *rule; 521 const struct rule *rule;
439 522
440 str_to_match = ""; 523 str_to_match = device_name;
441 524
442 rule = next_rule(); 525 rule = next_rule();
443 526
@@ -455,10 +538,8 @@ static void make_device(char *path, int delete)
455 dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); 538 dbg("getenv('%s'):'%s'", rule->envvar, str_to_match);
456 if (!str_to_match) 539 if (!str_to_match)
457 continue; 540 continue;
458 } else {
459 /* regex to match [subsystem/]device_name */
460 str_to_match = (rule->regex_has_slash ? path : device_name);
461 } 541 }
542 /* else: str_to_match = device_name */
462 543
463 if (rule->regex_compiled) { 544 if (rule->regex_compiled) {
464 int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); 545 int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0);
@@ -537,7 +618,7 @@ static void make_device(char *path, int delete)
537 /* Are we running this command now? 618 /* Are we running this command now?
538 * Run $cmd on delete, @cmd on create, *cmd on both 619 * Run $cmd on delete, @cmd on create, *cmd on both
539 */ 620 */
540 if (s2 - s != delete) { 621 if (s2 - s != (operation == OP_remove) || *s2 == '*') {
541 /* We are here if: '*', 622 /* We are here if: '*',
542 * or: '@' and delete = 0, 623 * or: '@' and delete = 0,
543 * or: '$' and delete = 1 624 * or: '$' and delete = 1
@@ -556,21 +637,30 @@ static void make_device(char *path, int delete)
556 dbg("alias2:'%s'", alias); 637 dbg("alias2:'%s'", alias);
557 } 638 }
558 639
559 if (!delete && major >= 0) { 640 if (operation == OP_add && major >= 0) {
560 dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor); 641 char *slash = strrchr(node_name, '/');
642 if (slash) {
643 *slash = '\0';
644 bb_make_directory(node_name, 0755, FILEUTILS_RECUR);
645 *slash = '/';
646 }
647 if (G.verbose)
648 bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type);
561 if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) 649 if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST)
562 bb_perror_msg("can't create '%s'", node_name); 650 bb_perror_msg("can't create '%s'", node_name);
563 if (major == G.root_major && minor == G.root_minor)
564 symlink(node_name, "root");
565 if (ENABLE_FEATURE_MDEV_CONF) { 651 if (ENABLE_FEATURE_MDEV_CONF) {
566 chmod(node_name, rule->mode); 652 chmod(node_name, rule->mode);
567 chown(node_name, rule->ugid.uid, rule->ugid.gid); 653 chown(node_name, rule->ugid.uid, rule->ugid.gid);
568 } 654 }
655 if (major == G.root_major && minor == G.root_minor)
656 symlink(node_name, "root");
569 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 657 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
570 if (aliaslink == '>') { 658 if (aliaslink == '>') {
571//TODO: on devtmpfs, device_name already exists and symlink() fails. 659//TODO: on devtmpfs, device_name already exists and symlink() fails.
572//End result is that instead of symlink, we have two nodes. 660//End result is that instead of symlink, we have two nodes.
573//What should be done? 661//What should be done?
662 if (G.verbose)
663 bb_error_msg("symlink: %s", device_name);
574 symlink(node_name, device_name); 664 symlink(node_name, device_name);
575 } 665 }
576 } 666 }
@@ -582,17 +672,24 @@ static void make_device(char *path, int delete)
582 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); 672 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
583 putenv(s); 673 putenv(s);
584 putenv(s1); 674 putenv(s1);
675 if (G.verbose)
676 bb_error_msg("running: %s", command);
585 if (system(command) == -1) 677 if (system(command) == -1)
586 bb_perror_msg("can't run '%s'", command); 678 bb_perror_msg("can't run '%s'", command);
587 bb_unsetenv_and_free(s1); 679 bb_unsetenv_and_free(s1);
588 bb_unsetenv_and_free(s); 680 bb_unsetenv_and_free(s);
589 } 681 }
590 682
591 if (delete && major >= -1) { 683 if (operation == OP_remove && major >= -1) {
592 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 684 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
593 if (aliaslink == '>') 685 if (aliaslink == '>') {
686 if (G.verbose)
687 bb_error_msg("unlink: %s", device_name);
594 unlink(device_name); 688 unlink(device_name);
689 }
595 } 690 }
691 if (G.verbose)
692 bb_error_msg("unlink: %s", node_name);
596 unlink(node_name); 693 unlink(node_name);
597 } 694 }
598 695
@@ -605,8 +702,6 @@ static void make_device(char *path, int delete)
605 if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching) 702 if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching)
606 break; 703 break;
607 } /* for (;;) */ 704 } /* for (;;) */
608
609 free(subsystem_slash_devname);
610} 705}
611 706
612/* File callback for /sys/ traversal */ 707/* File callback for /sys/ traversal */
@@ -624,7 +719,7 @@ static int FAST_FUNC fileAction(const char *fileName,
624 719
625 strcpy(scratch, fileName); 720 strcpy(scratch, fileName);
626 scratch[len] = '\0'; 721 scratch[len] = '\0';
627 make_device(scratch, /*delete:*/ 0); 722 make_device(/*DEVNAME:*/ NULL, scratch, OP_add);
628 723
629 return TRUE; 724 return TRUE;
630} 725}
@@ -661,37 +756,45 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
661static void load_firmware(const char *firmware, const char *sysfs_path) 756static void load_firmware(const char *firmware, const char *sysfs_path)
662{ 757{
663 int cnt; 758 int cnt;
664 int firmware_fd, loading_fd, data_fd; 759 int firmware_fd, loading_fd;
665 760
666 /* check for /lib/firmware/$FIRMWARE */ 761 /* check for /lib/firmware/$FIRMWARE */
667 xchdir("/lib/firmware"); 762 xchdir("/lib/firmware");
668 firmware_fd = xopen(firmware, O_RDONLY); 763 firmware_fd = open(firmware, O_RDONLY); /* can fail */
669
670 /* in case we goto out ... */
671 data_fd = -1;
672 764
673 /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ 765 /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
674 xchdir(sysfs_path); 766 xchdir(sysfs_path);
675 for (cnt = 0; cnt < 30; ++cnt) { 767 for (cnt = 0; cnt < 30; ++cnt) {
676 loading_fd = open("loading", O_WRONLY); 768 loading_fd = open("loading", O_WRONLY);
677 if (loading_fd != -1) 769 if (loading_fd >= 0)
678 goto loading; 770 goto loading;
679 sleep(1); 771 sleep(1);
680 } 772 }
681 goto out; 773 goto out;
682 774
683 loading: 775 loading:
684 /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */ 776 cnt = 0;
685 if (full_write(loading_fd, "1", 1) != 1) 777 if (firmware_fd >= 0) {
686 goto out; 778 int data_fd;
687 779
688 /* load firmware into /sys/$DEVPATH/data */ 780 /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */
689 data_fd = open("data", O_WRONLY); 781 if (full_write(loading_fd, "1", 1) != 1)
690 if (data_fd == -1) 782 goto out;
691 goto out; 783
692 cnt = bb_copyfd_eof(firmware_fd, data_fd); 784 /* load firmware into /sys/$DEVPATH/data */
785 data_fd = open("data", O_WRONLY);
786 if (data_fd < 0)
787 goto out;
788 cnt = bb_copyfd_eof(firmware_fd, data_fd);
789 if (ENABLE_FEATURE_CLEAN_UP)
790 close(data_fd);
791 }
693 792
694 /* tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" */ 793 /* Tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading"
794 * Note: we emit -1 also if firmware file wasn't found.
795 * There are cases when otherwise kernel would wait for minutes
796 * before timing out.
797 */
695 if (cnt > 0) 798 if (cnt > 0)
696 full_write(loading_fd, "0", 1); 799 full_write(loading_fd, "0", 1);
697 else 800 else
@@ -701,7 +804,6 @@ static void load_firmware(const char *firmware, const char *sysfs_path)
701 if (ENABLE_FEATURE_CLEAN_UP) { 804 if (ENABLE_FEATURE_CLEAN_UP) {
702 close(firmware_fd); 805 close(firmware_fd);
703 close(loading_fd); 806 close(loading_fd);
704 close(data_fd);
705 } 807 }
706} 808}
707 809
@@ -762,9 +864,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
762 char *fw; 864 char *fw;
763 char *seq; 865 char *seq;
764 char *action; 866 char *action;
765 char *env_path; 867 char *env_devname;
766 static const char keywords[] ALIGN1 = "remove\0add\0"; 868 char *env_devpath;
767 enum { OP_remove = 0, OP_add };
768 smalluint op; 869 smalluint op;
769 870
770 /* Hotplug: 871 /* Hotplug:
@@ -773,12 +874,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
773 * DEVPATH is like "/block/sda" or "/class/input/mice" 874 * DEVPATH is like "/block/sda" or "/class/input/mice"
774 */ 875 */
775 action = getenv("ACTION"); 876 action = getenv("ACTION");
776 env_path = getenv("DEVPATH"); 877 op = index_in_strings(keywords, action);
878 env_devname = getenv("DEVNAME"); /* can be NULL */
879 env_devpath = getenv("DEVPATH");
777 G.subsystem = getenv("SUBSYSTEM"); 880 G.subsystem = getenv("SUBSYSTEM");
778 if (!action || !env_path /*|| !G.subsystem*/) 881 if (!action || !env_devpath /*|| !G.subsystem*/)
779 bb_show_usage(); 882 bb_show_usage();
780 fw = getenv("FIRMWARE"); 883 fw = getenv("FIRMWARE");
781 op = index_in_strings(keywords, action);
782 /* If it exists, does /dev/mdev.seq match $SEQNUM? 884 /* If it exists, does /dev/mdev.seq match $SEQNUM?
783 * If it does not match, earlier mdev is running 885 * If it does not match, earlier mdev is running
784 * in parallel, and we need to wait */ 886 * in parallel, and we need to wait */
@@ -804,16 +906,25 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
804 } while (--timeout); 906 } while (--timeout);
805 } 907 }
806 908
807 snprintf(temp, PATH_MAX, "/sys%s", env_path); 909 {
910 int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND);
911 if (logfd >= 0) {
912 xmove_fd(logfd, STDERR_FILENO);
913 G.verbose = 1;
914 bb_error_msg("seq: %s action: %s", seq, action);
915 }
916 }
917
918 snprintf(temp, PATH_MAX, "/sys%s", env_devpath);
808 if (op == OP_remove) { 919 if (op == OP_remove) {
809 /* Ignoring "remove firmware". It was reported 920 /* Ignoring "remove firmware". It was reported
810 * to happen and to cause erroneous deletion 921 * to happen and to cause erroneous deletion
811 * of device nodes. */ 922 * of device nodes. */
812 if (!fw) 923 if (!fw)
813 make_device(temp, /*delete:*/ 1); 924 make_device(env_devname, temp, op);
814 } 925 }
815 else if (op == OP_add) { 926 else if (op == OP_add) {
816 make_device(temp, /*delete:*/ 0); 927 make_device(env_devname, temp, op);
817 if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { 928 if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) {
818 if (fw) 929 if (fw)
819 load_firmware(fw, temp); 930 load_firmware(fw, temp);