Changeset df6ded8 in mainline for uspace/lib/usbhost/src/usb_transfer_batch.c
- Timestamp:
- 2018-02-28T16:37:50Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1b20da0
- Parents:
- f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
- git-committer:
- Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbhost/src/usb_transfer_batch.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 33 34 */ 34 35 35 #include <usb/host/usb_transfer_batch.h>36 #include <usb/debug.h>37 38 36 #include <assert.h> 39 37 #include <errno.h> 40 #include <macros.h>41 #include <mem.h>42 38 #include <stdlib.h> 43 #include <usbhc_iface.h> 44 45 /** Allocate and initialize usb_transfer_batch structure. 46 * @param ep endpoint used by the transfer batch. 47 * @param buffer data to send/recieve. 48 * @param buffer_size Size of data buffer. 49 * @param setup_buffer Data to send in SETUP stage of control transfer. 50 * @param func_in callback on IN transfer completion. 51 * @param func_out callback on OUT transfer completion. 52 * @param fun DDF function (passed to callback function). 53 * @param arg Argument to pass to the callback function. 54 * @param private_data driver specific per batch data. 55 * @param private_data_dtor Function to properly destroy private_data. 56 * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure. 57 */ 58 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer, 59 size_t buffer_size, 60 uint64_t setup_buffer, 61 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, 63 void *arg) 64 { 65 if (func_in == NULL && func_out == NULL) 66 return NULL; 67 if (func_in != NULL && func_out != NULL) 68 return NULL; 69 70 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 71 if (instance) { 72 instance->ep = ep; 73 instance->callback_in = func_in; 74 instance->callback_out = func_out; 75 instance->arg = arg; 76 instance->buffer = buffer; 77 instance->buffer_size = buffer_size; 78 instance->setup_size = 0; 79 instance->transfered_size = 0; 80 instance->error = EOK; 81 if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) { 82 memcpy(instance->setup_buffer, &setup_buffer, 83 USB_SETUP_PACKET_SIZE); 84 instance->setup_size = USB_SETUP_PACKET_SIZE; 39 #include <str_error.h> 40 #include <usb/debug.h> 41 42 #include "endpoint.h" 43 #include "bus.h" 44 45 #include "usb_transfer_batch.h" 46 47 /** 48 * Create a batch on a given endpoint. 49 * 50 * If the bus callback is not defined, it just creates a default batch. 51 */ 52 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep) 53 { 54 assert(ep); 55 56 bus_t *bus = endpoint_get_bus(ep); 57 58 if (!bus->ops->batch_create) { 59 usb_transfer_batch_t *batch = calloc(1, sizeof(usb_transfer_batch_t)); 60 if (!batch) 61 return NULL; 62 usb_transfer_batch_init(batch, ep); 63 return batch; 64 } 65 66 return bus->ops->batch_create(ep); 67 } 68 69 /** 70 * Initialize given batch structure. 71 */ 72 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep) 73 { 74 assert(ep); 75 /* Batch reference */ 76 endpoint_add_ref(ep); 77 batch->ep = ep; 78 } 79 80 /** 81 * Destroy the batch. If there's no bus callback, just free it. 82 */ 83 void usb_transfer_batch_destroy(usb_transfer_batch_t *batch) 84 { 85 assert(batch); 86 assert(batch->ep); 87 88 bus_t *bus = endpoint_get_bus(batch->ep); 89 endpoint_t *ep = batch->ep; 90 91 if (bus->ops) { 92 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " destroying.", 93 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 94 bus->ops->batch_destroy(batch); 95 } 96 else { 97 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.", 98 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 99 free(batch); 100 } 101 102 /* Batch reference */ 103 endpoint_del_ref(ep); 104 } 105 106 bool usb_transfer_batch_bounce_required(usb_transfer_batch_t *batch) 107 { 108 if (!batch->size) 109 return false; 110 111 unsigned flags = batch->dma_buffer.policy & DMA_POLICY_FLAGS_MASK; 112 unsigned required_flags = 113 batch->ep->required_transfer_buffer_policy & DMA_POLICY_FLAGS_MASK; 114 115 if (required_flags & ~flags) 116 return true; 117 118 size_t chunk_mask = dma_policy_chunk_mask(batch->dma_buffer.policy); 119 size_t required_chunk_mask = 120 dma_policy_chunk_mask(batch->ep->required_transfer_buffer_policy); 121 122 /* If the chunks are at least as large as required, we're good */ 123 if ((required_chunk_mask & ~chunk_mask) == 0) 124 return false; 125 126 size_t start_chunk = batch->offset & ~chunk_mask; 127 size_t end_chunk = (batch->offset + batch->size - 1) & ~chunk_mask; 128 129 /* The requested area crosses a chunk boundary */ 130 if (start_chunk != end_chunk) 131 return true; 132 133 return false; 134 } 135 136 errno_t usb_transfer_batch_bounce(usb_transfer_batch_t *batch) 137 { 138 assert(batch); 139 assert(!batch->is_bounced); 140 141 dma_buffer_release(&batch->dma_buffer); 142 143 batch->original_buffer = batch->dma_buffer.virt + batch->offset; 144 145 usb_log_debug("Batch(%p): Buffer cannot be used directly, " 146 "falling back to bounce buffer!", batch); 147 148 const errno_t err = dma_buffer_alloc_policy(&batch->dma_buffer, 149 batch->size, batch->ep->transfer_buffer_policy); 150 if (err) 151 return err; 152 153 /* Copy the data out */ 154 if (batch->dir == USB_DIRECTION_OUT) 155 memcpy(batch->dma_buffer.virt, 156 batch->original_buffer, 157 batch->size); 158 159 batch->is_bounced = true; 160 batch->offset = 0; 161 162 return err; 163 } 164 165 /** 166 * Finish a transfer batch: call handler, destroy batch, release endpoint. 167 * 168 * Call only after the batch have been scheduled && completed! 169 */ 170 void usb_transfer_batch_finish(usb_transfer_batch_t *batch) 171 { 172 assert(batch); 173 assert(batch->ep); 174 175 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.", 176 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 177 178 if (batch->error == EOK && batch->size > 0) { 179 if (batch->is_bounced) { 180 /* We we're forced to use bounce buffer, copy it back */ 181 if (batch->dir == USB_DIRECTION_IN) 182 memcpy(batch->original_buffer, 183 batch->dma_buffer.virt, 184 batch->transferred_size); 185 186 dma_buffer_free(&batch->dma_buffer); 85 187 } 86 if (instance->ep) 87 endpoint_use(instance->ep); 88 } 89 return instance; 90 } 91 92 /** Correctly dispose all used data structures. 93 * 94 * @param[in] instance Batch structure to use. 95 */ 96 void usb_transfer_batch_destroy(usb_transfer_batch_t *instance) 97 { 98 if (!instance) 99 return; 100 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 101 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 102 if (instance->ep) { 103 endpoint_release(instance->ep); 104 } 105 free(instance); 106 } 107 108 /** Prepare data and call the right callback. 109 * 110 * @param[in] instance Batch structure to use. 111 * @param[in] data Data to copy to the output buffer. 112 * @param[in] size Size of @p data. 113 * @param[in] error Error value to use. 114 */ 115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 116 const void *data, size_t size, errno_t error) 117 { 118 assert(instance); 119 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 120 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 121 122 /* NOTE: Only one of these pointers should be set. */ 123 if (instance->callback_out) { 124 instance->callback_out(error, instance->arg); 125 } 126 127 if (instance->callback_in) { 128 /* We care about the data and there are some to copy */ 129 const size_t safe_size = min(size, instance->buffer_size); 130 if (data) { 131 memcpy(instance->buffer, data, safe_size); 188 else { 189 dma_buffer_release(&batch->dma_buffer); 132 190 } 133 instance->callback_in(error, safe_size, instance->arg); 134 } 135 } 191 } 192 193 if (batch->on_complete) { 194 const int err = batch->on_complete(batch->on_complete_data, batch->error, batch->transferred_size); 195 if (err) 196 usb_log_warning("Batch %p failed to complete: %s", 197 batch, str_error(err)); 198 } 199 200 usb_transfer_batch_destroy(batch); 201 } 202 136 203 /** 137 204 * @}
Note:
See TracChangeset
for help on using the changeset viewer.