-/* $OpenBSD: ucc.c,v 1.5 2021/08/23 17:50:26 anton Exp $ */
+/* $OpenBSD: ucc.c,v 1.6 2021/08/24 10:53:43 anton Exp $ */
/*
* Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org>
keysym_t *sc_map;
u_int sc_maplen;
u_int sc_mapsiz;
- u_int sc_nkeys;
/* Key mappings used in raw mode. */
const struct ucc_keysym **sc_raw;
- u_int sc_rawlen;
u_int sc_rawsiz;
+ u_int sc_nusages;
+ int sc_isarray;
int sc_mode;
/* Last pressed key. */
void ucc_set_leds(void *, int);
int ucc_ioctl(void *, u_long, caddr_t, int, struct proc *);
-int ucc_parse_hid(struct ucc_softc *, void *, int);
+int ucc_hid_parse(struct ucc_softc *, void *, int);
+int ucc_hid_parse_array(struct ucc_softc *, const struct hid_item *);
+int ucc_add_key(struct ucc_softc *, int32_t, u_int);
int ucc_bit_to_raw(struct ucc_softc *, u_int, u_char *);
int ucc_usage_to_sym(int32_t, const struct ucc_keysym **);
-void ucc_raw_to_scancode(u_char *, int *, u_char, int);
+int ucc_intr_to_usage(u_char *, u_int, int32_t *);
void ucc_input(struct ucc_softc *, u_int, int);
void ucc_rawinput(struct ucc_softc *, u_char, int);
int ucc_setbits(u_char *, int, u_int *);
sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
- error = ucc_parse_hid(sc, desc, size);
+ error = ucc_hid_parse(sc, desc, size);
if (error) {
printf(" hid error %d\n", error);
return;
}
- printf(" %d key%s, %d mapping%s\n",
- sc->sc_nkeys, sc->sc_nkeys == 1 ? "" : "s",
- sc->sc_rawlen, sc->sc_rawlen == 1 ? "" : "s");
+ printf(": %d usage%s, %d key%s, %s\n",
+ sc->sc_nusages, sc->sc_nusages == 1 ? "" : "s",
+ sc->sc_maplen / 2, sc->sc_maplen / 2 == 1 ? "" : "s",
+ sc->sc_isarray ? "array" : "enum");
/* Cannot load an empty map. */
if (sc->sc_maplen > 0)
if (sc->sc_wskbddev != NULL)
error = config_detach(sc->sc_wskbddev, flags);
uhidev_close(&sc->sc_hdev);
- free(sc->sc_map, M_USBDEV, sc->sc_mapsiz);
- free(sc->sc_raw, M_USBDEV, sc->sc_rawsiz);
+ free(sc->sc_map, M_USBDEV, sc->sc_mapsiz * sizeof(*sc->sc_map));
+ free(sc->sc_raw, M_USBDEV, sc->sc_rawsiz * sizeof(*sc->sc_raw));
return error;
}
struct ucc_softc *sc = (struct ucc_softc *)addr;
int raw = sc->sc_mode == WSKBD_RAW;
u_int bit = 0;
+ u_char c = 0;
ucc_dump(__func__, data, len);
}
}
return;
- }
- if (bit >= sc->sc_nkeys)
- goto unknown;
-
- if (raw) {
- u_char c;
+ } else if (sc->sc_isarray) {
+ const struct ucc_keysym *us;
+ int32_t usage;
+ if (ucc_intr_to_usage(data, len, &usage) ||
+ ucc_usage_to_sym(usage, &us))
+ goto unknown;
+ bit = us->us_usage;
+ c = us->us_raw;
+ } else if (raw) {
if (ucc_bit_to_raw(sc, bit, &c))
goto unknown;
+ }
+
+ if (raw) {
if (c != 0) {
ucc_rawinput(sc, c, 0);
sc->sc_last_raw = c;
* report and the corresponding pressed key.
*/
int
-ucc_parse_hid(struct ucc_softc *sc, void *desc, int descsiz)
+ucc_hid_parse(struct ucc_softc *sc, void *desc, int descsiz)
{
struct hid_item hi;
struct hid_data *hd;
- u_int mapsiz, rawsiz;
+ int nsyms = nitems(ucc_keysyms);
int isize;
/*
return ENXIO;
/*
- * Create mapping between each input bit and the corresponding key used
- * in translating mode. Two entries are needed per bit in order
- * construct a mapping.
+ * Create mapping between each input bit and the corresponding usage,
+ * used in translating mode. Two entries are needed per bit in order
+ * construct a mapping. Note that at most all known usages as given by
+ * ucc_keysyms can be inserted into this map.
*/
- mapsiz = isize * 2;
- sc->sc_mapsiz = mapsiz * sizeof(*sc->sc_map);
- sc->sc_map = mallocarray(isize, 2 * sizeof(*sc->sc_map), M_USBDEV,
+ sc->sc_mapsiz = nsyms * 2;
+ sc->sc_map = mallocarray(nsyms, 2 * sizeof(*sc->sc_map), M_USBDEV,
M_WAITOK | M_ZERO);
/*
- * Create mapping between each input bit and the corresponding scan
- * code used in raw mode.
+ * Create mapping between each input bit and the corresponding usage,
+ * used in raw mode.
*/
- rawsiz = isize;
- sc->sc_rawsiz = rawsiz * sizeof(*sc->sc_raw);
+ sc->sc_rawsiz = isize;
sc->sc_raw = mallocarray(isize, sizeof(*sc->sc_raw), M_USBDEV,
M_WAITOK | M_ZERO);
hd = hid_start_parse(desc, descsiz, hid_input);
while (hid_get_item(hd, &hi)) {
- const struct ucc_keysym *us;
- int bit;
+ u_int bit;
+ int error;
- if (HID_GET_USAGE_PAGE(hi.usage) != HUP_CONSUMER ||
- HID_GET_USAGE(hi.usage) == HUC_CONTROL)
+ if (HID_GET_USAGE_PAGE(hi.usage) != HUP_CONSUMER)
continue;
- bit = sc->sc_nkeys++;
- if (ucc_usage_to_sym(HID_GET_USAGE(hi.usage), &us))
+ /*
+ * The usages could be expressed as an array instead of
+ * enumerating all supported ones.
+ */
+ if (HID_GET_USAGE(hi.usage) == HUC_CONTROL) {
+ error = ucc_hid_parse_array(sc, &hi);
+ if (error)
+ return error;
continue;
+ }
- if (sc->sc_maplen + 2 >= mapsiz)
- return ENOMEM;
- sc->sc_map[sc->sc_maplen++] = KS_KEYCODE(bit);
- sc->sc_map[sc->sc_maplen++] = us->us_key;
+ bit = sc->sc_nusages++;
+ error = ucc_add_key(sc, HID_GET_USAGE(hi.usage), bit);
+ if (error)
+ return error;
+ }
+ hid_end_parse(hd);
+
+ return 0;
+}
+
+int
+ucc_hid_parse_array(struct ucc_softc *sc, const struct hid_item *hi)
+{
+ int32_t max, min, usage;
+
+ min = HID_GET_USAGE(hi->usage_minimum);
+ max = HID_GET_USAGE(hi->usage_maximum);
+ if (min < 0 || max < 0 || min >= max)
+ return 0;
+
+ sc->sc_isarray = 1;
- if (bit >= rawsiz)
+ for (usage = min; usage <= max; usage++) {
+ int error;
+
+ sc->sc_nusages++;
+ error = ucc_add_key(sc, usage, 0);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+int
+ucc_add_key(struct ucc_softc *sc, int32_t usage, u_int bit)
+{
+ const struct ucc_keysym *us;
+
+ if (ucc_usage_to_sym(usage, &us))
+ return 0;
+
+ if (sc->sc_maplen + 2 > sc->sc_mapsiz)
+ return ENOMEM;
+ sc->sc_map[sc->sc_maplen++] = KS_KEYCODE(sc->sc_isarray ? usage : bit);
+ sc->sc_map[sc->sc_maplen++] = us->us_key;
+
+ if (!sc->sc_isarray) {
+ if (bit >= sc->sc_rawsiz)
return ENOMEM;
sc->sc_raw[bit] = us;
- sc->sc_rawlen++;
-
- DPRINTF("%s: bit %d, usage %s\n", __func__,
- bit, us->us_name);
}
- hid_end_parse(hd);
+ DPRINTF("%s: bit %d, usage %s\n", __func__,
+ bit, us->us_name);
return 0;
}
int
ucc_bit_to_raw(struct ucc_softc *sc, u_int bit, u_char *raw)
{
- if (bit >= sc->sc_nkeys)
+ if (bit >= sc->sc_rawsiz)
return 1;
*raw = sc->sc_raw[bit]->us_raw;
return 0;
return 1;
}
+int
+ucc_intr_to_usage(u_char *buf, u_int buflen, int32_t *usage)
+{
+ int32_t x = 0;
+ int i;
+
+ if (buflen == 0 || buflen > sizeof(*usage))
+ return 1;
+
+ for (i = buflen - 1; i >= 0; i--) {
+ x |= buf[i];
+ if (i > 0)
+ x <<= 8;
+ }
+ *usage = x;
+ return 0;
+}
+
void
ucc_input(struct ucc_softc *sc, u_int bit, int release)
{