2 * firmware - Kernel firmware loader
4 * Copyright (C) 2009 Piter Punk <piterpunk@slackware.com>
5 * Copyright (C) 2009-2011 Kay Sievers <kay@vrfy.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details:*
25 #include <sys/utsname.h>
30 static bool set_loading(struct udev
*udev
, char *loadpath
, const char *state
)
34 ldfile
= fopen(loadpath
, "we");
36 log_error("error: can not open '%s'", loadpath
);
39 fprintf(ldfile
, "%s\n", state
);
44 static bool copy_firmware(struct udev
*udev
, const char *source
, const char *target
, size_t size
)
47 FILE *fsource
= NULL
, *ftarget
= NULL
;
52 log_error("No memory available to load firmware file");
56 log_debug("writing '%s' (%zi) to '%s'", source
, size
, target
);
58 fsource
= fopen(source
, "re");
61 ftarget
= fopen(target
, "we");
64 if (fread(buf
, size
, 1, fsource
) != 1)
66 if (fwrite(buf
, size
, 1, ftarget
) == 1)
77 static int builtin_firmware(struct udev_device
*dev
, int argc
, char *argv
[], bool test
)
79 struct udev
*udev
= udev_device_get_udev(dev
);
80 static const char *searchpath
[] = { FIRMWARE_PATH
};
81 char loadpath
[UTIL_PATH_SIZE
];
82 char datapath
[UTIL_PATH_SIZE
];
83 char fwpath
[UTIL_PATH_SIZE
];
86 struct utsname kernel
;
89 int rc
= EXIT_SUCCESS
;
91 firmware
= udev_device_get_property_value(dev
, "FIRMWARE");
92 if (firmware
== NULL
) {
93 log_error("firmware parameter missing");
98 /* lookup firmware file */
100 for (i
= 0; i
< ELEMENTSOF(searchpath
); i
++) {
101 strscpyl(fwpath
, sizeof(fwpath
), searchpath
[i
], kernel
.release
, "/", firmware
, NULL
);
102 fwfile
= fopen(fwpath
, "re");
106 strscpyl(fwpath
, sizeof(fwpath
), searchpath
[i
], firmware
, NULL
);
107 fwfile
= fopen(fwpath
, "re");
112 strscpyl(loadpath
, sizeof(loadpath
), udev_device_get_syspath(dev
), "/loading", NULL
);
114 if (fwfile
== NULL
) {
115 log_debug("did not find firmware file '%s'", firmware
);
118 * Do not cancel the request in the initrd, the real root might have
119 * the firmware file and the 'coldplug' run in the real root will find
120 * this pending request and fulfill or cancel it.
123 set_loading(udev
, loadpath
, "-1");
127 if (stat(fwpath
, &statbuf
) < 0 || statbuf
.st_size
== 0) {
129 set_loading(udev
, loadpath
, "-1");
134 if (!set_loading(udev
, loadpath
, "1"))
137 strscpyl(datapath
, sizeof(datapath
), udev_device_get_syspath(dev
), "/data", NULL
);
138 if (!copy_firmware(udev
, fwpath
, datapath
, statbuf
.st_size
)) {
139 log_error("error sending firmware '%s' to device", firmware
);
140 set_loading(udev
, loadpath
, "-1");
145 set_loading(udev
, loadpath
, "0");
152 const struct udev_builtin udev_builtin_firmware
= {
154 .cmd
= builtin_firmware
,
155 .help
= "kernel firmware loader",