From mboxrd@z Thu Jan 1 00:00:00 1970 From: Piter PUNK Date: Mon, 09 Nov 2009 03:19:42 +0000 Subject: [PATCH]: Convert firmware.sh to C Message-Id: <4AF78A4E.3080305@unitednerds.org> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------060606040907000709040809" List-Id: To: linux-hotplug@vger.kernel.org This is a multi-part message in MIME format. --------------060606040907000709040809 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi, This patch removes firmware.sh and adds a firmware.c to do the same job. The patch also changes 50-firmware.rules to use the new binary (with a bit changed syntax). The binary loads the firmware file to device. If the firmware file isn't found, it creates the a broken symlink under /dev/.udev/firmware, like the shell script does. If in a next load the firmware file is found, the symlink is removed. Many thanks to Kay that helps with fixes and sugestions in this code. Hope I have understand those tips and it is OK now. :) Piter Punk --------------060606040907000709040809 Content-Type: text/plain; name="udev_convert-firmware.sh-to-C.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="udev_convert-firmware.sh-to-C.patch" diff --git a/Makefile.am b/Makefile.am index cf7d364..d1243a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -181,15 +181,9 @@ udev_test_udev_SOURCES = \ udev_test_udev_LDADD = libudev/libudev-private.la # ------------------------------------------------------------------------------ -# firmware.sh - firmware loading -# ------------------------------------------------------------------------------ -dist_libexec_SCRIPTS = extras/firmware/firmware.sh -dist_udevrules_DATA += extras/firmware/50-firmware.rules - -# ------------------------------------------------------------------------------ # rule_generator - persistent network and optical device rule generator # ------------------------------------------------------------------------------ -dist_libexec_SCRIPTS += \ +dist_libexec_SCRIPTS = \ extras/rule_generator/write_cd_rules \ extras/rule_generator/write_net_rules @@ -272,6 +266,14 @@ extras_usb_id_usb_id_LDADD = libudev/libudev-private.la libexec_PROGRAMS += extras/usb_id/usb_id # ------------------------------------------------------------------------------ +# firmware - Firmware loading +# ------------------------------------------------------------------------------ +extras_firmware_firmware_SOURCES = extras/firmware/firmware.c +extras_firmware_firmware_LDADD = libudev/libudev-private.la +libexec_PROGRAMS += extras/firmware/firmware +dist_udevrules_DATA += extras/firmware/50-firmware.rules + +# ------------------------------------------------------------------------------ # v4l_id - video4linux capabilities # ------------------------------------------------------------------------------ extras_v4l_id_v4l_id_SOURCES = extras/v4l_id/v4l_id.c diff --git a/TODO b/TODO index 1f85973..8e34d82 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ - o convert firmware.sh to C o get rid of braindead "scan all devices to find myself" libusb interface if it can not be fixed, drop libusb entirely o drop all support for the DEPRECATED sysfs layout diff --git a/extras/firmware/50-firmware.rules b/extras/firmware/50-firmware.rules index a28e2a8..1a85225 100644 --- a/extras/firmware/50-firmware.rules +++ b/extras/firmware/50-firmware.rules @@ -1,4 +1,4 @@ # do not edit this file, it will be overwritten on update # firmware-class requests, copies files into the kernel -SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware.sh" +SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware -f $env{FIRMWARE} %p" diff --git a/extras/firmware/firmware.c b/extras/firmware/firmware.c new file mode 100644 index 0000000..9c206f3 --- /dev/null +++ b/extras/firmware/firmware.c @@ -0,0 +1,214 @@ +/* + * firmware - Load firmware device + * + * Copyright(c) 2009 - Piter Punk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details:* + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libudev.h" +#include "libudev-private.h" + +int debug; + +static int set_loading(char *loadpath, int flag, struct udev *udev) { + FILE* ldfile; + if (!(ldfile = fopen(loadpath, "w"))) { + err(udev, "Error opening %s file\n", loadpath); + return 1; + }; + + if (flag) { + fprintf(ldfile, "1\n"); + } else { + fprintf(ldfile, "0\n"); + } + fclose(ldfile); +} + +static int sendfile(FILE *source, FILE *target, int len, struct udev *udev) { + char *buf; + + // Allocate a buffer to put source file + buf = calloc(len + 1, sizeof(char)); + if (buf == NULL) { + err(udev,"No memory available to load firmware file"); + fclose(target); + fclose(source); + return 0; + } + + // Copy file the buffer will be freed on process termination + fread(buf, len, 1, source); + fwrite(buf, len, 1, target); + + fclose(target); + fclose(source); + return 1; +} + +static int usage() { + fprintf(stderr,"Usage: firmware [--debug|-d] {--firmware|-f} \n" + " firmware {--help|-h}\n\n"); +}; + +int main(int argc, char **argv) { + static const struct option options[] = { + { "firmware", required_argument, NULL, 'f' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + static const char *searchpath[] = { + "/lib/firmware/updates/", + "/lib/firmware/" + }; + char syspath[UTIL_PATH_SIZE], filepath[UTIL_PATH_SIZE], misspath[UTIL_PATH_SIZE]; + char *devpath = NULL, *firmware = NULL; + FILE *fwfile; + FILE *tgfile; + struct utsname kernel; + struct stat statbuf; + struct udev *udev; + struct udev_device *dev = NULL; + int i, retval=0; + + udev = udev_new(); + if (udev == NULL) { + retval=1; + goto exit; + }; + + udev_log_init("firmware"); + + while (1) { + int option; + + option = getopt_long(argc, argv, "f:dh", options, NULL); + if (option == -1) + break; + + switch (option) { + case 'd': + debug = 1; + if (udev_get_log_priority(udev) < LOG_INFO) + udev_set_log_priority(udev, LOG_INFO); + break; + case 'f': + firmware = optarg; + break; + case 'h': + usage(); + default: + retval=1; + goto exit; + } + } + + if ( argc < 4 ) { + usage(); + retval=1; + goto exit; + } + + uname(&kernel); + devpath = argv[optind]; + + util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL); + dev = udev_device_new_from_syspath(udev, syspath); + if (dev == NULL) { + err(udev, "Unable to access '%s'\n", devpath); + retval=1; + goto exit; + } + + // Directory and symlink to be created if firmware is missing + util_path_encode(firmware, filepath, sizeof(filepath)); + util_strscpyl(misspath, sizeof(misspath), udev_get_dev_path(udev), + "/.udev/firmware-missing/", filepath, NULL); + + // Trying to open firmware file + for (i=0;i&2 - logger -t "${0##*/}[$$]" "$@" 2>/dev/null || true -} - -if [ ! -e /sys$DEVPATH/loading ]; then - err "udev firmware loader misses sysfs directory" - exit 1 -fi - -for DIR in $FIRMWARE_DIRS; do - [ -e "$DIR/$FIRMWARE" ] || continue - echo 1 > /sys$DEVPATH/loading - cat "$DIR/$FIRMWARE" > /sys$DEVPATH/data - echo 0 > /sys$DEVPATH/loading - exit 0 -done - -echo -1 > /sys$DEVPATH/loading -err "Cannot find firmware file '$FIRMWARE'" -mkdir -p /dev/.udev/firmware-missing -file=$(echo "$FIRMWARE" | sed 's:/:\\x2f:g') -ln -s -f "$DEVPATH" /dev/.udev/firmware-missing/$file -exit 1 --------------060606040907000709040809--