static inline void interrupt_request( usb_transfer_batch_t *request, uint16_t mask, size_t size) { assert(request); usb_log_debug("Sending interrupt vector(%zu) %hhx:%hhx.\n", size, ((uint8_t*)&mask)[0], ((uint8_t*)&mask)[1]); usb_transfer_batch_finish_error(request, &mask, size, EOK); usb_transfer_batch_destroy(request); }
/** Prepare generic usb_transfer_batch and schedule it. * @param hcd Host controller driver. * @param fun DDF fun * @param target address and endpoint number. * @param setup_data Data to use in setup stage (Control communication type) * @param in Callback for device to host communication. * @param out Callback for host to device communication. * @param arg Callback parameter. * @param name Communication identifier (for nicer output). * @return Error code. */ int hcd_send_batch( hcd_t *hcd, usb_target_t target, usb_direction_t direction, void *data, size_t size, uint64_t setup_data, usbhc_iface_transfer_in_callback_t in, usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) { assert(hcd); endpoint_t *ep = usb_bus_find_ep(&hcd->bus, target.address, target.endpoint, direction); if (ep == NULL) { usb_log_error("Endpoint(%d:%d) not registered for %s.\n", target.address, target.endpoint, name); return ENOENT; } usb_log_debug2("%s %d:%d %zu(%zu).\n", name, target.address, target.endpoint, size, ep->max_packet_size); const size_t bw = bandwidth_count_usb11( ep->speed, ep->transfer_type, size, ep->max_packet_size); /* Check if we have enough bandwidth reserved */ if (ep->bandwidth < bw) { usb_log_error("Endpoint(%d:%d) %s needs %zu bw " "but only %zu is reserved.\n", ep->address, ep->endpoint, name, bw, ep->bandwidth); return ENOSPC; } if (!hcd->ops.schedule) { usb_log_error("HCD does not implement scheduler.\n"); return ENOTSUP; } /* Check for commands that reset toggle bit */ if (ep->transfer_type == USB_TRANSFER_CONTROL) { const int reset_toggle = usb_request_needs_toggle_reset( (usb_device_request_setup_packet_t *) &setup_data); if (reset_toggle >= 0) { assert(out); toggle_t *toggle = malloc(sizeof(toggle_t)); if (!toggle) return ENOMEM; toggle->target.address = target.address; toggle->target.endpoint = reset_toggle; toggle->original_callback = out; toggle->original_data = arg; toggle->hcd = hcd; arg = toggle; out = toggle_reset_callback; } } usb_transfer_batch_t *batch = usb_transfer_batch_create( ep, data, size, setup_data, in, out, arg); if (!batch) { usb_log_error("Failed to create transfer batch.\n"); return ENOMEM; } const int ret = hcd->ops.schedule(hcd, batch); if (ret != EOK) usb_transfer_batch_destroy(batch); /* Drop our own reference to ep. */ endpoint_del_ref(ep); return ret; }