static int uhid_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct uhid_softc *sc = device_get_softc(dev); int unit = device_get_unit(dev); int error = 0; DPRINTFN(10, "sc=%p\n", sc); device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE); sc->sc_udev = uaa->device; sc->sc_iface_no = uaa->info.bIfaceNum; sc->sc_iface_index = uaa->info.bIfaceIndex; error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config, UHID_N_TRANSFER, sc, &sc->sc_mtx); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); goto detach; } if (uaa->info.idVendor == USB_VENDOR_WACOM) { /* the report descriptor for the Wacom Graphire is broken */ if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) { sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_graphire_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) { static uint8_t reportbuf[] = {2, 2, 2}; /* * The Graphire3 needs 0x0202 to be written to * feature report ID 2 before it'll start * returning digitizer data. */ error = usbd_req_set_report(uaa->device, NULL, reportbuf, sizeof(reportbuf), uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2); if (error) { DPRINTF("set report failed, error=%s (ignored)\n", usbd_errstr(error)); } sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_graphire3_4x5_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } } else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) && (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) && (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) { /* the Xbox 360 gamepad has no report descriptor */ sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_xb360gp_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } if (sc->sc_repdesc_ptr == NULL) { error = usbd_req_get_hid_desc(uaa->device, NULL, &sc->sc_repdesc_ptr, &sc->sc_repdesc_size, M_USBDEV, uaa->info.bIfaceIndex); if (error) { device_printf(dev, "no report descriptor\n"); goto detach; } } error = usbd_req_set_idle(uaa->device, NULL, uaa->info.bIfaceIndex, 0, 0); if (error) { DPRINTF("set idle failed, error=%s (ignored)\n", usbd_errstr(error)); } sc->sc_isize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid); sc->sc_osize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid); sc->sc_fsize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid); if (sc->sc_isize > UHID_BSIZE) { DPRINTF("input size is too large, " "%d bytes (truncating)\n", sc->sc_isize); sc->sc_isize = UHID_BSIZE; } if (sc->sc_osize > UHID_BSIZE) { DPRINTF("output size is too large, " "%d bytes (truncating)\n", sc->sc_osize); sc->sc_osize = UHID_BSIZE; } if (sc->sc_fsize > UHID_BSIZE) { DPRINTF("feature size is too large, " "%d bytes (truncating)\n", sc->sc_fsize); sc->sc_fsize = UHID_BSIZE; } error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, &uhid_fifo_methods, &sc->sc_fifo, unit, -1, uaa->info.bIfaceIndex, UID_ROOT, GID_OPERATOR, 0644); if (error) { goto detach; } return (0); /* success */ detach: uhid_detach(dev); return (ENOMEM); }
void bthidev_attach(struct device *parent, struct device *self, void *aux) { struct bthidev_softc *sc = (struct bthidev_softc *)self; struct btdev_attach_args *bda = (struct btdev_attach_args *)aux; struct bthidev_attach_args bha; struct bthidev *hidev; struct hid_data *d; struct hid_item h; int maxid, rep; /* * Init softc */ LIST_INIT(&sc->sc_list); timeout_set(&sc->sc_reconnect, bthidev_timeout, sc); sc->sc_state = BTHID_CLOSED; sc->sc_flags = BTHID_CONNECTING; sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; sc->sc_intpsm = L2CAP_PSM_HID_INTR; sc->sc_mode = 0; /* * copy in our configuration info */ bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr); bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr); if (bda->bd_mode != BTDEV_MODE_NONE) { if (bda->bd_mode == BTDEV_MODE_AUTH) { sc->sc_mode = L2CAP_LM_AUTH; printf(" auth"); } else if (bda->bd_mode == BTDEV_MODE_ENCRYPT) { sc->sc_mode = L2CAP_LM_ENCRYPT; printf(" encrypt"); } else if (bda->bd_mode == BTDEV_MODE_SECURE) { sc->sc_mode = L2CAP_LM_SECURE; printf(" secure"); } else { printf(" unknown link-mode: %d\n", bda->bd_mode); return; } } if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_ctl)) sc->sc_ctlpsm = bda->bd_hid.hid_ctl; if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_int)) sc->sc_intpsm = bda->bd_hid.hid_int; if (bda->bd_hid.hid_flags & BTHID_INITIATE) sc->sc_flags |= BTHID_RECONNECT; if (bda->bd_hid.hid_desc == NULL || bda->bd_hid.hid_dlen == 0 || bda->bd_hid.hid_dlen > MAX_DESCRIPTOR_LEN) { printf(": no descriptor\n"); return; } sc->sc_dlen = bda->bd_hid.hid_dlen; sc->sc_desc = malloc(bda->bd_hid.hid_dlen, M_BTHIDEV, M_WAITOK | M_CANFAIL); if (sc->sc_desc == NULL) { printf(": no memory\n"); return; } if (copyin(bda->bd_hid.hid_desc, sc->sc_desc, bda->bd_hid.hid_dlen)) { free(sc->sc_desc, M_BTHIDEV); printf(": no descriptor"); return; } /* * Parse the descriptor and attach child devices, one per report. */ maxid = -1; h.report_ID = 0; d = hid_start_parse(sc->sc_desc, sc->sc_dlen, hid_none); while (hid_get_item(d, &h)) { if (h.report_ID > maxid) maxid = h.report_ID; } hid_end_parse(d); if (maxid < 0) { printf(": no reports found\n"); return; } printf("\n"); for (rep = 0 ; rep <= maxid ; rep++) { if (hid_report_size(sc->sc_desc, sc->sc_dlen, hid_feature, rep) == 0 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_input, rep) == 0 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_output, rep) == 0) continue; bha.ba_desc = sc->sc_desc; bha.ba_dlen = sc->sc_dlen; bha.ba_input = bthidev_null; bha.ba_feature = bthidev_null; bha.ba_output = bthidev_output; bha.ba_id = rep; hidev = (struct bthidev *)config_found_sm(self, &bha, bthidev_print, bthidevsubmatch); if (hidev != NULL) { hidev->sc_parent = &sc->sc_btdev; hidev->sc_id = rep; hidev->sc_input = bha.ba_input; hidev->sc_feature = bha.ba_feature; LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next); } } /* * start bluetooth connections */ mutex_enter(&bt_lock); if ((sc->sc_flags & BTHID_RECONNECT) == 0) bthidev_listen(sc); if (sc->sc_flags & BTHID_CONNECTING) bthidev_connect(sc); mutex_exit(&bt_lock); }
static void bthidev_attach(device_t parent, device_t self, void *aux) { struct bthidev_softc *sc = device_private(self); prop_dictionary_t dict = aux; prop_object_t obj; device_t dev; struct bthidev_attach_args bha; struct bthidev *hidev; struct hid_data *d; struct hid_item h; const void *desc; int locs[BTHIDBUSCF_NLOCS]; int maxid, rep, dlen; int vendor, product; int err; /* * Init softc */ sc->sc_dev = self; LIST_INIT(&sc->sc_list); MBUFQ_INIT(&sc->sc_inq); callout_init(&sc->sc_reconnect, 0); callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc); sc->sc_state = BTHID_CLOSED; sc->sc_flags = BTHID_CONNECTING; sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL; sc->sc_intpsm = L2CAP_PSM_HID_INTR; sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); cv_init(&sc->sc_cv, device_xname(self)); /* * extract config from proplist */ obj = prop_dictionary_get(dict, BTDEVladdr); bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj)); obj = prop_dictionary_get(dict, BTDEVraddr); bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj)); obj = prop_dictionary_get(dict, BTDEVvendor); vendor = (int)prop_number_integer_value(obj); obj = prop_dictionary_get(dict, BTDEVproduct); product = (int)prop_number_integer_value(obj); obj = prop_dictionary_get(dict, BTDEVmode); if (prop_object_type(obj) == PROP_TYPE_STRING) { if (prop_string_equals_cstring(obj, BTDEVauth)) sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH); else if (prop_string_equals_cstring(obj, BTDEVencrypt)) sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT); else if (prop_string_equals_cstring(obj, BTDEVsecure)) sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE); else { aprint_error(" unknown %s\n", BTDEVmode); return; } aprint_verbose(" %s %s", BTDEVmode, prop_string_cstring_nocopy(obj)); } else sockopt_setint(&sc->sc_mode, 0); obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm); if (prop_object_type(obj) == PROP_TYPE_NUMBER) { sc->sc_ctlpsm = prop_number_integer_value(obj); if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) { aprint_error(" invalid %s\n", BTHIDEVcontrolpsm); return; } } obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm); if (prop_object_type(obj) == PROP_TYPE_NUMBER) { sc->sc_intpsm = prop_number_integer_value(obj); if (L2CAP_PSM_INVALID(sc->sc_intpsm)) { aprint_error(" invalid %s\n", BTHIDEVinterruptpsm); return; } } obj = prop_dictionary_get(dict, BTHIDEVdescriptor); if (prop_object_type(obj) == PROP_TYPE_DATA) { dlen = prop_data_size(obj); desc = prop_data_data_nocopy(obj); } else { aprint_error(" no %s\n", BTHIDEVdescriptor); return; } obj = prop_dictionary_get(dict, BTHIDEVreconnect); if (prop_object_type(obj) == PROP_TYPE_BOOL && !prop_bool_true(obj)) sc->sc_flags |= BTHID_RECONNECT; /* * Parse the descriptor and attach child devices, one per report. */ maxid = -1; h.report_ID = 0; d = hid_start_parse(desc, dlen, hid_none); while (hid_get_item(d, &h)) { if (h.report_ID > maxid) maxid = h.report_ID; } hid_end_parse(d); if (maxid < 0) { aprint_error(" no reports found\n"); return; } aprint_normal("\n"); if (kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, bthidev_process, sc, &sc->sc_lwp, "%s", device_xname(self)) != 0) { aprint_error_dev(self, "failed to create input thread\n"); return; } for (rep = 0 ; rep <= maxid ; rep++) { if (hid_report_size(desc, dlen, hid_feature, rep) == 0 && hid_report_size(desc, dlen, hid_input, rep) == 0 && hid_report_size(desc, dlen, hid_output, rep) == 0) continue; bha.ba_vendor = vendor; bha.ba_product = product; bha.ba_desc = desc; bha.ba_dlen = dlen; bha.ba_input = bthidev_null; bha.ba_feature = bthidev_null; bha.ba_output = bthidev_output; bha.ba_id = rep; locs[BTHIDBUSCF_REPORTID] = rep; dev = config_found_sm_loc(self, "bthidbus", locs, &bha, bthidev_print, config_stdsubmatch); if (dev != NULL) { hidev = device_private(dev); hidev->sc_dev = dev; hidev->sc_parent = self; hidev->sc_id = rep; hidev->sc_input = bha.ba_input; hidev->sc_feature = bha.ba_feature; LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next); } } pmf_device_register(self, NULL, NULL); /* * start bluetooth connections */ mutex_enter(bt_lock); if ((sc->sc_flags & BTHID_RECONNECT) == 0 && (err = bthidev_listen(sc)) != 0) aprint_error_dev(self, "failed to listen (%d)\n", err); if (sc->sc_flags & BTHID_CONNECTING) bthidev_connect(sc); mutex_exit(bt_lock); }
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 uhidev_attach(struct device *parent, struct device *self, void *aux) { struct uhidev_softc *sc = (struct uhidev_softc *)self; struct usb_attach_arg *uaa = aux; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; struct uhidev_attach_arg uha; int size = 0, nrepid, repid, repsz; int i, repsizes[256]; void *desc = NULL; struct device *dev; sc->sc_udev = uaa->device; sc->sc_iface = uaa->iface; id = usbd_get_interface_descriptor(sc->sc_iface); usbd_set_idle(sc->sc_iface, 0, 0); #if 0 if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 && id->bInterfaceSubClass != UISUBCLASS_BOOT) usbd_set_protocol(sc->sc_iface, 1); #endif sc->sc_iep_addr = sc->sc_oep_addr = -1; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); if (ed == NULL) { printf("%s: could not read endpoint descriptor\n", DEVNAME(sc)); return; } DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" " bInterval=%d\n", ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR, UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", ed->bmAttributes & UE_XFERTYPE, UGETW(ed->wMaxPacketSize), ed->bInterval)); if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->sc_iep_addr = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->sc_oep_addr = ed->bEndpointAddress; } else { printf("%s: unexpected endpoint\n", DEVNAME(sc)); return; } } /* * Check that we found an input interrupt endpoint. * The output interrupt endpoint is optional */ if (sc->sc_iep_addr == -1) { printf("%s: no input interrupt endpoint\n", DEVNAME(sc)); return; } #ifndef SMALL_KERNEL if (uhidev_use_rdesc(sc, uaa->vendor, uaa->product, &desc, &size)) return; #endif /* !SMALL_KERNEL */ if (desc == NULL) { if (usbd_read_report_desc(sc->sc_iface, &desc, &size, M_USBDEV)) { printf("%s: no report descriptor\n", DEVNAME(sc)); return; } } sc->sc_repdesc = desc; sc->sc_repdesc_size = size; nrepid = uhidev_maxrepid(desc, size); if (nrepid < 0) return; printf("%s: iclass %d/%d", DEVNAME(sc), id->bInterfaceClass, id->bInterfaceSubClass); if (nrepid > 0) printf(", %d report id%s", nrepid, nrepid > 1 ? "s" : ""); printf("\n"); nrepid++; sc->sc_subdevs = malloc(nrepid * sizeof(struct device *), M_USBDEV, M_NOWAIT | M_ZERO); if (sc->sc_subdevs == NULL) { printf("%s: no memory\n", DEVNAME(sc)); return; } sc->sc_nrepid = nrepid; sc->sc_isize = 0; for (repid = 0; repid < nrepid; repid++) { repsz = hid_report_size(desc, size, hid_input, repid); DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); repsizes[repid] = repsz; if (repsz > sc->sc_isize) sc->sc_isize = repsz; } sc->sc_isize += (nrepid != 1); /* one byte for the report ID */ DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); uha.uaa = uaa; uha.parent = sc; uha.reportid = UHIDEV_CLAIM_ALLREPORTID; /* Look for a driver claiming all report IDs first. */ dev = config_found_sm(self, &uha, NULL, uhidevsubmatch); if (dev != NULL) { for (repid = 0; repid < nrepid; repid++) sc->sc_subdevs[repid] = (struct uhidev *)dev; return; } for (repid = 0; repid < nrepid; repid++) { DPRINTF(("%s: try repid=%d\n", __func__, repid)); if (hid_report_size(desc, size, hid_input, repid) == 0 && hid_report_size(desc, size, hid_output, repid) == 0 && hid_report_size(desc, size, hid_feature, repid) == 0) continue; uha.reportid = repid; dev = config_found_sm(self, &uha, uhidevprint, uhidevsubmatch); sc->sc_subdevs[repid] = (struct uhidev *)dev; } }
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) { const char *conf = NULL; const char *dev = NULL; const char *table = NULL; int fd, fp, ch, n, val, i; size_t sz, sz1; int demon, ignore, dieearly; report_desc_t repd; char buf[100]; char devnamebuf[PATH_MAX]; struct command *cmd; int reportid = -1; demon = 1; ignore = 0; dieearly = 0; while ((ch = getopt(argc, argv, "c:def:ip:r:t:v")) != -1) { switch(ch) { case 'c': conf = optarg; break; case 'd': demon ^= 1; break; case 'e': dieearly = 1; break; case 'i': ignore++; break; case 'f': dev = optarg; break; case 'p': pidfile = optarg; break; case 'r': reportid = atoi(optarg); break; case 't': table = optarg; break; case 'v': demon = 0; verbose++; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (conf == NULL || dev == NULL) usage(); hid_init(table); if (dev[0] != '/') { snprintf(devnamebuf, sizeof(devnamebuf), "/dev/%s%s", isdigit(dev[0]) ? "uhid" : "", dev); dev = devnamebuf; } fd = open(dev, O_RDWR); if (fd < 0) err(1, "%s", dev); repd = hid_get_report_desc(fd); if (repd == NULL) err(1, "hid_get_report_desc() failed"); commands = parse_conf(conf, repd, reportid, ignore); sz = (size_t)hid_report_size(repd, hid_input, -1); if (verbose) printf("report size %zu\n", sz); if (sz > sizeof buf) errx(1, "report too large"); (void)signal(SIGHUP, sighup); if (demon) { fp = open(pidfile, O_WRONLY|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH); if (fp >= 0) { sz1 = snprintf(buf, sizeof buf, "%d\n", getpid()); if (sz1 > sizeof buf) sz1 = sizeof buf; write(fp, buf, sz1); close(fp); } else err(1, "%s", pidfile); if (daemon(0, 0) < 0) err(1, "daemon()"); isdemon = 1; } for(;;) { n = read(fd, buf, sz); if (verbose > 2) { printf("read %d bytes:", n); for (i = 0; i < n; i++) printf(" %02x", buf[i]); printf("\n"); } if (n < 0) { if (verbose) err(1, "read"); else exit(1); } #if 0 if (n != sz) { err(2, "read size"); } #endif for (cmd = commands; cmd; cmd = cmd->next) { if (cmd->item.report_ID != 0 && buf[0] != cmd->item.report_ID) continue; if (cmd->item.flags & HIO_VARIABLE) val = hid_get_data(buf, &cmd->item); else { uint32_t pos = cmd->item.pos; for (i = 0; i < cmd->item.report_count; i++) { val = hid_get_data(buf, &cmd->item); if (val == cmd->value) break; cmd->item.pos += cmd->item.report_size; } cmd->item.pos = pos; val = (i < cmd->item.report_count) ? cmd->value : -1; } if (cmd->value != val && cmd->anyvalue == 0) goto next; if ((cmd->debounce == 0) || ((cmd->debounce == 1) && ((cmd->lastseen == -1) || (cmd->lastseen != val)))) { docmd(cmd, val, dev, argc, argv); goto next; } if ((cmd->debounce > 1) && ((cmd->lastused == -1) || (abs(cmd->lastused - val) >= cmd->debounce))) { docmd(cmd, val, dev, argc, argv); cmd->lastused = val; goto next; } next: cmd->lastseen = val; } if (dieearly) exit(0); if (reparse) { struct command *cmds = parse_conf(conf, repd, reportid, ignore); if (cmds) { freecommands(commands); commands = cmds; } reparse = 0; } } exit(0); }
void uhidev_attach(device_t parent, device_t self, void *aux) { struct uhidev_softc *sc = device_private(self); struct usbif_attach_arg *uiaa = aux; struct usbd_interface *iface = uiaa->uiaa_iface; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; struct uhidev_attach_arg uha; device_t dev; struct uhidev *csc; int maxinpktsize, size, nrepid, repid, repsz; int *repsizes; int i; void *desc; const void *descptr; usbd_status err; char *devinfop; int locs[UHIDBUSCF_NLOCS]; sc->sc_dev = self; sc->sc_udev = uiaa->uiaa_device; sc->sc_iface = iface; aprint_naive("\n"); aprint_normal("\n"); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); id = usbd_get_interface_descriptor(iface); devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); aprint_normal_dev(self, "%s, iclass %d/%d\n", devinfop, id->bInterfaceClass, id->bInterfaceSubClass); usbd_devinfo_free(devinfop); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); (void)usbd_set_idle(iface, 0, 0); #if 0 if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 && id->bInterfaceSubClass != UISUBCLASS_BOOT) (void)usbd_set_protocol(iface, 1); #endif maxinpktsize = 0; sc->sc_iep_addr = sc->sc_oep_addr = -1; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(iface, i); if (ed == NULL) { aprint_error_dev(self, "could not read endpoint descriptor\n"); sc->sc_dying = 1; return; } DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" " bInterval=%d\n", ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR, UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", ed->bmAttributes & UE_XFERTYPE, UGETW(ed->wMaxPacketSize), ed->bInterval)); if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { maxinpktsize = UGETW(ed->wMaxPacketSize); sc->sc_iep_addr = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->sc_oep_addr = ed->bEndpointAddress; } else { aprint_verbose_dev(self, "endpoint %d: ignored\n", i); } } /* * Check that we found an input interrupt endpoint. The output interrupt * endpoint is optional */ if (sc->sc_iep_addr == -1) { aprint_error_dev(self, "no input interrupt endpoint\n"); sc->sc_dying = 1; return; } /* XXX need to extend this */ descptr = NULL; if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { static uByte reportbuf[] = {2, 2, 2}; /* The report descriptor for the Wacom Graphire is broken. */ switch (uiaa->uiaa_product) { case USB_PRODUCT_WACOM_GRAPHIRE: case USB_PRODUCT_WACOM_GRAPHIRE2: case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: case USB_PRODUCT_WACOM_GRAPHIRE3_6X8: case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: /* The 6x8 too? */ /* * The Graphire3 needs 0x0202 to be written to * feature report ID 2 before it'll start * returning digitizer data. */ usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 2, &reportbuf, sizeof(reportbuf)); size = sizeof(uhid_graphire3_4x5_report_descr); descptr = uhid_graphire3_4x5_report_descr; break; default: /* Keep descriptor */ break; } } if (USBIF_IS_XINPUT(uiaa)) { size = sizeof(uhid_xinput_report_descr); descptr = uhid_xinput_report_descr; } if (USBIF_IS_X1INPUT(uiaa)) { sc->sc_flags |= UHIDEV_F_XB1; size = sizeof(uhid_x1input_report_descr); descptr = uhid_x1input_report_descr; } if (descptr) { desc = kmem_alloc(size, KM_SLEEP); if (desc == NULL) err = USBD_NOMEM; else { err = USBD_NORMAL_COMPLETION; memcpy(desc, descptr, size); } } else { desc = NULL; err = usbd_read_report_desc(uiaa->uiaa_iface, &desc, &size); } if (err) { aprint_error_dev(self, "no report descriptor\n"); sc->sc_dying = 1; return; } if (uiaa->uiaa_vendor == USB_VENDOR_HOSIDEN && uiaa->uiaa_product == USB_PRODUCT_HOSIDEN_PPP) { static uByte reportbuf[] = { 1 }; /* * This device was sold by Konami with its ParaParaParadise * game for PlayStation2. It needs to be "turned on" * before it will send any reports. */ usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 0, &reportbuf, sizeof(reportbuf)); } if (uiaa->uiaa_vendor == USB_VENDOR_LOGITECH && uiaa->uiaa_product == USB_PRODUCT_LOGITECH_CBT44 && size == 0xb1) { uint8_t *data = desc; /* * This device has a odd USAGE_MINIMUM value that would * cause the multimedia keys to have their usage number * shifted up one usage. Adjust so the usages are sane. */ if (data[0x56] == 0x19 && data[0x57] == 0x01 && data[0x58] == 0x2a && data[0x59] == 0x8c) data[0x57] = 0x00; } /* * Enable the Six Axis and DualShock 3 controllers. * See http://ps3.jim.sh/sixaxis/usb/ */ if (uiaa->uiaa_vendor == USB_VENDOR_SONY && uiaa->uiaa_product == USB_PRODUCT_SONY_PS3CONTROLLER) { usb_device_request_t req; char data[17]; int actlen; req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = 1; USETW(req.wValue, 0x3f2); USETW(req.wIndex, 0); USETW(req.wLength, sizeof(data)); usbd_do_request_flags(sc->sc_udev, &req, data, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); } sc->sc_repdesc = desc; sc->sc_repdesc_size = size; uha.uiaa = uiaa; nrepid = uhidev_maxrepid(desc, size); if (nrepid < 0) return; if (nrepid > 0) aprint_normal_dev(self, "%d report ids\n", nrepid); nrepid++; repsizes = kmem_alloc(nrepid * sizeof(*repsizes), KM_SLEEP); if (repsizes == NULL) goto nomem; sc->sc_subdevs = kmem_zalloc(nrepid * sizeof(device_t), KM_SLEEP); if (sc->sc_subdevs == NULL) { kmem_free(repsizes, nrepid * sizeof(*repsizes)); nomem: aprint_error_dev(self, "no memory\n"); return; } /* Just request max packet size for the interrupt pipe */ sc->sc_isize = maxinpktsize; sc->sc_nrepid = nrepid; usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); for (repid = 0; repid < nrepid; repid++) { repsz = hid_report_size(desc, size, hid_input, repid); DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); repsizes[repid] = repsz; } DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); uha.parent = sc; for (repid = 0; repid < nrepid; repid++) { DPRINTF(("uhidev_match: try repid=%d\n", repid)); if (hid_report_size(desc, size, hid_input, repid) == 0 && hid_report_size(desc, size, hid_output, repid) == 0 && hid_report_size(desc, size, hid_feature, repid) == 0) { ; /* already NULL in sc->sc_subdevs[repid] */ } else { uha.reportid = repid; locs[UHIDBUSCF_REPORTID] = repid; dev = config_found_sm_loc(self, "uhidbus", locs, &uha, uhidevprint, config_stdsubmatch); sc->sc_subdevs[repid] = dev; if (dev != NULL) { csc = device_private(dev); csc->sc_in_rep_size = repsizes[repid]; #ifdef DIAGNOSTIC DPRINTF(("uhidev_match: repid=%d dev=%p\n", repid, dev)); if (csc->sc_intr == NULL) { kmem_free(repsizes, nrepid * sizeof(*repsizes)); aprint_error_dev(self, "sc_intr == NULL\n"); return; } #endif rnd_attach_source(&csc->rnd_source, device_xname(dev), RND_TYPE_TTY, RND_FLAG_DEFAULT); } } } kmem_free(repsizes, nrepid * sizeof(*repsizes)); return; }
void ukbd_attach(struct device *parent, struct device *self, void *aux) { struct ukbd_softc *sc = (struct ukbd_softc *)self; struct hidkbd *kbd = &sc->sc_kbd; struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; struct usb_hid_descriptor *hid; u_int32_t qflags; int dlen, repid; void *desc; kbd_t layout = (kbd_t)-1; sc->sc_hdev.sc_intr = ukbd_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_udev = uha->uaa->device; sc->sc_hdev.sc_report_id = uha->reportid; uhidev_get_report_desc(uha->parent, &desc, &dlen); repid = uha->reportid; sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid); sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid); sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid); qflags = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags; if (hidkbd_attach(self, kbd, 1, qflags, repid, desc, dlen) != 0) return; if (uha->uaa->vendor == USB_VENDOR_APPLE) { int iso = 0; if ((uha->uaa->product == USB_PRODUCT_APPLE_FOUNTAIN_ISO) || (uha->uaa->product == USB_PRODUCT_APPLE_GEYSER_ISO)) iso = 1; if (hid_locate(desc, dlen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), uha->reportid, hid_input, &sc->sc_apple_fn, &qflags)) { if (qflags & HIO_VARIABLE) { if (iso) sc->sc_munge = ukbd_apple_iso_munge; else sc->sc_munge = ukbd_apple_munge; } } } if (uha->uaa->vendor == USB_VENDOR_TOPRE && uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) { /* ignore country code on purpose */ } else { hid = usbd_get_hid_descriptor(uha->uaa->iface); if (hid->bCountryCode <= HCC_MAX) layout = ukbd_countrylayout[hid->bCountryCode]; #ifdef DIAGNOSTIC if (hid->bCountryCode != 0) printf(", country code %d", hid->bCountryCode); #endif } if (layout == (kbd_t)-1) { #ifdef UKBD_LAYOUT layout = UKBD_LAYOUT; #else layout = KB_US | KB_DEFAULT; #endif } printf("\n"); #ifdef __loongson__ if (uha->uaa->vendor == USB_VENDOR_CYPRESS && uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK) sc->sc_munge = ukbd_gdium_munge; #endif if (kbd->sc_console_keyboard) { extern struct wskbd_mapdata ukbd_keymapdata; DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc)); ukbd_keymapdata.layout = layout; wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata); ukbd_enable(sc, 1); } /* Flash the leds; no real purpose, just shows we're alive. */ ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS | WSKBD_LED_COMPOSE); usbd_delay_ms(sc->sc_hdev.sc_udev, 400); ukbd_set_leds(sc, 0); hidkbd_attach_wskbd(kbd, layout, &ukbd_accessops); }
int main(int argc, char **argv) { const char *conf = NULL; const char *dev = NULL; int fd, ch, sz, n, val, i; int demon, ignore; report_desc_t repd; char buf[100]; char devnamebuf[PATH_MAX]; struct command *cmd; int reportid; demon = 1; ignore = 0; while ((ch = getopt(argc, argv, "c:df:iv")) != -1) { switch(ch) { case 'c': conf = optarg; break; case 'd': demon ^= 1; break; case 'i': ignore++; break; case 'f': dev = optarg; break; case 'v': demon = 0; verbose++; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (conf == NULL || dev == NULL) usage(); if (hid_start(NULL) == -1) errx(1, "hid_init"); if (dev[0] != '/') { snprintf(devnamebuf, sizeof(devnamebuf), "/dev/%s%s", isdigit((unsigned char)dev[0]) ? "uhid" : "", dev); dev = devnamebuf; } if (demon && conf[0] != '/') errx(1, "config file must have an absolute path, %s", conf); fd = open(dev, O_RDWR | O_CLOEXEC); if (fd < 0) err(1, "%s", dev); if (ioctl(fd, USB_GET_REPORT_ID, &reportid) < 0) reportid = -1; repd = hid_get_report_desc(fd); if (repd == NULL) err(1, "hid_get_report_desc() failed"); commands = parse_conf(conf, repd, reportid, ignore); sz = hid_report_size(repd, hid_input, reportid); if (verbose) printf("report size %d\n", sz); if (sz > sizeof buf) errx(1, "report too large"); (void)signal(SIGHUP, sighup); /* we do not care about the children, so ignore them */ (void)signal(SIGCHLD, SIG_IGN); if (demon) { if (daemon(0, 0) < 0) err(1, "daemon()"); isdemon = 1; } for(;;) { n = read(fd, buf, sz); if (verbose > 2) { printf("read %d bytes:", n); for (i = 0; i < n; i++) printf(" %02x", buf[i]); printf("\n"); } if (n < 0) { if (verbose) err(1, "read"); else exit(1); } if (n != sz) { err(2, "read size"); } for (cmd = commands; cmd; cmd = cmd->next) { val = hid_get_data(buf, &cmd->item); if (cmd->value == val || cmd->anyvalue) docmd(cmd, val, dev, argc, argv); } if (reparse) { struct command *cmds = parse_conf(conf, repd, reportid, ignore); if (cmds) { freecommands(commands); commands = cmds; } reparse = 0; } } exit(0); }
void dumpdata(int f, report_desc_t rd, int loop) { struct hid_data *d; struct hid_item h, *hids, *n; int r, dlen; u_char *dbuf; u_int32_t colls[100]; int sp = 0; char namebuf[10000], *namep; hids = 0; for (d = hid_start_parse(rd, 1<<hid_input, -1); hid_get_item(d, &h); ) { if (h.kind == hid_collection) colls[++sp] = h.usage; else if (h.kind == hid_endcollection) --sp; if (h.kind != hid_input || (h.flags & HIO_CONST)) continue; h.next = hids; h.collection = colls[sp]; hids = malloc(sizeof *hids); *hids = h; } hid_end_parse(d); rev(&hids); dlen = hid_report_size(rd, hid_input, -1); dbuf = malloc(dlen); if (!loop) if (hid_set_immed(f, 1) < 0) { if (errno == EOPNOTSUPP) warnx("device does not support immediate mode, only changes reported."); else err(1, "USB_SET_IMMED"); } do { r = read(f, dbuf, dlen); if (r < 1) { err(1, "read error"); } for (n = hids; n; n = n->next) { if (n->report_ID != 0 && dbuf[0] != n->report_ID) continue; namep = namebuf; namep += sprintf(namep, "%s:%s.", hid_usage_page(HID_PAGE(n->collection)), hid_usage_in_page(n->collection)); namep += sprintf(namep, "%s:%s", hid_usage_page(HID_PAGE(n->usage)), hid_usage_in_page(n->usage)); if (all || gotname(namebuf)) { if (!noname) printf("%s=", namebuf); prdata(dbuf, n); printf("\n"); } } if (loop) printf("\n"); } while (loop); free(dbuf); }