/* * 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; }
/* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick *joy) { report_free(&joy->hwdata->inreport); hid_dispose_report_desc(joy->hwdata->repdesc); close(joy->hwdata->fd); free(joy->hwdata->path); free(joy->hwdata); 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; }
int hid_get_report_id(int fd) { report_desc_t rep; hid_data_t d; hid_item_t h; int kindset; int temp = -1; int ret; if ((rep = hid_get_report_desc(fd)) == NULL) goto use_ioctl; kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature; for (d = hid_start_parse(rep, kindset, -1); hid_get_item(d, &h); ) { /* Return the first report ID we met. */ if (h.report_ID != 0) { temp = h.report_ID; break; } } hid_end_parse(d); hid_dispose_report_desc(rep); if (temp > 0) return (temp); use_ioctl: ret = ioctl(fd, USB_GET_REPORT_ID, &temp); #ifdef HID_COMPAT7 if (ret < 0) ret = hid_get_report_id_compat7(fd); else #endif ret = temp; return (ret); }
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; }
int main(int argc, char **argv) { report_desc_t r; char *table = NULL; char devnam[100], *dev = NULL; int f; int all = 0; int ch; int repdump = 0; int loop = 0; while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) { switch(ch) { case 'a': all++; break; case 'f': dev = optarg; break; case 'l': loop ^= 1; break; case 'n': noname++; break; case 'r': repdump++; break; case 't': table = optarg; break; case 'v': verbose++; break; case 'w': wflag = 1; break; case 'x': hexdump = 1; break; case 'z': zflag = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (dev == NULL) usage(); if (argc == 0 && !all && !repdump) usage(); if (dev[0] != '/') { if (isdigit(dev[0])) snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); else snprintf(devnam, sizeof(devnam), "/dev/%s", dev); dev = devnam; } hid_init(table); f = open(dev, O_RDWR); if (f < 0) err(1, "%s", dev); r = hid_get_report_desc(f); if (r == 0) errx(1, "USB_GET_REPORT_DESC"); if (repdump) { printf("Report descriptor:\n"); dumpitems(r); } if (argc != 0 || all) { parceargs(r, all, argc, argv); if (wflag) writedata(f, r); else dumpdata(f, r, loop); } hid_dispose_report_desc(r); exit(0); }
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 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; }
int main (int argc, char **argv) { char *device_file; int fd = -1; int report_id; report_desc_t report_desc; struct hid_data *data; hid_item_t item; boolean is_keyboard = FALSE; boolean is_keypad = FALSE; boolean is_mouse = FALSE; boolean is_joystick = FALSE; if (! hfp_init(argc, argv)) goto end; device_file = getenv("HAL_PROP_HIDDEV_DEVICE"); if (! device_file) goto end; fd = open(device_file, O_RDONLY); if (fd < 0) goto end; /* give a meaningful process title for ps(1) */ setproctitle("%s", device_file); #ifdef HAVE_LIBUSB20 report_id = hid_get_report_id(fd); if (report_id == -1) #else if (ioctl(fd, USB_GET_REPORT_ID, &report_id) < 0) #endif goto end; hid_init(NULL); report_desc = hid_get_report_desc(fd); if (! report_desc) goto end; for (data = hid_start_parse(report_desc, ~0, report_id); hid_get_item(data, &item);) if (item.kind == hid_collection) { if (item.collection == HID_COLLECTION_APPLICATION) { const char *page; char *full_page; int i; page = hid_usage_page(HID_PAGE(item.usage)); full_page = hfp_strdup_printf("%s Page", page); for (i = 0; full_page[i] != 0; i++) if (full_page[i] == '_') full_page[i] = ' '; libhal_device_property_strlist_append(hfp_ctx, hfp_udi, "hiddev.application_pages", full_page, &hfp_error); hfp_free(full_page); } switch (item.usage) { case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE): is_mouse = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_JOYSTICK): case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_GAME_PAD): is_joystick = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD): is_keyboard = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYPAD): is_keypad = TRUE; break; } } hid_end_parse(data); hid_dispose_report_desc(report_desc); if (is_keyboard || is_mouse || is_joystick || is_keypad) { libhal_device_add_capability(hfp_ctx, hfp_udi, "input", &hfp_error); libhal_device_set_property_string(hfp_ctx, hfp_udi, "info.category", "input", &hfp_error); libhal_device_set_property_string(hfp_ctx, hfp_udi, "input.device", device_file, &hfp_error); } if (is_keyboard) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keyboard", &hfp_error); if (is_keypad) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keypad", &hfp_error); if (is_keyboard || is_keypad) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keys", &hfp_error); if (is_mouse) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.mouse", &hfp_error); if (is_joystick) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.joystick", &hfp_error); end: return 0; }