1From e415372cc7a2f52e70e1cfa8c6c1f633b411355d Mon Sep 17 00:00:00 2001 2From: Lauren Post <lauren.post@nxp.com> 3Date: Wed, 8 Jun 2016 06:51:56 -0500 4Subject: [PATCH] Revert "udev: remove userspace firmware loading support" 5 6This reverts commit 3b717594600fa717cdf9bcfd0c7c1b703b245482. 7 8Conflicts: 9 configure.ac 10 src/udev/udevd.c 11 12Upstream-Status: Inappropriate [OE specific] 13 14Signed-off-by: Lauren Post <lauren.post@nxp.com> 15--- 16 configure.ac | 39 +++++++++- 17 rules/Makefile.am | 5 ++ 18 src/udev/Makefile.am | 10 +++ 19 src/udev/udev-builtin-firmware.c | 154 +++++++++++++++++++++++++++++++++++++++ 20 src/udev/udev-builtin.c | 3 + 21 src/udev/udev.h | 6 ++ 22 src/udev/udevd.c | 13 ++++ 23 7 files changed, 227 insertions(+), 3 deletions(-) 24 create mode 100644 src/udev/udev-builtin-firmware.c 25 26diff --git a/configure.ac b/configure.ac 27index 8691891..65028c2 100644 28--- a/configure.ac 29+++ b/configure.ac 30@@ -238,9 +238,42 @@ AC_CHECK_DECL([unshare], 31 [#include <sched.h>]) 32 33 # ------------------------------------------------------------------------------ 34-AC_PATH_TOOL(GPERF, gperf) 35-if test -z "$GPERF" ; then 36- AC_MSG_ERROR([*** gperf not found]) 37+AC_ARG_WITH(firmware-path, 38+ AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]], 39+ [Firmware search path (default=ROOTPREFIX/lib/firmware/updates:ROOTPREFIX/lib/firmware)]), 40+ [], [with_firmware_path="$rootprefix/lib/firmware/updates:$rootprefix/lib/firmware"]) 41+OLD_IFS=$IFS 42+IFS=: 43+for i in $with_firmware_path; do 44+ if test "x${FIRMWARE_PATH}" = "x"; then 45+ FIRMWARE_PATH="\\\"${i}/\\\"" 46+ else 47+ FIRMWARE_PATH="${FIRMWARE_PATH}, \\\"${i}/\\\"" 48+ fi 49+done 50+IFS=$OLD_IFS 51+AC_SUBST(FIRMWARE_PATH) 52+AS_IF([test "x${FIRMWARE_PATH}" != "x"], [ AC_DEFINE(HAVE_FIRMWARE, 1, [Define if FIRMWARE is available]) ]) 53+AM_CONDITIONAL(ENABLE_FIRMWARE, [test "x${FIRMWARE_PATH}" != "x"]) 54+ 55+# ------------------------------------------------------------------------------ 56+AC_ARG_ENABLE([gudev], 57+ AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]), 58+ [], [enable_gudev=yes]) 59+AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0]) ]) 60+AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"]) 61+ 62+# ------------------------------------------------------------------------------ 63+AC_ARG_ENABLE([keymap], 64+ AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]), 65+ [], [enable_keymap=yes]) 66+ 67+if test "x$enable_keymap" = "xyes"; then 68+ AC_PATH_TOOL(GPERF, gperf) 69+ if test -z "$GPERF" ; then 70+ AC_MSG_ERROR([*** gperf not found]) 71+ fi 72+ AC_DEFINE([ENABLE_KEYMAP], [1], [Define if we are enabling rule generator]) 73 fi 74 75 # ------------------------------------------------------------------------------ 76diff --git a/rules/Makefile.am b/rules/Makefile.am 77index 24c099c..d714ae3 100644 78--- a/rules/Makefile.am 79+++ b/rules/Makefile.am 80@@ -22,6 +22,11 @@ dist_udevrules_DATA += \ 81 80-net-name-slot.rules 82 endif 83 84+if ENABLE_FIRMWARE 85+dist_udevrules_DATA += \ 86+ 50-firmware.rules 87+endif 88+ 89 if HAVE_BLKID 90 dist_udevrules_DATA += \ 91 60-persistent-storage.rules 92diff --git a/src/udev/Makefile.am b/src/udev/Makefile.am 93index 401af01..742fbc8 100644 94--- a/src/udev/Makefile.am 95+++ b/src/udev/Makefile.am 96@@ -53,12 +53,18 @@ libudev_core_la_SOURCES = \ 97 udev-ctrl.c \ 98 udev-builtin.c \ 99 udev-builtin-btrfs.c \ 100+ udev-builtin-firmware.c \ 101 udev-builtin-hwdb.c \ 102 udev-builtin-input_id.c \ 103 udev-builtin-net_id.c \ 104 udev-builtin-path_id.c \ 105 udev-builtin-usb_id.c 106 107+if ENABLE_FIRMWARE 108+libudev_core_la_SOURCES += \ 109+ udev-builtin-firmware.c 110+endif 111+ 112 include_HEADERS = \ 113 udev.h 114 115@@ -86,6 +92,10 @@ libudev_core_la_LIBADD += \ 116 $(KMOD_LIBS) 117 endif 118 119+libudev_core_la_CPPFLAGS = \ 120+ $(AM_CPPFLAGS) \ 121+ -DFIRMWARE_PATH="$(FIRMWARE_PATH)" 122+ 123 # 124 # Extras 125 # 126diff --git a/src/udev/udev-builtin-firmware.c b/src/udev/udev-builtin-firmware.c 127new file mode 100644 128index 0000000..bd8c2fb 129--- /dev/null 130+++ b/src/udev/udev-builtin-firmware.c 131@@ -0,0 +1,154 @@ 132+/* 133+ * firmware - Kernel firmware loader 134+ * 135+ * Copyright (C) 2009 Piter Punk <piterpunk@slackware.com> 136+ * Copyright (C) 2009-2011 Kay Sievers <kay@vrfy.org> 137+ * 138+ * This program is free software; you can redistribute it and/or 139+ * modify it under the terms of the GNU General Public License as 140+ * published by the Free Software Foundation; either version 2 of the 141+ * License, or (at your option) any later version. 142+ * 143+ * This program is distributed in the hope that it will be useful, but 144+ * WITHOUT ANY WARRANTY; without even the implied warranty of 145+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 146+ * General Public License for more details:* 147+ */ 148+ 149+#include <unistd.h> 150+#include <stdlib.h> 151+#include <string.h> 152+#include <stdio.h> 153+#include <getopt.h> 154+#include <errno.h> 155+#include <stdbool.h> 156+#include <sys/utsname.h> 157+#include <sys/stat.h> 158+ 159+#include "udev.h" 160+ 161+static bool set_loading(struct udev *udev, char *loadpath, const char *state) { 162+ FILE *ldfile; 163+ 164+ ldfile = fopen(loadpath, "we"); 165+ if (ldfile == NULL) { 166+ log_error("error: can not open '%s'", loadpath); 167+ return false; 168+ }; 169+ fprintf(ldfile, "%s\n", state); 170+ fclose(ldfile); 171+ return true; 172+} 173+ 174+static bool copy_firmware(struct udev *udev, const char *source, const char *target, size_t size) { 175+ char *buf; 176+ FILE *fsource = NULL, *ftarget = NULL; 177+ bool ret = false; 178+ 179+ buf = malloc(size); 180+ if (buf == NULL) { 181+ log_error("No memory available to load firmware file"); 182+ return false; 183+ } 184+ 185+ log_debug("writing '%s' (%zi) to '%s'", source, size, target); 186+ 187+ fsource = fopen(source, "re"); 188+ if (fsource == NULL) 189+ goto exit; 190+ ftarget = fopen(target, "we"); 191+ if (ftarget == NULL) 192+ goto exit; 193+ if (fread(buf, size, 1, fsource) != 1) 194+ goto exit; 195+ if (fwrite(buf, size, 1, ftarget) == 1) 196+ ret = true; 197+exit: 198+ if (ftarget != NULL) 199+ fclose(ftarget); 200+ if (fsource != NULL) 201+ fclose(fsource); 202+ free(buf); 203+ return ret; 204+} 205+ 206+static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test) { 207+ struct udev *udev = udev_device_get_udev(dev); 208+ static const char *searchpath[] = { FIRMWARE_PATH }; 209+ char loadpath[UTIL_PATH_SIZE]; 210+ char datapath[UTIL_PATH_SIZE]; 211+ char fwpath[UTIL_PATH_SIZE]; 212+ const char *firmware; 213+ FILE *fwfile = NULL; 214+ struct utsname kernel; 215+ struct stat statbuf; 216+ unsigned int i; 217+ int rc = EXIT_SUCCESS; 218+ 219+ firmware = udev_device_get_property_value(dev, "FIRMWARE"); 220+ if (firmware == NULL) { 221+ log_error("firmware parameter missing"); 222+ rc = EXIT_FAILURE; 223+ goto exit; 224+ } 225+ 226+ /* lookup firmware file */ 227+ uname(&kernel); 228+ for (i = 0; i < ELEMENTSOF(searchpath); i++) { 229+ strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL); 230+ fwfile = fopen(fwpath, "re"); 231+ if (fwfile != NULL) 232+ break; 233+ 234+ strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL); 235+ fwfile = fopen(fwpath, "re"); 236+ if (fwfile != NULL) 237+ break; 238+ } 239+ 240+ strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL); 241+ 242+ if (fwfile == NULL) { 243+ log_debug("did not find firmware file '%s'", firmware); 244+ rc = EXIT_FAILURE; 245+ /* 246+ * Do not cancel the request in the initrd, the real root might have 247+ * the firmware file and the 'coldplug' run in the real root will find 248+ * this pending request and fulfill or cancel it. 249+ * */ 250+ if (!in_initrd()) 251+ set_loading(udev, loadpath, "-1"); 252+ goto exit; 253+ } 254+ 255+ if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) { 256+ if (!in_initrd()) 257+ set_loading(udev, loadpath, "-1"); 258+ rc = EXIT_FAILURE; 259+ goto exit; 260+ } 261+ 262+ if (!set_loading(udev, loadpath, "1")) 263+ goto exit; 264+ 265+ strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL); 266+ if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) { 267+ log_error("error sending firmware '%s' to device", firmware); 268+ set_loading(udev, loadpath, "-1"); 269+ rc = EXIT_FAILURE; 270+ goto exit; 271+ }; 272+ 273+ set_loading(udev, loadpath, "0"); 274+exit: 275+ if (fwfile) 276+ fclose(fwfile); 277+ return rc; 278+} 279+ 280+const struct udev_builtin udev_builtin_firmware = { 281+ .name = "firmware", 282+ .cmd = builtin_firmware, 283+ .help = "kernel firmware loader", 284+ .run_once = true, 285+}; 286diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c 287index 74b3bdc..3657106 100644 288--- a/src/udev/udev-builtin.c 289+++ b/src/udev/udev-builtin.c 290@@ -34,6 +34,9 @@ static const struct udev_builtin *builtins[] = { 291 [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid, 292 #endif 293 [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs, 294+#ifdef HAVE_FIRMWARE 295+ [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware, 296+#endif 297 [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb, 298 [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id, 299 [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard, 300diff --git a/src/udev/udev.h b/src/udev/udev.h 301index 198cb2c..01a1e9c 100644 302--- a/src/udev/udev.h 303+++ b/src/udev/udev.h 304@@ -149,6 +149,9 @@ enum udev_builtin_cmd { 305 UDEV_BUILTIN_BLKID, 306 #endif 307 UDEV_BUILTIN_BTRFS, 308+#ifdef HAVE_FIRMWARE 309+ UDEV_BUILTIN_FIRMWARE, 310+#endif 311 UDEV_BUILTIN_HWDB, 312 UDEV_BUILTIN_INPUT_ID, 313 UDEV_BUILTIN_KEYBOARD, 314@@ -173,6 +176,9 @@ struct udev_builtin { 315 extern const struct udev_builtin udev_builtin_blkid; 316 #endif 317 extern const struct udev_builtin udev_builtin_btrfs; 318+#ifdef HAVE_FIRMWARE 319+extern const struct udev_builtin udev_builtin_firmware; 320+#endif 321 extern const struct udev_builtin udev_builtin_hwdb; 322 extern const struct udev_builtin udev_builtin_input_id; 323 extern const struct udev_builtin udev_builtin_keyboard; 324diff --git a/src/udev/udevd.c b/src/udev/udevd.c 325index b1de97a..35655d8 100644 326--- a/src/udev/udevd.c 327+++ b/src/udev/udevd.c 328@@ -101,6 +101,9 @@ struct event { 329 bool is_block; 330 usec_t start_usec; 331 bool warned; 332+#ifdef HAVE_FIRMWARE 333+ bool nodelay; 334+#endif 335 }; 336 337 static inline struct event *node_to_event(struct udev_list_node *node) { 338@@ -491,6 +494,10 @@ static int event_queue_insert(struct udev_device *dev) { 339 event->devnum = udev_device_get_devnum(dev); 340 event->is_block = streq("block", udev_device_get_subsystem(dev)); 341 event->ifindex = udev_device_get_ifindex(dev); 342+#ifdef HAVE_FIRMWARE 343+ if (streq(udev_device_get_subsystem(dev), "firmware")) 344+ event->nodelay = true; 345+#endif 346 347 log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev), 348 udev_device_get_action(dev), udev_device_get_subsystem(dev)); 349@@ -566,6 +573,12 @@ static bool is_devpath_busy(struct event *event) { 350 return true; 351 } 352 353+#ifdef HAVE_FIRMWARE 354+ /* allow to bypass the dependency tracking */ 355+ if (event->nodelay) 356+ continue; 357+#endif 358+ 359 /* parent device event found */ 360 if (event->devpath[common] == '/') { 361 event->delaying_seqnum = loop_event->seqnum; 362-- 3631.9.1 364 365