HelenOS sources
This source file includes following definitions.
- usb_transfer_batch_create
- usb_transfer_batch_init
- usb_transfer_batch_destroy
- usb_transfer_batch_bounce_required
- usb_transfer_batch_bounce
- usb_transfer_batch_finish
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <str_error.h>
#include <usb/debug.h>
#include "endpoint.h"
#include "bus.h"
#include "usb_transfer_batch.h"
usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep)
{
assert(ep);
bus_t *bus = endpoint_get_bus(ep);
if (!bus->ops->batch_create) {
usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t));
if (!batch)
return NULL;
usb_transfer_batch_init(batch, ep);
return batch;
}
return bus->ops->batch_create(ep);
}
void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep)
{
assert(ep);
endpoint_add_ref(ep);
batch->ep = ep;
}
void usb_transfer_batch_destroy(usb_transfer_batch_t *batch)
{
assert(batch);
assert(batch->ep);
bus_t *bus = endpoint_get_bus(batch->ep);
endpoint_t *ep = batch->ep;
if (bus->ops) {
usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.",
batch, USB_TRANSFER_BATCH_ARGS(*batch));
bus->ops->batch_destroy(batch);
} else {
usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.",
batch, USB_TRANSFER_BATCH_ARGS(*batch));
free(batch);
}
endpoint_del_ref(ep);
}
bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *batch)
{
if (!batch->size)
return false;
unsigned flags = batch->dma_buffer.policy & DMA_POLICY_FLAGS_MASK;
unsigned required_flags =
batch->ep->required_transfer_buffer_policy & DMA_POLICY_FLAGS_MASK;
if (required_flags & ~flags)
return true;
size_t chunk_mask = dma_policy_chunk_mask(batch->dma_buffer.policy);
size_t required_chunk_mask =
dma_policy_chunk_mask(batch->ep->required_transfer_buffer_policy);
if ((required_chunk_mask & ~chunk_mask) == 0)
return false;
size_t start_chunk = batch->offset & ~chunk_mask;
size_t end_chunk = (batch->offset + batch->size - 1) & ~chunk_mask;
if (start_chunk != end_chunk)
return true;
return false;
}
errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *batch)
{
assert(batch);
assert(!batch->is_bounced);
dma_buffer_release(&batch->dma_buffer);
batch->original_buffer = batch->dma_buffer.virt + batch->offset;
usb_log_debug("Batch(%p): Buffer cannot be used directly, "
"falling back to bounce buffer!", batch);
const errno_t err = dma_buffer_alloc_policy(&batch->dma_buffer,
batch->size, batch->ep->transfer_buffer_policy);
if (err)
return err;
if (batch->dir == USB_DIRECTION_OUT)
memcpy(batch->dma_buffer.virt,
batch->original_buffer,
batch->size);
batch->is_bounced = true;
batch->offset = 0;
return err;
}
void usb_transfer_batch_finish(usb_transfer_batch_t *batch)
{
assert(batch);
assert(batch->ep);
usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.",
batch, USB_TRANSFER_BATCH_ARGS(*batch));
if (batch->error == EOK && batch->size > 0) {
if (batch->is_bounced) {
if (batch->dir == USB_DIRECTION_IN)
memcpy(batch->original_buffer,
batch->dma_buffer.virt,
batch->transferred_size);
dma_buffer_free(&batch->dma_buffer);
} else {
dma_buffer_release(&batch->dma_buffer);
}
}
if (batch->on_complete) {
const int err = batch->on_complete(batch->on_complete_data, batch->error, batch->transferred_size);
if (err)
usb_log_warning("Batch %p failed to complete: %s",
batch, str_error(err));
}
usb_transfer_batch_destroy(batch);
}
HelenOS homepage, sources at GitHub