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