Changeset 5fd9c30 in mainline for uspace/drv/bus/usb/ehci/ehci_batch.c
- Timestamp:
- 2017-10-21T20:52:56Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 766043c
- Parents:
- 74b852b
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ehci/ehci_batch.c
r74b852b r5fd9c30 53 53 #define EHCI_TD_MAX_TRANSFER (16 * 1024) 54 54 55 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t);55 static void (*const batch_setup[])(ehci_transfer_batch_t*); 56 56 57 57 /** Safely destructs ehci_transfer_batch_t structure … … 59 59 * @param[in] ehci_batch Instance to destroy. 60 60 */ 61 static void ehci_transfer_batch_dispose(ehci_transfer_batch_t *ehci_batch) 62 { 63 if (!ehci_batch) 64 return; 61 void ehci_transfer_batch_destroy(ehci_transfer_batch_t *ehci_batch) 62 { 63 assert(ehci_batch); 65 64 if (ehci_batch->tds) { 66 65 for (size_t i = 0; i < ehci_batch->td_count; ++i) { … … 69 68 free(ehci_batch->tds); 70 69 } 71 usb_transfer_batch_destroy(ehci_batch->usb_batch);72 70 free32(ehci_batch->device_buffer); 73 71 free(ehci_batch); … … 75 73 } 76 74 77 /** Finishes usb_transfer_batch and destroys the structure.78 *79 * @param[in] uhci_batch Instance to finish and destroy.80 */81 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *ehci_batch)82 {83 assert(ehci_batch);84 assert(ehci_batch->usb_batch);85 usb_transfer_batch_finish(ehci_batch->usb_batch,86 ehci_batch->device_buffer + ehci_batch->usb_batch->setup_size);87 ehci_transfer_batch_dispose(ehci_batch);88 }89 90 75 /** Allocate memory and initialize internal data structure. 91 76 * … … 94 79 * NULL otherwise. 95 80 * 81 */ 82 ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep) 83 { 84 assert(ep); 85 86 ehci_transfer_batch_t *ehci_batch = calloc(1, sizeof(ehci_transfer_batch_t)); 87 if (!ehci_batch) { 88 usb_log_error("Failed to allocate EHCI batch data."); 89 return NULL; 90 } 91 92 usb_transfer_batch_init(&ehci_batch->base, ep); 93 link_initialize(&ehci_batch->link); 94 95 return ehci_batch; 96 } 97 98 /** Prepares a batch to be sent. 99 * 96 100 * Determines the number of needed transfer descriptors (TDs). 97 101 * Prepares a transport buffer (that is accessible by the hardware). 98 102 * Initializes parameters needed for the transfer and callback. 99 103 */ 100 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 101 { 102 assert(usb_batch); 103 104 ehci_transfer_batch_t *ehci_batch = 105 calloc(1, sizeof(ehci_transfer_batch_t)); 106 if (!ehci_batch) { 107 usb_log_error("Batch %p: Failed to allocate EHCI batch data.", 108 usb_batch); 109 goto dispose; 110 } 111 link_initialize(&ehci_batch->link); 112 ehci_batch->td_count = 113 (usb_batch->buffer_size + EHCI_TD_MAX_TRANSFER - 1) 114 / EHCI_TD_MAX_TRANSFER; 104 int ehci_transfer_batch_prepare(ehci_transfer_batch_t *ehci_batch) 105 { 106 assert(ehci_batch); 107 108 const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 109 ? USB_SETUP_PACKET_SIZE 110 : 0; 111 112 const size_t size = ehci_batch->base.buffer_size; 113 114 /* Mix setup stage and data together, we have enough space */ 115 if (size + setup_size > 0) { 116 /* Use one buffer for setup and data stage */ 117 ehci_batch->device_buffer = malloc32(size + setup_size); 118 if (!ehci_batch->device_buffer) { 119 usb_log_error("Batch %p: Failed to allocate device " 120 "buffer", ehci_batch); 121 return ENOMEM; 122 } 123 /* Copy setup data */ 124 memcpy(ehci_batch->device_buffer, ehci_batch->base.setup.buffer, 125 setup_size); 126 /* Copy generic data */ 127 if (ehci_batch->base.dir != USB_DIRECTION_IN) 128 memcpy(ehci_batch->device_buffer + setup_size, 129 ehci_batch->base.buffer, ehci_batch->base.buffer_size); 130 } 131 132 /* Add TD left over by the previous transfer */ 133 ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh; 134 135 /* Determine number of TDs needed */ 136 ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1) 137 / EHCI_TD_MAX_TRANSFER; 115 138 116 139 /* Control transfer need Setup and Status stage */ 117 if ( usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {140 if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) { 118 141 ehci_batch->td_count += 2; 119 142 } … … 122 145 if (!ehci_batch->tds) { 123 146 usb_log_error("Batch %p: Failed to allocate EHCI transfer " 124 "descriptors.", usb_batch); 125 goto dispose; 126 } 127 128 /* Add TD left over by the previous transfer */ 129 ehci_batch->qh = ehci_endpoint_get(usb_batch->ep)->qh; 147 "descriptors.", ehci_batch); 148 return ENOMEM; 149 } 130 150 131 151 for (unsigned i = 0; i < ehci_batch->td_count; ++i) { … … 133 153 if (!ehci_batch->tds[i]) { 134 154 usb_log_error("Batch %p: Failed to allocate TD %d.", 135 usb_batch, i);136 goto dispose;155 ehci_batch, i); 156 return ENOMEM; 137 157 } 138 158 memset(ehci_batch->tds[i], 0, sizeof(td_t)); 139 159 } 140 160 141 142 /* Mix setup stage and data together, we have enough space */ 143 if (usb_batch->setup_size + usb_batch->buffer_size > 0) { 144 /* Use one buffer for setup and data stage */ 145 ehci_batch->device_buffer = 146 malloc32(usb_batch->setup_size + usb_batch->buffer_size); 147 if (!ehci_batch->device_buffer) { 148 usb_log_error("Batch %p: Failed to allocate device " 149 "buffer", usb_batch); 150 goto dispose; 151 } 152 /* Copy setup data */ 153 memcpy(ehci_batch->device_buffer, usb_batch->setup_buffer, 154 usb_batch->setup_size); 155 /* Copy generic data */ 156 if (usb_batch->ep->direction != USB_DIRECTION_IN) 157 memcpy( 158 ehci_batch->device_buffer + usb_batch->setup_size, 159 usb_batch->buffer, usb_batch->buffer_size); 160 } 161 ehci_batch->usb_batch = usb_batch; 162 163 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch); 164 assert(batch_setup[usb_batch->ep->transfer_type]); 165 batch_setup[usb_batch->ep->transfer_type](ehci_batch, dir); 161 assert(batch_setup[ehci_batch->base.ep->transfer_type]); 162 batch_setup[ehci_batch->base.ep->transfer_type](ehci_batch); 166 163 167 164 usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.\n", 168 usb_batch, usb_str_direction(dir), 169 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 170 171 return ehci_batch; 172 dispose: 173 ehci_transfer_batch_dispose(ehci_batch); 174 return NULL; 165 ehci_batch, usb_str_direction(ehci_batch->base.dir), 166 USB_TRANSFER_BATCH_ARGS(ehci_batch->base)); 167 168 return EOK; 175 169 } 176 170 … … 184 178 * completes with the last TD. 185 179 */ 186 bool ehci_transfer_batch_is_complete(const ehci_transfer_batch_t *ehci_batch) 187 { 188 assert(ehci_batch); 189 assert(ehci_batch->usb_batch); 180 bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *ehci_batch) 181 { 182 assert(ehci_batch); 190 183 191 184 usb_log_debug("Batch %p: checking %zu td(s) for completion.\n", 192 ehci_batch ->usb_batch, ehci_batch->td_count);185 ehci_batch, ehci_batch->td_count); 193 186 194 187 usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.\n", 195 ehci_batch ->usb_batch,188 ehci_batch, 196 189 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 197 190 ehci_batch->qh->status, ehci_batch->qh->current, … … 206 199 207 200 /* Assume all data got through */ 208 ehci_batch->usb_batch->transfered_size = 209 ehci_batch->usb_batch->buffer_size; 201 ehci_batch->base.transfered_size = ehci_batch->base.buffer_size; 210 202 211 203 /* Check all TDs */ … … 213 205 assert(ehci_batch->tds[i] != NULL); 214 206 usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.", 215 ehci_batch ->usb_batch, i,207 ehci_batch, i, 216 208 ehci_batch->tds[i]->status, ehci_batch->tds[i]->next, 217 209 ehci_batch->tds[i]->alternate); 218 210 219 ehci_batch-> usb_batch->error = td_error(ehci_batch->tds[i]);220 if (ehci_batch-> usb_batch->error == EOK) {211 ehci_batch->base.error = td_error(ehci_batch->tds[i]); 212 if (ehci_batch->base.error == EOK) { 221 213 /* If the TD got all its data through, it will report 222 214 * 0 bytes remain, the sole exception is INPUT with … … 231 223 * we leave the very last(unused) TD behind. 232 224 */ 233 ehci_batch-> usb_batch->transfered_size225 ehci_batch->base.transfered_size 234 226 -= td_remain_size(ehci_batch->tds[i]); 235 227 } else { 236 228 usb_log_debug("Batch %p found error TD(%zu):%08x (%d).", 237 ehci_batch ->usb_batch, i,229 ehci_batch, i, 238 230 ehci_batch->tds[i]->status, 239 ehci_batch-> usb_batch->error);231 ehci_batch->base.error); 240 232 /* Clear possible ED HALT */ 241 233 qh_clear_halt(ehci_batch->qh); … … 244 236 } 245 237 246 assert(ehci_batch->usb_batch->transfered_size <= 247 ehci_batch->usb_batch->buffer_size); 238 assert(ehci_batch->base.transfered_size <= ehci_batch->base.buffer_size); 239 240 if (ehci_batch->base.dir == USB_DIRECTION_IN) 241 memcpy(ehci_batch->base.buffer, ehci_batch->device_buffer, ehci_batch->base.transfered_size); 242 248 243 /* Clear TD pointers */ 249 244 ehci_batch->qh->next = LINK_POINTER_TERM; 250 245 ehci_batch->qh->current = LINK_POINTER_TERM; 251 usb_log_debug("Batch %p complete: %s", ehci_batch ->usb_batch,252 str_error(ehci_batch-> usb_batch->error));246 usb_log_debug("Batch %p complete: %s", ehci_batch, 247 str_error(ehci_batch->base.error)); 253 248 254 249 return true; … … 268 263 * 269 264 * @param[in] ehci_batch Batch structure to use. 270 * @param[in] dir Communication direction271 265 * 272 266 * Setup stage with toggle 0 and direction BOTH(SETUP_PID) 273 * Data stage with alternating toggle and direction supplied by parameter. 274 * Status stage with toggle 1 and direction supplied by parameter. 275 */ 276 static void batch_control(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 277 { 278 assert(ehci_batch); 279 assert(ehci_batch->usb_batch); 267 * Data stage with alternating toggle and direction 268 * Status stage with toggle 1 and direction 269 */ 270 static void batch_control(ehci_transfer_batch_t *ehci_batch) 271 { 272 assert(ehci_batch); 273 274 usb_direction_t dir = ehci_batch->base.dir; 280 275 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 281 276 282 277 usb_log_debug2("Batch %p: Control QH(%"PRIxn"): " 283 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch ->usb_batch,278 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 284 279 addr_to_phys(ehci_batch->qh), 285 280 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, … … 298 293 /* Setup stage */ 299 294 td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH, 300 buffer, ehci_batch->usb_batch->setup_size, toggle, false);295 buffer, USB_SETUP_PACKET_SIZE, toggle, false); 301 296 usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): " 302 "%08x:%08x:%08x", ehci_batch ->usb_batch,297 "%08x:%08x:%08x", ehci_batch, 303 298 addr_to_phys(ehci_batch->tds[0]), 304 299 ehci_batch->tds[0]->status, ehci_batch->tds[0]->next, 305 300 ehci_batch->tds[0]->alternate); 306 buffer += ehci_batch->usb_batch->setup_size;301 buffer += USB_SETUP_PACKET_SIZE; 307 302 308 303 /* Data stage */ 309 304 size_t td_current = 1; 310 size_t remain_size = ehci_batch-> usb_batch->buffer_size;305 size_t remain_size = ehci_batch->base.buffer_size; 311 306 while (remain_size > 0) { 312 307 const size_t transfer_size = … … 318 313 transfer_size, toggle, false); 319 314 usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): " 320 "%08x:%08x:%08x", ehci_batch ->usb_batch,315 "%08x:%08x:%08x", ehci_batch, 321 316 addr_to_phys(ehci_batch->tds[td_current]), 322 317 ehci_batch->tds[td_current]->status, … … 334 329 td_init(ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true); 335 330 usb_log_debug2("Batch %p: Created CONTROL STATUS TD(%"PRIxn"): " 336 "%08x:%08x:%08x", ehci_batch ->usb_batch,331 "%08x:%08x:%08x", ehci_batch, 337 332 addr_to_phys(ehci_batch->tds[td_current]), 338 333 ehci_batch->tds[td_current]->status, … … 349 344 * EHCI hw in ED. 350 345 */ 351 static void batch_data(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 352 { 353 assert(ehci_batch); 354 assert(ehci_batch->usb_batch); 355 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 346 static void batch_data(ehci_transfer_batch_t *ehci_batch) 347 { 348 assert(ehci_batch); 356 349 357 350 usb_log_debug2("Batch %p: Data QH(%"PRIxn"): " 358 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch ->usb_batch,351 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 359 352 addr_to_phys(ehci_batch->qh), 360 353 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, … … 363 356 364 357 size_t td_current = 0; 365 size_t remain_size = ehci_batch-> usb_batch->buffer_size;358 size_t remain_size = ehci_batch->base.buffer_size; 366 359 char *buffer = ehci_batch->device_buffer; 367 360 while (remain_size > 0) { … … 373 366 ehci_batch->tds[td_current], 374 367 last ? NULL : ehci_batch->tds[td_current + 1], 375 dir, buffer, transfer_size, -1, last);368 ehci_batch->base.dir, buffer, transfer_size, -1, last); 376 369 377 370 usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x", 378 ehci_batch ->usb_batch,371 ehci_batch, 379 372 addr_to_phys(ehci_batch->tds[td_current]), 380 373 ehci_batch->tds[td_current]->status, … … 390 383 391 384 /** Transfer setup table. */ 392 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t) =385 static void (*const batch_setup[])(ehci_transfer_batch_t*) = 393 386 { 394 387 [USB_TRANSFER_CONTROL] = batch_control,
Note:
See TracChangeset
for help on using the changeset viewer.