const char * ukbd_parse_desc(struct ukbd_softc *sc) { struct hid_data *d; struct hid_item h; int size; void *desc; int imod; uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); imod = 0; sc->sc_nkeycode = 0; d = hid_start_parse(desc, size, hid_input); while (hid_get_item(d, &h)) { /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n", h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/ if (h.kind != hid_input || (h.flags & HIO_CONST) || HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || h.report_ID != sc->sc_hdev.sc_report_id) continue; DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d " "cnt=%d\n", imod, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); if (h.flags & HIO_VARIABLE) { if (h.loc.size != 1) return ("bad modifier size"); /* Single item */ if (imod < MAXMOD) { sc->sc_modloc[imod] = h.loc; sc->sc_mods[imod].mask = 1 << imod; sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); imod++; } else return ("too many modifier keys"); } else { /* Array */ if (h.loc.size != 8) return ("key code size != 8"); if (h.loc.count > MAXKEYCODE) return ("too many key codes"); if (h.loc.pos % 8 != 0) return ("key codes not on byte boundary"); if (sc->sc_nkeycode != 0) return ("multiple key code arrays\n"); sc->sc_keycodeloc = h.loc; sc->sc_nkeycode = h.loc.count; } } sc->sc_nmod = imod; hid_end_parse(d); hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL); hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL); hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL); return (NULL); }
static const char * btkbd_parse_desc(struct btkbd_softc *sc, int id, const void *desc, int dlen) { struct hid_data *d; struct hid_item h; int imod; imod = 0; sc->sc_nkeycode = 0; d = hid_start_parse(desc, dlen, hid_input); while (hid_get_item(d, &h)) { if (h.kind != hid_input || (h.flags & HIO_CONST) || HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || h.report_ID != id) continue; if (h.flags & HIO_VARIABLE) { if (h.loc.size != 1) return ("bad modifier size"); /* Single item */ if (imod < MAXMOD) { sc->sc_modloc[imod] = h.loc; sc->sc_mods[imod].mask = 1 << imod; sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); imod++; } else return ("too many modifier keys"); } else { /* Array */ if (h.loc.size != 8) return ("key code size != 8"); if (h.loc.count > MAXKEYCODE) return ("too many key codes"); if (h.loc.pos % 8 != 0) return ("key codes not on byte boundary"); if (sc->sc_nkeycode != 0) return ("multiple key code arrays\n"); sc->sc_keycodeloc = h.loc; sc->sc_nkeycode = h.loc.count; } } sc->sc_nmod = imod; hid_end_parse(d); hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), id, hid_output, &sc->sc_numloc, NULL); hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), id, hid_output, &sc->sc_capsloc, NULL); hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), id, hid_output, &sc->sc_scroloc, NULL); return (NULL); }
int hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks, int id, void *desc, int dlen) { struct hid_item h; struct hid_data *d; uint32_t flags; int i, wheel, twheel; ms->sc_device = self; ms->sc_rawmode = 1; ms->sc_flags = quirks; if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), id, hid_input, &ms->sc_loc_x, &flags)) { printf("\n%s: mouse has no X report\n", self->dv_xname); return ENXIO; } switch(flags & MOUSE_FLAGS_MASK) { case 0: ms->sc_flags |= HIDMS_ABSX; break; case HIO_RELATIVE: break; default: printf("\n%s: X report 0x%04x not supported\n", self->dv_xname, flags); return ENXIO; } if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), id, hid_input, &ms->sc_loc_y, &flags)) { printf("\n%s: mouse has no Y report\n", self->dv_xname); return ENXIO; } switch(flags & MOUSE_FLAGS_MASK) { case 0: ms->sc_flags |= HIDMS_ABSY; break; case HIO_RELATIVE: break; default: printf("\n%s: Y report 0x%04x not supported\n", self->dv_xname, flags); return ENXIO; } /* * Try to guess the Z activator: check WHEEL, TWHEEL, and Z, * in that order. */ wheel = hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), id, hid_input, &ms->sc_loc_z, &flags); if (wheel == 0) twheel = hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL), id, hid_input, &ms->sc_loc_z, &flags); else twheel = 0; if (wheel || twheel) { if (NOTMOUSE(flags)) { DPRINTF(("\n%s: Wheel report 0x%04x not supported\n", self->dv_xname, flags)); ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ } else { ms->sc_flags |= HIDMS_Z; /* Wheels need the Z axis reversed. */ ms->sc_flags ^= HIDMS_REVZ; } /* * We might have both a wheel and Z direction; in this case, * report the Z direction on the W axis. * * Otherwise, check for a W direction as an AC Pan input used * on some newer mice. */ if (hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id, hid_input, &ms->sc_loc_w, &flags)) { if (NOTMOUSE(flags)) { DPRINTF(("\n%s: Z report 0x%04x not supported\n", self->dv_xname, flags)); /* Bad Z coord, ignore it */ ms->sc_loc_w.size = 0; } else ms->sc_flags |= HIDMS_W; } else if (hid_locate(desc, dlen, HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), id, hid_input, &ms->sc_loc_w, &flags)) { ms->sc_flags |= HIDMS_W; } } else if (hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id, hid_input, &ms->sc_loc_z, &flags)) { if (NOTMOUSE(flags)) { DPRINTF(("\n%s: Z report 0x%04x not supported\n", self->dv_xname, flags)); ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ } else { ms->sc_flags |= HIDMS_Z; } } /* * The Microsoft Wireless Intellimouse 2.0 reports its wheel * using 0x0048 (I've called it HUG_TWHEEL) and seems to expect * us to know that the byte after the wheel is the tilt axis. * There are no other HID axis descriptors other than X, Y and * TWHEEL, so we report TWHEEL on the W axis. */ if (twheel) { ms->sc_loc_w = ms->sc_loc_z; ms->sc_loc_w.pos = ms->sc_loc_w.pos + 8; ms->sc_flags |= HIDMS_W | HIDMS_LEADINGBYTE; /* Wheels need their axis reversed. */ ms->sc_flags ^= HIDMS_REVW; } /* figure out the number of buttons */ for (i = 1; i <= MAX_BUTTONS; i++) if (!hid_locate(desc, dlen, HID_USAGE2(HUP_BUTTON, i), id, hid_input, &ms->sc_loc_btn[i - 1], NULL)) break; ms->sc_num_buttons = i - 1; if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH), id, hid_input, &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){ ms->sc_flags |= HIDMS_TIP; ms->sc_num_buttons++; } if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_ERASER), id, hid_input, &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){ ms->sc_flags |= HIDMS_ERASER; ms->sc_num_buttons++; } if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS, HUD_BARREL_SWITCH), id, hid_input, &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){ ms->sc_flags |= HIDMS_BARREL; ms->sc_num_buttons++; } /* * The Microsoft Wireless Notebook Optical Mouse seems to be in worse * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and * all of its other button positions are all off. It also reports that * it has two addional buttons and a tilt wheel. */ if (ms->sc_flags & HIDMS_MS_BAD_CLASS) { /* HIDMS_LEADINGBYTE cleared on purpose */ ms->sc_flags = HIDMS_Z | HIDMS_SPUR_BUT_UP; ms->sc_num_buttons = 3; /* XXX change sc_hdev isize to 5? */ /* 1st byte of descriptor report contains garbage */ ms->sc_loc_x.pos = 16; ms->sc_loc_y.pos = 24; ms->sc_loc_z.pos = 32; ms->sc_loc_btn[0].pos = 8; ms->sc_loc_btn[1].pos = 9; ms->sc_loc_btn[2].pos = 10; } /* Parse descriptors to get touch panel bounds */ d = hid_start_parse(desc, dlen, hid_input); while (hid_get_item(d, &h)) { if (h.kind != hid_input || HID_GET_USAGE_PAGE(h.usage) != HUP_GENERIC_DESKTOP) continue; DPRINTF(("hidms: usage=0x%x range %d..%d\n", h.usage, h.logical_minimum, h.logical_maximum)); switch (HID_GET_USAGE(h.usage)) { case HUG_X: if (ms->sc_flags & HIDMS_ABSX) { ms->sc_tsscale.minx = h.logical_minimum; ms->sc_tsscale.maxx = h.logical_maximum; } break; case HUG_Y: if (ms->sc_flags & HIDMS_ABSY) { ms->sc_tsscale.miny = h.logical_minimum; ms->sc_tsscale.maxy = h.logical_maximum; } break; } } hid_end_parse(d); return 0; }
Static void uts_attach(device_t parent, device_t self, void *aux) { struct uts_softc *sc = device_private(self); struct uhidev_attach_arg *uha = aux; struct wsmousedev_attach_args a; int size; void *desc; uint32_t flags; struct hid_data * d; struct hid_item item; aprint_naive("\n"); sc->sc_hdev.sc_dev = self; sc->sc_hdev.sc_intr = uts_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; uhidev_get_report_desc(uha->parent, &desc, &size); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); /* requires HID usage Generic_Desktop:X */ if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), uha->reportid, hid_input, &sc->sc_loc_x, &flags)) { aprint_error_dev(sc->sc_hdev.sc_dev, "touchscreen has no X report\n"); return; } switch (flags & TSCREEN_FLAGS_MASK) { case 0: sc->flags |= UTS_ABS; break; case HIO_RELATIVE: break; default: aprint_error_dev(sc->sc_hdev.sc_dev, "X report 0x%04x not supported\n", flags); return; } /* requires HID usage Generic_Desktop:Y */ if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), uha->reportid, hid_input, &sc->sc_loc_y, &flags)) { aprint_error_dev(sc->sc_hdev.sc_dev, "touchscreen has no Y report\n"); return; } switch (flags & TSCREEN_FLAGS_MASK) { case 0: sc->flags |= UTS_ABS; break; case HIO_RELATIVE: break; default: aprint_error_dev(sc->sc_hdev.sc_dev, "Y report 0x%04x not supported\n", flags); return; } /* requires HID usage Digitizer:Tip_Switch */ if (!hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH), uha->reportid, hid_input, &sc->sc_loc_btn, 0)) { aprint_error_dev(sc->sc_hdev.sc_dev, "touchscreen has no tip switch report\n"); return; } /* requires HID usage Digitizer:In_Range */ if (!hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE), uha->reportid, hid_input, &sc->sc_loc_z, &flags)) { aprint_error_dev(sc->sc_hdev.sc_dev, "touchscreen has no range report\n"); return; } /* multi-touch support would need HUD_CONTACTID and HUD_CONTACTMAX */ #ifdef UTS_DEBUG DPRINTF(("uts_attach: sc=%p\n", sc)); DPRINTF(("uts_attach: X\t%d/%d\n", sc->sc_loc_x.pos, sc->sc_loc_x.size)); DPRINTF(("uts_attach: Y\t%d/%d\n", sc->sc_loc_y.pos, sc->sc_loc_y.size)); DPRINTF(("uts_attach: Z\t%d/%d\n", sc->sc_loc_z.pos, sc->sc_loc_z.size)); #endif a.accessops = &uts_accessops; a.accesscookie = sc; sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); /* calibrate the touchscreen */ memset(&sc->sc_calibcoords, 0, sizeof(sc->sc_calibcoords)); sc->sc_calibcoords.maxx = 4095; sc->sc_calibcoords.maxy = 4095; sc->sc_calibcoords.samplelen = WSMOUSE_CALIBCOORDS_RESET; d = hid_start_parse(desc, size, hid_input); while (hid_get_item(d, &item)) { if (item.kind != hid_input || HID_GET_USAGE_PAGE(item.usage) != HUP_GENERIC_DESKTOP || item.report_ID != sc->sc_hdev.sc_report_id) continue; if (HID_GET_USAGE(item.usage) == HUG_X) { sc->sc_calibcoords.minx = item.logical_minimum; sc->sc_calibcoords.maxx = item.logical_maximum; } if (HID_GET_USAGE(item.usage) == HUG_Y) { sc->sc_calibcoords.miny = item.logical_minimum; sc->sc_calibcoords.maxy = item.logical_maximum; } } hid_end_parse(d); tpcalib_init(&sc->sc_tpcalib); tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS, (void *)&sc->sc_calibcoords, 0, 0); return; }