예제 #1
0
파일: usb.c 프로젝트: helaibai/usbip
static void handle_control (int fd, struct usb_ctrlrequest *setup)
{
	int		status, tmp;
	__u8		buf [256];
	__u16		value, index, length;

	value = __le16_to_cpu(setup->wValue);
	index = __le16_to_cpu(setup->wIndex);
	length = __le16_to_cpu(setup->wLength);

	if (verbose)
		fprintf (stderr, "SETUP %02x.%02x "
				"v%04x i%04x %d\n",
			setup->bRequestType, setup->bRequest,
			value, index, length);

	/*
	if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
		goto special;
	*/

	switch (setup->bRequest) {	/* usb 2.0 spec ch9 requests */
	case USB_REQ_GET_DESCRIPTOR:
		if (setup->bRequestType != USB_DIR_IN)
			goto stall;
		switch (value >> 8) {
		case USB_DT_STRING:
			tmp = value & 0x0ff;
			if (verbose > 1)
				fprintf (stderr,
					"... get string %d lang %04x\n",
					tmp, index);
			if (tmp != 0 && index != strings.language)
				goto stall;
			status = usb_gadget_get_string (&strings, tmp, buf);
			if (status < 0)
				goto stall;
			tmp = status;
			if (length < tmp)
				tmp = length;
			status = write (fd, buf, tmp);
			if (status < 0) {
				if (errno == EIDRM)
					fprintf (stderr, "string timeout\n");
				else
					perror ("write string data");
			} else if (status != tmp) {
				fprintf (stderr, "short string write, %d\n",
					status);
			}
			break;
		default:
			goto stall;
		}
		return;
	case USB_REQ_SET_CONFIGURATION:
		if (setup->bRequestType != USB_DIR_OUT)
			goto stall;
		if (verbose)
			fprintf (stderr, "CONFIG #%d\n", value);

		/* Kernel is normally waiting for us to finish reconfiguring
		 * the device.
		 *
		 * Some hardware can't, notably older PXA2xx hardware.  (With
		 * racey and restrictive config change automagic.  PXA 255 is
		 * OK, most PXA 250s aren't.  If it has a UDC CFR register,
		 * it can handle deferred response for SET_CONFIG.)  To handle
		 * such hardware, don't write code this way ... instead, keep
		 * the endpoints always active and don't rely on seeing any
		 * config change events, either this or SET_INTERFACE.
		 */
		switch (value) {
		case CONFIG_VALUE:
			start_io ();
			break;
		case 0:
			stop_io ();
			break;
		default:
			/* kernel bug -- "can't happen" */
			fprintf (stderr, "? illegal config\n");
			goto stall;
		}

		/* ... ack (a write would stall) */
		status = read (fd, &status, 0);
		if (status)
			perror ("ack SET_CONFIGURATION");
		return;
	case USB_REQ_GET_INTERFACE:
		if (setup->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
				|| index != 0
				|| length > 1)
			goto stall;

		/* only one altsetting in this driver */
		buf [0] = 0;
		status = write (fd, buf, length);
		if (status < 0) {
			if (errno == EIDRM)
				fprintf (stderr, "GET_INTERFACE timeout\n");
			else
				perror ("write GET_INTERFACE data");
		} else if (status != length) {
			fprintf (stderr, "short GET_INTERFACE write, %d\n",
				status);
		}
		return;
	case USB_REQ_SET_INTERFACE:
		if (setup->bRequestType != USB_RECIP_INTERFACE
				|| index != 0
				|| value != 0)
			goto stall;

		/* just reset toggle/halt for the interface's endpoints */
		status = 0;
		if (ioctl (source_fd, GADGETFS_CLEAR_HALT) < 0) {
			status = errno;
			perror ("reset source fd");
		}
		if (ioctl (sink_fd, GADGETFS_CLEAR_HALT) < 0) {
			status = errno;
			perror ("reset sink fd");
		}
		/* FIXME eventually reset the status endpoint too */
		if (status)
			goto stall;

		/* ... and ack (a write would stall) */
		status = read (fd, &status, 0);
		if (status)
			perror ("ack SET_INTERFACE");
		return;
	default:
		goto stall;
	}

stall:
	if (verbose)
		fprintf (stderr, "... protocol stall %02x.%02x\n",
			setup->bRequestType, setup->bRequest);

	/* non-iso endpoints are stalled by issuing an i/o request
	 * in the "wrong" direction.  ep0 is special only because
	 * the direction isn't fixed.
	 */
	if (setup->bRequestType & USB_DIR_IN)
		status = read (fd, &status, 0);
	else
		status = write (fd, &status, 0);
	if (status != -1)
		fprintf (stderr, "can't stall ep0 for %02x.%02x\n",
			setup->bRequestType, setup->bRequest);
	else if (errno != EL2HLT)
		perror ("ep0 stall");
}
예제 #2
0
파일: zero.c 프로젝트: sserg31/sca3_main
/*
 * The setup() callback implements all the ep0 functionality that's
 * not handled lower down, in hardware or the hardware driver (like
 * device and endpoint feature flags, and their status).  It's all
 * housekeeping for the gadget function we're implementing.  Most of
 * the work is in config-specific setup.
 */
