[PATCH] Add subsystem support to mdev (firmware loading)
Erik Andersen
andersen at codepoet.org
Thu Oct 19 13:11:26 PDT 2006
On Tue Oct 03, 2006 at 07:21:58PM +0200, Denis Vlasenko wrote:
> > I'm just going to reiterate how vital firmware loading is to a small
> > but growing proportion of embedded Linux users, and hope that you see
> > it as a valid addition to the codebase.
> >
> > As well as the patch, a very simple script (also attached below)
> > should be added to the examples directory to handle firmware loading.
I ended up needing to do some firmware loading myself, so I've
put together an alternative patch to handle firmware loading
within mdev. My patch is a bit larger, but does not require any
external script (or even a shell), making it faster, better
suited for use in early userspace, and (most importantly) it does
what I happened to need yesterday. I've tested it using a
usb speedtouch modem and an AIC-9405W SAS adapter and It Worked
For Me(tm). So perhaps it might work for others as well...
On an unrelated note, somebody remind me why mdev lives under
util-linux as it has little (except portions of the end result)
in common with udev? Any any reason not to have it install
itself as /sbin/hotplug or set /proc/sys/kernel/hotplug pointing
to /sbin/mdev when run with 'mdev -s'?
-Erik
--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--
-------------- next part --------------
Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c (revision 16402)
+++ util-linux/mdev.c (working copy)
@@ -5,6 +5,7 @@
*
* Copyright 2005 Rob Landley <rob at landley.net>
* Copyright 2005 Frank Sorenson <frank at tuxrocks.com>
+ * Copyright 2006 Erik Andersen <andersen at codepoet.org>
*
* Licensed under GPL version 2, see file LICENSE in this tarball for details.
*/
@@ -231,17 +232,16 @@
int mdev_main(int argc, char *argv[])
{
+ int status = 0;
char *action;
char *env_path;
RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
xchdir(DEV_PATH);
- /* Scan */
-
+ /* Scan for existing (aka coldplugged) devices */
if (argc == 2 && !strcmp(argv[1],"-s")) {
struct stat st;
-
xstat("/", &st);
bbg.root_major = major(st.st_dev);
bbg.root_minor = minor(st.st_dev);
@@ -249,20 +249,105 @@
find_dev(temp);
strcpy(temp,"/sys/class");
find_dev(temp);
-
- /* Hotplug */
-
- } else {
+ } else
+ {
+ /* Hotplug -- the kernel called us as /sbin/hotplug */
action = getenv("ACTION");
env_path = getenv("DEVPATH");
if (!action || !env_path)
bb_show_usage();
- sprintf(temp, "/sys%s", env_path);
- if (!strcmp(action, "add")) make_device(temp,0);
- else if (!strcmp(action, "remove")) make_device(temp,1);
- }
+ snprintf(temp, PATH_MAX, "/sys%s", env_path);
+ if (!strcmp(action, "remove")) make_device(temp,1);
+ else if (!strcmp(action, "add"))
+ {
+ char *firmware;
+ /* Create a device node to access the new device */
+ make_device(temp,0);
+
+ /* Check if we need to load some firmware in order to
+ * make this particular device actually work */
+ firmware = getenv("FIRMWARE");
+ if (firmware)
+ {
+ int fd;
+ FILE *src, *dst;
+ struct stat st;
+ char echobuf[4];
+
+ /* First check if we even have the requested firmware
+ * file waiting under /lib/firmware as there is not point
+ * in doing anything further if the needed firmware is not
+ * even present. */
+ snprintf(temp, PATH_MAX, "/lib/firmware/%s", firmware);
+ xstat(temp, &st);
+
+ /* sleep until the driver says it is ready for us to
+ * upload the firmware. Just as a safeguard, if the
+ * driver takes longer than 30 seconds, give up... */
+ fd = 0;
+ snprintf(temp, PATH_MAX, "/sys%s/loading", env_path);
+ while(1) {
+ if (!stat(temp, &st) && S_ISREG(st.st_mode))
+ break;
+ sleep(1);
+ fd++;
+ if (fd >= 30) {
+ status = 1;
+ goto endgame;
+ }
+ }
+
+ /* We need to do an 'echo 1 > /sys/$DEVPATH/loading'
+ * to tell the driver we are ready to upload the firmware */
+ fd = xopen(temp, O_WRONLY);
+ echobuf[0]='1'; echobuf[1]='\n';
+ if (write(fd, echobuf, 2) != 2) {
+ status = 1;
+ goto endgame;
+ }
+ close(fd);
+
+ /* Write the firmware to the driver's data file, i.e.
+ * 'cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data' */
+ status=-1;
+ snprintf(temp, PATH_MAX, "/lib/firmware/%s", firmware);
+ if ((src = bb_wfopen(temp, "r")) != NULL) {
+ snprintf(temp, PATH_MAX, "/sys%s/data", env_path);
+ if ((dst = bb_wfopen(temp, "w")) != NULL) {
+ int r = bb_copyfd_eof(fileno(src), fileno(dst));
+ fclose(src);
+ if (r > 0) {
+ status=0;
+ }
+ }
+ }
+
+ /* Tell the driver we are done messing with firmware */
+ snprintf(temp, PATH_MAX, "/sys%s/loading", env_path);
+ fd = xopen(temp, O_WRONLY);
+ if (status == 0) {
+ /* success -- do an 'echo 0 > /sys/$DEVPATH/loading' */
+ echobuf[0]='0'; echobuf[1]='\n';
+ if (write(fd, echobuf, 2) != 2) {
+ status = 1;
+ //goto endgame;
+ }
+ } else {
+ /* failure -- do an 'echo -1 > /sys/$DEVPATH/loading' */
+ echobuf[0]='-'; echobuf[1]='1'; echobuf[2]='\n';
+ if (write(fd, echobuf, 3) != 3) {
+ status = 1;
+ //goto endgame;
+ }
+ }
+ close(fd);
+ } // firmware
+ } // add action
+ } // hotplug
+
+endgame:
if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);
- return 0;
+ return status;
}
More information about the busybox
mailing list