Ejemplo n.º 1
0
/**
 * \brief   this function undoes the setup of the usb transfers
 *
 * \param   xfers       array of pointers to usb transfers to unsetup
 * \param   xfer_count  the number of xfers to unsetup
 */
void usb_transfer_unsetup(struct usb_xfer **xfers, uint16_t xfer_count)
{
    USB_DEBUG_TR_ENTER;

    if (*xfers == NULL || xfer_count == 0) {
        return;
    }

    struct usb_xfer *xfer;

    while (xfer_count > 0) {
        xfer_count--;
        xfer = xfers[xfer_count];

        if (xfer == NULL) {
            continue;
        }

        xfers[xfer_count] = NULL;

        usb_transfer_stop(xfer);

        while (!usb_transfer_completed(xfer)) {
            xfer->flags_internal.draining = 1;
            event_dispatch(get_default_waitset());
        }

        xfer->endpoint->ref_allocation--;

        (xfer->host_controller->hcdi_bus_fn->xfer_unsetup)(xfer);

        struct usb_device *dev = xfer->device;
        struct usb_xfer *prev = dev->xfers;
        while (prev != NULL) {
            if (dev->xfers == xfer) {
                dev->xfers = xfer->device_xfers_next;
                break;
            } else if (prev->device_xfers_next == xfer) {
                debug_printf("removing from device xfers..\n");
                prev->device_xfers_next = xfer->device_xfers_next;
                break;
            }
            prev = prev->device_xfers_next;
        }

        free(xfer);
    }

    USB_DEBUG_TR_RETURN;
}
Ejemplo n.º 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);
}