示例#1
0
/**
 * \brief   this function allocates the resources for a number of usb transfers
 *
 * \param   device      the device we want to allocate the transfers
 * \param   ifaces      array of interfaces
 * \param   usb_xfers   pointer to an array of usb_xfer
 * \param   setups      setup parameter array
 * \para    setup_count the number of setups we have to do
 * \
 */
usb_error_t usb_transfer_setup(struct usb_device *device, const uint8_t iface,
                               struct usb_xfer **ret_xfer, const struct usb_xfer_config *setup)
{
    USB_DEBUG_TR_ENTER;

    struct usb_xfer_setup_params params;
    memset(&params, 0, sizeof(params));

    params.device = device;
    params.speed = device->speed;
    params.hc_max_packet_count = 1;
    params.err = USB_ERR_OK;
    params.type = setup->usb_type;
    params.size[0] = 0;
    params.buf = NULL;
    params.xfer_setup = setup;

    struct usb_endpoint *ep = usb_endpoint_lookup(device, iface, setup);

    if ((ep == NULL) || (ep->pipe_fn == NULL)) {
        USB_DEBUG_XFER("WARNING: No associated pipe!\n");
        USB_DEBUG_TR_RETURN;
        return (USB_ERR_NO_PIPE);
    }

    struct usb_xfer *xfer = malloc(sizeof(struct usb_xfer));
    memset(xfer, 0, sizeof(*xfer));
    xfer->xfer_id = device->xfer_id++;
    xfer->device_xfers_next = device->xfers;
    device->xfers = xfer;
    xfer->xfer_done_cb = setup->xfer_done_cb;
    xfer->type = setup->usb_type;
    xfer->device_address = device->device_address;
    xfer->host_controller = device->controller;
    xfer->device = device;
    xfer->endpoint = ep;
    params.curr_xfer = xfer;
    params.pipe_fn = xfer->endpoint->pipe_fn;

    (device->controller->hcdi_bus_fn->xfer_setup)(&params);

    if (params.err != USB_ERR_OK) {
        USB_DEBUG(
            "ERROR: hcdi_xfer_setup failed: %s\n", usb_get_error_string(params.err));
        return (params.err);
    }

    xfer->endpoint->ref_allocation++;
    assert(xfer->endpoint->ref_allocation);

    *ret_xfer = xfer;

    USB_DEBUG_TR_RETURN;
    return (USB_ERR_OK);
}
示例#2
0
/**
 * \brief   this function handles the USB requests and executes them either
 *          on the device or calls the root hub emulation function
 */
