All of lore.kernel.org
 help / color / mirror / Atom feed
From: Piter PUNK <piterpunk@unitednerds.org>
To: linux-hotplug@vger.kernel.org
Subject: [PATCH]: Convert firmware.sh to C
Date: Mon, 09 Nov 2009 03:19:42 +0000	[thread overview]
Message-ID: <4AF78A4E.3080305@unitednerds.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 549 bytes --]

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


[-- Attachment #2: udev_convert-firmware.sh-to-C.patch --]
[-- Type: text/plain, Size: 9234 bytes --]

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 <piterpunk@slackware.com>
+ * 
+ * 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 <sys/utsname.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+#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} <firmware_name> <devpath>\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<ARRAY_SIZE(searchpath);i++) {
+		// The priority is the path with kernel release
+		util_strscpyl(filepath, sizeof(filepath), searchpath[i],
+				kernel.release, "/", firmware, NULL);
+		dbg(udev, "Trying %s\n", filepath);
+		if((fwfile = fopen(filepath, "r"))) {
+			break;
+		} else {
+			// If this fail, without kernel release
+			util_strscpyl(filepath, sizeof(filepath), searchpath[i],
+					firmware, NULL);
+			dbg(udev, "Trying %s\n", filepath);
+			if((fwfile = fopen(filepath, "r"))) {
+				break;
+			};
+		};
+	};
+	if (fwfile == NULL) {
+		err(udev, "Cannot find firmware file %s\n", firmware);
+		// This link indicates the missing firmware file and the associated device
+		do {
+			util_create_path(udev, misspath);
+			udev_selinux_setfscreatecon(udev, misspath, S_IFLNK);
+			retval = symlink(devpath, misspath);
+			if ( retval != 0 )
+				retval = errno;
+			udev_selinux_resetfscreatecon(udev);
+		} while ( retval == ENOENT );
+		retval=1;
+		goto exit;
+	} else {
+		// Pick information about firmware file (we need the file's size)
+		lstat(filepath, &statbuf);
+		// If we find the firmware, remove any existing link about
+		// missing firmware file
+		if (unlink(misspath) == 0)
+			util_delete_path(udev,misspath);
+	};
+
+	// Open target device firmware data file
+	util_strscpyl(filepath, sizeof(filepath), syspath, "/data", NULL);
+	if (!(tgfile = fopen(filepath, "w"))) {
+		err(udev, "Error opening %s file\n", filepath);
+		retval=1;
+		goto exit;
+	};
+
+	util_strscpyl(filepath, sizeof(filepath), syspath, "/loading", NULL);
+
+	// Start "loading" firmware
+	set_loading(filepath, 1, udev);
+
+	// Send firmware file to device
+	if (!(sendfile(fwfile,tgfile,statbuf.st_size,udev))) {
+		err(udev, "Error sending %s to device\n", firmware);
+		set_loading(filepath, -1, udev);
+		retval=1;
+		goto exit;
+	};
+
+	// Close "loading" firmware
+	set_loading(filepath, 0, udev);
+
+exit:
+	udev_unref(udev);
+	udev_log_close();
+	return retval;
+};
diff --git a/extras/firmware/firmware.sh b/extras/firmware/firmware.sh
deleted file mode 100755
index 9d4659a..0000000
--- a/extras/firmware/firmware.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh -e
-
-FIRMWARE_DIRS="/lib/firmware/updates/$(uname -r) /lib/firmware/updates \
-               /lib/firmware/$(uname -r) /lib/firmware"
-
-err() {
-	echo "$@" >&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

             reply	other threads:[~2009-11-09  3:19 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-09  3:19 Piter PUNK [this message]
2009-11-09  3:51 ` [PATCH]: Convert firmware.sh to C Marco d'Itri

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4AF78A4E.3080305@unitednerds.org \
    --to=piterpunk@unitednerds.org \
    --cc=linux-hotplug@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.