/*------------------------------------------------------------------------* * usb_handle_request_callback * * This function is the USB callback for generic USB Device control * transfers. *------------------------------------------------------------------------*/ void usb_handle_request_callback(struct usb_xfer *xfer, usb_error_t error) { usb_error_t err; /* check the current transfer state */ switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: case USB_ST_TRANSFERRED: /* handle the request */ err = usb_handle_request(xfer); if (err) { if (err == USB_ERR_BAD_CONTEXT) { /* we need to re-setup the control transfer */ usb_needs_explore(xfer->xroot->bus, 0); break; } goto tr_restart; } usbd_transfer_submit(xfer); break; default: /* check if a control transfer is active */ if (xfer->flags_int.control_rem != 0xFFFF) { /* handle the request */ err = usb_handle_request(xfer); } if (xfer->error != USB_ERR_CANCELLED) { /* should not happen - try stalling */ goto tr_restart; } break; } return; tr_restart: /* * If a control transfer is active, stall it, and wait for the * next control transfer. */ usbd_xfer_set_frame_len(xfer, 0, sizeof(struct usb_device_request)); xfer->nframes = 1; xfer->flags.manual_status = 1; xfer->flags.force_short_xfer = 0; usbd_xfer_set_stall(xfer); /* cancel previous transfer, if any */ usbd_transfer_submit(xfer); }
void usb_rx_request_write_call(struct usb_manager_binding *binding, uint8_t *request, size_t req_length, uint8_t *data, size_t data_length) { USB_DEBUG_TR_ENTER; USB_DEBUG_IDC("received usb_rx_request_call() of %i bytes\n", data_length); struct usb_device_request *req = (struct usb_device_request *) request; /* check if we have received the correct amount of data */ if ((req_length != sizeof(struct usb_device_request)) || (req->wLength != data_length)) { USB_DEBUG_IDC("ERROR in usb_rx_request_call(): received too less data" " to full fill the request:\n " "request length: expected %i bytes, was %i\n" "data length: expected %i, was %i\n", sizeof(struct usb_device_request), req_length, req->wLength, data_length); usb_request_send_error(USB_ERR_INVAL, binding, usb_tx_request_write_response); } /* execute request and prepare reply */ struct usb_request_state *st = malloc(sizeof(struct usb_request_state)); if (st == NULL) { USB_DEBUG_IDC("WARNING: usb_rx_request_write_call(): out of memory\b"); usb_request_send_error(USB_ERR_NOMEM, binding, usb_tx_request_write_response); return; } /* fill in the struct */ st->bind = binding; st->req = req; /* write requests have no data to return */ st->data_length = data_length; st->data = data; st->callback = usb_tx_request_write_response; struct usb_device *device = (struct usb_device *) binding->st; usb_handle_request(device, 0, req, st, st->data, &st->data_length); }
void usb_rx_request_read_call(struct usb_manager_binding *binding, uint8_t *request, size_t req_length) { USB_DEBUG_TR_ENTER; USB_DEBUG_IDC("received usb_rx_request_read_call()\n"); // check if we have received the correct amount of data if (req_length != sizeof(struct usb_device_request)) { USB_DEBUG_IDC("received too less data to fullfill the request:\n " "request length: expected %i bytes, was %i\n", sizeof(struct usb_device_request), req_length); usb_request_send_error(USB_ERR_INVAL, binding, usb_tx_request_read_response); } /* * execute request and prepare reply */ struct usb_request_state *st = malloc(sizeof(struct usb_request_state)); struct usb_device *device = (struct usb_device *) binding->st; struct usb_device_request *req = (struct usb_device_request *) request; st->req = req; st->bind = binding; st->data_length = 0; if (req->wLength > 0) { st->data = malloc(req->wLength); } else { /* XXX: Just allocating some memory, note this may not be enough */ st->data = malloc(1024); req->wLength = 1024; // setting the maximum data length } st->callback = usb_tx_request_read_response; usb_handle_request(device, 0, req, st, st->data, &st->data_length); }
usb_error_t usb_exec_request(struct usb_device *device, uint16_t flags, struct usb_device_request *request, void *data, uint16_t *ret_length) { return (usb_handle_request(device, flags, request, NULL, data, ret_length)); }