Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
/*
 *  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;
}
Example #5
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);
}
Example #6
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;
}