Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions sys/dev/evdev/evdev_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ static uint16_t evdev_usb_scancodes[256] = {
NONE, NONE, NONE, NONE,
NONE, NONE, NONE, NONE,
/* 0xc0 - 0xdf */
NONE, NONE, NONE, NONE,
NONE, NONE, NONE, NONE,
KEY_BRIGHTNESSDOWN, KEY_BRIGHTNESSUP, KEY_SCALE, KEY_DASHBOARD,
KEY_KBDILLUMDOWN, KEY_KBDILLUMUP, NONE, NONE,
NONE, NONE, NONE, NONE,
NONE, NONE, NONE, NONE,
NONE, NONE, NONE, NONE,
Expand All @@ -108,7 +108,10 @@ static uint16_t evdev_usb_scancodes[256] = {
KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP,
KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT,
KEY_SLEEP, KEY_COFFEE, KEY_REFRESH, KEY_CALC,
NONE, NONE, NONE, NONE,
/* last item maps to APPLE_FN_KEY in hkbd.c. using KEY_WAKEUP instead
* of KEY_FN as evdev translates the latter to too high of a code for
* xkb to parse. */
NONE, NONE, NONE, KEY_WAKEUP,

};

Expand Down
2 changes: 2 additions & 0 deletions sys/dev/hid/hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#define HUP_ARCADE 0x0091
#define HUP_FIDO 0xf1d0
#define HUP_MICROSOFT 0xff00
#define HUP_APPLE 0x00ff
#define HUP_HP 0xff01

/* Usages, generic desktop */
#define HUG_POINTER 0x0001
Expand Down
119 changes: 90 additions & 29 deletions sys/dev/hid/hkbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
static int hkbd_debug = 0;
#endif
static int hkbd_no_leds = 0;
static int hkbd_apple_fn_mode = 0;

static SYSCTL_NODE(_hw_hid, OID_AUTO, hkbd, CTLFLAG_RW, 0, "USB keyboard");
#ifdef HID_DEBUG
Expand All @@ -105,6 +106,8 @@ SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, debug, CTLFLAG_RWTUN,
#endif
SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, no_leds, CTLFLAG_RWTUN,
&hkbd_no_leds, 0, "Disables setting of keyboard leds");
SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, apple_fn_mode, CTLFLAG_RWTUN,
&hkbd_apple_fn_mode, 0, "0 = Fn + F1..12 -> media, 1 = F1..F12 -> media");

#define INPUT_EPOCH global_epoch_preempt

Expand All @@ -126,6 +129,10 @@ SYSCTL_INT(_hw_hid_hkbd, OID_AUTO, no_leds, CTLFLAG_RWTUN,
#define MOD_MIN 0xe0
#define MOD_MAX 0xe7

/* check evdev_usb_scancodes[] for names */
#define APPLE_FN_KEY 0xff
#define APPLE_EJECT_KEY 0xec

struct hkbd_softc {
device_t sc_dev;

Expand Down Expand Up @@ -289,9 +296,9 @@ static const uint8_t hkbd_trtab[256] = {
NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */
NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */
29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */
NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */
NN, NN, NN, NN, 254, NN, NN, NN, /* E8 - EF */
NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */
NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */
NN, NN, NN, NN, NN, NN, NN, 255, /* F8 - FF */
};

static const uint8_t hkbd_boot_desc[] = { HID_KBD_BOOTPROTO_DESCR() };
Expand Down Expand Up @@ -516,13 +523,14 @@ hkbd_interrupt(struct hkbd_softc *sc)
continue;
hkbd_put_key(sc, key | KEY_PRESS);

sc->sc_co_basetime = sbinuptime();
sc->sc_delay = sc->sc_kbd.kb_delay1;
hkbd_start_timer(sc);

/* set repeat time for last key */
sc->sc_repeat_time = now + sc->sc_kbd.kb_delay1;
sc->sc_repeat_key = key;
if (key != APPLE_FN_KEY) {
sc->sc_co_basetime = sbinuptime();
sc->sc_delay = sc->sc_kbd.kb_delay1;
hkbd_start_timer(sc);
/* set repeat time for last key */
sc->sc_repeat_time = now + sc->sc_kbd.kb_delay1;
sc->sc_repeat_key = key;
}
}

/* synchronize old data with new data */
Expand Down Expand Up @@ -623,6 +631,27 @@ hkbd_apple_fn(uint32_t keycode)
}
}

/* separate so the sysctl doesn't butcher non-fn keys */
static uint32_t
hkbd_apple_fn_media(uint32_t keycode)
{
switch (keycode) {
case 0x3a: return 0xc0; /* F1 -> BRIGHTNESS DOWN */
case 0x3b: return 0xc1; /* F2 -> BRIGHTNESS UP */
case 0x3c: return 0xc2; /* F3 -> SCALE (MISSION CTRL)*/
case 0x3d: return 0xc3; /* F4 -> DASHBOARD (LAUNCHPAD) */
case 0x3e: return 0xc4; /* F5 -> KBD BACKLIGHT DOWN */
case 0x3f: return 0xc5; /* F6 -> KBD BACKLIGHT UP */
case 0x40: return 0xEA; /* F7 -> MEDIA PREV */
case 0x41: return 0xE8; /* F8 -> PLAY/PAUSE */
case 0x42: return 0xEB; /* F9 -> MEDIA NEXT */
case 0x43: return 0xEF; /* F10 -> MUTE */
case 0x44: return 0xEE; /* F11 -> VOLUME DOWN */
case 0x45: return 0xED; /* F12 -> VOLUME UP */
default: return keycode;
}
}

