Esempio n. 1
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;
}
Esempio n. 2
0
static void
hid_set_report_done(void *buf, ssize_t len, void *cbdata)
{
    struct hid_ctx *ctx = cbdata;
    int ret = -1;

    ret = ctx->hidf->set_report(ctx->set_report_type, ctx->set_report_id, &buf, ctx->set_report_length);

    if (ret > 0)
        usb_handle_control_status(0);
    else
        usb_handle_control_status(1);
}
Esempio n. 3
0
File: usb.c Progetto: dwhacks/mchck
/**
 * This is called by the interrupt handler
 */
void
usb_handle_transaction(struct usb_xfer_info *info)
{
	enum usb_tok_pid pid = usb_get_xfer_pid(info);
	struct usbd_ep_state_t *eps = &usb.ep_state[usb_get_xfer_ep(info)];
	struct usbd_ep_pipe_state_t *s = &eps->pipe[usb_get_xfer_dir(info)];

	switch (pid) {
	case USB_PID_SETUP:
	case USB_PID_OUT:
		/**
		 * If we receive a SETUP transaction, but don't expect
		 * it (callback set to somewhere else), stall the EP.
		 */
		if (pid == USB_PID_SETUP && s->callback != usb_handle_control)
			usb_handle_control_status(1);
		else
			usb_rx_next(s);
		if (pid == USB_PID_SETUP)
			usb_enable_xfers();
		break;
	case USB_PID_IN:
		usb_tx_next(s);
		break;
	default:
		break;
	}
}
Esempio n. 4
0
File: usb.c Progetto: koson/mchck-os
/**
 * Dispatch non-standard request to registered USB functions.
 */
static int
usb_handle_control_nonstddev(struct usb_ctrl_req_t *req)
{
	/* XXX filter by interface/endpoint? */
	for (struct usbd_function_ctx_header *fh = &usb.functions; fh != NULL; fh = fh->next) {
		int handle_it = 0;

		if (req->recp != USB_CTRL_REQ_IFACE)
			handle_it = 1;
		else if ((req->wIndex >= fh->interface_offset &&
			  (req->wIndex < (fh->interface_offset + fh->function->interface_count))) ||
			 fh->function->interface_count == 0)
			handle_it = 1;

		if (handle_it &&
		    fh->function->control != NULL &&
		    fh->function->control(req, fh))
			return (1);
	}

	for (const struct usbd_global *g = usb.identity->global; g != NULL; g = g->next) {
		if (g->control &&
		    g->control(g, req))
			return (1);
	}

	usb_handle_control_status(-1);
	return (1);
}
Esempio n. 5
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);
    }
}
Esempio n. 6
0
void
hid_update_data(struct hid_ctx *ctx, uint8_t report_id, const void *data, size_t len)
{
    if (ctx->get_report_outstanding_length != 0) {
        usb_ep0_tx(data, len, ctx->get_report_outstanding_length, NULL, NULL);
        ctx->get_report_outstanding_length = 0;
        usb_handle_control_status(0);
    } else if (ctx->hidf->report_max_size > 0)  {
        usb_tx(ctx->tx_pipe, data, len, ctx->hidf->report_max_size, NULL, NULL);
    }
}
Esempio n. 7
0
File: usb.c Progetto: dwhacks/mchck
/**
 * Dispatch non-standard request to registered USB functions.
 */
static void
usb_handle_control_nonstd(struct usb_ctrl_req_t *req)
{
	/* XXX filter by interface/endpoint? */
	for (struct usbd_function_ctx_header *fh = &usb.functions; fh != NULL; fh = fh->next) {
		/* ->control() returns != 0 if it handled the request */
		if (fh->function->control != NULL &&
		    fh->function->control(req, fh))
			return;
	}

	usb_handle_control_status(-1);
}
Esempio n. 8
0
static void
dfu_dnload_complete(void *buf, ssize_t len, void *cbdata)
{
        struct dfu_ctx *ctx = cbdata;

        enum dfu_status s = ctx->dfuf->segment[ctx->segment].finish_write(ctx, buf, ctx->off, len);
        ctx->off += len;
        ctx->len = len;

        if (s != DFU_STATUS_async)
                dfu_write_done(s, ctx);

        usb_handle_control_status(ctx->state == DFU_STATE_dfuERROR);
}
Esempio n. 9
0
int
wcid_handle_control(const struct usbd_global *f, struct usb_ctrl_req_t *req)
{
        const struct wcid_function *wcid = (const void *)f;

        if (req->bRequest != WCID_REQ_ID)
                return (0);

        size_t pos, len;
        const struct wcid_generic_header *desc;

        switch (req->wIndex) {
        case WCID_DESC_COMPAT_OS:
                desc = wcid->compat_id;
                break;

        case WCID_DESC_EXTENDED_PROP: {
                static const struct wcid_extended_prop_header ex_prop = {
                        .dwLength = sizeof(ex_prop),
                        .bcdVersion = { .raw = 0x0100 },
                        .wIndex = WCID_DESC_EXTENDED_PROP,
                        .wCount = 0,
                };

                desc = &ex_prop;
                break;
        }

        default:
                return (0);
        }

        pos = (req->wValue & 0xff00) << 8;
        len = req->wLength;
        if (pos > desc->dwLength)
                return (0);
        if (pos + len > desc->dwLength)
                len = desc->dwLength - pos;
        usb_ep0_tx((uint8_t *)desc + pos, len, req->wLength, NULL, NULL);
        usb_handle_control_status(0);
        return (1);
}
Esempio n. 10
0
File: usb.c Progetto: 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);
}
Esempio n. 11
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);
}
Esempio n. 12
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);
    }
}
Esempio n. 13
0
static void
cdc_handle_control_set_line_coding(void *buf, ssize_t len, void *cbdata)
{
    usb_handle_control_status(0);
}