int uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) { int s; int error = 0; int extra; size_t length; u_char buffer[UHID_CHUNK]; usbd_status err; DPRINTFN(1, ("uhidread\n")); if (sc->sc_state & UHID_IMMED) { DPRINTFN(1, ("uhidread immed\n")); extra = sc->sc_hdev.sc_report_id != 0; err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, sc->sc_hdev.sc_report_id, buffer, sc->sc_hdev.sc_isize + extra); if (err) return (EIO); return (uiomove(buffer+extra, sc->sc_hdev.sc_isize, uio)); } s = splusb(); while (sc->sc_q.c_cc == 0) { if (flag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); } sc->sc_state |= UHID_ASLP; DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0); DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); if (usbd_is_dying(sc->sc_hdev.sc_udev)) error = EIO; if (error) { sc->sc_state &= ~UHID_ASLP; break; } } splx(s); /* Transfer as many chunks as possible. */ while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { length = min(sc->sc_q.c_cc, uio->uio_resid); if (length > sizeof(buffer)) length = sizeof(buffer); /* Remove a small chunk from the input queue. */ (void) q_to_b(&sc->sc_q, buffer, length); DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length)); /* Copy the data to the user process. */ if ((error = uiomove(buffer, length, uio)) != 0) break; } return (error); }
int uslhcom_get_uart_status(struct uslhcom_softc *sc, struct uslhcom_uart_status *status) { int len; len = sizeof(*status); return uhidev_get_report(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT, GET_UART_STATUS, status, len) < len; }
int uslhcom_get_version(struct uslhcom_softc *sc, struct uslhcom_version_info *version) { int len; len = sizeof(*version); return uhidev_get_report(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT, GET_VERSION, version, len) < len; }
/* * basic procedure to issue command to the OAK device. * 1) check the device is ready to accept command. * if a report of a FEATURE_REPORT request is not start 0xff, * wait for a while, and retry till the reponse start with 0xff. * 2) issue command. (set or get) * 3) if the command will response, wait for a while, and issue * FEATURE_REPORT. leading 0xff indicate the response is valid. * if the first byte is not 0xff, retry. */ int uoak_check_device_ready(struct uoak_softc *sc) { if (uhidev_get_report(sc->sc_hdev, UHID_FEATURE_REPORT, &sc->sc_buf, sc->sc_flen)) return EIO; if (sc->sc_buf[0] != 0xff) return -1; return 0; }
int uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, int flag, struct proc *p) { u_char buffer[UHID_CHUNK]; int size, extra; usbd_status err; int rc; DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); if (sc->sc_dying) return (EIO); switch (cmd) { case FIONBIO: /* All handled in the upper FS layer. */ break; case FIOASYNC: if (*(int *)addr) { if (sc->sc_async != NULL) return (EBUSY); sc->sc_async = p->p_p; DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", p)); } else sc->sc_async = NULL; break; /* XXX this is not the most general solution. */ case TIOCSPGRP: if (sc->sc_async == NULL) return (EINVAL); if (*(int *)addr != sc->sc_async->ps_pgid) return (EPERM); break; case USB_SET_IMMED: if (*(int *)addr) { extra = sc->sc_hdev.sc_report_id != 0; err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, buffer, sc->sc_hdev.sc_isize + extra); if (err) return (EOPNOTSUPP); sc->sc_state |= UHID_IMMED; } else sc->sc_state &= ~UHID_IMMED; break; case USB_GET_DEVICEINFO: usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev, (struct usb_device_info *)addr, 1); break; case USB_GET_STRING_DESC: { struct usb_string_desc *si = (struct usb_string_desc *)addr; err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev, si->usd_string_index, si->usd_language_id, &si->usd_desc, &size); if (err) return (EINVAL); break; } case USB_GET_REPORT_DESC: case USB_GET_REPORT: case USB_SET_REPORT: case USB_GET_REPORT_ID: default: rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p); if (rc == -1) rc = EINVAL; return rc; } return (0); }
int uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct usb_ctl_report_desc *rd; struct usb_ctl_report *re; int size, extra; usbd_status err; void *desc; switch (cmd) { case USB_GET_REPORT_DESC: uhidev_get_report_desc(sc->sc_parent, &desc, &size); rd = (struct usb_ctl_report_desc *)addr; size = min(size, sizeof rd->ucrd_data); rd->ucrd_size = size; memcpy(rd->ucrd_data, desc, size); break; case USB_GET_REPORT: re = (struct usb_ctl_report *)addr; switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; break; default: return EINVAL; } extra = sc->sc_report_id != 0; err = uhidev_get_report(sc, re->ucr_report, re->ucr_data, size + extra); if (extra) memcpy(re->ucr_data, re->ucr_data + 1, size); if (err) return EIO; break; case USB_SET_REPORT: re = (struct usb_ctl_report *)addr; switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; break; default: return EINVAL; } err = uhidev_set_report(sc, re->ucr_report, re->ucr_data, size); if (err) return EIO; break; case USB_GET_REPORT_ID: *(int *)addr = sc->sc_report_id; break; default: return -1; } return 0; }