summaryrefslogtreecommitdiff
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2007-06-13 07:34:15 +0000
committerMike Frysinger <vapier@gentoo.org>2007-06-13 07:34:15 +0000
commita78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b (patch)
tree8f76a7bf9fc29d1b8ed6d27e4155321660aa37ca /util-linux/mdev.c
parentd67cef2425fb5e75b75d52d9a308da6d29cd7a0d (diff)
downloadbusybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.tar.gz
busybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.tar.bz2
busybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.zip
add support for firmware loading
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r--util-linux/mdev.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index d1b2684bc..8e5b8a94b 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -226,6 +226,71 @@ static void find_dev(char *path)
226 closedir(dir); 226 closedir(dir);
227} 227}
228 228
229/* For the full gory details, see linux/Documentation/firmware_class/README
230 *
231 * Firmware loading works like this:
232 * - kernel sets FIRMWARE env var
233 * - userspace checks /lib/firmware/$FIRMWARE
234 * - userspace waits for /sys/$DEVPATH/loading to appear
235 * - userspace writes "1" to /sys/$DEVPATH/loading
236 * - userspace copies /lib/firmware/$FIRMWARE into /sys/$DEVPATH/data
237 * - userspace writes "0" (worked) or "-1" (failed) to /sys/$DEVPATH/loading
238 * - kernel loads firmware into device
239 */
240static inline void load_firmware(const char * const firmware, const char * const sysfs_path)
241{
242 int cnt;
243 int firmware_fd, loading_fd, data_fd;
244
245 /* check for $FIRMWARE from kernel */
246 /* XXX: dont bother: open(NULL) works same as open("no-such-file")
247 * if (!firmware)
248 * return;
249 */
250
251 /* check for /lib/firmware/$FIRMWARE */
252 xchdir("/lib/firmware");
253 firmware_fd = xopen(firmware, O_WRONLY);
254
255 /* in case we goto out ... */
256 data_fd = -1;
257
258 /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */
259 xchdir(sysfs_path);
260 for (cnt = 0; cnt < 30; ++cnt) {
261 loading_fd = open("loading", O_WRONLY);
262 if (loading_fd == -1)
263 sleep(1);
264 else
265 break;
266 }
267 if (loading_fd == -1)
268 goto out;
269
270 /* tell kernel we're loading by `echo 1 > /sys/$DEVPATH/loading` */
271 if (write(loading_fd, "1", 1) != 1)
272 goto out;
273
274 /* load firmware by `cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data */
275 data_fd = open("data", O_WRONLY);
276 if (data_fd == -1)
277 goto out;
278 cnt = bb_copyfd_eof(firmware_fd, data_fd);
279
280 /* tell kernel result by `echo [0|-1] > /sys/$DEVPATH/loading` */
281 if (cnt > 0)
282 write(loading_fd, "0", 1);
283 else
284 write(loading_fd, "-1", 2);
285
286 out:
287 if (ENABLE_FEATURE_CLEAN_UP) {
288 close(firmware_fd);
289 close(loading_fd);
290 close(data_fd);
291 }
292}
293
229int mdev_main(int argc, char **argv); 294int mdev_main(int argc, char **argv);
230int mdev_main(int argc, char **argv) 295int mdev_main(int argc, char **argv)
231{ 296{
@@ -257,8 +322,14 @@ int mdev_main(int argc, char **argv)
257 bb_show_usage(); 322 bb_show_usage();
258 323
259 sprintf(temp, "/sys%s", env_path); 324 sprintf(temp, "/sys%s", env_path);
260 if (!strcmp(action, "add")) make_device(temp,0); 325 if (!strcmp(action, "remove"))
261 else if (!strcmp(action, "remove")) make_device(temp,1); 326 make_device(temp, 1);
327 else if (!strcmp(action, "add")) {
328 make_device(temp, 0);
329
330 if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE)
331 load_firmware(getenv("FIRMWARE"), temp);
332 }
262 } 333 }
263 334
264 if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp); 335 if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);