Re: udev keymaps: support for force_release quirk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 27, 2009 at 04:57:48PM +0100, Martin Pitt wrote:
> Johannes Stezenbach [2009-11-27 16:48 +0100]:
> > I simply don't know if at does harm to apply the force_release quirk
> > to the other models which share samsung-other.
> 
> I don't know for sure either, but if it was harmless, the kernel could
> just unconditionally do it for all keys and not bother about this
> mechanism at all. So I guess it is important after all.
> 
> > Another solution than the proposed -f switch would be to copy
> > samsung-other to samsung-other-force-release and add the
> > force_release flag only to the latter.
> 
> Right, that's what I had in mind.

Below is a first cut. It works but it has the following
potential problems:

- I used %n in sscanf even though the man page warns:

  "The  C  standard says:  "Execution  of  a %n directive
  does not increment the assignment count returned at the
  completion of execution" but the Corrigendum seems to
  contradict this.  Probably it  is  wise not to make any
  assumptions on the effect of %n conversions on the return value."
  http://www.kernel.org/doc/man-pages/online/pages/man3/sscanf.3.html

  But IMHO the C standard (C99 as well as N1336) is pretty
  clear. I've no idea if all libcs implement it correctly
  though. It works with glibc.

- For the force_release attribute we need DEVPATH.
  I used getenv() and added a hardcoded /sys prefix
  (like done e.g. in input_id.c or firmware.sh).
  Alternatively we could pass $sys$devpath on the
  commandline. Or we could use libudev.

- To get from the DEVPATH to the force_release attribute
  we need to go two parents up. I just used the
  "device" symlinks:
    DEVPATH:  eventX
    DEVPATH/device: inputX
    DEVPATH/device/device: serioY
    (e.g. /sys/devices/platform/i8042/serio0/input/input2/event2/device/device/)
  Alternatively we could use udev_device_get_parent()
  from libudev.

- For setting the force_release attr I did not bother to
  parse the previous setting. I just add potential new
  scancodes and let the kernel sort it out.

Let me know what you think.


Thanks
Johannes

diff --git a/extras/keymap/keymap.c b/extras/keymap/keymap.c
index b565c33..0a5523b 100644
--- a/extras/keymap/keymap.c
+++ b/extras/keymap/keymap.c
@@ -41,6 +41,86 @@ const struct key* lookup_key (const char *str, unsigned int len);
 
 #define MAX_SCANCODES 1024
 
