/** * \brief callback function that initiates the sending the transfer done msg * * \param xfer the transfer that was done * \param err the outcome of the transfer * * NOTE: this function sends xfer done notification to the device driver * interrupt transfers may automatically be restarted */ static void usb_transfer_complete_notify(struct usb_xfer *xfer, usb_error_t err) { uint32_t data_length = xfer->actual_bytes; xfer->error = err; switch (xfer->type) { case USB_TYPE_INTR: xfer->frame_lengths[0] = xfer->max_data_length; if (data_length > 0) { struct usb_tdone_state *st = malloc( sizeof(struct usb_tdone_state)); st->xfer = xfer; st->buf = xfer->frame_buffers[0]->buffer; st->bind = xfer->usb_driver_binding; usb_transfer_complete_tx(st); } /* autorestart if the transfer completed successfully */ if (xfer->flags.auto_restart && (err == USB_ERR_OK)) { usb_transfer_start(xfer); } break; default: /* noop */ break; } }
void usb_rx_transfer_start_call(struct usb_manager_binding *bind, uint32_t tid) { USB_DEBUG_IDC("usb_rx_transfer_start_call()\n"); struct usb_tstart_state *st = malloc(sizeof(struct usb_tstart_state)); if (st == NULL) { debug_printf("WARNING: Cannot reply, out of memory!\n"); } st->bind = bind; struct usb_device *dev = (struct usb_device *) (bind->st); assert(dev != NULL); struct usb_xfer *xfer = dev->xfers; while (xfer) { if (xfer->xfer_id == tid) { break; } xfer = xfer->device_xfers_next; } if (xfer == NULL) { USB_DEBUG("no xfer!\n"); st->error = USB_ERR_BAD_CONTEXT; usb_tx_transfer_start_response(st); } usb_transfer_start(xfer); st->error = xfer->error; usb_tx_transfer_start_response(st); }
/** * \brief this function is used to allocate the structure and resources * needed for the default USB control endpoint transfer * * \param device the usb device we want to setup a usb transfer */ void usb_transfer_setup_ctrl_default(struct usb_device *device, struct usb_request_state *st) { USB_DEBUG_TR_ENTER; /* setting up transfers for the USB root hub is not allowed */ if (device->parent_hub == NULL) { USB_DEBUG("ERROR: setting up transfers for root hub not allowed\n"); return; } /* * since the control transfers are always on the special control * ep, we can cache them and reuse later */ struct usb_xfer *xfer = device->ctrl_xfer[0]; uint8_t xfer_reuse = 0; if (xfer) { xfer_reuse = ((xfer->device_address == device->device_address) && (device->ctrl_ep_desc.wMaxPacketSize == device->device_desc.bMaxPacketSize0)); if ((device->flags.usb_mode == USB_MODE_DEVICE) && xfer_reuse) { assert(!"NYI: device mode\n"); usb_transfer_start(xfer); return; } } if (xfer_reuse) { USB_DEBUG_XFER("reusing the xfer... return.\n"); return; } /* * we cannot reuse the USB transfer so we have to update the fields */ device->ctrl_ep_desc.wMaxPacketSize = device->device_desc.bMaxPacketSize0; device->ctrl_ep.descriptor = &device->ctrl_ep_desc; usb_transfer_unsetup(device->ctrl_xfer, USB_DEVICE_CTRL_XFER_MAX); USB_DEBUG_XFER("setting up device ctrl xfer[0]\n"); if (usb_transfer_setup(device, 0, &(device->ctrl_xfer[0]), usb_control_ep_cfg)) { USB_DEBUG("usb_transfer_setup_ctrl_default(): " "ERROR: could not allocate default control transfer\n"); return; } USB_DEBUG_XFER("setting up device ctrl xfer[1]\n"); if (usb_transfer_setup(device, 0, &(device->ctrl_xfer[1]), usb_control_ep_cfg)) { debug_printf("usb_transfer_setup_ctrl_default(): " "ERROR: could not allocate default control transfer\n"); return; } USB_DEBUG_TR_RETURN; }
/** * \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); }