static uint32_t
hkbd_apple_swap(uint32_t keycode)
{
Expand Down Expand Up @@ -675,18 +704,30 @@ hkbd_intr_callback(void *context, void *data, hid_size_t len)
/* clear modifiers */
modifiers = 0;

/* scan through HID data */
/* scan through HID data and expose magic apple keys */
if ((sc->sc_flags & HKBD_FLAG_APPLE_EJECT) &&
(id == sc->sc_id_apple_eject)) {
if (hid_get_data(buf, len, &sc->sc_loc_apple_eject))
if (hid_get_data(buf, len, &sc->sc_loc_apple_eject)) {
bit_set(sc->sc_ndata, APPLE_EJECT_KEY);
modifiers |= MOD_EJECT;
} else {
bit_clear(sc->sc_ndata, APPLE_EJECT_KEY);
}
}
if ((sc->sc_flags & HKBD_FLAG_APPLE_FN) &&
(id == sc->sc_id_apple_fn)) {
if (hid_get_data(buf, len, &sc->sc_loc_apple_fn))
if (hid_get_data(buf, len, &sc->sc_loc_apple_fn)) {
bit_set(sc->sc_ndata, APPLE_FN_KEY);
modifiers |= MOD_FN;
} else {
bit_clear(sc->sc_ndata, APPLE_FN_KEY);
}
}

int apply_apple_fn_media = (modifiers & MOD_FN) ? 1 : 0;
if (hkbd_apple_fn_mode) /* toggle from sysctl value */
apply_apple_fn_media = !apply_apple_fn_media;

bit_foreach(sc->sc_loc_key_valid, HKBD_NKEYCODE, i) {
if (id != sc->sc_id_loc_key[i]) {
continue; /* invalid HID ID */
Expand All @@ -710,6 +751,8 @@ hkbd_intr_callback(void *context, void *data, hid_size_t len)
}
if (modifiers & MOD_FN)
key = hkbd_apple_fn(key);
if (apply_apple_fn_media)
key = hkbd_apple_fn_media(key);
if (sc->sc_flags & HKBD_FLAG_APPLE_SWAP)
key = hkbd_apple_swap(key);
if (key == KEY_NONE || key >= HKBD_NKEYCODE)
Expand All @@ -723,6 +766,8 @@ hkbd_intr_callback(void *context, void *data, hid_size_t len)

if (modifiers & MOD_FN)
key = hkbd_apple_fn(key);
if (apply_apple_fn_media)
key = hkbd_apple_fn_media(key);
if (sc->sc_flags & HKBD_FLAG_APPLE_SWAP)
key = hkbd_apple_swap(key);
if (key == KEY_NONE || key == KEY_ERROR || key >= HKBD_NKEYCODE)
Expand Down Expand Up @@ -783,25 +828,41 @@ hkbd_parse_hid(struct hkbd_softc *sc, const uint8_t *ptr, uint32_t len,
sc->sc_kbd_size = hid_report_size_max(ptr, len,
hid_input, &sc->sc_kbd_id);

const struct hid_device_info *hw = hid_get_device_info(sc->sc_dev);

/* investigate if this is an Apple Keyboard */
if (hidbus_locate(ptr, len,
HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT),
hid_input, tlc_index, 0, &sc->sc_loc_apple_eject, &flags,
&sc->sc_id_apple_eject, NULL)) {
if (flags & HIO_VARIABLE)
sc->sc_flags |= HKBD_FLAG_APPLE_EJECT |
HKBD_FLAG_APPLE_SWAP;
DPRINTFN(1, "Found Apple eject-key\n");
}
if (hidbus_locate(ptr, len,
HID_USAGE2(0xFFFF, 0x0003),
hid_input, tlc_index, 0, &sc->sc_loc_apple_fn, &flags,
&sc->sc_id_apple_fn, NULL)) {
if (flags & HIO_VARIABLE)
sc->sc_flags |= HKBD_FLAG_APPLE_FN;
DPRINTFN(1, "Found Apple FN-key\n");
if (hw->idVendor == 0x05ac) { /* belt & braces! */
if (hidbus_locate(ptr, len,
HID_USAGE2(HUP_CONSUMER, HUG_APPLE_EJECT),
hid_input, tlc_index, 0, &sc->sc_loc_apple_eject, &flags,
&sc->sc_id_apple_eject, NULL)) {
if (flags & HIO_VARIABLE)
sc->sc_flags |= HKBD_FLAG_APPLE_EJECT |
HKBD_FLAG_APPLE_SWAP;
DPRINTFN(1, "Found Apple eject-key\n");
}
/* check the same vendor pages that linux does to find the one
* apple uses for the function key. */
static const uint16_t apple_pages[] = {
HUP_APPLE, /* HID_UP_CUSTOM in linux */
HUP_MICROSOFT, /* HID_UP_MSVENDOR in linux */
HUP_HP, /* HID_UP_HPVENDOR2 in linux */
0xFFFF /* Original FreeBSD check (Remove?) */
};
for (int i = 0; i < (int)nitems(apple_pages); i++) {
if (hidbus_locate(ptr, len,
HID_USAGE2(apple_pages[i], 0x0003),
hid_input, tlc_index, 0, &sc->sc_loc_apple_fn, &flags,
&sc->sc_id_apple_fn, NULL)) {
if (flags & HIO_VARIABLE)
sc->sc_flags |= HKBD_FLAG_APPLE_FN;
DPRINTFN(1, "Found Apple FN-key on page 0x%04x\n",
apple_pages[i]);
break;
}
}
}

/* figure out event buffer */
if (hidbus_locate(ptr, len,
HID_USAGE2(HUP_KEYBOARD, 0x00),
Expand Down
Loading