Example #1
0
/*
 * Handle non standard and non device calls.
 *
 * return non-zero if the call was handled.
 */
int
hid_handle_control(struct usb_ctrl_req_t *req, void *data)
{
    struct hid_ctx *ctx = data;
    const void *buf = NULL;
    size_t len = 0;

    if (req->type == USB_CTRL_REQ_CLASS)
        return (hid_handle_control_class(req, ctx));

    switch (req->bRequest) {
    case USB_CTRL_REQ_GET_DESCRIPTOR:
        if (req->wValueHigh == USB_HID_REPORT_DESC_TYPE_REPORT) {
            buf = ctx->hidf->report_desc;
            len = ctx->hidf->report_desc_size;
        } else {
            if (ctx->hidf->get_descriptor)
                len = ctx->hidf->get_descriptor(req->wValueHigh, req->wValueLow, &buf);
        }
        if (len == 0)
            return (0);
        usb_ep0_tx_cp(buf, len, req->wLength, NULL, NULL);
        usb_handle_control_status(0);
        return (1);

    case USB_CTRL_REQ_SET_DESCRIPTOR: // TODO
        return (0);

    default:
        return (0);
    }
}
Example #2
0
/* Windows 7 fails to configure device unless this is implemented */
static int
cdc_handle_control(struct usb_ctrl_req_t *req, void *data)
{
    struct cdc_ctx *ctx = data;
    switch ((enum cdc_ctrl_req_code)req->bRequest) {
    case USB_CTRL_REQ_CDC_SET_LINE_CODING: {
        if (req->wLength != sizeof(struct cdc_line_coding)) {
            usb_handle_control_status(1);
        } else {
            usb_ep0_rx(&ctx->line_coding, req->wLength, cdc_handle_control_set_line_coding, ctx);
            return 1;
        }
        break;
    }
    case USB_CTRL_REQ_CDC_GET_LINE_CODING: {
        usb_ep0_tx_cp(&ctx->line_coding, sizeof(struct cdc_line_coding), req->wLength, NULL, NULL);
        usb_handle_control_status(0);
        break;
    }
    case USB_CTRL_REQ_CDC_SET_CTRL_LINE_STATE: {
        /*
         * We should remain inactive unless there is a terminal on the other end of the link,
         * indicated by the first two bits of wValue
         */
        ctx->control_lines = req->wValue;
        usb_handle_control_status(0);
        break;
    }
    default:
        return 0;
    }
    return 0;
}
Example #3
0
File: usb.c Project: dwhacks/mchck
static int
usb_tx_config_desc(int idx, int reqlen)
{
	const struct usb_desc_config_t *d = usb.identity->configs[idx]->desc;

	usb_ep0_tx_cp(d, d->wTotalLength, reqlen, NULL, NULL);
	return (0);
}
Example #4
0
File: usb.c Project: dwhacks/mchck
static int
usb_tx_string_desc(int idx, int reqlen)
{
	const struct usb_desc_string_t * const *d;

	for (d = usb.identity->string_descs; idx != 0 && *d != NULL; ++d)
		--idx;
	if (*d == NULL)
		return (-1);
	usb_ep0_tx_cp(*d, (*d)->bLength, reqlen, NULL, NULL);
	return (0);
}
Example #5
0
File: usb.c Project: koson/mchck-os
__noinline
void
usb_handle_control_status_cb(ep_callback_t cb, void *cbdata)
{
	/* empty status transfer */
	switch (usb.ctrl_dir) {
	case USB_CTRL_REQ_IN:
		usbd_pipe_state[USBD_PIPE_EP0_RX].data01 = USB_DATA01_DATA1;
		usb_rx(&usbd_pipe_state[USBD_PIPE_EP0_RX], NULL, 0, cb, cbdata);
		break;

	default:
		usbd_pipe_state[USBD_PIPE_EP0_TX].data01 = USB_DATA01_DATA1;
		usb_ep0_tx_cp(NULL, 0, 1 /* short packet */, cb, cbdata);
		break;
	}
}
Example #6
0
File: usb.c Project: Zuph/mchck
static int
usb_tx_string_desc(int idx, int reqlen)
{
	const struct usb_desc_string_t * const *d;

	for (d = usb.identity->string_descs; idx != 0 && *d != NULL; ++d)
		--idx;
	switch ((uintptr_t)*d) {
	case (uintptr_t)NULL:
		return (-1);
	case (uintptr_t)USB_DESC_STRING_SERIALNO:
		return (usb_tx_serialno(reqlen));
	default:
		usb_ep0_tx_cp(*d, (*d)->bLength, reqlen, NULL, NULL);
		return (0);
	}
}
Example #7
0
__noinline
void
usb_handle_control_status_cb(ep_callback_t cb)
{
	/* empty status transfer */
	switch (usb.ctrl_dir) {
	case USB_CTRL_REQ_IN:
		usbd_ep_state[0].rx.data01 = USB_DATA01_DATA1;
		usb_rx(&usbd_ep_state[0].rx, NULL, 0, cb, NULL);
		break;

	default:
		usbd_ep_state[0].tx.data01 = USB_DATA01_DATA1;
		usb_ep0_tx_cp(NULL, 0, 1 /* short packet */, cb, NULL);
		break;
	}
}
Example #8
0
File: usb.c Project: dwhacks/mchck
void
usb_handle_control_status(int fail)
{
	if (fail) {
		usb_pipe_stall(&usb.ep_state[0].rx);
		usb_pipe_stall(&usb.ep_state[0].tx);
		return;
	}

	/* empty status transfer */
	switch (usb.ctrl_dir) {
	case USB_CTRL_REQ_IN:
		usb.ep_state[0].rx.data01 = USB_DATA01_DATA1;
		usb_rx(&usb.ep_state[0].rx, NULL, 0, usb_handle_control_done, NULL);
		break;

	default:
		usb.ep_state[0].tx.data01 = USB_DATA01_DATA1;
		usb_ep0_tx_cp(NULL, 0, 1 /* short packet */, usb_handle_control_done, NULL);
		break;
	}
}
Example #9
0
File: usb.c Project: dwhacks/mchck
static void
usb_handle_control(void *data, ssize_t len, void *cbdata)
{
	struct usb_ctrl_req_t *req = data;
	uint16_t zero16 = 0;
	int fail = 1;

	usb_clear_transfers();
	usb.ctrl_dir = req->in;

	if (req->type != USB_CTRL_REQ_STD) {
		usb_handle_control_nonstd(req);
		return;
	}

	/* Only STD requests here */
	switch (req->bRequest) {
	case USB_CTRL_REQ_GET_STATUS:
		/**
		 * Because we don't support remote wakeup or
		 * self-powered operation, and we are specialized to
		 * only EP 0 so far, all GET_STATUS replies are just
		 * empty.
		 */
		usb_ep0_tx_cp(&zero16, sizeof(zero16), req->wLength, NULL, NULL);
		break;

	case USB_CTRL_REQ_CLEAR_FEATURE:
	case USB_CTRL_REQ_SET_FEATURE:
		/**
		 * Nothing to do.  Maybe return STALLs on illegal
		 * accesses?
		 */
		break;

	case USB_CTRL_REQ_SET_ADDRESS:
		/**
		 * We must keep our previous address until the end of
		 * the status stage;  therefore we can't set the
		 * address right now.  Since this is a special case,
		 * the EP 0 handler will take care of this later on.
		 */
		usb.address = req->wValue & 0x7f;
		usb.state = USBD_STATE_SETTING_ADDRESS;
		break;

	case USB_CTRL_REQ_GET_DESCRIPTOR:
		switch (req->wValue >> 8) {
		case USB_DESC_DEV:
			usb_ep0_tx_cp(usb.identity->dev_desc, usb.identity->dev_desc->bLength,
				      req->wLength, NULL, NULL);
			fail = 0;
			break;
		case USB_DESC_CONFIG:
			fail = usb_tx_config_desc(req->wValue & 0xff, req->wLength);
			break;
		case USB_DESC_STRING:
			fail = usb_tx_string_desc(req->wValue & 0xff, req->wLength);
			break;
		default:
			fail = -1;
			break;
		}
		/* we set fail already, so we can go directly to `err' */
		goto err;

	case USB_CTRL_REQ_GET_CONFIGURATION:
		usb_ep0_tx_cp(&usb.config, 1, req->wLength, NULL, NULL); /* XXX implicit LE */
		break;

	case USB_CTRL_REQ_SET_CONFIGURATION:
		if (usb_set_config(req->wValue) < 0)
			goto err;
		break;

	case USB_CTRL_REQ_GET_INTERFACE:
		/* We only support iface setting 0 */
		usb_ep0_tx_cp(&zero16, 1, req->wLength, NULL, NULL);
		break;

	case USB_CTRL_REQ_SET_INTERFACE:
		if (usb_set_interface(req->wIndex, req->wValue) < 0)
			goto err;
		break;

	default:
		goto err;
	}

	fail = 0;

err:
	usb_handle_control_status(fail);
}
Example #10
0
int
dfu_handle_control(struct usb_ctrl_req_t *req, void *data)
{
        struct dfu_ctx *ctx = data;
        int fail = 1;

        /* XXX check for std vs class request */
        switch ((uint8_t)req->bRequest) {
        case USB_CTRL_REQ_SET_INTERFACE:
                if (req->wValue >= ctx->dfuf->segment_count)
                        goto out;
                ctx->segment = req->wValue;
                ctx->state = DFU_STATE_dfuIDLE;
                break;

        case USB_CTRL_REQ_GET_INTERFACE:
                usb_ep0_tx_cp(&ctx->segment, 1, req->wLength, NULL, NULL);
                break;

        case USB_CTRL_REQ_DFU_DNLOAD: {
                void *buf;

                switch (ctx->state) {
                case DFU_STATE_dfuIDLE:
                        ctx->off = 0;
                        break;
                case DFU_STATE_dfuDNLOAD_IDLE:
                        break;
                default:
                        goto err;
                }

                /**
                 * XXX we are not allowed to STALL here, and we need to eat all transferred data.
                 * better not allow setup_write to break the protocol.
                 */
                ctx->status = ctx->dfuf->segment[ctx->segment].setup_write(ctx, ctx->off, req->wLength, &buf);
                if (ctx->status != DFU_STATUS_OK) {
                        ctx->state = DFU_STATE_dfuERROR;
                        goto err_have_status;
                }

                if (req->wLength > 0) {
                        ctx->state = DFU_STATE_dfuDNLOAD_SYNC;
                        usb_ep0_rx(buf, req->wLength, dfu_dnload_complete, ctx);
                } else {
                        ctx->state = DFU_STATE_dfuMANIFEST_SYNC;
                        dfu_dnload_complete(NULL, 0, ctx);
                }
                goto out_no_status;
        }
        case USB_CTRL_REQ_DFU_GETSTATUS: {
                struct dfu_status_t st;

                st.bState = ctx->state;
                st.bStatus = ctx->status;
                st.bwPollTimeout = 1; /* XXX allow setting in desc? */
                /**
                 * If we're in DFU_STATE_dfuMANIFEST, we just finished
                 * the download, and we're just about to send our last
                 * status report.  Once the report has been sent, go
                 * and reset the system to put the new firmware into
                 * effect.
                 */
                usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
                break;
        }
        case USB_CTRL_REQ_DFU_CLRSTATUS:
                if (ctx->state != DFU_STATE_dfuERROR)
                        goto err;
                ctx->state = DFU_STATE_dfuIDLE;
                ctx->status = DFU_STATUS_OK;
                break;
        case USB_CTRL_REQ_DFU_GETSTATE: {
                uint8_t st = ctx->state;
                usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL);
                break;
        }
        case USB_CTRL_REQ_DFU_ABORT:
                switch (ctx->state) {
                case DFU_STATE_dfuIDLE:
                case DFU_STATE_dfuDNLOAD_IDLE:
                /* case DFU_STATE_dfuUPLOAD_IDLE: */
                        ctx->state = DFU_STATE_dfuIDLE;
                        break;
                default:
                        goto err;
                }
                break;
        /* case USB_CTRL_REQ_DFU_UPLOAD: */
        default:
                return (0);
        }

        fail = 0;
        goto out;