+static int n_quirks, n_quirks_alloc;
+static int *quirks;
+
+static void add_force_release_quirk(int scancode)
+{
+	if (n_quirks >= n_quirks_alloc) {
+		n_quirks_alloc = n_quirks_alloc ? n_quirks_alloc * 2 : 32;
+		quirks = realloc(quirks, n_quirks_alloc);
+		if (!quirks) {
+			fprintf(stderr, "error: cannot allocate %d bytes\n", n_quirks_alloc);
+			exit(1);
+		}
+	}
+	quirks[n_quirks++] = scancode;
+}
+
+static int force_relase_attr_open(void)
+{
+	int fd;
+	char fn[PATH_MAX], *env;
+
+	strcpy(fn, "/sys");
+	env = getenv("DEVPATH");
+	if (!env) {
+		fprintf(stderr, "error: DEVPATH not set\n");
+		return -1;
+	}
+	strncat(fn, env, sizeof(fn));
+	strncat(fn, "/device/device/force_release", sizeof(fn));
+
+	if ((fd = open(fn, O_RDWR)) < 0) {
+		fprintf(stderr, "error: open('%s'): %m\n", fn);
+		return -1;
+	}
+	return fd;
+}
+
+static int set_quirks(void)
+{
+	int q, fd, bytes;
+	size_t i;
+	char force_release[1024], scancode[20];;
+
+	if (!n_quirks)
+		return 0;
+
+	fd = force_relase_attr_open();
+	if (fd == -1)
+		return -1;
+	bytes = read(fd, force_release, sizeof(force_release) - 1);
+	if (bytes == -1) {
+		fprintf(stderr, "error: read force_release attribute %m\n");
+		close(fd);
+		return -1;
+	}
+	i = bytes;
+	force_release[i] = '\0';
+	if (i && force_release[i - 1] == '\n')
+		force_release[--i] = '\0';
+	fprintf(stderr, "info: old force_release attribute '%s'\n", force_release);
+	for (q = 0; q < n_quirks; q++) {
+		fprintf(stderr, "adding force_release quirk for scancode %d\n", quirks[q]);
+		if (i && (i + 2 < sizeof(force_release)))
+			strcat(force_release + i++, ",");
+		snprintf(scancode, sizeof(scancode), "%d", quirks[q]);
+		strncat(force_release + i, scancode, sizeof(force_release) - i);
+		i += strlen(scancode);
+	}
+	fprintf(stderr, "info: new force_release attribute '%*s'\n", i, force_release);
+	lseek(fd, 0, SEEK_SET);
+	bytes = write(fd, force_release, i);
+	if (bytes == -1) {
+		fprintf(stderr, "error: write force_release attribute %m\n");
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
 static int evdev_open(const char *dev)
 {
 	int fd;
@@ -194,8 +274,8 @@ static int merge_table(int fd, const char *filename) {
 	}
 
 	while (!feof(f)) {
-		char s[256], *p;
-		int scancode, new_keycode, old_keycode;
+		char s[256], flags[100], *p;
+		int scancode, new_keycode, old_keycode, n;
 
 		if (!fgets(s, sizeof(s), f))
 			break;
@@ -205,11 +285,11 @@ static int merge_table(int fd, const char *filename) {
 		if (*p == '#' || *p == '\n')
 			continue;
 
-		if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) {
+		if (sscanf(p, "%i %i %n", &scancode, &new_keycode, &n) != 2) {
 			char t[105] = "KEY_UNKNOWN";
 			const struct key *k;
 
-			if (sscanf(p, "%i %100s", &scancode, t+4) != 2) {
+			if (sscanf(p, "%i %100s %n", &scancode, t+4, &n) != 2) {
 				fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line);
 				r = -1;
 				continue;
@@ -224,6 +304,10 @@ static int merge_table(int fd, const char *filename) {
 			new_keycode = k->id;
 		}
 
+		if (sscanf(p+n, "%99s", flags) == 1) {
+			if (strcmp(flags, "force_release") == 0)
+				add_force_release_quirk(scancode);
+		}
 
 		if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) {
 			r = -1;
@@ -369,6 +453,7 @@ int main(int argc, char **argv)
 	/* two arguments (device, mapfile): set map file */
 	if (argc == optind+2) {
 		merge_table(fd, default_keymap_path(argv[optind+1]));
+		set_quirks();
 		return 0;
 	}
 
diff --git a/extras/keymap/keymaps/samsung-other-force-release b/extras/keymap/keymaps/samsung-other-force-release
new file mode 100644
index 0000000..67decb2
--- /dev/null
+++ b/extras/keymap/keymaps/samsung-other-force-release
@@ -0,0 +1,14 @@
+0x74 prog1 # User key
+0x75 www
+0x78 mail
+0x82 switchvideomode force_release # Fn+F4 CRT/LCD (high keycode: "displaytoggle")
+0x83 battery force_release # Fn+F2
+0x84 prog1 force_release # Fn+F5 backlight on/off
+0x86 wlan force_release # Fn+F9
+0x88 brightnessup force_release # Fn-Up
+0x89 brightnessdown force_release # Fn-Down
+0xB1 prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice)
+0xB3 prog3 force_release # Fn+F8 switch power mode (battery/dynamic/performance)
+0xB4 wlan # Fn+F9 (X60P)
+0xF7 f22 force_release # Fn+F10 Touchpad on
+0xF9 f22 force_release # Fn+F10 Touchpad off
--
To unsubscribe from this list: send the line "unsubscribe linux-hotplug" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Linux DVB]     [Asterisk Internet PBX]     [DCCP]     [Netdev]     [X.org]     [Util Linux NG]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux