Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Dec 2007 10:50:52 +0000
From:      Rui Paulo <rpaulo@fnop.net>
To:        Ed Schouten <ed@fxq.nl>
Cc:        freebsd-usb@freebsd.org
Subject:   Re: USB keyboard translation - Apple hardware
Message-ID:  <86mys0mkmr.wl%rpaulo@fnop.net>
In-Reply-To: <20071224094642.GO1169@hoeg.nl>
References:  <20071224094642.GO1169@hoeg.nl>

next in thread | previous in thread | raw e-mail | index | archive | help
At Mon, 24 Dec 2007 10:46:42 +0100,
Ed Schouten wrote:
> 
> [1  <text/plain; us-ascii (quoted-printable)>]
> Hello everyone,
> 
> One of the things that really made me mad when I got FreeBSD working on
> my Apple MacBook, was that the Fn button on the keyboard doesn't work.
> This means that I don't have the Delete, Page-{Up,Down}, Home and End
> buttons.
> 
> I took a look at kbdmap(1), but it turned out you can't add any new
> modifiers, which is needed in this case, because we have a new Fn
> modifier key. Maybe you could solve this in X, but I also work a lot
> outside of X, so I really want to have the translation to be performed
> everywhere.
> 
> I've written the following patch for ukbd, which adds a method for
> easily adding translation functions to the driver, to remap keys:
> 
> 	http://g-rave.nl/unix/freebsd/freebsd-ukbd-translate.diff
> 
> I tried to keep the code as clean as possible, so I also put some
> #ifdef's around it, so that people who dislike it, can just undef it.
> I've only added the quirks for the Apple MacBook keyboard, but there are
> some other Apple keyboards that have some strange scancodes. I still
> have to add those.
> 
> Any comments so far?

I do like this approach. The Fn key is a special key that needs
special handling, but there seems to be a problem with our USB stack.

The code code to detect the Fn key is:

Index: ukbd.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/ukbd.c,v
retrieving revision 1.75
diff -u -p -r1.75 ukbd.c
--- ukbd.c	5 Nov 2007 19:51:12 -0000	1.75
+++ ukbd.c	17 Dec 2007 21:24:35 -0000
@@ -110,6 +110,9 @@ struct ukbd_data {
 
 typedef struct ukbd_softc {
 	device_t		sc_dev;		/* base device */
+#define UKBD_FN		0x01
+	int			sc_flags;
+	struct hid_location	sc_loc_fn;	/* location of the Fn key */	
 } ukbd_softc_t;
 
 #define	UKBD_CHUNK	128	/* chunk size for read */
@@ -178,6 +181,10 @@ ukbd_attach(device_t self)
 	struct usb_attach_arg *uaa = device_get_ivars(self);
 	usbd_interface_handle iface = uaa->iface;
 	usb_interface_descriptor_t *id;
+	void *desc;
+	int size;
+	usbd_status err;
+	uint32_t flags;
 
 	keyboard_switch_t *sw;
 	keyboard_t *kbd;
@@ -191,6 +198,21 @@ ukbd_attach(device_t self)
 
 	id = usbd_get_interface_descriptor(iface);
 
+	/*
+	 * Locate the Fn key on Apple keyboards.
+	 */
+	err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP);
+	if (err) {
+		device_printf(self, "could not read report descriptor\n");
+		return ENXIO;
+	}
+	if (hid_locate(desc, size, HID_USAGE2(HUP_CUSTOM, HUC_FNKEY),
+		hid_input, &sc->sc_loc_fn, &flags)) {
+		device_printf(self, "Fn key.\n");
+		sc->sc_flags |= UKBD_FN;
+	}
+	free(desc, M_TEMP);
+
 	arg[0] = (void *)uaa;
 	arg[1] = (void *)ukbd_intr;
 	kbd = NULL;
Index: usbhid.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usbhid.h,v
retrieving revision 1.15
diff -u -p -r1.15 usbhid.h
--- usbhid.h	6 Jan 2005 01:43:29 -0000	1.15
+++ usbhid.h	22 Dec 2007 19:18:50 -0000
@@ -94,6 +94,7 @@ typedef struct usb_hid_descriptor {
 #define HUP_SCALE		0x008c
 #define HUP_CAMERA_CONTROL	0x0090
 #define HUP_ARCADE		0x0091
+#define HUP_CUSTOM		0xffff
 #define HUP_MICROSOFT		0xff00
 
 /* Usages, generic desktop */
@@ -165,6 +166,9 @@ typedef struct usb_hid_descriptor {
 #define HUD_ERASER		0x0045
 #define HUD_TABLET_PICK		0x0046
 
+/* Usages custom */
+#define HUC_FNKEY		0x0003
+
 #define HID_USAGE2(p,u) (((p) << 16) | u)
 
 #define UHID_INPUT_REPORT 0x01


But the problem relies in HUP_CUSTOM. Linux seems to be using 0x00ff
instead of 0xffff, but with that value, the Fn key is not detected in
FreeBSD.
Another problem is reading the value of the register. When a
ukbd_intr() occurs, we should be able to read the register, but
somehow it's always 0.

In August, I mailed the original USB stack driver, but he didn't
reply. I'll try to find a solution.

Regards.
--
Rui Paulo



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?86mys0mkmr.wl%rpaulo>