diff options
author | Mike Frysinger <vapier@gentoo.org> | 2007-06-13 07:34:15 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2007-06-13 07:34:15 +0000 |
commit | a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b (patch) | |
tree | 8f76a7bf9fc29d1b8ed6d27e4155321660aa37ca | |
parent | d67cef2425fb5e75b75d52d9a308da6d29cd7a0d (diff) | |
download | busybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.tar.gz busybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.tar.bz2 busybox-w32-a78ef2ccf14a0b3bc50b8fd8fd3239ca1385ee2b.zip |
add support for firmware loading
-rw-r--r-- | util-linux/Config.in | 11 | ||||
-rw-r--r-- | util-linux/mdev.c | 75 |
2 files changed, 84 insertions, 2 deletions
diff --git a/util-linux/Config.in b/util-linux/Config.in index 2184df153..1040ce282 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in | |||
@@ -294,6 +294,17 @@ config FEATURE_MDEV_EXEC | |||
294 | 294 | ||
295 | For more information, please see docs/mdev.txt | 295 | For more information, please see docs/mdev.txt |
296 | 296 | ||
297 | config FEATURE_MDEV_LOAD_FIRMWARE | ||
298 | bool "Support loading of firmwares" | ||
299 | default n | ||
300 | depends on MDEV | ||
301 | help | ||
302 | Some devices need to load firmware before they can be usable. | ||
303 | |||
304 | These devices will request userspace look up the files in | ||
305 | /lib/firmware/ and if it exists, send it to the kernel for | ||
306 | loading into the hardware. | ||
307 | |||
297 | config MKSWAP | 308 | config MKSWAP |
298 | bool "mkswap" | 309 | bool "mkswap" |
299 | default n | 310 | default n |
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 | */ | ||
240 | static 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 | |||
229 | int mdev_main(int argc, char **argv); | 294 | int mdev_main(int argc, char **argv); |
230 | int mdev_main(int argc, char **argv) | 295 | int 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); |