void cc_recv(struct hid_appcol *ha, struct hid_report *hr) { struct hid_interface *hi; struct hid_field *hf; struct hid_key keycodes[MAX_KEYCODE]; unsigned int usage, up; int i, value, cnt, flags, total; hi = hid_appcol_get_parser_private(ha); assert(hi != NULL); total = 0; cnt = 0; memset(keycodes, 0, sizeof(keycodes)); hf = NULL; while ((hf = hid_report_get_next_field(hr, hf, HID_INPUT)) != NULL) { flags = hid_field_get_flags(hf); if (flags & HIO_CONST) continue; for (i = 0; i < hf->hf_count; i++) { up = hid_field_get_usage_page(hf); hid_field_get_usage_value(hf, i, &usage, &value); if (total >= MAX_KEYCODE) continue; total++; if (up == HUP_CONSUMER && HID_USAGE(usage) == HUG_VOLUME && value) { cc_process_volume_usage(ha, hr, value); continue; } if (value) { if (cnt >= MAX_KEYCODE) continue; keycodes[cnt].code = HID_USAGE(usage); keycodes[cnt].up = up; cnt++; } } } if (total > 0 && verbose > 1) { PRINT1("hid codes: "); if (cnt == 0) printf("none"); for (i = 0; i < cnt; i++) printf("0x%02X ", keycodes[i].code); putchar('\n'); } kbd_input(ha, 0, keycodes, total); }
/* * return appropriate mode for HID descriptor */ const char * hid_mode(prop_data_t desc) { report_desc_t r; hid_data_t d; struct hid_item h; const char *mode; hid_init(NULL); mode = BTDEVauth; /* default */ r = hid_use_report_desc(prop_data_data_nocopy(desc), prop_data_size(desc)); if (r == NULL) err(EXIT_FAILURE, "hid_use_report_desc"); d = hid_start_parse(r, ~0, -1); while (hid_get_item(d, &h) > 0) { if (h.kind == hid_collection && HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP && HID_USAGE(h.usage) == HUG_KEYBOARD) mode = BTDEVencrypt; } hid_end_parse(d); hid_dispose_report_desc(r); return mode; }
const char * hid_usage_in_page(unsigned int u) { int page = HID_PAGE(u); int i = HID_USAGE(u); static char b[100]; int j, k, us; for (k = 0; k < npages; k++) if (pages[k].usage == page) break; if (k >= npages) goto bad; for (j = 0; j < pages[k].pagesize; j++) { us = pages[k].page_contents[j].usage; if (us == -1) { sprintf(b, fmtcheck(pages[k].page_contents[j].name, "%d"), i); return b; } if (us == i) return pages[k].page_contents[j].name; } bad: sprintf(b, "0x%04x", i); return b; }
void USBJoystick::poll() { int len; /* * The device will buffer a lot of deltas. This can lead to a lot of * latency. To avoid this, we will empty the buffer every time. * It's possible the device may report only changed entries, so we * must process all of the frames to avoid dropping buttons (for example). */ while ((len = read(fd, data_buf, data_buf_size)) == data_buf_size) { struct hid_item *h; for (h = hids; h; h = h->next) { int d = hid_get_data(data_buf + data_buf_offset, h); int page = HID_PAGE(h->usage); int usage = HID_USAGE(h->usage); int which_axis; if (page == HUP_GENERIC_DESKTOP) { switch (usage) { case HUG_X: case HUG_RX: which_axis = 0; break; case HUG_Y: case HUG_RY: which_axis = 1; break; case HUG_Z: case HUG_RZ: which_axis = 2; break; } axis[which_axis] = d; } else if (page == HUP_BUTTON) { buttons &= ~ (1 << (usage - 1)); buttons |= (d == h->logical_maximum)?1 << (usage - 1):0; } } } }
int SDL_SYS_JoystickOpen(SDL_Joystick *joy) { char *path = joynames[joy->index]; struct joystick_hwdata *hw; struct hid_item hitem; struct hid_data *hdata; struct report *rep; int fd; int i; fd = open(path, O_RDONLY); if (fd == -1) { SDL_SetError("%s: %s", path, strerror(errno)); return (-1); } hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata)); if (hw == NULL) { SDL_OutOfMemory(); close(fd); return (-1); } joy->hwdata = hw; hw->fd = fd; hw->path = strdup(path); hw->x = 0; hw->y = 0; hw->xmin = 0xffff; hw->ymin = 0xffff; hw->xmax = 0; hw->ymax = 0; if (! SDL_strncmp(path, "/dev/joy", 8)) { hw->type = BSDJOY_JOY; joy->naxes = 2; joy->nbuttons = 2; joy->nhats = 0; joy->nballs = 0; joydevnames[joy->index] = strdup("Gameport joystick"); goto usbend; } else { hw->type = BSDJOY_UHID; } { int ax; for (ax = 0; ax < JOYAXE_count; ax++) hw->axis_map[ax] = -1; } hw->repdesc = hid_get_report_desc(fd); if (hw->repdesc == NULL) { SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path, strerror(errno)); goto usberr; } #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) rep->rid = hid_get_report_id(fd); if (rep->rid < 0) { #else rep = &hw->inreport; if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { #endif rep->rid = -1; /* XXX */ } if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) { goto usberr; } if (rep->size <= 0) { SDL_SetError("%s: Input report descriptor has invalid length", hw->path); goto usberr; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(hw->repdesc, 1 << hid_input); #endif if (hdata == NULL) { SDL_SetError("%s: Cannot start HID parser", hw->path); goto usberr; } joy->naxes = 0; joy->nbuttons = 0; joy->nhats = 0; joy->nballs = 0; for (i=0; i<JOYAXE_count; i++) hw->axis_map[i] = -1; while (hid_get_item(hdata, &hitem) > 0) { char *sp; const char *s; switch (hitem.kind) { case hid_collection: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: switch (HID_USAGE(hitem.usage)) { case HUG_JOYSTICK: case HUG_GAME_PAD: s = hid_usage_in_page(hitem.usage); sp = SDL_malloc(SDL_strlen(s) + 5); SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s, joy->index); joydevnames[joy->index] = sp; } } break; case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { hw->axis_map[joyaxe] = 1; } else if (usage == HUG_HAT_SWITCH) { joy->nhats++; } break; } case HUP_BUTTON: joy->nbuttons++; break; default: break; } break; default: break; } } hid_end_parse(hdata); for (i=0; i<JOYAXE_count; i++) if (hw->axis_map[i] > 0) hw->axis_map[i] = joy->naxes++; usbend: /* The poll blocks the event thread. */ fcntl(fd, F_SETFL, O_NONBLOCK); return (0); usberr: close(hw->fd); SDL_free(hw->path); SDL_free(hw); return (-1); } void SDL_SYS_JoystickUpdate(SDL_Joystick *joy) { struct hid_item hitem; struct hid_data *hdata; struct report *rep; int nbutton, naxe = -1; Sint32 v; #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H struct joystick gameport; if (joy->hwdata->type == BSDJOY_JOY) { if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport) return; if (abs(joy->hwdata->x - gameport.x) > 8) { joy->hwdata->x = gameport.x; if (joy->hwdata->x < joy->hwdata->xmin) { joy->hwdata->xmin = joy->hwdata->x; } if (joy->hwdata->x > joy->hwdata->xmax) { joy->hwdata->xmax = joy->hwdata->x; } if (joy->hwdata->xmin == joy->hwdata->xmax) { joy->hwdata->xmin--; joy->hwdata->xmax++; } v = (Sint32)joy->hwdata->x; v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2; v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2); SDL_PrivateJoystickAxis(joy, 0, v); } if (abs(joy->hwdata->y - gameport.y) > 8) { joy->hwdata->y = gameport.y; if (joy->hwdata->y < joy->hwdata->ymin) { joy->hwdata->ymin = joy->hwdata->y; } if (joy->hwdata->y > joy->hwdata->ymax) { joy->hwdata->ymax = joy->hwdata->y; } if (joy->hwdata->ymin == joy->hwdata->ymax) { joy->hwdata->ymin--; joy->hwdata->ymax++; } v = (Sint32)joy->hwdata->y; v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2; v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2); SDL_PrivateJoystickAxis(joy, 1, v); } if (gameport.b1 != joy->buttons[0]) { SDL_PrivateJoystickButton(joy, 0, gameport.b1); } if (gameport.b2 != joy->buttons[1]) { SDL_PrivateJoystickButton(joy, 1, gameport.b2); } return; } #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */ rep = &joy->hwdata->inreport; if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) { return; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); #endif if (hdata == NULL) { fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path); return; } for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { switch (hitem.kind) { case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { naxe = joy->hwdata->axis_map[joyaxe]; /* scaleaxe */ v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2; v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2); if (v != joy->axes[naxe]) { SDL_PrivateJoystickAxis(joy, naxe, v); } } else if (usage == HUG_HAT_SWITCH) { v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v)-hitem.logical_minimum); } break; } case HUP_BUTTON: v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); if (joy->buttons[nbutton] != v) { SDL_PrivateJoystickButton(joy, nbutton, v); } nbutton++; break; default: continue; } break; default: break; } } hid_end_parse(hdata); return; } /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick *joy) { if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) { report_free(&joy->hwdata->inreport); hid_dispose_report_desc(joy->hwdata->repdesc); } close(joy->hwdata->fd); SDL_free(joy->hwdata->path); SDL_free(joy->hwdata); return; } void SDL_SYS_JoystickQuit(void) { int i; for (i = 0; i < MAX_JOYS; i++) { if (joynames[i] != NULL) SDL_free(joynames[i]); if (joydevnames[i] != NULL) SDL_free(joydevnames[i]); } return; }
void SDL_SYS_JoystickUpdate(SDL_Joystick *joy) { struct hid_item hitem; struct hid_data *hdata; struct report *rep; int nbutton, naxe = -1; Sint32 v; #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H struct joystick gameport; if (joy->hwdata->type == BSDJOY_JOY) { if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport) return; if (abs(joy->hwdata->x - gameport.x) > 8) { joy->hwdata->x = gameport.x; if (joy->hwdata->x < joy->hwdata->xmin) { joy->hwdata->xmin = joy->hwdata->x; } if (joy->hwdata->x > joy->hwdata->xmax) { joy->hwdata->xmax = joy->hwdata->x; } if (joy->hwdata->xmin == joy->hwdata->xmax) { joy->hwdata->xmin--; joy->hwdata->xmax++; } v = (Sint32)joy->hwdata->x; v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2; v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2); SDL_PrivateJoystickAxis(joy, 0, v); } if (abs(joy->hwdata->y - gameport.y) > 8) { joy->hwdata->y = gameport.y; if (joy->hwdata->y < joy->hwdata->ymin) { joy->hwdata->ymin = joy->hwdata->y; } if (joy->hwdata->y > joy->hwdata->ymax) { joy->hwdata->ymax = joy->hwdata->y; } if (joy->hwdata->ymin == joy->hwdata->ymax) { joy->hwdata->ymin--; joy->hwdata->ymax++; } v = (Sint32)joy->hwdata->y; v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2; v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2); SDL_PrivateJoystickAxis(joy, 1, v); } if (gameport.b1 != joy->buttons[0]) { SDL_PrivateJoystickButton(joy, 0, gameport.b1); } if (gameport.b2 != joy->buttons[1]) { SDL_PrivateJoystickButton(joy, 1, gameport.b2); } return; } #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */ rep = &joy->hwdata->inreport; if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) { return; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_version >= 500111) hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); #endif if (hdata == NULL) { fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path); return; } for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { switch (hitem.kind) { case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { naxe = joy->hwdata->axis_map[joyaxe]; /* scaleaxe */ v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2; v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2); if (v != joy->axes[naxe]) { SDL_PrivateJoystickAxis(joy, naxe, v); } } else if (usage == HUG_HAT_SWITCH) { v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v)-hitem.logical_minimum); } break; } case HUP_BUTTON: v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); if (joy->buttons[nbutton] != v) { SDL_PrivateJoystickButton(joy, nbutton, v); } nbutton++; break; default: continue; } break; default: break; } } hid_end_parse(hdata); return; }
int SDL_SYS_JoystickOpen(SDL_Joystick *joy) { char *path = joynames[joy->index]; struct joystick_hwdata *hw; struct hid_item hitem; struct hid_data *hdata; struct report *rep; int fd; int i; fd = open(path, O_RDONLY); if (fd == -1) { SDL_SetError("%s: %s", path, strerror(errno)); return (-1); } hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata)); if (hw == NULL) { SDL_OutOfMemory(); close(fd); return (-1); } joy->hwdata = hw; hw->fd = fd; hw->path = strdup(path); hw->x = 0; hw->y = 0; hw->xmin = 0xffff; hw->ymin = 0xffff; hw->xmax = 0; hw->ymax = 0; if (! SDL_strncmp(path, "/dev/joy", 8)) { hw->type = BSDJOY_JOY; joy->naxes = 2; joy->nbuttons = 2; joy->nhats = 0; joy->nballs = 0; joydevnames[joy->index] = strdup("Gameport joystick"); goto usbend; } else { hw->type = BSDJOY_UHID; } { int ax; for (ax = 0; ax < JOYAXE_count; ax++) hw->axis_map[ax] = -1; } hw->repdesc = hid_get_report_desc(fd); if (hw->repdesc == NULL) { SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path, strerror(errno)); goto usberr; } rep = &hw->inreport; if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { rep->rid = -1; /* XXX */ } if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) { goto usberr; } if (rep->size <= 0) { SDL_SetError("%s: Input report descriptor has invalid length", hw->path); goto usberr; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_version >= 500111) hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(hw->repdesc, 1 << hid_input); #endif if (hdata == NULL) { SDL_SetError("%s: Cannot start HID parser", hw->path); goto usberr; } joy->naxes = 0; joy->nbuttons = 0; joy->nhats = 0; joy->nballs = 0; for (i=0; i<JOYAXE_count; i++) hw->axis_map[i] = -1; while (hid_get_item(hdata, &hitem) > 0) { char *sp; const char *s; switch (hitem.kind) { case hid_collection: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: switch (HID_USAGE(hitem.usage)) { case HUG_JOYSTICK: case HUG_GAME_PAD: s = hid_usage_in_page(hitem.usage); sp = SDL_malloc(SDL_strlen(s) + 5); SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s, joy->index); joydevnames[joy->index] = sp; } } break; case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { hw->axis_map[joyaxe] = 1; } else if (usage == HUG_HAT_SWITCH) { joy->nhats++; } break; } case HUP_BUTTON: joy->nbuttons++; break; default: break; } break; default: break; } } hid_end_parse(hdata); for (i=0; i<JOYAXE_count; i++) if (hw->axis_map[i] > 0) hw->axis_map[i] = joy->naxes++; usbend: /* The poll blocks the event thread. */ fcntl(fd, F_SETFL, O_NONBLOCK); return (0); usberr: close(hw->fd); SDL_free(hw->path); SDL_free(hw); return (-1); }
int32_t kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len) { vkbd_status_t st; uint8_t leds, report_id; hid_device_p hid_device; hid_data_t d; hid_item_t h; assert(s != NULL); assert(len == sizeof(vkbd_status_t)); memcpy(&st, data, sizeof(st)); leds = 0; report_id = NO_REPORT_ID; hid_device = get_hid_device(&s->bdaddr); assert(hid_device != NULL); for (d = hid_start_parse(hid_device->desc, 1 << hid_output, -1); hid_get_item(d, &h) > 0; ) { if (HID_PAGE(h.usage) == HUP_LEDS) { if (report_id == NO_REPORT_ID) report_id = h.report_ID; else if (h.report_ID != report_id) syslog(LOG_WARNING, "Output HID report IDs " \ "for %s do not match: %d vs. %d. " \ "Please report", bt_ntoa(&s->bdaddr, NULL), h.report_ID, report_id); switch(HID_USAGE(h.usage)) { case 0x01: /* Num Lock LED */ if (st.leds & LED_NUM) hid_set_data(&leds, &h, 1); break; case 0x02: /* Caps Lock LED */ if (st.leds & LED_CAP) hid_set_data(&leds, &h, 1); break; case 0x03: /* Scroll Lock LED */ if (st.leds & LED_SCR) hid_set_data(&leds, &h, 1); break; /* XXX add other LEDs ? */ } } } hid_end_parse(d); data[0] = 0xa2; /* DATA output (HID output report) */ if (report_id != NO_REPORT_ID) { data[1] = report_id; data[2] = leds; len = 3; } else { data[1] = leds; len = 2; } write(s->intr, data, len); return (0); }
enum StringDescriptorId_t { StringDescriptorId_Language = 0, StringDescriptorId_Manufacturer = 1, StringDescriptorId_Product = 2 }; /* Note that the key report is split into several similar items, because: An item field cannot span more than 4 bytes in a report. For example, a 32-bit item must start on a byte boundary to satisfy this condition. - USB HID 1.11 Specification, p. 57 */ local const u8 PROGMEM NkroKeyboardReportDescriptor[] = { HID_USAGE_PAGE (8, HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS), HID_USAGE (8, HID_DESKTOP_KEYBOARD), HID_COLLECTION (8, HID_COLLECTION_APPLICATION), HID_USAGE_PAGE (8, HID_USAGE_PAGE_KEYBOARD_KEYPAD), HID_LOGICAL_MINIMUM (8, 0x00), HID_LOGICAL_MAXIMUM (8, 0x01), HID_REPORT_SIZE (8, 0x01), HID_REPORT_COUNT (8, 0x20), HID_USAGE_MINIMUM (8, 0x00), HID_USAGE_MAXIMUM (8, 0x1F), HID_INPUT (8, HID_DATA | HID_VARIABLE | HID_ABSOLUTE), HID_USAGE_MINIMUM (8, 0x20), HID_USAGE_MAXIMUM (8, 0x3F), HID_INPUT (8, HID_DATA | HID_VARIABLE | HID_ABSOLUTE),
int32_t hid_interrupt(bthid_session_p s, uint8_t *data, int32_t len) { hid_device_p hid_device; hid_data_t d; hid_item_t h; int32_t report_id, usage, page, val, mouse_x, mouse_y, mouse_z, mouse_butt, mevents, kevents, i; assert(s != NULL); assert(s->srv != NULL); assert(data != NULL); if (len < 3) { syslog(LOG_ERR, "Got short message (%d bytes) on Interrupt " \ "channel from %s", len, bt_ntoa(&s->bdaddr, NULL)); return (-1); } if (data[0] != 0xa1) { syslog(LOG_ERR, "Got unexpected message 0x%x on " \ "Interrupt channel from %s", data[0], bt_ntoa(&s->bdaddr, NULL)); return (-1); } report_id = data[1]; data ++; len --; hid_device = get_hid_device(&s->bdaddr); assert(hid_device != NULL); mouse_x = mouse_y = mouse_z = mouse_butt = mevents = kevents = 0; for (d = hid_start_parse(hid_device->desc, 1 << hid_input, -1); hid_get_item(d, &h) > 0; ) { if ((h.flags & HIO_CONST) || (h.report_ID != report_id) || (h.kind != hid_input)) continue; page = HID_PAGE(h.usage); val = hid_get_data(data, &h); /* * When the input field is an array and the usage is specified * with a range instead of an ID, we have to derive the actual * usage by using the item value as an index in the usage range * list. */ if ((h.flags & HIO_VARIABLE)) { usage = HID_USAGE(h.usage); } else { const uint32_t usage_offset = val - h.logical_minimum; usage = HID_USAGE(h.usage_minimum + usage_offset); } switch (page) { case HUP_GENERIC_DESKTOP: switch (usage) { case HUG_X: mouse_x = val; mevents ++; break; case HUG_Y: mouse_y = val; mevents ++; break; case HUG_WHEEL: mouse_z = -val; mevents ++; break; case HUG_SYSTEM_SLEEP: if (val) syslog(LOG_NOTICE, "Sleep button pressed"); break; } break; case HUP_KEYBOARD: kevents ++; if (h.flags & HIO_VARIABLE) { if (val && usage < kbd_maxkey()) bit_set(s->keys1, usage); } else { if (val && val < kbd_maxkey()) bit_set(s->keys1, val); for (i = 1; i < h.report_count; i++) { h.pos += h.report_size; val = hid_get_data(data, &h); if (val && val < kbd_maxkey()) bit_set(s->keys1, val); } } break; case HUP_BUTTON: if (usage != 0) { if (usage == 2) usage = 3; else if (usage == 3) usage = 2; mouse_butt |= (val << (usage - 1)); mevents ++; } break; case HUP_CONSUMER: if (!val) break; switch (usage) { case HUC_AC_PAN: /* Horizontal scroll */ if (val < 0) mouse_butt |= (1 << 5); else mouse_butt |= (1 << 6); mevents ++; val = 0; break; case 0xb5: /* Scan Next Track */ val = 0x19; break; case 0xb6: /* Scan Previous Track */ val = 0x10; break; case 0xb7: /* Stop */ val = 0x24; break; case 0xcd: /* Play/Pause */ val = 0x22; break; case 0xe2: /* Mute */ val = 0x20; break; case 0xe9: /* Volume Up */ val = 0x30; break; case 0xea: /* Volume Down */ val = 0x2E; break; case 0x183: /* Media Select */ val = 0x6D; break; case 0x018a: /* Mail */ val = 0x6C; break; case 0x192: /* Calculator */ val = 0x21; break; case 0x194: /* My Computer */ val = 0x6B; break; case 0x221: /* WWW Search */ val = 0x65; break; case 0x223: /* WWW Home */ val = 0x32; break; case 0x224: /* WWW Back */ val = 0x6A; break; case 0x225: /* WWW Forward */ val = 0x69; break; case 0x226: /* WWW Stop */ val = 0x68; break; case 0x227: /* WWW Refresh */ val = 0x67; break; case 0x22a: /* WWW Favorites */ val = 0x66; break; default: val = 0; break; } /* XXX FIXME - UGLY HACK */ if (val != 0) { if (hid_device->keyboard) { int32_t buf[4] = { 0xe0, val, 0xe0, val|0x80 }; assert(s->vkbd != -1); write(s->vkbd, buf, sizeof(buf)); } else syslog(LOG_ERR, "Keyboard events " \ "received from non-keyboard " \ "device %s. Please report", bt_ntoa(&s->bdaddr, NULL)); } break; case HUP_MICROSOFT: switch (usage) { case 0xfe01: if (!hid_device->battery_power) break; switch (val) { case 1: syslog(LOG_INFO, "Battery is OK on %s", bt_ntoa(&s->bdaddr, NULL)); break; case 2: syslog(LOG_NOTICE, "Low battery on %s", bt_ntoa(&s->bdaddr, NULL)); break; case 3: syslog(LOG_WARNING, "Very low battery "\ "on %s", bt_ntoa(&s->bdaddr, NULL)); break; } break; } break; } } hid_end_parse(d); /* * XXX FIXME Feed keyboard events into kernel. * The code below works, bit host also needs to track * and handle repeat. * * Key repeat currently works in X, but not in console. */ if (kevents > 0) { if (hid_device->keyboard) { assert(s->vkbd != -1); kbd_process_keys(s); } else syslog(LOG_ERR, "Keyboard events received from " \ "non-keyboard device %s. Please report", bt_ntoa(&s->bdaddr, NULL)); } /* * XXX FIXME Feed mouse events into kernel. * The code block below works, but it is not good enough. * Need to track double-clicks etc. * * Double click currently works in X, but not in console. */ if (mevents > 0) { struct mouse_info mi; mi.operation = MOUSE_ACTION; mi.u.data.x = mouse_x; mi.u.data.y = mouse_y; mi.u.data.z = mouse_z; mi.u.data.buttons = mouse_butt; if (ioctl(s->srv->cons, CONS_MOUSECTL, &mi) < 0) syslog(LOG_ERR, "Could not process mouse events from " \ "%s. %s (%d)", bt_ntoa(&s->bdaddr, NULL), strerror(errno), errno); } return (0); }
.bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x1209, .idProduct = 0xCC86, .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1, }; static const uint8_t hid_report_descriptor[] = { 0x06, 0x00, 0xff, HID_USAGE (0x01), HID_COLLECTION (HID_COLLECTION_APPLICATION), HID_REPORT_ID(1), HID_LOGICAL_MINIMUM (0), HID_LOGICAL_MAXIMUM (255), HID_REPORT_SIZE (8), HID_REPORT_COUNT (9), HID_USAGE (0x01), HID_INPUT (0x02), HID_END_COLLECTION, 0x06, 0x00, 0xff, HID_USAGE (0x01), HID_COLLECTION (HID_COLLECTION_APPLICATION), HID_REPORT_ID(2), HID_LOGICAL_MINIMUM (0), HID_LOGICAL_MAXIMUM (255),
int jstkOpenDevice_bsd(JoystickDevPtr joystick, Bool probe) { int cur_axis; int is_joystick, report_id = 0; int got_something; struct hid_data *d; struct hid_item h; report_desc_t rd; struct jstk_bsd_hid_data *bsddata; if (joystick->fd == -1) { if ((joystick->fd = open(joystick->device, O_RDWR | O_NDELAY, 0)) < 0) { xf86Msg(X_ERROR, "Cannot open joystick '%s' (%s)\n", joystick->device, strerror(errno)); return -1; } } if ((rd = hid_get_report_desc(joystick->fd)) == 0) { xf86Msg(X_ERROR, "Joystick: hid_get_report_desc failed: %s\n", strerror(errno)); jstkCloseDevice_bsd(joystick); return -1; } if (ioctl(joystick->fd, USB_GET_REPORT_ID, &report_id) < 0) { xf86Msg(X_ERROR, "Joystick: ioctl USB_GET_REPORT_ID failed: %s\n", strerror(errno)); jstkCloseDevice_bsd(joystick); return -1; } bsddata = (struct jstk_bsd_hid_data*) malloc(sizeof(struct jstk_bsd_hid_data)); joystick->devicedata = (void*) bsddata; bsddata->dlen = hid_report_size(rd, hid_input, report_id); if ((bsddata->data_buf = malloc(bsddata->dlen)) == NULL) { fprintf(stderr, "error: couldn't malloc %d bytes\n", bsddata->dlen); hid_dispose_report_desc(rd); jstkCloseDevice_bsd(joystick); return -1; } is_joystick = 0; got_something = 0; cur_axis = 0; bsddata->hats = 0; joystick->num_axes = 0; joystick->num_buttons = 0; for (d = hid_start_parse(rd, 1 << hid_input, report_id); hid_get_item(d, &h); ) { int usage, page; page = HID_PAGE(h.usage); usage = HID_USAGE(h.usage); is_joystick = is_joystick || (h.kind == hid_collection && page == HUP_GENERIC_DESKTOP && (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD)); if (h.kind != hid_input) continue; if (!is_joystick) continue; if (page == HUP_GENERIC_DESKTOP) { if (usage == HUG_HAT_SWITCH) { if ((bsddata->hats < MAXAXES) && (joystick->num_axes <= MAXAXES-2)) { got_something = 1; memcpy(&bsddata->hat_item[bsddata->hats], &h, sizeof(h)); bsddata->hats++; joystick->num_axes += 2; } } else { if (joystick->num_axes < MAXAXES) { got_something = 1; memcpy(&bsddata->axis_item[cur_axis], &h, sizeof(h)); cur_axis++; joystick->num_axes++; } } } else if (page == HUP_BUTTON) { if (joystick->num_buttons < MAXBUTTONS) { got_something = 1; memcpy(&bsddata->button_item[joystick->num_buttons], &h, sizeof(h)); joystick->num_buttons++; } } } hid_end_parse(d); if (!got_something) { free(bsddata->data_buf); xf86Msg(X_ERROR, "Joystick: Didn't find any usable axes.\n"); jstkCloseDevice_bsd(joystick); return -1; } bsddata->hotdata = 0; if (probe == TRUE) { xf86Msg(X_INFO, "Joystick: %d buttons, %d axes\n", joystick->num_buttons, joystick->num_axes); } joystick->open_proc = jstkOpenDevice_bsd; joystick->read_proc = jstkReadData_bsd; joystick->close_proc = jstkCloseDevice_bsd; return joystick->fd; }
void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) { int status; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) int len; if ( joy->pJoystick.os->is_analog ) { int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) ); if ( status != sizeof(joy->pJoystick.os->ajs) ) { perror ( joy->pJoystick.os->fname ); joy->error = GL_TRUE; return; } if ( buttons != NULL ) *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 ); if ( axes != NULL ) { axes[0] = (float) joy->pJoystick.os->ajs.x; axes[1] = (float) joy->pJoystick.os->ajs.y; } return; } # ifdef HAVE_USB_JS while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen ) { struct hid_item *h; for ( h = joy->pJoystick.os->hids; h; h = h->next ) { int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h ); int page = HID_PAGE ( h->usage ); int usage = HID_USAGE ( h->usage ); if ( page == HUP_GENERIC_DESKTOP ) { int i; for ( i = 0; i < joy->num_axes; i++ ) if (joy->pJoystick.os->axes_usage[i] == usage) { if (usage == HUG_HAT_SWITCH) { if (d < 0 || d > 8) d = 0; /* safety */ joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d]; joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d]; } else { joy->pJoystick.os->cache_axes[i] = (float)d; } break; } } else if (page == HUP_BUTTON) { if (usage > 0 && usage < _JS_MAX_BUTTONS + 1) { if (d) joy->pJoystick.os->cache_buttons |= (1 << ( usage - 1 )); else joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 )); } } } } # ifdef HAVE_ERRNO_H if ( len < 0 && errno != EAGAIN ) # else if ( len < 0 ) # endif { perror( joy->pJoystick.os->fname ); joy->error = 1; } if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons; if ( axes != NULL ) memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes ); # endif #endif #ifdef JS_NEW while ( 1 ) { status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) ); if ( status != sizeof( struct js_event ) ) { # ifdef HAVE_ERRNO_H if ( errno == EAGAIN ) { /* Use the old values */ if ( buttons ) *buttons = joy->pJoystick.tmp_buttons; if ( axes ) memcpy( axes, joy->pJoystick.tmp_axes, sizeof( float ) * joy->num_axes ); return; } # endif fgWarning ( "%s", joy->pJoystick.fname ); joy->error = GL_TRUE; return; } switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT ) { case JS_EVENT_BUTTON: if( joy->pJoystick.js.value == 0 ) /* clear the flag */ joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number ); else joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number ); break; case JS_EVENT_AXIS: if ( joy->pJoystick.js.number < joy->num_axes ) { joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value; if( axes ) memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes ); } break; default: fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" ); /* use the old values */ if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons; if ( axes != NULL ) memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes ); return; } if( buttons ) *buttons = joy->pJoystick.tmp_buttons; } #else status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN ); if ( status != JS_RETURN ) { fgWarning( "%s", joy->pJoystick.fname ); joy->error = GL_TRUE; return; } if ( buttons ) # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ ) *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */ # else *buttons = joy->pJoystick.js.buttons; # endif if ( axes ) { axes[ 0 ] = (float) joy->pJoystick.js.x; axes[ 1 ] = (float) joy->pJoystick.js.y; } #endif }
void USBJoystick::initJoystick(const char *name) { report_desc_t rd; hid_data *d; hid_item h; int report_id; status = false; hids = NULL; num_axis = 0; if ((fd = open(name, O_RDONLY | O_NONBLOCK)) < 0) return; if ((rd = hid_get_report_desc(fd)) == 0) { close(fd); return; } data_buf_size = hid_report_size(rd, hid_input, &report_id); if ((data_buf = (char *)malloc(data_buf_size)) == NULL) { hid_dispose_report_desc(rd); } data_buf_offset = (report_id != 0); int is_joystick = 0; int interesting_hid = FALSE; for (d = hid_start_parse(rd, 1 << hid_input); hid_get_item(d, &h); ) { int page = HID_PAGE(h.usage); int usage = HID_USAGE(h.usage); is_joystick = is_joystick || (h.kind == hid_collection && page == HUP_GENERIC_DESKTOP && (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD)); if (h.kind != hid_input) continue; if (!is_joystick) continue; interesting_hid = TRUE; if (page == HUP_GENERIC_DESKTOP) { int which_axis; switch (usage) { case HUG_X: case HUG_RX: which_axis = 0; break; case HUG_Y: case HUG_RY: which_axis = 1; break; case HUG_Z: case HUG_RZ: which_axis = 2; break; default: interesting_hid = FALSE; } if (interesting_hid) { axis_const[which_axis] = 1000 + (2000 * h.logical_maximum) / (h.logical_minimum - h.logical_maximum); axis_scale[which_axis] = (2000 * 10000) / (h.logical_maximum - h.logical_minimum); axis[which_axis] = (h.logical_minimum + h.logical_maximum) / 2; if (num_axis < (which_axis + 1)) num_axis = which_axis + 1; } } if (interesting_hid) { struct hid_item *newhid = new struct hid_item; if (newhid == NULL) { close(fd); return; } *newhid = h; newhid->next = hids; hids = newhid; } } hid_end_parse(d); status = true; }
void mouse_recv(struct hid_appcol *ha, struct hid_report *hr) { struct hid_interface *hi; struct hid_field *hf; struct mouse_dev *md; struct mouse_info mi; unsigned int usage, up; int has_wheel, has_twheel, has_fake_twheel, has_z, flags; int b, btn, dx, dy, dw, dt, df, dz, i; hi = hid_appcol_get_parser_private(ha); assert(hi != NULL); md = hid_appcol_get_private(ha); assert(md != NULL); dx = dy = dw = dt = df = dz = 0; has_wheel = has_twheel = has_fake_twheel = has_z = 0; btn = 0; hf = NULL; while ((hf = hid_report_get_next_field(hr, hf, HID_INPUT)) != NULL) { flags = hid_field_get_flags(hf); if (flags & HIO_CONST || (flags & HIO_VARIABLE) == 0) continue; for (i = 0; i < hf->hf_count; i++) { usage = HID_USAGE(hf->hf_usage[i]); up = HID_PAGE(hf->hf_usage[i]); if (up == HUP_BUTTON) { if (usage < BUTTON_MAX && hf->hf_value[i]) { b = usage - 1; if (b == 1) b = 2; else if (b == 2) b = 1; btn |= (1 << b); } continue; } switch (hf->hf_usage[i]) { case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X): dx = hf->hf_value[i]; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y): dy = hf->hf_value[i]; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL): /* * HUG_WHEEL is the most common place for * mouse wheel. */ has_wheel = 1; dw = -hf->hf_value[i]; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL): /* * Some older Microsoft mouse (e.g. Microsoft * Wireless Intellimouse 2.0) used * HUG_TWHEEL(0x48) to report its wheel. Note * that HUG_TWHEEL seems to be a temporary thing * at the time. (The name TWHEEL is also a * non-standard name) Later new HID usage spec * defined 0x48 as usage "Resolution Multiplier" * and newer M$ mouse stopped using 0x48 for * mouse wheel. */ has_fake_twheel = 1; df = -hf->hf_value[i]; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z): /* Some mouse use HUG_Z to report its wheel. */ has_z = 1; dz = -hf->hf_value[i]; break; case HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN): /* Tilt wheel. */ has_twheel = 1; dt = -hf->hf_value[i]; break; } } } if (verbose > 1) PRINT1("mouse received data: dx(%d) dy(%d) dw(%d) dt(%d) " "btn(%#x)\n", dx, dy, dw, dt, btn); /* * There is no way to report tilt wheel to the kernel, for now * translate them to button #8 and #9. */ if (has_twheel) { if (dt > 0) btn |= (1 << 8); else if (dt < 0) btn |= (1 << 9); } /* Push the data to console device. (and sysmouse) */ mi.operation = MOUSE_ACTION; mi.u.data.x = dx; mi.u.data.y = dy; mi.u.data.buttons = btn; if (has_wheel) mi.u.data.z = dw; else if (has_fake_twheel) mi.u.data.z = df; else if (has_z) mi.u.data.z = dz; else mi.u.data.z = 0; if (ioctl(md->cons_fd, CONS_MOUSECTL, &mi) < 0) syslog(LOG_ERR, "%s[%d] could not submit mouse data:" " ioctl failed: %m", basename(hi->dev), hi->ndx); }
void SDL_SYS_JoystickUpdate(SDL_Joystick *joy) { struct hid_item hitem; struct hid_data *hdata; struct report *rep; int nbutton, naxe = -1; Sint32 v; rep = &joy->hwdata->inreport; if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) { return; } #if defined(USBHID_NEW) || (defined(__FreeBSD__) && __FreeBSD_version >= 500111) hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); #endif if (hdata == NULL) { fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path); return; } for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { switch (hitem.kind) { case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { naxe = joy->hwdata->axis_map[joyaxe]; /* scaleaxe */ v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2; v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2); if (v != joy->axes[naxe]) { SDL_PrivateJoystickAxis(joy, naxe, v); } } else if (usage == HUG_HAT_SWITCH) { v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v)); } break; } case HUP_BUTTON: v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); if (joy->buttons[nbutton] != v) { SDL_PrivateJoystickButton(joy, nbutton, v); } nbutton++; break; default: continue; } break; default: break; } } hid_end_parse(hdata); return; }