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); |