usb_error_t usb_handle_request(struct usb_device *device, uint16_t flags,
        struct usb_device_request *req, struct usb_request_state *req_state,
        void *data, uint16_t *ret_length)
{
    USB_DEBUG_TR_ENTER;

    struct usb_xfer *xfer;
    usb_error_t err = USB_ERR_OK;
    uint16_t length = req->wLength;
    uint16_t actual_length = 0;

    USB_DEBUG_REQ("bmRequestType = %x\n", *((uint8_t *)(&req->bType)));USB_DEBUG_REQ("bRequest  = %x\n", *((uint8_t *)(&req->bRequest)));USB_DEBUG_REQ("wValue = %x\n", *((uint16_t *)(&req->wValue)));USB_DEBUG_REQ("wIndex = %x\n", *((uint16_t *)(&req->wIndex)));USB_DEBUG_REQ("wLength= %x\n", *((uint16_t *)(&req->wLength)));

    /*
     * check if the device is in the correct state to handle requests
     * the device must be at lease in the powered state
     */
    if (device->state < USB_DEVICE_STATE_POWERED) {
        USB_DEBUG("Error: USB Device has not been configured\n");
        if (req_state) {
            req_state->error = USB_ERR_NOT_CONFIGURED;
            req_state->callback(req_state->bind);
        }

        USB_DEBUG_TR_RETURN;
        return (USB_ERR_NOT_CONFIGURED);
    }

    /*
     * reset the length value
     */
    if (ret_length) {
        *ret_length = 0;
    }

    /*
     * the device may be the root hub, so we need to take the root hub
     * execution function for this, the root hub is the device which
     * does not have a parent hub associated
     */
    if (device->parent_hub == NULL) {
        /*
         * cannot write data to the root hub
         */
        if ((req->bType.direction != USB_REQUEST_READ) && (length != 0)) {
            USB_DEBUG("Error: root hub does not support writing of data\n");
            if (req_state) {
                req_state->error = USB_ERR_INVAL;
                req_state->callback(req_state->bind);
            }

            USB_DEBUG_TR_RETURN;
            return (USB_ERR_INVAL);
        }

        const void *ret_desc;
        uint16_t ret_size;
        err = USB_ERR_NO_ROOT_HUB;
        if (device->controller->hcdi_bus_fn->roothub_exec != NULL) {
            err = device->controller->hcdi_bus_fn->roothub_exec(device, req,
                    &ret_desc, &ret_size);
        }
        if (err != USB_ERR_OK) {
            USB_DEBUG(
                    "ERROR: root_hub_exec failed(): %s\n", usb_get_error_string(err));
            if (req_state) {
                req_state->error = err;
                req_state->callback(req_state->bind);
            }USB_DEBUG_TR_RETURN;
            return (err);
        }

        /*
         * we have encountered a short transfer, this may be ok when the flag
         * is set
         */
        if (length > ret_size) {

            if (!(flags & USB_REQUEST_FLAG_IGNORE_SHORT_XFER)) {
                if (req_state) {
                    req_state->error = USB_ERR_SHORT_XFER;
                    req_state->callback(req_state->bind);
                }USB_DEBUG_TR_RETURN;
                return (USB_ERR_SHORT_XFER);
            }

            // short xfers are ok so update the length
            length = ret_size;
        }

        if (ret_length) {
            *ret_length = length;
        }

        /*
         * we have some data that we have to return
         */
        if (length > 0 && data != NULL) {
            memcpy(data, ret_desc, length);
        }
        if (req_state) {
            req_state->error = USB_ERR_OK;
        }

        return (USB_ERR_OK);
    }

    /*
     * we are executing the request on a real device so we have to setup
     * a new USB control transfer on this device
     */

    usb_transfer_setup_ctrl_default(device, req_state);

    xfer = device->ctrl_xfer[0];
    xfer->ed_direction =
            (req->bType.direction == USB_REQUEST_READ) ?
                    USB_ENDPOINT_DIRECTION_IN : USB_ENDPOINT_DIRECTION_OUT;
    if (xfer == NULL) {
        USB_DEBUG("ERROR: No memory for setting up transfers\n");
        return (USB_ERR_NOMEM);
    }

    if (req_state) {
        req_state->xfer = xfer;
    }
    /*
     * we have a xfer so set it up according to the setup
     * and the given flags
     */
    if (flags & USB_REQUEST_FLAG_DELAY_STATUS) {
        xfer->flags.manual_status = 1;
    } else {
        xfer->flags.manual_status = 0;
    }

    if (flags & USB_REQUEST_FLAG_IGNORE_SHORT_XFER) {
        xfer->flags.short_xfer_ok = 1;
    } else {
        xfer->flags.short_xfer_ok = 1;
    }

    xfer->timeout = 1000;   // TODO: TIMEOUT

    /*
     * copy the request into DMA memory
     */
    usb_mem_copy_in(xfer->frame_buffers[0], 0, req,
            sizeof(struct usb_device_request));
    xfer->frame_lengths[0] = sizeof(struct usb_device_request);

    /*
     * loop till we got all requested data
     */
    uint16_t current_data_length;
    while (1) {
        current_data_length = length;
        if (current_data_length > xfer->max_data_length) {
            USB_DEBUG(
                    "NOTICE: current_data_length (%u)> xfer->max_data_length (%u)\n", current_data_length, xfer->max_data_length);
            current_data_length = xfer->max_data_length;
        }
        // set the frame length of the data stage
        xfer->frame_lengths[1] = current_data_length;

        /*
         * we have a data stage, so we have to handle the data read or write
         * in the case of data write, we have to copy the data into the
         * second frame buffer and indicate that we have two frames
         */
        if (current_data_length > 0) {
            if ((req->bType.direction == USB_REQUEST_WRITE)) {
                usb_mem_copy_in(xfer->frame_buffers[1], 0, data,
                        current_data_length);
            }
            xfer->num_frames = 2;
        } else {
            if (xfer->frame_lengths[0] == 0) {
                if (xfer->flags.manual_status) {
                    xfer->flags.manual_status = 0;
                } else {
                    break;
                }
            }
            xfer->num_frames = 1;
        }

        USB_DEBUG_REQ("-------------------- starting transfer\n");
        usb_transfer_start(xfer);

        /* wait till completed... */
        while (!usb_transfer_completed(xfer)) {
            USB_WAIT(10);
            //thread_yield();
        }

        /*
         * transfer is complete, check for error condition
         */
        err = xfer->error;

        if (err != USB_ERR_OK) {
            break;
        }

        /*
         * get the actual number of frames
         */
        if (xfer->actual_frames < 2) {
            actual_length = 0;  // no data stage
        } else {
            actual_length = xfer->frame_lengths[1];
        }

        /*
         * updating variables to catch short packets
         */
        if (current_data_length > actual_length) {
            current_data_length = actual_length;
            length = current_data_length;
        }

        /*
         * copy the data out to buffer if it is a read request
         * and we have some bytes to read
         */
        if ((current_data_length > 0)
                && (req->bType.direction == USB_REQUEST_READ)) {
            usb_mem_copy_out(xfer->frame_buffers[1], 0, data,
                    current_data_length);
        }

        /*
         * update the frame length accordingly
         */
        xfer->frame_lengths[0] = 0;
        length -= current_data_length;

        /*
         * advance buffer pointer
         */
        data += current_data_length;

        if (ret_length) {
            (*ret_length) += current_data_length;
        }

        /*
         * TODO: Timeout
         */

    }

    if (err != USB_ERR_OK) {
        usb_transfer_stop(xfer);
    }

    if (req_state) {
        req_state->error = (usb_error_t) err;
        req_state->callback(req_state);
    }

    USB_DEBUG_TR_RETURN;
    return ((usb_error_t) err);
}