err:
        ctx->status = DFU_STATUS_errSTALLEDPKT;
err_have_status:
        ctx->state = DFU_STATE_dfuERROR;
out:
        usb_handle_control_status(fail);
out_no_status:
        return (1);
}
Example #11
0
/*
 * Handle class (HID) specific calls.
 *
 * see hid_handle_control()
 */
static int
hid_handle_control_class(struct usb_ctrl_req_t *req, struct hid_ctx *ctx)
{
    size_t len = 0;

    /* XXX maintain state for all report descriptors */

    switch ((enum hid_ctrl_req_code)req->bRequest) {
    case USB_CTRL_REQ_HID_GET_REPORT: {
        enum hid_report_type report_type = req->wValue >> 8;
        uint8_t report_id = req->wValue & 0xff;
        int ret = -1;

        ctx->get_report_outstanding_length = req->wLength;
        if (ctx->hidf->get_report)
            ret = ctx->hidf->get_report(ctx, report_type, report_id);
        if (ret <= 0) {
            ctx->get_report_outstanding_length = 0;
            usb_handle_control_status(1);
        }
        return (1);
    }

    case USB_CTRL_REQ_HID_SET_REPORT: {
        int ret = -1;
        void *buf = NULL;
        ctx->set_report_length = req->wLength;
        ctx->set_report_type = req->wValue >> 8;
        ctx->set_report_id = req->wValue & 0xff;

        if (ctx->hidf->set_report)
            ret = ctx->hidf->set_report(ctx->set_report_type, ctx->set_report_id, &buf, ctx->set_report_length);
        if (ret > 0)
            usb_ep0_rx(buf, ctx->set_report_length, hid_set_report_done, ctx);
        else
            usb_handle_control_status(1);
        return (1);
    }

    case USB_CTRL_REQ_HID_GET_IDLE:
        /* XXX implement */
        usb_ep0_tx_cp(&len, 1, req->wLength, NULL, NULL);
        usb_handle_control_status(0);
        return (1);

    case USB_CTRL_REQ_HID_SET_IDLE:
        /* XXX implement */
        usb_handle_control_status(0);
        return (1);

    case USB_CTRL_REQ_HID_GET_PROTOCOL:
        /* XXX implement */
        /* usb_ep0_tx_cp(&len, 1, req->wLength, NULL, NULL); */
        /* usb_handle_control_status(0); */
        return (0);

    case USB_CTRL_REQ_HID_SET_PROTOCOL:
        /* XXX implement */
        usb_handle_control_status(0);
        return (1);

    default:
        return (0);
    }
}