static int
zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
    struct zero_dev		*dev = get_gadget_data(gadget);
    struct usb_request	*req = dev->req;
    int			value = -EOPNOTSUPP;
    u16			w_index = le16_to_cpu(ctrl->wIndex);
    u16			w_value = le16_to_cpu(ctrl->wValue);
    u16			w_length = le16_to_cpu(ctrl->wLength);

    /* usually this stores reply data in the pre-allocated ep0 buffer,
     * but config change events will reconfigure hardware.
     */
    req->zero = 0;
    switch (ctrl->bRequest) {

    case USB_REQ_GET_DESCRIPTOR:
        if (ctrl->bRequestType != USB_DIR_IN)
            goto unknown;
        switch (w_value >> 8) {

        case USB_DT_DEVICE:
            value = min(w_length, (u16) sizeof device_desc);
            memcpy(req->buf, &device_desc, value);
            break;
        case USB_DT_DEVICE_QUALIFIER:
            if (!gadget_is_dualspeed(gadget))
                break;
            value = min(w_length, (u16) sizeof dev_qualifier);
            memcpy(req->buf, &dev_qualifier, value);
            break;

        case USB_DT_OTHER_SPEED_CONFIG:
            if (!gadget_is_dualspeed(gadget))
                break;
        // FALLTHROUGH
        case USB_DT_CONFIG:
            value = config_buf(gadget, req->buf,
                               w_value >> 8,
                               w_value & 0xff);
            if (value >= 0)
                value = min(w_length, (u16) value);
            break;

        case USB_DT_STRING:
            /* wIndex == language code.
             * this driver only handles one language, you can
             * add string tables for other languages, using
             * any UTF-8 characters
             */
            value = usb_gadget_get_string(&stringtab,
                                          w_value & 0xff, req->buf);
            if (value >= 0)
                value = min(w_length, (u16) value);
            break;
        }
        break;

    /* currently two configs, two speeds */
    case USB_REQ_SET_CONFIGURATION:
        if (ctrl->bRequestType != 0)
            goto unknown;
        if (gadget->a_hnp_support)
            DBG(dev, "HNP available\n");
        else if (gadget->a_alt_hnp_support)
            DBG(dev, "HNP needs a different root port\n");
        else
            VDBG(dev, "HNP inactive\n");
        spin_lock(&dev->lock);
        value = zero_set_config(dev, w_value);
        spin_unlock(&dev->lock);
        break;
    case USB_REQ_GET_CONFIGURATION:
        if (ctrl->bRequestType != USB_DIR_IN)
            goto unknown;
        *(u8 *)req->buf = dev->config;
        value = min(w_length, (u16) 1);
        break;

    /* until we add altsetting support, or other interfaces,
     * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)
     * and already killed pending endpoint I/O.
     */
    case USB_REQ_SET_INTERFACE:
        if (ctrl->bRequestType != USB_RECIP_INTERFACE)
            goto unknown;
        spin_lock(&dev->lock);
        if (dev->config && w_index == 0 && w_value == 0) {
            u8		config = dev->config;

            /* resets interface configuration, forgets about
             * previous transaction state (queued bufs, etc)
             * and re-inits endpoint state (toggle etc)
             * no response queued, just zero status == success.
             * if we had more than one interface we couldn't
             * use this "reset the config" shortcut.
             */
            zero_reset_config(dev);
            zero_set_config(dev, config);
            value = 0;
        }
        spin_unlock(&dev->lock);
        break;
    case USB_REQ_GET_INTERFACE:
        if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
            goto unknown;
        if (!dev->config)
            break;
        if (w_index != 0) {
            value = -EDOM;
            break;
        }
        *(u8 *)req->buf = 0;
        value = min(w_length, (u16) 1);
        break;

    /*
     * These are the same vendor-specific requests supported by
     * Intel's USB 2.0 compliance test devices.  We exceed that
     * device spec by allowing multiple-packet requests.
     */
    case 0x5b:	/* control WRITE test -- fill the buffer */
        if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
            goto unknown;
        if (w_value || w_index)
            break;
        /* just read that many bytes into the buffer */
        if (w_length > USB_BUFSIZ)
            break;
        value = w_length;
        break;
    case 0x5c:	/* control READ test -- return the buffer */
        if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
            goto unknown;
        if (w_value || w_index)
            break;
        /* expect those bytes are still in the buffer; send back */
        if (w_length > USB_BUFSIZ
                || w_length != req->length)
            break;
        value = w_length;
        break;

    default:
unknown:
        VDBG(dev,
             "unknown control req%02x.%02x v%04x i%04x l%d\n",
             ctrl->bRequestType, ctrl->bRequest,
             w_value, w_index, w_length);
    }

    /* respond with data transfer before status phase? */
    if (value >= 0) {
        req->length = value;
        req->zero = value < w_length;
        value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
        if (value < 0) {
            DBG(dev, "ep_queue --> %d\n", value);
            req->status = 0;
            zero_setup_complete(gadget->ep0, req);
        }
    }

    /* device either stalls (value < 0) or reports success */
    return value;
}
예제 #3
0
/*
 * The setup() callback implements all the ep0 functionality that's not
 * handled lower down.  CDC has a number of less-common features:
 *
 *  - two interfaces:  control, and ethernet data
 *  - Ethernet data interface has two altsettings:  default, and active
 *  - class-specific descriptors for the control interface
 *  - class-specific control requests
 */
