Changeset 5fd9c30 in mainline
- Timestamp:
- 2017-10-21T20:52:56Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 766043c
- Parents:
- 74b852b
- Location:
- uspace
- Files:
-
- 28 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, -
uspace/drv/bus/usb/ehci/ehci_batch.h
r74b852b r5fd9c30 45 45 /** EHCI specific data required for USB transfer */ 46 46 typedef struct ehci_transfer_batch { 47 usb_transfer_batch_t base; 47 48 /** Link */ 48 49 link_t link; … … 59 60 } ehci_transfer_batch_t; 60 61 61 ehci_transfer_batch_t * ehci_transfer_batch_ get(usb_transfer_batch_t *batch);62 bool ehci_transfer_batch_is_complete(constehci_transfer_batch_t *batch);62 ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep); 63 int ehci_transfer_batch_prepare(ehci_transfer_batch_t *batch); 63 64 void ehci_transfer_batch_commit(const ehci_transfer_batch_t *batch); 64 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *batch); 65 bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *batch); 66 void ehci_transfer_batch_destroy(ehci_transfer_batch_t *batch); 65 67 66 68 static inline ehci_transfer_batch_t *ehci_transfer_batch_from_link(link_t *l) … … 69 71 return list_get_instance(l, ehci_transfer_batch_t, link); 70 72 } 73 74 static inline ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 75 { 76 assert(usb_batch); 77 78 return (ehci_transfer_batch_t *) usb_batch; 79 } 80 71 81 #endif 72 82 /** -
uspace/drv/bus/usb/ehci/ehci_bus.c
r74b852b r5fd9c30 41 41 42 42 #include "ehci_bus.h" 43 #include "ehci_batch.h" 43 44 #include "hc.h" 44 45 … … 140 141 hc_dequeue_endpoint(bus->hc, ep); 141 142 return EOK; 143 } 142 144 145 static usb_transfer_batch_t *ehci_bus_create_batch(bus_t *bus, endpoint_t *ep) 146 { 147 ehci_transfer_batch_t *batch = ehci_transfer_batch_create(ep); 148 return &batch->base; 149 } 150 151 static void ehci_bus_destroy_batch(usb_transfer_batch_t *batch) 152 { 153 ehci_transfer_batch_destroy(ehci_transfer_batch_get(batch)); 143 154 } 144 155 … … 161 172 ops->release_endpoint = ehci_release_ep; 162 173 174 ops->create_batch = ehci_bus_create_batch; 175 ops->destroy_batch = ehci_bus_destroy_batch; 176 163 177 bus->hc = hc; 164 178 -
uspace/drv/bus/usb/ehci/ehci_rh.c
r74b852b r5fd9c30 146 146 const usb_target_t target = batch->ep->target; 147 147 batch->error = virthub_base_request(&instance->base, target, 148 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,148 batch->dir, (void*) batch->setup.buffer, 149 149 batch->buffer, batch->buffer_size, &batch->transfered_size); 150 150 if (batch->error == ENAK) { … … 157 157 instance->unfinished_interrupt_transfer = batch; 158 158 } else { 159 usb_transfer_batch_finish(batch, NULL);160 usb_transfer_batch_destroy(batch);161 159 usb_log_debug("RH(%p): BATCH(%p) virtual request complete: %s", 162 160 instance, batch, str_error(batch->error)); 161 usb_transfer_batch_finish(batch); 163 162 } 164 163 return EOK; … … 182 181 const usb_target_t target = batch->ep->target; 183 182 batch->error = virthub_base_request(&instance->base, target, 184 usb_transfer_batch_direction(batch), 185 (void*)batch->setup_buffer, 183 batch->dir, (void*) batch->setup.buffer, 186 184 batch->buffer, batch->buffer_size, &batch->transfered_size); 187 usb_transfer_batch_finish(batch, NULL); 188 usb_transfer_batch_destroy(batch); 185 usb_transfer_batch_finish(batch); 189 186 } 190 187 return EOK; -
uspace/drv/bus/usb/ehci/hc.c
r74b852b r5fd9c30 296 296 return ehci_rh_schedule(&instance->rh, batch); 297 297 } 298 298 299 ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch); 299 if (!ehci_batch) 300 return ENOMEM; 300 301 const int err = ehci_transfer_batch_prepare(ehci_batch); 302 if (err) 303 return err; 301 304 302 305 fibril_mutex_lock(&instance->guard); … … 343 346 ehci_transfer_batch_from_link(current); 344 347 345 if (ehci_transfer_batch_ is_complete(batch)) {348 if (ehci_transfer_batch_check_completed(batch)) { 346 349 list_remove(current); 347 ehci_transfer_batch_finish_dispose(batch);350 usb_transfer_batch_finish(&batch->base); 348 351 } 349 352 } -
uspace/drv/bus/usb/ohci/hc.c
r74b852b r5fd9c30 295 295 return ENOMEM; 296 296 297 const int err = ohci_transfer_batch_prepare(ohci_batch); 298 if (err) 299 return err; 300 297 301 fibril_mutex_lock(&instance->guard); 298 302 list_append(&ohci_batch->link, &instance->pending_batches); … … 346 350 ohci_transfer_batch_from_link(current); 347 351 348 if (ohci_transfer_batch_ is_complete(batch)) {352 if (ohci_transfer_batch_check_completed(batch)) { 349 353 list_remove(current); 350 ohci_transfer_batch_finish_dispose(batch);354 usb_transfer_batch_finish(&batch->base); 351 355 } 352 356 -
uspace/drv/bus/usb/ohci/ohci_batch.c
r74b852b r5fd9c30 47 47 #include "ohci_bus.h" 48 48 49 static void (*const batch_setup[])(ohci_transfer_batch_t* , usb_direction_t);49 static void (*const batch_setup[])(ohci_transfer_batch_t*); 50 50 51 51 /** Safely destructs ohci_transfer_batch_t structure … … 53 53 * @param[in] ohci_batch Instance to destroy. 54 54 */ 55 static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch) 56 { 57 if (!ohci_batch) 58 return; 55 void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch) 56 { 57 assert(ohci_batch); 59 58 if (ohci_batch->tds) { 60 59 const ohci_endpoint_t *ohci_ep = … … 67 66 free(ohci_batch->tds); 68 67 } 69 usb_transfer_batch_destroy(ohci_batch->usb_batch);70 68 free32(ohci_batch->device_buffer); 71 69 free(ohci_batch); 72 }73 74 /** Finishes usb_transfer_batch and destroys the structure.75 *76 * @param[in] uhci_batch Instance to finish and destroy.77 */78 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)79 {80 assert(ohci_batch);81 assert(ohci_batch->usb_batch);82 usb_transfer_batch_finish(ohci_batch->usb_batch,83 ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);84 ohci_transfer_batch_dispose(ohci_batch);85 70 } 86 71 … … 90 75 * @return Valid pointer if all structures were successfully created, 91 76 * NULL otherwise. 92 * 93 * Determines the number of needed transfer descriptors (TDs). 94 * Prepares a transport buffer (that is accessible by the hardware). 95 * Initializes parameters needed for the transfer and callback. 96 */ 97 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 98 { 99 assert(usb_batch); 77 */ 78 ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *ep) 79 { 80 assert(ep); 100 81 101 82 ohci_transfer_batch_t *ohci_batch = … … 103 84 if (!ohci_batch) { 104 85 usb_log_error("Failed to allocate OHCI batch data."); 105 goto dispose; 106 } 86 return NULL; 87 } 88 89 usb_transfer_batch_init(&ohci_batch->base, ep); 107 90 link_initialize(&ohci_batch->link); 108 ohci_batch->td_count = 109 (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1) 91 92 return ohci_batch; 93 } 94 95 /** Prepares a batch to be sent. 96 * 97 * Determines the number of needed transfer descriptors (TDs). 98 * Prepares a transport buffer (that is accessible by the hardware). 99 * Initializes parameters needed for the transfer and callback. 100 */ 101 int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch) 102 { 103 assert(ohci_batch); 104 105 const size_t setup_size = (ohci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 106 ? USB_SETUP_PACKET_SIZE 107 : 0; 108 109 usb_transfer_batch_t *usb_batch = &ohci_batch->base; 110 111 ohci_batch->td_count = (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1) 110 112 / OHCI_TD_MAX_TRANSFER; 111 113 /* Control transfer need Setup and Status stage */ … … 118 120 if (!ohci_batch->tds) { 119 121 usb_log_error("Failed to allocate OHCI transfer descriptors."); 120 goto dispose;122 return ENOMEM; 121 123 } 122 124 … … 129 131 if (!ohci_batch->tds[i]) { 130 132 usb_log_error("Failed to allocate TD %d.", i); 131 goto dispose;133 return ENOMEM; 132 134 } 133 135 } 134 135 136 136 137 /* NOTE: OHCI is capable of handling buffer that crosses page boundaries … … 138 139 * than two pages (the first page is computed using start pointer, the 139 140 * other using the end pointer) */ 140 if ( usb_batch->setup_size + usb_batch->buffer_size > 0) {141 if (setup_size + usb_batch->buffer_size > 0) { 141 142 /* Use one buffer for setup and data stage */ 142 143 ohci_batch->device_buffer = 143 malloc32( usb_batch->setup_size + usb_batch->buffer_size);144 malloc32(setup_size + usb_batch->buffer_size); 144 145 if (!ohci_batch->device_buffer) { 145 146 usb_log_error("Failed to allocate device buffer"); 146 goto dispose;147 return ENOMEM; 147 148 } 148 149 /* Copy setup data */ 149 memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer, 150 usb_batch->setup_size); 150 memcpy(ohci_batch->device_buffer, usb_batch->setup.buffer, setup_size); 151 151 /* Copy generic data */ 152 152 if (usb_batch->ep->direction != USB_DIRECTION_IN) 153 153 memcpy( 154 ohci_batch->device_buffer + usb_batch->setup_size,154 ohci_batch->device_buffer + setup_size, 155 155 usb_batch->buffer, usb_batch->buffer_size); 156 156 } 157 ohci_batch->usb_batch = usb_batch; 158 159 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch); 157 160 158 assert(batch_setup[usb_batch->ep->transfer_type]); 161 batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir); 162 163 return ohci_batch; 164 dispose: 165 ohci_transfer_batch_dispose(ohci_batch); 166 return NULL; 159 batch_setup[usb_batch->ep->transfer_type](ohci_batch); 160 161 return EOK; 167 162 } 168 163 … … 176 171 * completes with the last TD. 177 172 */ 178 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch) 179 { 180 assert(ohci_batch); 181 assert(ohci_batch->usb_batch); 173 bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *ohci_batch) 174 { 175 assert(ohci_batch); 182 176 183 177 usb_log_debug("Batch %p checking %zu td(s) for completion.\n", … … 194 188 195 189 /* Assume all data got through */ 196 ohci_batch->usb_batch->transfered_size = 197 ohci_batch->usb_batch->buffer_size; 190 ohci_batch->base.transfered_size = ohci_batch->base.buffer_size; 198 191 199 192 /* Assume we will leave the last(unused) TD behind */ … … 207 200 ohci_batch->tds[i]->next, ohci_batch->tds[i]->be); 208 201 209 ohci_batch-> usb_batch->error = td_error(ohci_batch->tds[i]);210 if (ohci_batch-> usb_batch->error == EOK) {202 ohci_batch->base.error = td_error(ohci_batch->tds[i]); 203 if (ohci_batch->base.error == EOK) { 211 204 /* If the TD got all its data through, it will report 212 205 * 0 bytes remain, the sole exception is INPUT with … … 221 214 * we leave the very last(unused) TD behind. 222 215 */ 223 ohci_batch-> usb_batch->transfered_size216 ohci_batch->base.transfered_size 224 217 -= td_remain_size(ohci_batch->tds[i]); 225 218 } else { … … 252 245 } 253 246 } 254 assert(ohci_batch->usb_batch->transfered_size <= 255 ohci_batch->usb_batch->buffer_size); 247 assert(ohci_batch->base.transfered_size <= 248 ohci_batch->base.buffer_size); 249 250 if (ohci_batch->base.dir == USB_DIRECTION_IN) 251 memcpy(ohci_batch->base.buffer, ohci_batch->device_buffer, ohci_batch->base.transfered_size); 256 252 257 253 /* Store the remaining TD */ 258 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch-> usb_batch->ep);254 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep); 259 255 assert(ohci_ep); 260 256 ohci_ep->td = ohci_batch->tds[leave_td]; … … 286 282 * Status stage with toggle 1 and direction supplied by parameter. 287 283 */ 288 static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir) 289 { 290 assert(ohci_batch); 291 assert(ohci_batch->usb_batch); 284 static void batch_control(ohci_transfer_batch_t *ohci_batch) 285 { 286 assert(ohci_batch); 287 288 usb_direction_t dir = ohci_batch->base.dir; 292 289 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 290 293 291 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed, 294 292 ohci_batch->ed->status, ohci_batch->ed->td_tail, … … 307 305 td_init( 308 306 ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH, 309 buffer, ohci_batch->usb_batch->setup_size, toggle);307 buffer, USB_SETUP_PACKET_SIZE, toggle); 310 308 usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n", 311 309 ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp, 312 310 ohci_batch->tds[0]->next, ohci_batch->tds[0]->be); 313 buffer += ohci_batch->usb_batch->setup_size;311 buffer += USB_SETUP_PACKET_SIZE; 314 312 315 313 /* Data stage */ … … 361 359 * OHCI hw in ED. 362 360 */ 363 static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir) 364 { 365 assert(ohci_batch); 366 assert(ohci_batch->usb_batch); 361 static void batch_data(ohci_transfer_batch_t *ohci_batch) 362 { 363 assert(ohci_batch); 364 365 usb_direction_t dir = ohci_batch->base.dir; 367 366 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 368 367 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed, … … 401 400 402 401 /** Transfer setup table. */ 403 static void (*const batch_setup[])(ohci_transfer_batch_t* , usb_direction_t) =402 static void (*const batch_setup[])(ohci_transfer_batch_t*) = 404 403 { 405 404 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/ohci/ohci_batch.h
r74b852b r5fd9c30 45 45 /** OHCI specific data required for USB transfer */ 46 46 typedef struct ohci_transfer_batch { 47 usb_transfer_batch_t base; 48 47 49 /** Link */ 48 50 link_t link; … … 59 61 } ohci_transfer_batch_t; 60 62 61 ohci_transfer_batch_t * ohci_transfer_batch_ get(usb_transfer_batch_t *batch);62 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);63 ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *batch); 64 int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch); 63 65 void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch); 64 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch); 66 bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *batch); 67 void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch); 65 68 66 69 static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l) … … 69 72 return list_get_instance(l, ohci_transfer_batch_t, link); 70 73 } 74 75 static inline ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 76 { 77 assert(usb_batch); 78 79 return (ohci_transfer_batch_t *) usb_batch; 80 } 81 71 82 #endif 72 83 /** -
uspace/drv/bus/usb/ohci/ohci_bus.c
r74b852b r5fd9c30 40 40 41 41 #include "ohci_bus.h" 42 #include "ohci_batch.h" 42 43 #include "hc.h" 43 44 … … 141 142 hc_dequeue_endpoint(bus->hc, ep); 142 143 return EOK; 144 } 143 145 146 static usb_transfer_batch_t *ohci_bus_create_batch(bus_t *bus, endpoint_t *ep) 147 { 148 ohci_transfer_batch_t *batch = ohci_transfer_batch_create(ep); 149 return &batch->base; 150 } 151 152 static void ohci_bus_destroy_batch(usb_transfer_batch_t *batch) 153 { 154 ohci_transfer_batch_destroy(ohci_transfer_batch_get(batch)); 144 155 } 145 156 … … 161 172 ops->release_endpoint = ohci_release_ep; 162 173 174 ops->create_batch = ohci_bus_create_batch; 175 ops->destroy_batch = ohci_bus_destroy_batch; 176 163 177 bus->hc = hc; 164 178 -
uspace/drv/bus/usb/ohci/ohci_rh.c
r74b852b r5fd9c30 180 180 const usb_target_t target = batch->ep->target; 181 181 batch->error = virthub_base_request(&instance->base, target, 182 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,182 batch->dir, &batch->setup.packet, 183 183 batch->buffer, batch->buffer_size, &batch->transfered_size); 184 184 if (batch->error == ENAK) { … … 189 189 instance->unfinished_interrupt_transfer = batch; 190 190 } else { 191 usb_transfer_batch_finish(batch, NULL); 192 usb_transfer_batch_destroy(batch); 191 usb_transfer_batch_finish(batch); 193 192 } 194 193 return EOK; … … 210 209 const usb_target_t target = batch->ep->target; 211 210 batch->error = virthub_base_request(&instance->base, target, 212 usb_transfer_batch_direction(batch), 213 (void*)batch->setup_buffer, 211 batch->dir, &batch->setup.packet, 214 212 batch->buffer, batch->buffer_size, &batch->transfered_size); 215 usb_transfer_batch_finish(batch, NULL); 216 usb_transfer_batch_destroy(batch); 213 usb_transfer_batch_finish(batch); 217 214 } 218 215 return EOK; -
uspace/drv/bus/usb/uhci/hc.c
r74b852b r5fd9c30 177 177 uhci_transfer_batch_t *batch = 178 178 uhci_transfer_batch_from_link(current); 179 u hci_transfer_batch_finish_dispose(batch);179 usb_transfer_batch_finish(&batch->base); 180 180 } 181 181 } … … 309 309 } 310 310 311 static usb_transfer_batch_t *create_transfer_batch(bus_t *bus, endpoint_t *ep) 312 { 313 uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep); 314 return &batch->base; 315 } 316 317 static void destroy_transfer_batch(usb_transfer_batch_t *batch) 318 { 319 uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch)); 320 } 321 311 322 /** Initialize UHCI hc memory structures. 312 323 * … … 326 337 if ((err = usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11))) 327 338 return err; 339 340 instance->bus.base.ops.create_batch = create_transfer_batch; 341 instance->bus.base.ops.destroy_batch = destroy_transfer_batch; 328 342 329 343 /* Init USB frame list page */ … … 450 464 return uhci_rh_schedule(&instance->rh, batch); 451 465 452 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);466 uhci_transfer_batch_t *uhci_batch = (uhci_transfer_batch_t *) batch; 453 467 if (!uhci_batch) { 454 468 usb_log_error("Failed to create UHCI transfer structures.\n"); 455 469 return ENOMEM; 456 470 } 471 472 const int err = uhci_transfer_batch_prepare(uhci_batch); 473 if (err) 474 return err; 457 475 458 476 transfer_list_t *list = -
uspace/drv/bus/usb/uhci/transfer_list.c
r74b852b r5fd9c30 167 167 uhci_transfer_batch_from_link(current); 168 168 169 if (uhci_transfer_batch_ is_complete(batch)) {169 if (uhci_transfer_batch_check_completed(batch)) { 170 170 /* Save for processing */ 171 171 transfer_list_remove_batch(instance, batch); -
uspace/drv/bus/usb/uhci/uhci_batch.c
r74b852b r5fd9c30 50 50 #define DEFAULT_ERROR_COUNT 3 51 51 52 /** Safely destructs uhci_transfer_batch_t structure. 52 /** Transfer batch setup table. */ 53 static void (*const batch_setup[])(uhci_transfer_batch_t*); 54 55 /** Destroys uhci_transfer_batch_t structure. 53 56 * 54 57 * @param[in] uhci_batch Instance to destroy. 55 58 */ 56 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch) 57 { 58 if (uhci_batch) { 59 usb_transfer_batch_destroy(uhci_batch->usb_batch); 60 free32(uhci_batch->device_buffer); 61 free(uhci_batch); 62 } 63 } 64 65 /** Finishes usb_transfer_batch and destroys the structure. 66 * 67 * @param[in] uhci_batch Instance to finish and destroy. 68 */ 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch) 59 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch) 70 60 { 71 61 assert(uhci_batch); 72 assert(uhci_batch->usb_batch); 73 assert(!link_in_use(&uhci_batch->link)); 74 usb_transfer_batch_finish(uhci_batch->usb_batch, 75 uhci_transfer_batch_data_buffer(uhci_batch)); 76 uhci_transfer_batch_dispose(uhci_batch); 77 } 78 79 /** Transfer batch setup table. */ 80 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t); 62 free32(uhci_batch->device_buffer); 63 free(uhci_batch); 64 } 81 65 82 66 /** Allocate memory and initialize internal data structure. … … 85 69 * @return Valid pointer if all structures were successfully created, 86 70 * NULL otherwise. 71 */ 72 uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep) 73 { 74 uhci_transfer_batch_t *uhci_batch = 75 calloc(1, sizeof(uhci_transfer_batch_t)); 76 if (!uhci_batch) { 77 usb_log_error("Failed to allocate UHCI batch.\n"); 78 return NULL; 79 } 80 81 usb_transfer_batch_init(&uhci_batch->base, ep); 82 83 link_initialize(&uhci_batch->link); 84 return uhci_batch; 85 } 86 87 /* Prepares batch for commiting. 87 88 * 88 89 * Determines the number of needed transfer descriptors (TDs). … … 90 91 * Initializes parameters needed for the transfer and callback. 91 92 */ 92 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)93 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch) 93 94 { 94 95 static_assert((sizeof(td_t) % 16) == 0); 95 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 96 if (ptr == NULL) { \ 97 usb_log_error(message); \ 98 uhci_transfer_batch_dispose(uhci_batch); \ 99 return NULL; \ 100 } else (void)0 101 102 uhci_transfer_batch_t *uhci_batch = 103 calloc(1, sizeof(uhci_transfer_batch_t)); 104 CHECK_NULL_DISPOSE_RETURN(uhci_batch, 105 "Failed to allocate UHCI batch.\n"); 106 link_initialize(&uhci_batch->link); 107 uhci_batch->td_count = 108 (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1) 109 / usb_batch->ep->max_packet_size; 96 97 usb_transfer_batch_t *usb_batch = &uhci_batch->base; 98 99 uhci_batch->td_count = (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1) 100 / usb_batch->ep->max_packet_size; 101 110 102 if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 111 103 uhci_batch->td_count += 2; 112 104 } 113 105 106 const size_t setup_size = (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 107 ? USB_SETUP_PACKET_SIZE 108 : 0; 109 114 110 const size_t total_size = (sizeof(td_t) * uhci_batch->td_count) 115 + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size;111 + sizeof(qh_t) + setup_size + usb_batch->buffer_size; 116 112 uhci_batch->device_buffer = malloc32(total_size); 117 CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer, 118 "Failed to allocate UHCI buffer.\n"); 113 if (!uhci_batch->device_buffer) { 114 usb_log_error("Failed to allocate UHCI buffer.\n"); 115 return ENOMEM; 116 } 119 117 memset(uhci_batch->device_buffer, 0, total_size); 120 118 … … 130 128 + sizeof(qh_t); 131 129 /* Copy SETUP packet data to the device buffer */ 132 memcpy(dest, usb_batch->setup _buffer, usb_batch->setup_size);133 dest += usb_batch->setup_size;130 memcpy(dest, usb_batch->setup.buffer, setup_size); 131 dest += setup_size; 134 132 /* Copy generic data unless they are provided by the device */ 135 133 if (usb_batch->ep->direction != USB_DIRECTION_IN) { 136 134 memcpy(dest, usb_batch->buffer, usb_batch->buffer_size); 137 135 } 138 uhci_batch->usb_batch = usb_batch;139 136 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 140 137 " memory structures ready.\n", usb_batch, 141 138 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 142 139 143 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);144 145 140 assert(batch_setup[usb_batch->ep->transfer_type]); 146 batch_setup[usb_batch->ep->transfer_type](uhci_batch , dir);147 148 return uhci_batch;141 batch_setup[usb_batch->ep->transfer_type](uhci_batch); 142 143 return EOK; 149 144 } 150 145 … … 158 153 * is reached. 159 154 */ 160 bool uhci_transfer_batch_ is_complete(constuhci_transfer_batch_t *uhci_batch)155 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch) 161 156 { 162 157 assert(uhci_batch); 163 assert(uhci_batch->usb_batch);164 158 165 159 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT … … 168 162 USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 169 163 uhci_batch->td_count); 170 uhci_batch-> usb_batch->transfered_size = 0;164 uhci_batch->base.transfered_size = 0; 171 165 172 166 for (size_t i = 0;i < uhci_batch->td_count; ++i) { … … 175 169 } 176 170 177 uhci_batch-> usb_batch->error = td_status(&uhci_batch->tds[i]);178 if (uhci_batch-> usb_batch->error != EOK) {179 assert(uhci_batch-> usb_batch->ep != NULL);171 uhci_batch->base.error = td_status(&uhci_batch->tds[i]); 172 if (uhci_batch->base.error != EOK) { 173 assert(uhci_batch->base.ep != NULL); 180 174 181 175 usb_log_debug("Batch %p found error TD(%zu->%p):%" … … 184 178 td_print_status(&uhci_batch->tds[i]); 185 179 186 endpoint_toggle_set(uhci_batch-> usb_batch->ep,180 endpoint_toggle_set(uhci_batch->base.ep, 187 181 td_toggle(&uhci_batch->tds[i])); 188 182 if (i > 0) … … 191 185 } 192 186 193 uhci_batch-> usb_batch->transfered_size187 uhci_batch->base.transfered_size 194 188 += td_act_size(&uhci_batch->tds[i]); 195 189 if (td_is_short(&uhci_batch->tds[i])) … … 197 191 } 198 192 substract_ret: 199 uhci_batch->usb_batch->transfered_size200 -= uhci_batch->usb_batch->setup_size;193 if (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 194 uhci_batch->base.transfered_size -= USB_SETUP_PACKET_SIZE; 201 195 return true; 202 196 } … … 216 210 * The last transfer is marked with IOC flag. 217 211 */ 218 static void batch_data(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)212 static void batch_data(uhci_transfer_batch_t *uhci_batch) 219 213 { 220 214 assert(uhci_batch); 221 assert(uhci_batch->usb_batch); 222 assert(uhci_batch->usb_batch->ep);215 216 usb_direction_t dir = uhci_batch->base.dir; 223 217 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 224 218 … … 226 220 const usb_packet_id pid = direction_pids[dir]; 227 221 const bool low_speed = 228 uhci_batch-> usb_batch->ep->speed == USB_SPEED_LOW;229 const size_t mps = uhci_batch-> usb_batch->ep->max_packet_size;230 const usb_target_t target = uhci_batch-> usb_batch->ep->target;231 232 int toggle = endpoint_toggle_get(uhci_batch-> usb_batch->ep);222 uhci_batch->base.ep->speed == USB_SPEED_LOW; 223 const size_t mps = uhci_batch->base.ep->max_packet_size; 224 const usb_target_t target = uhci_batch->base.ep->target; 225 226 int toggle = endpoint_toggle_get(uhci_batch->base.ep); 233 227 assert(toggle == 0 || toggle == 1); 234 228 235 229 size_t td = 0; 236 size_t remain_size = uhci_batch-> usb_batch->buffer_size;230 size_t remain_size = uhci_batch->base.buffer_size; 237 231 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 238 232 … … 254 248 } 255 249 td_set_ioc(&uhci_batch->tds[td - 1]); 256 endpoint_toggle_set(uhci_batch-> usb_batch->ep, toggle);250 endpoint_toggle_set(uhci_batch->base.ep, toggle); 257 251 usb_log_debug2( 258 252 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \ 259 253 uhci_batch->usb_batch, 260 usb_str_transfer_type(uhci_batch-> usb_batch->ep->transfer_type),261 usb_str_direction(uhci_batch-> usb_batch->ep->direction),254 usb_str_transfer_type(uhci_batch->base.ep->transfer_type), 255 usb_str_direction(uhci_batch->base.ep->direction), 262 256 USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch)); 263 257 } … … 274 268 * The last transfer is marked with IOC. 275 269 */ 276 static void batch_control(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)270 static void batch_control(uhci_transfer_batch_t *uhci_batch) 277 271 { 278 272 assert(uhci_batch); 279 assert(uhci_batch->usb_batch); 280 assert(uhci_batch->usb_batch->ep);273 274 usb_direction_t dir = uhci_batch->base.dir; 281 275 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 282 276 assert(uhci_batch->td_count >= 2); … … 289 283 const usb_packet_id status_stage_pid = status_stage_pids[dir]; 290 284 const bool low_speed = 291 uhci_batch-> usb_batch->ep->speed == USB_SPEED_LOW;292 const size_t mps = uhci_batch-> usb_batch->ep->max_packet_size;293 const usb_target_t target = uhci_batch-> usb_batch->ep->target;285 uhci_batch->base.ep->speed == USB_SPEED_LOW; 286 const size_t mps = uhci_batch->base.ep->max_packet_size; 287 const usb_target_t target = uhci_batch->base.ep->target; 294 288 295 289 /* setup stage */ 296 290 td_init( 297 291 &uhci_batch->tds[0], DEFAULT_ERROR_COUNT, 298 uhci_batch->usb_batch->setup_size, 0, false,292 USB_SETUP_PACKET_SIZE, 0, false, 299 293 low_speed, target, USB_PID_SETUP, 300 294 uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]); … … 303 297 size_t td = 1; 304 298 unsigned toggle = 1; 305 size_t remain_size = uhci_batch-> usb_batch->buffer_size;299 size_t remain_size = uhci_batch->base.buffer_size; 306 300 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 307 301 … … 333 327 } 334 328 335 static void (*const batch_setup[])(uhci_transfer_batch_t* , usb_direction_t) =329 static void (*const batch_setup[])(uhci_transfer_batch_t*) = 336 330 { 337 331 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/uhci/uhci_batch.h
r74b852b r5fd9c30 43 43 #include <stddef.h> 44 44 #include <usb/host/usb_transfer_batch.h> 45 #include <usb/host/endpoint.h> 45 46 46 47 #include "hw_struct/queue_head.h" … … 49 50 /** UHCI specific data required for USB transfer */ 50 51 typedef struct uhci_transfer_batch { 52 usb_transfer_batch_t base; 53 51 54 /** Queue head 52 55 * This QH is used to maintain UHCI schedule structure and the element … … 66 69 } uhci_transfer_batch_t; 67 70 68 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch); 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch); 70 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch); 71 uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep); 72 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch); 73 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch); 74 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch); 71 75 72 76 /** Get offset to setup buffer accessible to the HC hw. … … 93 97 assert(uhci_batch->usb_batch); 94 98 return uhci_transfer_batch_setup_buffer(uhci_batch) + 95 uhci_batch->usb_batch->setup_size;99 (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL ? USB_SETUP_PACKET_SIZE : 0); 96 100 } 97 101 … … 107 111 uhci_batch->usb_batch->error = EINTR; 108 112 uhci_batch->usb_batch->transfered_size = 0; 109 u hci_transfer_batch_finish_dispose(uhci_batch);113 usb_transfer_batch_finish(&uhci_batch->base); 110 114 } 111 115 … … 120 124 } 121 125 126 static inline uhci_transfer_batch_t *uhci_transfer_batch_get(usb_transfer_batch_t *b) 127 { 128 assert(b); 129 return (uhci_transfer_batch_t *) b; 130 } 131 122 132 #endif 123 133 -
uspace/drv/bus/usb/uhci/uhci_rh.c
r74b852b r5fd9c30 39 39 #include <usb/classes/hub.h> 40 40 #include <usb/request.h> 41 #include <usb/host/endpoint.h> 41 42 #include <usb/usb.h> 42 43 … … 106 107 do { 107 108 batch->error = virthub_base_request(&instance->base, target, 108 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,109 batch->dir, (void*) batch->setup.buffer, 109 110 batch->buffer, batch->buffer_size, &batch->transfered_size); 110 111 if (batch->error == ENAK) … … 113 114 //ENAK is technically an error condition 114 115 } while (batch->error == ENAK); 115 usb_transfer_batch_finish(batch, NULL); 116 usb_transfer_batch_destroy(batch); 116 usb_transfer_batch_finish(batch); 117 117 return EOK; 118 118 } -
uspace/drv/bus/usb/vhc/transfer.c
r74b852b r5fd9c30 44 44 return false; 45 45 } 46 if ( usb_transfer_batch_direction(transfer->batch)!= USB_DIRECTION_OUT) {47 return false; 48 } 49 const usb_device_request_setup_packet_t *setup =50 (void*)transfer->batch->setup_buffer;46 if (transfer->batch->dir != USB_DIRECTION_OUT) { 47 return false; 48 } 49 const usb_device_request_setup_packet_t *setup 50 = &transfer->batch->setup.packet; 51 51 if (setup->request_type != 0) { 52 52 return false; … … 63 63 { 64 64 int rc; 65 66 const usb_direction_t dir = usb_transfer_batch_direction(batch);65 66 const usb_direction_t dir = batch->dir; 67 67 68 68 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 69 69 if (dir == USB_DIRECTION_IN) { 70 70 rc = usbvirt_control_read(dev, 71 batch->setup _buffer, batch->setup_size,71 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 72 72 batch->buffer, batch->buffer_size, 73 73 actual_data_size); … … 75 75 assert(dir == USB_DIRECTION_OUT); 76 76 rc = usbvirt_control_write(dev, 77 batch->setup _buffer, batch->setup_size,77 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 78 78 batch->buffer, batch->buffer_size); 79 79 } … … 100 100 int rc; 101 101 102 const usb_direction_t dir = usb_transfer_batch_direction(batch);102 const usb_direction_t dir = batch->dir; 103 103 104 104 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 105 105 if (dir == USB_DIRECTION_IN) { 106 106 rc = usbvirt_ipc_send_control_read(sess, 107 batch->setup _buffer, batch->setup_size,107 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 108 108 batch->buffer, batch->buffer_size, 109 109 actual_data_size); … … 111 111 assert(dir == USB_DIRECTION_OUT); 112 112 rc = usbvirt_ipc_send_control_write(sess, 113 batch->setup _buffer, batch->setup_size,113 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 114 114 batch->buffer, batch->buffer_size); 115 115 } … … 149 149 assert(transfer); 150 150 assert(transfer->batch); 151 usb_transfer_batch_finish_error(transfer->batch, NULL,152 data_transfer_size, outcome);153 usb_transfer_batch_ destroy(transfer->batch);151 transfer->batch->error = outcome; 152 transfer->batch->transfered_size = data_transfer_size; 153 usb_transfer_batch_finish(transfer->batch); 154 154 free(transfer); 155 155 } … … 236 236 if (is_set_address_transfer(transfer)) { 237 237 usb_device_request_setup_packet_t *setup = 238 (void*) transfer->batch->setup _buffer;238 (void*) transfer->batch->setup.buffer; 239 239 dev->address = setup->value; 240 240 usb_log_debug2("Address changed to %d\n", -
uspace/drv/bus/usb/xhci/bus.c
r74b852b r5fd9c30 48 48 #include "bus.h" 49 49 #include "endpoint.h" 50 #include "transfers.h" 50 51 51 52 /** Element of the hash table. */ … … 310 311 } 311 312 313 static usb_transfer_batch_t *create_batch(bus_t *bus, endpoint_t *ep) 314 { 315 xhci_transfer_t *transfer = xhci_transfer_create(ep); 316 return &transfer->batch; 317 } 318 319 static void destroy_batch(usb_transfer_batch_t *batch) 320 { 321 xhci_transfer_destroy(xhci_transfer_from_batch(batch)); 322 } 323 312 324 static const bus_ops_t xhci_bus_ops = { 313 325 .enumerate_device = enumerate_device, … … 329 341 .endpoint_get_toggle = endpoint_get_toggle, 330 342 .endpoint_set_toggle = endpoint_set_toggle, 343 344 .create_batch = create_batch, 345 .destroy_batch = destroy_batch, 331 346 }; 332 347 -
uspace/drv/bus/usb/xhci/hc.c
r74b852b r5fd9c30 37 37 #include <str_error.h> 38 38 #include <usb/debug.h> 39 #include <usb/host/endpoint.h> 39 40 #include <usb/host/utils/malloc32.h> 40 41 #include "debug.h" … … 472 473 } 473 474 474 switch (batch->ep->transfer_type) { 475 case USB_TRANSFER_CONTROL: 476 return xhci_schedule_control_transfer(hc, batch); 477 case USB_TRANSFER_ISOCHRONOUS: 478 return xhci_schedule_isochronous_transfer(hc, batch); 479 case USB_TRANSFER_BULK: 480 return xhci_schedule_bulk_transfer(hc, batch); 481 case USB_TRANSFER_INTERRUPT: 482 return xhci_schedule_interrupt_transfer(hc, batch); 483 } 484 485 return EOK; 475 return xhci_transfer_schedule(hc, batch); 486 476 } 487 477 -
uspace/drv/bus/usb/xhci/main.c
r74b852b r5fd9c30 186 186 { 187 187 log_init(NAME); 188 logctl_set_log_level(NAME, LVL_DEBUG );188 logctl_set_log_level(NAME, LVL_DEBUG2); 189 189 return ddf_driver_main(&xhci_driver); 190 190 } -
uspace/drv/bus/usb/xhci/transfers.c
r74b852b r5fd9c30 108 108 } 109 109 110 xhci_transfer_t* xhci_transfer_ alloc(usb_transfer_batch_t* batch) {111 xhci_transfer_t* transfer = malloc(sizeof(xhci_transfer_t));110 xhci_transfer_t* xhci_transfer_create(endpoint_t* ep) { 111 xhci_transfer_t* transfer = calloc(1, sizeof(xhci_transfer_t)); 112 112 if (!transfer) 113 113 return NULL; 114 114 115 memset(transfer, 0, sizeof(xhci_transfer_t));116 transfer->batch = batch; 115 usb_transfer_batch_init(&transfer->batch, ep); 116 117 117 link_initialize(&transfer->link); 118 transfer->hc_buffer = batch->buffer_size > 0 ? malloc32(batch->buffer_size) : NULL;119 118 120 119 return transfer; 121 120 } 122 121 123 void xhci_transfer_fini(xhci_transfer_t* transfer) { 124 if (transfer) { 125 if (transfer->batch->buffer_size > 0) 126 free32(transfer->hc_buffer); 127 128 usb_transfer_batch_destroy(transfer->batch); 129 130 free(transfer); 131 } 132 } 133 134 int xhci_schedule_control_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 135 { 136 if (!batch->setup_size) { 137 usb_log_error("Missing setup packet for the control transfer."); 138 return EINVAL; 139 } 140 if (batch->ep->transfer_type != USB_TRANSFER_CONTROL) { 141 /* This method only works for control transfers. */ 142 usb_log_error("Attempted to schedule a control transfer to non control endpoint."); 143 return EINVAL; 144 } 145 146 usb_device_request_setup_packet_t* setup = 147 (usb_device_request_setup_packet_t*) batch->setup_buffer; 148 149 /* For the TRB formats, see xHCI specification 6.4.1.2 */ 150 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 151 152 if (!transfer->direction) { 153 // Sending stuff from host to device, we need to copy the actual data. 154 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 155 } 156 157 xhci_trb_t trbs[3]; 158 int trbs_used = 0; 122 void xhci_transfer_destroy(xhci_transfer_t* transfer) 123 { 124 assert(transfer); 125 126 if (transfer->hc_buffer) 127 free32(transfer->hc_buffer); 128 129 free(transfer); 130 } 131 132 static xhci_trb_ring_t *get_ring(xhci_hc_t *hc, xhci_transfer_t *transfer) 133 { 134 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 135 uint8_t slot_id = xhci_ep->device->slot_id; 136 137 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 138 assert(ring); 139 return ring; 140 } 141 142 static int schedule_control(xhci_hc_t* hc, xhci_transfer_t* transfer) 143 { 144 usb_transfer_batch_t *batch = &transfer->batch; 145 xhci_trb_ring_t *ring = get_ring(hc, transfer); 146 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 147 148 usb_device_request_setup_packet_t* setup = &batch->setup.packet; 149 150 xhci_trb_t trbs[3]; 151 int trbs_used = 0; 159 152 160 153 xhci_trb_t *trb_setup = trbs + trbs_used++; … … 178 171 xhci_trb_t *trb_data = NULL; 179 172 if (setup->length > 0) { 180 181 173 trb_data = trbs + trbs_used++; 174 xhci_trb_clean(trb_data); 182 175 183 176 trb_data->parameter = addr_to_phys(transfer->hc_buffer); … … 191 184 TRB_CTRL_SET_TRB_TYPE(*trb_data, XHCI_TRB_TYPE_DATA_STAGE); 192 185 193 transfer->direction= REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)186 int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type) 194 187 ? STAGE_IN : STAGE_OUT; 195 TRB_CTRL_SET_DIR(*trb_data, transfer->direction);188 TRB_CTRL_SET_DIR(*trb_data, stage_dir); 196 189 } 197 190 … … 207 200 TRB_CTRL_SET_DIR(*trb_status, get_status_direction_flag(trb_setup, setup->request_type, setup->length)); 208 201 209 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);210 uint8_t slot_id = xhci_ep->device->slot_id;211 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];212 213 int err = xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys);214 if (err != EOK)215 return err;216 217 list_append(&transfer->link, &hc->transfers);218 219 202 // Issue a Configure Endpoint command, if needed. 220 203 if (configure_endpoint_needed(setup)) { 221 // TODO: figure out the best time to issue this command 222 // FIXME: on fail, we need to "cancel" in-flight TRBs and remove transfer from the list 223 err = xhci_device_configure(xhci_ep->device, hc); 224 if (err != EOK) 225 return err; 226 } 227 228 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbels start at 1 */ 229 return hc_ring_doorbell(hc, slot_id, target); 230 } 231 232 int xhci_schedule_bulk_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 233 { 234 if (batch->setup_size) { 235 usb_log_warning("Setup packet present for a bulk transfer. Ignored."); 236 } 237 if (batch->ep->transfer_type != USB_TRANSFER_BULK) { 238 /* This method only works for bulk transfers. */ 239 usb_log_error("Attempted to schedule a bulk transfer to non bulk endpoint."); 240 return EINVAL; 241 } 242 243 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 244 if (!transfer->direction) { 245 // Sending stuff from host to device, we need to copy the actual data. 246 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 247 } 248 204 const int err = xhci_device_configure(xhci_ep->device, hc); 205 if (err) 206 return err; 207 } 208 209 return xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys); 210 } 211 212 static int schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer) 213 { 249 214 xhci_trb_t trb; 250 215 xhci_trb_clean(&trb); … … 252 217 253 218 // data size (sent for OUT, or buffer size) 254 TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);219 TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size); 255 220 // FIXME: TD size 4.11.2.4 256 221 TRB_CTRL_SET_TD_SIZE(trb, 1); … … 261 226 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL); 262 227 263 xhci_endpoint_t *xhci_ep = xhci_endpoint_get( batch->ep);228 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 264 229 uint8_t slot_id = xhci_ep->device->slot_id; 265 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint]; 266 267 xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 268 list_append(&transfer->link, &hc->transfers); 269 270 // TODO: target = endpoint | stream_id << 16 271 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 272 return hc_ring_doorbell(hc, slot_id, target); 273 } 274 275 int xhci_schedule_interrupt_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 276 { 277 if (batch->setup_size) { 278 usb_log_warning("Setup packet present for a interrupt transfer. Ignored."); 279 } 280 if (batch->ep->transfer_type != USB_TRANSFER_INTERRUPT) { 281 /* This method only works for interrupt transfers. */ 282 usb_log_error("Attempted to schedule a interrupt transfer to non interrupt endpoint."); 283 return EINVAL; 284 } 285 286 xhci_transfer_t *transfer = xhci_transfer_alloc(batch); 287 if (!transfer->direction) { 288 // Sending stuff from host to device, we need to copy the actual data. 289 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 290 } 291 230 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 231 232 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 233 } 234 235 static int schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer) 236 { 292 237 xhci_trb_t trb; 293 238 xhci_trb_clean(&trb); … … 295 240 296 241 // data size (sent for OUT, or buffer size) 297 TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);242 TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size); 298 243 // FIXME: TD size 4.11.2.4 299 244 TRB_CTRL_SET_TD_SIZE(trb, 1); … … 304 249 TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL); 305 250 306 xhci_endpoint_t *xhci_ep = xhci_endpoint_get( batch->ep);251 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep); 307 252 uint8_t slot_id = xhci_ep->device->slot_id; 308 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint]; 309 310 xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 311 list_append(&transfer->link, &hc->transfers); 312 313 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 314 return hc_ring_doorbell(hc, slot_id, target); 315 } 316 317 int xhci_schedule_isochronous_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch) 318 { 319 if (batch->setup_size) { 320 usb_log_warning("Setup packet present for a isochronous transfer. Ignored."); 321 } 322 if (batch->ep->transfer_type != USB_TRANSFER_ISOCHRONOUS) { 323 /* This method only works for isochronous transfers. */ 324 usb_log_error("Attempted to schedule a isochronous transfer to non isochronous endpoint."); 325 return EINVAL; 326 } 327 328 /* TODO: Implement me. */ 329 usb_log_error("Isochronous transfers are not yet implemented!"); 330 return ENOTSUP; 253 xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint]; 254 255 return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys); 256 } 257 258 static int schedule_isochronous(xhci_hc_t* hc, xhci_transfer_t* transfer) 259 { 260 /* TODO: Implement me. */ 261 usb_log_error("Isochronous transfers are not yet implemented!"); 262 return ENOTSUP; 331 263 } 332 264 … … 352 284 353 285 list_remove(transfer_link); 354 usb_transfer_batch_t *batch = transfer->batch; 355 356 const int err = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK; 357 const size_t size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb); 358 usb_transfer_batch_finish_error(batch, transfer->hc_buffer, size, err); 359 xhci_transfer_fini(transfer); 286 usb_transfer_batch_t *batch = &transfer->batch; 287 288 batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK; 289 batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb); 290 291 if (batch->dir == USB_DIRECTION_IN) { 292 assert(batch->buffer); 293 assert(batch->transfered_size <= batch->buffer_size); 294 memcpy(batch->buffer, transfer->hc_buffer, batch->transfered_size); 295 } 296 297 usb_transfer_batch_finish(batch); 360 298 return EOK; 361 299 } 300 301 typedef int (*transfer_handler)(xhci_hc_t *, xhci_transfer_t *); 302 303 static const transfer_handler transfer_handlers[] = { 304 [USB_TRANSFER_CONTROL] = schedule_control, 305 [USB_TRANSFER_ISOCHRONOUS] = schedule_isochronous, 306 [USB_TRANSFER_BULK] = schedule_bulk, 307 [USB_TRANSFER_INTERRUPT] = schedule_interrupt, 308 }; 309 310 int xhci_transfer_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch) 311 { 312 assert(hc); 313 314 xhci_transfer_t *transfer = xhci_transfer_from_batch(batch); 315 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep); 316 uint8_t slot_id = xhci_ep->device->slot_id; 317 318 assert(xhci_ep); 319 assert(slot_id); 320 321 const usb_transfer_type_t type = batch->ep->transfer_type; 322 assert(type >= 0 && type < ARRAY_SIZE(transfer_handlers)); 323 assert(transfer_handlers[type]); 324 325 if (batch->buffer_size > 0) { 326 transfer->hc_buffer = malloc32(batch->buffer_size); 327 } 328 329 if (batch->dir != USB_DIRECTION_IN) { 330 // Sending stuff from host to device, we need to copy the actual data. 331 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size); 332 } 333 334 const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer); 335 if (err) 336 return err; 337 338 list_append(&transfer->link, &hc->transfers); 339 340 const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */ 341 return hc_ring_doorbell(hc, slot_id, target); 342 } -
uspace/drv/bus/usb/xhci/transfers.h
r74b852b r5fd9c30 34 34 */ 35 35 36 #ifndef XHCI_TRANSFERS_H 37 #define XHCI_TRANSFERS_H 38 39 #include <usb/host/usb_transfer_batch.h> 40 36 41 #include "hc.h" 37 42 #include "trb_ring.h" 38 43 39 44 typedef struct { 45 usb_transfer_batch_t batch; 40 46 link_t link; 41 47 42 uintptr_t interrupt_trb_phys;43 48 uint8_t direction; 44 49 45 usb_transfer_batch_t* batch; 50 void* hc_buffer; /* Virtual address of the buffer start. */ 51 uintptr_t hc_buffer_phys; 46 52 47 void* hc_buffer; /* Virtual address of the buffer start. */53 uintptr_t interrupt_trb_phys; 48 54 } xhci_transfer_t; 49 55 … … 51 57 void xhci_fini_transfers(xhci_hc_t*); 52 58 53 xhci_transfer_t* xhci_transfer_alloc(usb_transfer_batch_t*); 54 void xhci_transfer_fini(xhci_transfer_t*); 59 xhci_transfer_t* xhci_transfer_create(endpoint_t *); 60 int xhci_transfer_schedule(xhci_hc_t*, usb_transfer_batch_t *); 61 int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*); 62 void xhci_transfer_destroy(xhci_transfer_t*); 55 63 56 int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*); 64 static inline xhci_transfer_t *xhci_transfer_from_batch(usb_transfer_batch_t *batch) 65 { 66 assert(batch); 67 return (xhci_transfer_t *) batch; 68 } 57 69 58 int xhci_schedule_control_transfer(xhci_hc_t*, usb_transfer_batch_t*); 59 int xhci_schedule_bulk_transfer(xhci_hc_t*, usb_transfer_batch_t*); 60 int xhci_schedule_interrupt_transfer(xhci_hc_t*, usb_transfer_batch_t*); 61 int xhci_schedule_isochronous_transfer(xhci_hc_t* , usb_transfer_batch_t* ); 70 /** 71 * @} 72 */ 73 #endif -
uspace/lib/usb/include/usb/request.h
r74b852b r5fd9c30 109 109 int assert[(sizeof(usb_device_request_setup_packet_t) == 8) ? 1: -1]; 110 110 111 int usb_request_needs_toggle_reset( 111 /** How much toggles needs to be reset */ 112 typedef enum { 113 RESET_NONE, 114 RESET_EP, 115 RESET_ALL 116 } toggle_reset_mode_t; 117 118 toggle_reset_mode_t usb_request_get_toggle_reset_mode( 112 119 const usb_device_request_setup_packet_t *request); 113 120 -
uspace/lib/usb/src/usb.c
r74b852b r5fd9c30 128 128 * 129 129 */ 130 int usb_request_needs_toggle_reset(130 toggle_reset_mode_t usb_request_get_toggle_reset_mode( 131 131 const usb_device_request_setup_packet_t *request) 132 132 { … … 139 139 if ((request->request_type == 0x2) && 140 140 (request->value == USB_FEATURE_ENDPOINT_HALT)) 141 return uint16_usb2host(request->index);141 return RESET_EP; 142 142 break; 143 143 case USB_DEVREQ_SET_CONFIGURATION: … … 149 149 * interface of an already setup device. */ 150 150 if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST)) 151 return 0;151 return RESET_ALL; 152 152 break; 153 153 default: 154 154 break; 155 155 } 156 return -1; 156 157 return RESET_NONE; 157 158 } 158 159 -
uspace/lib/usbhost/include/usb/host/bus.h
r74b852b r5fd9c30 33 33 * 34 34 * The purpose of this structure is to keep information about connected devices 35 * and en points, manage available bandwidth and the toggle bit flipping.35 * and endpoints, manage available bandwidth and the toggle bit flipping. 36 36 * 37 37 * The generic implementation is provided for USB 1 and 2 in usb2_bus.c. Some … … 53 53 typedef struct bus bus_t; 54 54 typedef struct ddf_fun ddf_fun_t; 55 typedef struct usb_transfer_batch usb_transfer_batch_t; 55 56 56 57 typedef struct device { … … 85 86 int (*release_endpoint)(bus_t *, endpoint_t *); 86 87 endpoint_t *(*find_endpoint)(bus_t *, usb_target_t, usb_direction_t); 88 void (*destroy_endpoint)(endpoint_t *); /**< Optional */ 89 bool (*endpoint_get_toggle)(endpoint_t *); /**< Optional */ 90 void (*endpoint_set_toggle)(endpoint_t *, bool); /**< Optional */ 87 91 88 92 int (*request_address)(bus_t *, usb_address_t*, bool, usb_speed_t); … … 93 97 size_t (*count_bw) (endpoint_t *, size_t); 94 98 95 /* Endpoint ops, optional (have generic fallback) */ 96 void (*destroy_endpoint)(endpoint_t *); 97 bool (*endpoint_get_toggle)(endpoint_t *); 98 void (*endpoint_set_toggle)(endpoint_t *, bool); 99 usb_transfer_batch_t *(*create_batch)(bus_t *, endpoint_t *); /**< Optional */ 100 void (*destroy_batch)(usb_transfer_batch_t *); /**< Optional */ 99 101 } bus_ops_t; 100 102 … … 135 137 int bus_release_address(bus_t *, usb_address_t); 136 138 139 137 140 static inline int bus_reserve_default_address(bus_t *bus, usb_speed_t speed) { 138 141 usb_address_t addr = USB_ADDRESS_DEFAULT; -
uspace/lib/usbhost/include/usb/host/endpoint.h
r74b852b r5fd9c30 48 48 typedef struct bus bus_t; 49 49 typedef struct device device_t; 50 typedef struct usb_transfer_batch usb_transfer_batch_t; 50 51 51 52 /** Host controller side endpoint structure. */ -
uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
r74b852b r5fd9c30 37 37 #define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H 38 38 39 #include <usb/host/endpoint.h>40 39 #include <usb/usb.h> 40 #include <usb/request.h> 41 41 42 #include <assert.h>43 42 #include <stddef.h> 44 43 #include <stdint.h> … … 47 46 #define USB_SETUP_PACKET_SIZE 8 48 47 48 typedef struct endpoint endpoint_t; 49 typedef struct bus bus_t; 50 typedef struct usb_transfer_batch usb_transfer_batch_t; 51 52 /** Callback to be called on transfer. */ 53 typedef int (*usb_transfer_batch_callback_t)(usb_transfer_batch_t *); 54 49 55 /** Structure stores additional data needed for communication with EP */ 50 56 typedef struct usb_transfer_batch { 51 57 /** Endpoint used for communication */ 52 58 endpoint_t *ep; 53 /** Function called on completion (IN version) */ 54 usbhc_iface_transfer_in_callback_t callback_in; 55 /** Function called on completion (OUT version) */ 56 usbhc_iface_transfer_out_callback_t callback_out; 57 /** Argument to pass to the completion function */ 58 void *arg; 59 /** Size reported to be sent */ 60 size_t expected_size; 61 62 /** Direction of the transfer */ 63 usb_direction_t dir; 64 65 /** Function called on completion */ 66 usb_transfer_batch_callback_t on_complete; 67 /** Arbitrary data for the handler */ 68 void *on_complete_data; 69 70 /** Place to store SETUP data needed by control transfers */ 71 union { 72 char buffer [USB_SETUP_PACKET_SIZE]; 73 usb_device_request_setup_packet_t packet; 74 uint64_t packed; 75 } setup; 76 77 /** Resetting the Toggle */ 78 toggle_reset_mode_t toggle_reset_mode; 79 59 80 /** Place for data to send/receive */ 60 81 char *buffer; 61 82 /** Size of memory pointed to by buffer member */ 62 83 size_t buffer_size; 63 /** Place to store SETUP data needed by control transfers */64 char setup_buffer[USB_SETUP_PACKET_SIZE];65 /** Used portion of setup_buffer member66 *67 * SETUP buffer must be 8 bytes for control transfers and is left68 * unused for all other transfers. Thus, this field is either 0 or 8.69 */70 size_t setup_size;71 84 72 /** Actually used portion of the buffer 73 * This member is never accessed by functions provided in this header, 74 * with the exception of usb_transfer_batch_finish. For external use. 75 */ 85 /** Actually used portion of the buffer */ 76 86 size_t transfered_size; 77 /** Indicates success/failure of the communication 78 * This member is never accessed by functions provided in this header, 79 * with the exception of usb_transfer_batch_finish. For external use. 80 */ 87 /** Indicates success/failure of the communication */ 81 88 int error; 82 89 } usb_transfer_batch_t; … … 95 102 (batch).buffer_size, (batch).ep->max_packet_size 96 103 104 void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *); 105 void usb_transfer_batch_finish(usb_transfer_batch_t *); 97 106 98 usb_transfer_batch_t * usb_transfer_batch_create( 99 endpoint_t *ep, 100 char *buffer, 101 size_t buffer_size, 102 uint64_t setup_buffer, 103 usbhc_iface_transfer_in_callback_t func_in, 104 usbhc_iface_transfer_out_callback_t func_out, 105 void *arg 106 ); 107 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance); 107 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *); 108 void usb_transfer_batch_destroy(usb_transfer_batch_t *); 108 109 109 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 110 const void* data, size_t size, int error); 111 112 /** Finish batch using stored error value and transferred size. 113 * 114 * @param[in] instance Batch structure to use. 115 * @param[in] data Data to copy to the output buffer. 110 /** Provided to ease the transition. Wraps old-style handlers into a new one. 116 111 */ 117 static inline void usb_transfer_batch_finish( 118 const usb_transfer_batch_t *instance, const void* data) 119 { 120 assert(instance); 121 usb_transfer_batch_finish_error( 122 instance, data, instance->transfered_size, instance->error); 123 } 124 125 /** Determine batch direction based on the callbacks present 126 * @param[in] instance Batch structure to use, non-null. 127 * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT. 128 */ 129 static inline usb_direction_t usb_transfer_batch_direction( 130 const usb_transfer_batch_t *instance) 131 { 132 assert(instance); 133 if (instance->callback_in) { 134 assert(instance->callback_out == NULL); 135 assert(instance->ep == NULL 136 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 137 || instance->ep->direction == USB_DIRECTION_IN); 138 return USB_DIRECTION_IN; 139 } 140 if (instance->callback_out) { 141 assert(instance->callback_in == NULL); 142 assert(instance->ep == NULL 143 || instance->ep->transfer_type == USB_TRANSFER_CONTROL 144 || instance->ep->direction == USB_DIRECTION_OUT); 145 return USB_DIRECTION_OUT; 146 } 147 assert(false); 148 } 112 extern void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *, 113 usbhc_iface_transfer_in_callback_t, 114 usbhc_iface_transfer_out_callback_t, void *); 149 115 150 116 #endif -
uspace/lib/usbhost/src/hcd.c
r74b852b r5fd9c30 69 69 } 70 70 71 typedef struct {72 void *original_data;73 usbhc_iface_transfer_out_callback_t original_callback;74 usb_target_t target;75 hcd_t *hcd;76 } toggle_t;77 78 static void toggle_reset_callback(int retval, void *arg)79 {80 assert(arg);81 toggle_t *toggle = arg;82 if (retval == EOK) {83 usb_log_debug2("Reseting toggle on %d:%d.\n",84 toggle->target.address, toggle->target.endpoint);85 bus_reset_toggle(toggle->hcd->bus,86 toggle->target, toggle->target.endpoint == 0);87 }88 89 toggle->original_callback(retval, toggle->original_data);90 }91 92 71 /** Prepare generic usb_transfer_batch and schedule it. 93 72 * @param hcd Host controller driver. 94 * @param fun DDF fun95 73 * @param target address and endpoint number. 96 74 * @param setup_data Data to use in setup stage (Control communication type) … … 101 79 * @return Error code. 102 80 */ 103 int hcd_send_batch( 104 hcd_t *hcd, usb_target_t target, usb_direction_t direction, 105 void *data, size_t size, uint64_t setup_data, 106 usbhc_iface_transfer_in_callback_t in, 107 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name) 81 int hcd_send_batch(hcd_t *hcd, usb_target_t target, usb_direction_t direction, 82 void *data, size_t size, uint64_t setup_data, 83 usbhc_iface_transfer_in_callback_t in, usbhc_iface_transfer_out_callback_t out, 84 void *arg, const char *name) 108 85 { 109 86 assert(hcd); … … 132 109 } 133 110 134 /* Check for commands that reset toggle bit */ 135 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 136 const int reset_toggle = usb_request_needs_toggle_reset( 137 (usb_device_request_setup_packet_t *) &setup_data); 138 if (reset_toggle >= 0) { 139 assert(out); 140 toggle_t *toggle = malloc(sizeof(toggle_t)); 141 if (!toggle) 142 return ENOMEM; 143 toggle->target.address = target.address; 144 toggle->target.endpoint = reset_toggle; 145 toggle->original_callback = out; 146 toggle->original_data = arg; 147 toggle->hcd = hcd; 148 149 arg = toggle; 150 out = toggle_reset_callback; 151 } 152 } 153 154 usb_transfer_batch_t *batch = usb_transfer_batch_create( 155 ep, data, size, setup_data, in, out, arg); 111 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep); 156 112 if (!batch) { 157 113 usb_log_error("Failed to create transfer batch.\n"); 158 114 return ENOMEM; 159 115 } 116 117 batch->buffer = data; 118 batch->buffer_size = size; 119 batch->setup.packed = setup_data; 120 batch->dir = direction; 121 122 /* Check for commands that reset toggle bit */ 123 if (ep->transfer_type == USB_TRANSFER_CONTROL) 124 batch->toggle_reset_mode 125 = usb_request_get_toggle_reset_mode(&batch->setup.packet); 126 127 usb_transfer_batch_set_old_handlers(batch, in, out, arg); 160 128 161 129 const int ret = hcd->ops.schedule(hcd, batch); -
uspace/lib/usbhost/src/usb_transfer_batch.c
r74b852b r5fd9c30 34 34 35 35 #include <usb/host/usb_transfer_batch.h> 36 #include <usb/host/endpoint.h> 37 #include <usb/host/bus.h> 36 38 #include <usb/debug.h> 37 39 38 40 #include <assert.h> 39 41 #include <errno.h> 40 #include <macros.h>41 #include <mem.h>42 #include <stdlib.h>43 #include <usbhc_iface.h>44 42 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. 43 44 /** Create a batch on given endpoint. 57 45 */ 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) 46 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep) 64 47 { 65 if (func_in == NULL && func_out == NULL) 66 return NULL; 67 if (func_in != NULL && func_out != NULL) 68 return NULL; 48 assert(ep); 49 assert(ep->bus); 69 50 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; 85 } 86 if (instance->ep) 87 endpoint_use(instance->ep); 88 } 89 return instance; 51 usb_transfer_batch_t *batch; 52 if (ep->bus->ops.create_batch) 53 batch = ep->bus->ops.create_batch(ep->bus, ep); 54 else 55 batch = malloc(sizeof(usb_transfer_batch_t)); 56 57 return batch; 90 58 } 91 59 92 /** Correctly dispose all used data structures. 93 * 94 * @param[in] instance Batch structure to use. 60 /** Initialize given batch structure. 95 61 */ 96 void usb_transfer_batch_ destroy(const usb_transfer_batch_t *instance)62 void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep) 97 63 { 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); 64 memset(batch, 0, sizeof(*batch)); 65 66 batch->ep = ep; 67 68 endpoint_use(ep); 106 69 } 107 70 108 /** Prepare data and call the right callback.71 /** Call the handler of the batch. 109 72 * 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. 73 * @param[in] batch Batch structure to use. 114 74 */ 115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance, 116 const void *data, size_t size, int error) 75 static int batch_complete(usb_transfer_batch_t *batch) 117 76 { 118 assert(instance); 119 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n", 120 instance, USB_TRANSFER_BATCH_ARGS(*instance)); 77 assert(batch); 121 78 122 /* NOTE: Only one of these pointers should be set. */ 123 if (instance->callback_out) { 124 instance->callback_out(error, instance->arg); 79 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed.\n", 80 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 81 82 if (batch->error == EOK && batch->toggle_reset_mode != RESET_NONE) { 83 usb_log_debug2("Reseting %s due to transaction of %d:%d.\n", 84 batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle", 85 batch->ep->target.address, batch->ep->target.endpoint); 86 bus_reset_toggle(batch->ep->bus, 87 batch->ep->target, batch->toggle_reset_mode == RESET_ALL); 125 88 } 126 89 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); 132 } 133 instance->callback_in(error, safe_size, instance->arg); 134 } 90 return batch->on_complete 91 ? batch->on_complete(batch) 92 : EOK; 93 } 94 95 /** Destroy the batch. 96 * 97 * @param[in] batch Batch structure to use. 98 */ 99 void usb_transfer_batch_destroy(usb_transfer_batch_t *batch) 100 { 101 assert(batch); 102 assert(batch->ep); 103 assert(batch->ep->bus); 104 105 usb_log_debug2("batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n", 106 batch, USB_TRANSFER_BATCH_ARGS(*batch)); 107 108 bus_t *bus = batch->ep->bus; 109 if (bus->ops.destroy_batch) 110 bus->ops.destroy_batch(batch); 111 else 112 free(batch); 113 114 endpoint_release(batch->ep); 115 } 116 117 /** Finish a transfer batch: call handler, destroy batch, release endpoint. 118 * 119 * Call only after the batch have been scheduled && completed! 120 * 121 * @param[in] batch Batch structure to use. 122 */ 123 void usb_transfer_batch_finish(usb_transfer_batch_t *batch) 124 { 125 if (!batch_complete(batch)) 126 usb_log_warning("failed to complete batch %p!", batch); 127 128 usb_transfer_batch_destroy(batch); 129 } 130 131 132 struct old_handler_wrapper_data { 133 usbhc_iface_transfer_in_callback_t in_callback; 134 usbhc_iface_transfer_out_callback_t out_callback; 135 void *arg; 136 }; 137 138 static int old_handler_wrapper(usb_transfer_batch_t *batch) 139 { 140 struct old_handler_wrapper_data *data = batch->on_complete_data; 141 142 assert(data); 143 144 if (data->out_callback) 145 data->out_callback(batch->error, data->arg); 146 147 if (data->in_callback) 148 data->in_callback(batch->error, batch->transfered_size, data->arg); 149 150 free(data); 151 return EOK; 152 } 153 154 void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *batch, 155 usbhc_iface_transfer_in_callback_t in_callback, 156 usbhc_iface_transfer_out_callback_t out_callback, 157 void *arg) 158 { 159 struct old_handler_wrapper_data *data = malloc(sizeof(*data)); 160 161 data->in_callback = in_callback; 162 data->out_callback = out_callback; 163 data->arg = arg; 164 165 batch->on_complete = old_handler_wrapper; 166 batch->on_complete_data = data; 135 167 } 136 168 /**
Note:
See TracChangeset
for help on using the changeset viewer.