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