Esempio n. 1
0
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);
}
Esempio n. 2
0
/** 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;
}