Changes in uspace/drv/uhci-hcd/batch.c [f706355:06c552c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/batch.c
rf706355 r06c552c 30 30 */ 31 31 /** @file 32 * @brief UHCI driver USB trans ferstructure32 * @brief UHCI driver USB transaction structure 33 33 */ 34 34 #include <errno.h> … … 45 45 #define DEFAULT_ERROR_COUNT 3 46 46 47 typedef struct uhci_ transfer_batch {47 typedef struct uhci_batch { 48 48 qh_t *qh; 49 49 td_t *tds; 50 void *device_buffer; 51 size_t td_count; 52 } uhci_transfer_batch_t; 53 /*----------------------------------------------------------------------------*/ 54 static void uhci_transfer_batch_dispose(void *uhci_batch) 55 { 56 uhci_transfer_batch_t *instance = uhci_batch; 57 assert(instance); 58 free32(instance->device_buffer); 59 free(instance); 60 } 61 /*----------------------------------------------------------------------------*/ 50 size_t transfers; 51 } uhci_batch_t; 62 52 63 53 static void batch_control(usb_transfer_batch_t *instance, 64 54 usb_packet_id data_stage, usb_packet_id status_stage); 65 55 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid); 56 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance); 57 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance); 58 66 59 67 60 /** Allocate memory and initialize internal data structure. 68 61 * 69 62 * @param[in] fun DDF function to pass to callback. 70 * @param[in] ep Communication target 63 * @param[in] target Device and endpoint target of the transaction. 64 * @param[in] transfer_type Interrupt, Control or Bulk. 65 * @param[in] max_packet_size maximum allowed size of data transfers. 66 * @param[in] speed Speed of the transaction. 71 67 * @param[in] buffer Data source/destination. 72 68 * @param[in] size Size of the buffer. 73 69 * @param[in] setup_buffer Setup data source (if not NULL) 74 70 * @param[in] setup_size Size of setup_buffer (should be always 8) 75 * @param[in] func_in function to call on inbound trans fercompletion76 * @param[in] func_out function to call on outbound trans fercompletion71 * @param[in] func_in function to call on inbound transaction completion 72 * @param[in] func_out function to call on outbound transaction completion 77 73 * @param[in] arg additional parameter to func_in or func_out 78 * @return Valid pointer if all structures were successfully created, 74 * @param[in] ep Pointer to endpoint toggle management structure. 75 * @return Valid pointer if all substructures were successfully created, 79 76 * NULL otherwise. 80 77 * 81 * Determines the number of needed transfer descriptors (TDs).82 * Prepares a transport buffer (that is accessible by the hardware).83 * Initializes parameters needed for the transferand callback.78 * Determines the number of needed transfers (TDs). Prepares a transport buffer 79 * (that is accessible by the hardware). Initializes parameters needed for the 80 * transaction and callback. 84 81 */ 85 82 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, … … 95 92 if (ptr == NULL) { \ 96 93 usb_log_error(message); \ 97 if ( uhci_data) { \98 uhci_transfer_batch_dispose(uhci_data); \94 if (instance) { \ 95 batch_dispose(instance); \ 99 96 } \ 100 97 return NULL; \ 101 98 } else (void)0 102 99 103 uhci_transfer_batch_t *uhci_data =104 malloc(sizeof(uhci_transfer_batch_t));105 CHECK_NULL_DISPOSE_RETURN(uhci_data,106 "Failed to allocate UHCI batch.\n");107 bzero(uhci_data, sizeof(uhci_transfer_batch_t));108 109 uhci_data->td_count =110 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;111 if (ep->transfer_type == USB_TRANSFER_CONTROL) {112 uhci_data->td_count += 2;113 }114 115 assert((sizeof(td_t) % 16) == 0);116 const size_t total_size = (sizeof(td_t) * uhci_data->td_count)117 + sizeof(qh_t) + setup_size + buffer_size;118 uhci_data->device_buffer = malloc32(total_size);119 CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,120 "Failed to allocate UHCI buffer.\n");121 bzero(uhci_data->device_buffer, total_size);122 123 uhci_data->tds = uhci_data->device_buffer;124 uhci_data->qh =125 (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));126 127 qh_init(uhci_data->qh);128 qh_set_element_td(uhci_data->qh, uhci_data->tds);129 130 100 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 131 101 CHECK_NULL_DISPOSE_RETURN(instance, 132 102 "Failed to allocate batch instance.\n"); 133 void *setup =134 uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)135 + sizeof(qh_t);136 void *data_buffer = setup + setup_size;137 103 usb_target_t target = 138 104 { .address = ep->address, .endpoint = ep->endpoint }; 139 usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size, 140 setup, setup_size, func_in, func_out, arg, fun, 141 uhci_data, uhci_transfer_batch_dispose); 142 143 memcpy(instance->setup_buffer, setup_buffer, setup_size); 105 usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed, 106 ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size, 107 func_in, func_out, arg, fun, ep, NULL); 108 109 110 uhci_batch_t *data = malloc(sizeof(uhci_batch_t)); 111 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n"); 112 bzero(data, sizeof(uhci_batch_t)); 113 instance->private_data = data; 114 115 data->transfers = 116 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size; 117 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 118 data->transfers += 2; 119 } 120 121 data->tds = malloc32(sizeof(td_t) * data->transfers); 122 CHECK_NULL_DISPOSE_RETURN( 123 data->tds, "Failed to allocate transfer descriptors.\n"); 124 bzero(data->tds, sizeof(td_t) * data->transfers); 125 126 data->qh = malloc32(sizeof(qh_t)); 127 CHECK_NULL_DISPOSE_RETURN(data->qh, 128 "Failed to allocate batch queue head.\n"); 129 qh_init(data->qh); 130 qh_set_element_td(data->qh, addr_to_phys(data->tds)); 131 132 if (buffer_size > 0) { 133 instance->transport_buffer = malloc32(buffer_size); 134 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 135 "Failed to allocate device accessible buffer.\n"); 136 } 137 138 if (setup_size > 0) { 139 instance->setup_buffer = malloc32(setup_size); 140 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 141 "Failed to allocate device accessible setup buffer.\n"); 142 memcpy(instance->setup_buffer, setup_buffer, setup_size); 143 } 144 144 145 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 145 146 instance, target.address, target.endpoint); … … 153 154 * 154 155 * Walk all TDs. Stop with false if there is an active one (it is to be 155 * processed). Stop with true if an error is found. Return true if the last T D156 * processed). Stop with true if an error is found. Return true if the last TS 156 157 * is reached. 157 158 */ … … 159 160 { 160 161 assert(instance); 161 uhci_ transfer_batch_t *data = instance->private_data;162 uhci_batch_t *data = instance->private_data; 162 163 assert(data); 163 164 164 165 usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n", 165 instance, data->t d_count);166 instance, data->transfers); 166 167 instance->transfered_size = 0; 167 168 size_t i = 0; 168 for (;i < data->t d_count; ++i) {169 for (;i < data->transfers; ++i) { 169 170 if (td_is_active(&data->tds[i])) { 170 171 return false; … … 176 177 instance, i, data->tds[i].status); 177 178 td_print_status(&data->tds[i]); 178 179 179 assert(instance->ep != NULL); 180 180 181 endpoint_toggle_set(instance->ep, 181 182 td_toggle(&data->tds[i])); … … 194 195 } 195 196 /*----------------------------------------------------------------------------*/ 196 /** Prepares control write trans fer.197 * 198 * @param[in] instance Batch structure to use. 199 * 200 * Uses gener iccontrol function with pids OUT and IN.197 /** Prepares control write transaction. 198 * 199 * @param[in] instance Batch structure to use. 200 * 201 * Uses genercir control function with pids OUT and IN. 201 202 */ 202 203 void batch_control_write(usb_transfer_batch_t *instance) … … 204 205 assert(instance); 205 206 /* We are data out, we are supposed to provide data */ 206 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 207 memcpy(instance->transport_buffer, instance->buffer, 208 instance->buffer_size); 207 209 batch_control(instance, USB_PID_OUT, USB_PID_IN); 208 instance->next_step = usb_transfer_batch_call_out_and_dispose;210 instance->next_step = batch_call_out_and_dispose; 209 211 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 210 212 } 211 213 /*----------------------------------------------------------------------------*/ 212 /** Prepares control read trans fer.214 /** Prepares control read transaction. 213 215 * 214 216 * @param[in] instance Batch structure to use. … … 220 222 assert(instance); 221 223 batch_control(instance, USB_PID_IN, USB_PID_OUT); 222 instance->next_step = usb_transfer_batch_call_in_and_dispose;224 instance->next_step = batch_call_in_and_dispose; 223 225 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 224 226 } 225 227 /*----------------------------------------------------------------------------*/ 226 /** Prepare interrupt in trans fer.227 * 228 * @param[in] instance Batch structure to use. 229 * 230 * Data trans ferwith PID_IN.228 /** Prepare interrupt in transaction. 229 * 230 * @param[in] instance Batch structure to use. 231 * 232 * Data transaction with PID_IN. 231 233 */ 232 234 void batch_interrupt_in(usb_transfer_batch_t *instance) 233 235 { 234 236 assert(instance); 237 instance->direction = USB_DIRECTION_IN; 235 238 batch_data(instance, USB_PID_IN); 236 instance->next_step = usb_transfer_batch_call_in_and_dispose;239 instance->next_step = batch_call_in_and_dispose; 237 240 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 238 241 } 239 242 /*----------------------------------------------------------------------------*/ 240 /** Prepare interrupt out trans fer.241 * 242 * @param[in] instance Batch structure to use. 243 * 244 * Data trans ferwith PID_OUT.243 /** Prepare interrupt out transaction. 244 * 245 * @param[in] instance Batch structure to use. 246 * 247 * Data transaction with PID_OUT. 245 248 */ 246 249 void batch_interrupt_out(usb_transfer_batch_t *instance) 247 250 { 248 251 assert(instance); 252 instance->direction = USB_DIRECTION_OUT; 249 253 /* We are data out, we are supposed to provide data */ 250 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 254 memcpy(instance->transport_buffer, instance->buffer, 255 instance->buffer_size); 251 256 batch_data(instance, USB_PID_OUT); 252 instance->next_step = usb_transfer_batch_call_out_and_dispose;257 instance->next_step = batch_call_out_and_dispose; 253 258 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 254 259 } 255 260 /*----------------------------------------------------------------------------*/ 256 /** Prepare bulk in trans fer.257 * 258 * @param[in] instance Batch structure to use. 259 * 260 * Data trans ferwith PID_IN.261 /** Prepare bulk in transaction. 262 * 263 * @param[in] instance Batch structure to use. 264 * 265 * Data transaction with PID_IN. 261 266 */ 262 267 void batch_bulk_in(usb_transfer_batch_t *instance) … … 264 269 assert(instance); 265 270 batch_data(instance, USB_PID_IN); 266 instance->next_step = usb_transfer_batch_call_in_and_dispose; 271 instance->direction = USB_DIRECTION_IN; 272 instance->next_step = batch_call_in_and_dispose; 267 273 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 268 274 } 269 275 /*----------------------------------------------------------------------------*/ 270 /** Prepare bulk out trans fer.271 * 272 * @param[in] instance Batch structure to use. 273 * 274 * Data trans ferwith PID_OUT.276 /** Prepare bulk out transaction. 277 * 278 * @param[in] instance Batch structure to use. 279 * 280 * Data transaction with PID_OUT. 275 281 */ 276 282 void batch_bulk_out(usb_transfer_batch_t *instance) 277 283 { 278 284 assert(instance); 285 instance->direction = USB_DIRECTION_OUT; 279 286 /* We are data out, we are supposed to provide data */ 280 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 287 memcpy(instance->transport_buffer, instance->buffer, 288 instance->buffer_size); 281 289 batch_data(instance, USB_PID_OUT); 282 instance->next_step = usb_transfer_batch_call_out_and_dispose;290 instance->next_step = batch_call_out_and_dispose; 283 291 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 284 292 } 285 293 /*----------------------------------------------------------------------------*/ 286 /** Prepare generic data trans fer287 * 288 * @param[in] instance Batch structure to use. 289 * @param[in] pid Pid to use for data trans actions.290 * 291 * Transactions with alternating toggle bit and supplied pid value.294 /** Prepare generic data transaction 295 * 296 * @param[in] instance Batch structure to use. 297 * @param[in] pid Pid to use for data transfers. 298 * 299 * Packets with alternating toggle bit and supplied pid value. 292 300 * The last transfer is marked with IOC flag. 293 301 */ … … 295 303 { 296 304 assert(instance); 297 uhci_ transfer_batch_t *data = instance->private_data;305 uhci_batch_t *data = instance->private_data; 298 306 assert(data); 299 307 300 const bool low_speed = instance-> ep->speed == USB_SPEED_LOW;308 const bool low_speed = instance->speed == USB_SPEED_LOW; 301 309 int toggle = endpoint_toggle_get(instance->ep); 302 310 assert(toggle == 0 || toggle == 1); 303 311 304 size_t t d= 0;312 size_t transfer = 0; 305 313 size_t remain_size = instance->buffer_size; 306 char *buffer = instance->data_buffer;307 314 while (remain_size > 0) { 315 char *trans_data = 316 instance->transport_buffer + instance->buffer_size 317 - remain_size; 318 308 319 const size_t packet_size = 309 (instance->ep->max_packet_size > remain_size) ? 310 remain_size : instance->ep->max_packet_size; 311 312 td_t *next_td = (td + 1 < data->td_count) 313 ? &data->tds[td + 1] : NULL; 314 315 316 usb_target_t target = 317 { instance->ep->address, instance->ep->endpoint }; 318 319 assert(td < data->td_count); 320 (instance->max_packet_size > remain_size) ? 321 remain_size : instance->max_packet_size; 322 323 td_t *next_transfer = (transfer + 1 < data->transfers) 324 ? &data->tds[transfer + 1] : NULL; 325 326 assert(transfer < data->transfers); 327 assert(packet_size <= remain_size); 328 320 329 td_init( 321 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size, 322 toggle, false, low_speed, target, pid, buffer, next_td); 323 324 ++td; 330 &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size, 331 toggle, false, low_speed, instance->target, pid, trans_data, 332 next_transfer); 333 334 325 335 toggle = 1 - toggle; 326 buffer += packet_size;327 assert(packet_size <= remain_size);328 336 remain_size -= packet_size; 329 } 330 td_set_ioc(&data->tds[td - 1]); 337 ++transfer; 338 } 339 td_set_ioc(&data->tds[transfer - 1]); 331 340 endpoint_toggle_set(instance->ep, toggle); 332 341 } 333 342 /*----------------------------------------------------------------------------*/ 334 /** Prepare generic control trans fer335 * 336 * @param[in] instance Batch structure to use. 337 * @param[in] data_stage Pid to use for data t ds.338 * @param[in] status_stage Pid to use for data t ds.343 /** Prepare generic control transaction 344 * 345 * @param[in] instance Batch structure to use. 346 * @param[in] data_stage Pid to use for data transfers. 347 * @param[in] status_stage Pid to use for data transfers. 339 348 * 340 349 * Setup stage with toggle 0 and USB_PID_SETUP. … … 347 356 { 348 357 assert(instance); 349 uhci_ transfer_batch_t *data = instance->private_data;358 uhci_batch_t *data = instance->private_data; 350 359 assert(data); 351 assert(data->td_count >= 2); 352 353 const bool low_speed = instance->ep->speed == USB_SPEED_LOW; 354 const usb_target_t target = 355 { instance->ep->address, instance->ep->endpoint }; 356 360 assert(data->transfers >= 2); 361 362 const bool low_speed = instance->speed == USB_SPEED_LOW; 363 int toggle = 0; 357 364 /* setup stage */ 358 365 td_init( 359 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,360 low_speed, target, USB_PID_SETUP, instance->setup_buffer,366 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, toggle, false, 367 low_speed, instance->target, USB_PID_SETUP, instance->setup_buffer, 361 368 &data->tds[1]); 362 369 363 370 /* data stage */ 364 size_t td = 1; 365 unsigned toggle = 1; 371 size_t transfer = 1; 366 372 size_t remain_size = instance->buffer_size; 367 char *buffer = instance->data_buffer;368 373 while (remain_size > 0) { 374 char *control_data = 375 instance->transport_buffer + instance->buffer_size 376 - remain_size; 377 378 toggle = 1 - toggle; 379 369 380 const size_t packet_size = 370 (instance-> ep->max_packet_size > remain_size) ?371 remain_size : instance-> ep->max_packet_size;381 (instance->max_packet_size > remain_size) ? 382 remain_size : instance->max_packet_size; 372 383 373 384 td_init( 374 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size, 375 toggle, false, low_speed, target, data_stage, 376 buffer, &data->tds[td + 1]); 377 378 ++td; 379 toggle = 1 - toggle; 380 buffer += packet_size; 381 assert(td < data->td_count); 385 &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size, 386 toggle, false, low_speed, instance->target, data_stage, 387 control_data, &data->tds[transfer + 1]); 388 389 ++transfer; 390 assert(transfer < data->transfers); 382 391 assert(packet_size <= remain_size); 383 392 remain_size -= packet_size; … … 385 394 386 395 /* status stage */ 387 assert(t d == data->td_count- 1);396 assert(transfer == data->transfers - 1); 388 397 389 398 td_init( 390 &data->tds[t d], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,391 target, status_stage, NULL, NULL);392 td_set_ioc(&data->tds[t d]);399 &data->tds[transfer], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed, 400 instance->target, status_stage, NULL, NULL); 401 td_set_ioc(&data->tds[transfer]); 393 402 394 403 usb_log_debug2("Control last TD status: %x.\n", 395 data->tds[td].status); 396 } 397 /*----------------------------------------------------------------------------*/ 398 /** Provides access to QH data structure. 399 * @param[in] instance Batch pointer to use. 400 * @return Pointer to the QH used by the batch. 401 */ 404 data->tds[transfer].status); 405 } 406 /*----------------------------------------------------------------------------*/ 402 407 qh_t * batch_qh(usb_transfer_batch_t *instance) 403 408 { 404 409 assert(instance); 405 uhci_ transfer_batch_t *data = instance->private_data;410 uhci_batch_t *data = instance->private_data; 406 411 assert(data); 407 412 return data->qh; 408 413 } 414 /*----------------------------------------------------------------------------*/ 415 /** Helper function calls callback and correctly disposes of batch structure. 416 * 417 * @param[in] instance Batch structure to use. 418 */ 419 void batch_call_in_and_dispose(usb_transfer_batch_t *instance) 420 { 421 assert(instance); 422 usb_transfer_batch_call_in(instance); 423 batch_dispose(instance); 424 } 425 /*----------------------------------------------------------------------------*/ 426 /** Helper function calls callback and correctly disposes of batch structure. 427 * 428 * @param[in] instance Batch structure to use. 429 */ 430 void batch_call_out_and_dispose(usb_transfer_batch_t *instance) 431 { 432 assert(instance); 433 usb_transfer_batch_call_out(instance); 434 batch_dispose(instance); 435 } 436 /*----------------------------------------------------------------------------*/ 437 /** Correctly dispose all used data structures. 438 * 439 * @param[in] instance Batch structure to use. 440 */ 441 void batch_dispose(usb_transfer_batch_t *instance) 442 { 443 assert(instance); 444 uhci_batch_t *data = instance->private_data; 445 assert(data); 446 usb_log_debug("Batch(%p) disposing.\n", instance); 447 /* free32 is NULL safe */ 448 free32(data->tds); 449 free32(data->qh); 450 free32(instance->setup_buffer); 451 free32(instance->transport_buffer); 452 free(data); 453 free(instance); 454 } 409 455 /** 410 456 * @}
Note:
See TracChangeset
for help on using the changeset viewer.