static int fastboot_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
	struct fastboot_dev *dev = get_gadget_data(gadget);
	struct usb_request *req = dev->req;
	int value = -EOPNOTSUPP;
	u16 wIndex = le16_to_cpu(ctrl->wIndex);
	u16 wValue = le16_to_cpu(ctrl->wValue);
	u16 wLength = le16_to_cpu(ctrl->wLength);

	/*
	 * descriptors just go into the pre-allocated ep0 buffer,
	 * while config change events may enable network traffic.
	 */

	debug("%s\n", __func__);

	req->complete = fastboot_setup_complete;
	switch (ctrl->bRequest) {

	case USB_REQ_GET_DESCRIPTOR:
		if (ctrl->bRequestType != USB_DIR_IN)
			break;
		switch (wValue >> 8) {

		case USB_DT_DEVICE:
			value = min(wLength, (u16) sizeof device_desc);
			memcpy(req->buf, &device_desc, value);
			break;
		case USB_DT_DEVICE_QUALIFIER:
			if (!gadget_is_dualspeed(gadget))
				break;
			value = min(wLength, (u16) sizeof dev_qualifier);
			memcpy(req->buf, &dev_qualifier, value);
			break;

		case USB_DT_OTHER_SPEED_CONFIG:
			if (!gadget_is_dualspeed(gadget))
				break;
			/* FALLTHROUGH */
		case USB_DT_CONFIG:
			value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, gadget_is_otg(gadget));
			if (value >= 0)
				value = min(wLength, (u16) value);
			break;

		case USB_DT_STRING:
			value = usb_gadget_get_string(&stringtab, wValue & 0xff, req->buf);

			if (value >= 0)
				value = min(wLength, (u16) value);

			break;
		}
		break;

	case USB_REQ_SET_CONFIGURATION:
		if (ctrl->bRequestType != 0)
			break;
		value = fastboot_set_config(dev, wValue, GFP_ATOMIC);
		l_fbdev.network_started = 1;
		break;
	case USB_REQ_GET_CONFIGURATION:
		if (ctrl->bRequestType != USB_DIR_IN)
			break;
		*(u8 *) req->buf = dev->config;
		value = min(wLength, (u16) 1);
		break;

	case USB_REQ_SET_INTERFACE:
		if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->config || wIndex > 1)
			break;
		/*
		 * FIXME this is wrong, as is the assumption that
		 * all non-PXA hardware talks real CDC ...
		 */
		debug("set_interface ignored!\n");

done_set_intf:
		break;
	case USB_REQ_GET_INTERFACE:
		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)
		    || !dev->config || wIndex > 1)
			break;

		/* for CDC, iff carrier is on, data interface is active. */
		if (wIndex != 1)
			*(u8 *) req->buf = 0;
		else {
			/* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */
			/* carrier always ok ... */
			*(u8 *) req->buf = 1;
		}
		value = min(wLength, (u16) 1);
		break;
	default:
		debug("unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
	}

	/* respond with data transfer before status phase? */
	if (value >= 0) {
		debug("respond with data transfer before status phase\n");
		req->length = value;
		req->zero = value < wLength && (value % gadget->ep0->maxpacket) == 0;
		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
		if (value < 0) {
			debug("ep_queue --> %d\n", value);
			req->status = 0;
			fastboot_setup_complete(gadget->ep0, req);
		}
	}

	/* host either stalls (value < 0) or reports success */
	return value;
}