Changes in uspace/drv/uhci-hcd/batch.c [4abc304:a7e2f0d] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/batch.c
r4abc304 ra7e2f0d 35 35 #include <str_error.h> 36 36 37 #include <usb/usb.h> 37 38 #include <usb/debug.h> 38 39 … … 46 47 static int batch_schedule(batch_t *instance); 47 48 49 static void batch_control(batch_t *instance, 50 usb_packet_id data_stage, usb_packet_id status_stage); 51 static void batch_data(batch_t *instance, usb_packet_id pid); 48 52 static void batch_call_in(batch_t *instance); 49 53 static void batch_call_out(batch_t *instance); 50 54 static void batch_call_in_and_dispose(batch_t *instance); 51 55 static void batch_call_out_and_dispose(batch_t *instance); 52 53 56 static void batch_dispose(batch_t *instance); 57 58 59 /** Allocates memory and initializes internal data structures. 60 * 61 * @param[in] fun DDF function to pass to callback. 62 * @param[in] target Device and endpoint target of the transaction. 63 * @param[in] transfer_type Interrupt, Control or Bulk. 64 * @param[in] max_packet_size maximum allowed size of data packets. 65 * @param[in] speed Speed of the transaction. 66 * @param[in] buffer Data source/destination. 67 * @param[in] size Size of the buffer. 68 * @param[in] setup_buffer Setup data source (if not NULL) 69 * @param[in] setup_size Size of setup_buffer (should be always 8) 70 * @param[in] func_in function to call on inbound transaction completion 71 * @param[in] func_out function to call on outbound transaction completion 72 * @param[in] arg additional parameter to func_in or func_out 73 * @param[in] manager Pointer to toggle management structure. 74 * @return False, if there is an active TD, true otherwise. 75 */ 54 76 batch_t * batch_get(ddf_fun_t *fun, usb_target_t target, 55 77 usb_transfer_type_t transfer_type, size_t max_packet_size, … … 57 79 char* setup_buffer, size_t setup_size, 58 80 usbhc_iface_transfer_in_callback_t func_in, 59 usbhc_iface_transfer_out_callback_t func_out, void *arg) 81 usbhc_iface_transfer_out_callback_t func_out, void *arg, 82 device_keeper_t *manager 83 ) 60 84 { 61 85 assert(func_in == NULL || func_out == NULL); 62 86 assert(func_in != NULL || func_out != NULL); 63 87 88 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 89 if (ptr == NULL) { \ 90 usb_log_error(message); \ 91 if (instance) { \ 92 batch_dispose(instance); \ 93 } \ 94 return NULL; \ 95 } else (void)0 96 64 97 batch_t *instance = malloc(sizeof(batch_t)); 65 if (instance == NULL) { 66 usb_log_error("Failed to allocate batch instance.\n"); 67 return NULL; 68 } 69 70 instance->qh = queue_head_get(); 71 if (instance->qh == NULL) { 72 usb_log_error("Failed to allocate queue head.\n"); 73 free(instance); 74 return NULL; 75 } 98 CHECK_NULL_DISPOSE_RETURN(instance, 99 "Failed to allocate batch instance.\n"); 100 bzero(instance, sizeof(batch_t)); 101 102 instance->qh = malloc32(sizeof(queue_head_t)); 103 CHECK_NULL_DISPOSE_RETURN(instance->qh, 104 "Failed to allocate batch queue head.\n"); 105 queue_head_init(instance->qh); 76 106 77 107 instance->packets = (size + max_packet_size - 1) / max_packet_size; … … 80 110 } 81 111 82 instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets); 83 if (instance->tds == NULL) { 84 usb_log_error("Failed to allocate transfer descriptors.\n"); 85 queue_head_dispose(instance->qh); 86 free(instance); 87 return NULL; 88 } 89 bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets); 90 91 const size_t transport_size = max_packet_size * instance->packets; 92 93 instance->transport_buffer = 94 (size > 0) ? malloc32(transport_size) : NULL; 95 if ((size > 0) && (instance->transport_buffer == NULL)) { 96 usb_log_error("Failed to allocate device accessible buffer.\n"); 97 queue_head_dispose(instance->qh); 98 free32(instance->tds); 99 free(instance); 100 return NULL; 101 } 102 103 instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL; 104 if ((setup_size > 0) && (instance->setup_buffer == NULL)) { 105 usb_log_error("Failed to allocate device accessible setup buffer.\n"); 106 queue_head_dispose(instance->qh); 107 free32(instance->tds); 108 free32(instance->transport_buffer); 109 free(instance); 110 return NULL; 111 } 112 if (instance->setup_buffer) { 112 instance->tds = malloc32(sizeof(td_t) * instance->packets); 113 CHECK_NULL_DISPOSE_RETURN( 114 instance->tds, "Failed to allocate transfer descriptors.\n"); 115 bzero(instance->tds, sizeof(td_t) * instance->packets); 116 117 // const size_t transport_size = max_packet_size * instance->packets; 118 119 if (size > 0) { 120 instance->transport_buffer = malloc32(size); 121 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 122 "Failed to allocate device accessible buffer.\n"); 123 } 124 125 if (setup_size > 0) { 126 instance->setup_buffer = malloc32(setup_size); 127 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 128 "Failed to allocate device accessible setup buffer.\n"); 113 129 memcpy(instance->setup_buffer, setup_buffer, setup_size); 114 130 } 115 131 132 133 link_initialize(&instance->link); 134 116 135 instance->max_packet_size = max_packet_size; 117 118 link_initialize(&instance->link);119 120 136 instance->target = target; 121 137 instance->transfer_type = transfer_type; 122 123 if (func_out)124 instance->callback_out = func_out;125 if (func_in)126 instance->callback_in = func_in;127 128 138 instance->buffer = buffer; 129 139 instance->buffer_size = size; … … 132 142 instance->arg = arg; 133 143 instance->speed = speed; 134 135 queue_head_element_td(instance->qh, addr_to_phys(instance->tds)); 144 instance->manager = manager; 145 146 if (func_out) 147 instance->callback_out = func_out; 148 if (func_in) 149 instance->callback_in = func_in; 150 151 queue_head_set_element_td(instance->qh, addr_to_phys(instance->tds)); 152 136 153 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 137 154 instance, target.address, target.endpoint); … … 139 156 } 140 157 /*----------------------------------------------------------------------------*/ 158 /** Checks batch TDs for activity. 159 * 160 * @param[in] instance Batch structure to use. 161 * @return False, if there is an active TD, true otherwise. 162 */ 141 163 bool batch_is_complete(batch_t *instance) 142 164 { … … 147 169 size_t i = 0; 148 170 for (;i < instance->packets; ++i) { 149 if (t ransfer_descriptor_is_active(&instance->tds[i])) {171 if (td_is_active(&instance->tds[i])) { 150 172 return false; 151 173 } 152 instance->error = transfer_descriptor_status(&instance->tds[i]); 174 175 instance->error = td_status(&instance->tds[i]); 153 176 if (instance->error != EOK) { 177 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 178 instance, i, instance->tds[i].status); 179 180 device_keeper_set_toggle(instance->manager, 181 instance->target, td_toggle(&instance->tds[i])); 154 182 if (i > 0) 155 instance->transfered_size -= instance->setup_size; 156 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 157 instance, i, instance->tds[i].status); 183 goto substract_ret; 158 184 return true; 159 185 } 160 instance->transfered_size += 161 transfer_descriptor_actual_size(&instance->tds[i]); 162 } 186 187 instance->transfered_size += td_act_size(&instance->tds[i]); 188 if (td_is_short(&instance->tds[i])) 189 goto substract_ret; 190 } 191 substract_ret: 163 192 instance->transfered_size -= instance->setup_size; 164 193 return true; 165 194 } 166 195 /*----------------------------------------------------------------------------*/ 196 /** Prepares control write transaction. 197 * 198 * @param[in] instance Batch structure to use. 199 */ 167 200 void batch_control_write(batch_t *instance) 168 201 { 169 202 assert(instance); 170 203 /* we are data out, we are supposed to provide data */ 204 memcpy(instance->transport_buffer, instance->buffer, 205 instance->buffer_size); 206 batch_control(instance, USB_PID_OUT, USB_PID_IN); 207 instance->next_step = batch_call_out_and_dispose; 208 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 209 batch_schedule(instance); 210 } 211 /*----------------------------------------------------------------------------*/ 212 /** Prepares control read transaction. 213 * 214 * @param[in] instance Batch structure to use. 215 */ 216 void batch_control_read(batch_t *instance) 217 { 218 assert(instance); 219 batch_control(instance, USB_PID_IN, USB_PID_OUT); 220 instance->next_step = batch_call_in_and_dispose; 221 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 222 batch_schedule(instance); 223 } 224 /*----------------------------------------------------------------------------*/ 225 /** Prepares interrupt in transaction. 226 * 227 * @param[in] instance Batch structure to use. 228 */ 229 void batch_interrupt_in(batch_t *instance) 230 { 231 assert(instance); 232 batch_data(instance, USB_PID_IN); 233 instance->next_step = batch_call_in_and_dispose; 234 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 235 batch_schedule(instance); 236 } 237 /*----------------------------------------------------------------------------*/ 238 /** Prepares interrupt out transaction. 239 * 240 * @param[in] instance Batch structure to use. 241 */ 242 void batch_interrupt_out(batch_t *instance) 243 { 244 assert(instance); 171 245 /* we are data out, we are supposed to provide data */ 172 246 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 247 batch_data(instance, USB_PID_OUT); 248 instance->next_step = batch_call_out_and_dispose; 249 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 250 batch_schedule(instance); 251 } 252 /*----------------------------------------------------------------------------*/ 253 /** Prepares bulk in transaction. 254 * 255 * @param[in] instance Batch structure to use. 256 */ 257 void batch_bulk_in(batch_t *instance) 258 { 259 assert(instance); 260 batch_data(instance, USB_PID_IN); 261 instance->next_step = batch_call_in_and_dispose; 262 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 263 batch_schedule(instance); 264 } 265 /*----------------------------------------------------------------------------*/ 266 /** Prepares bulk out transaction. 267 * 268 * @param[in] instance Batch structure to use. 269 */ 270 void batch_bulk_out(batch_t *instance) 271 { 272 assert(instance); 273 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 274 batch_data(instance, USB_PID_OUT); 275 instance->next_step = batch_call_out_and_dispose; 276 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 277 batch_schedule(instance); 278 } 279 /*----------------------------------------------------------------------------*/ 280 /** Prepares generic data transaction 281 * 282 * @param[in] instance Batch structure to use. 283 * @param[in] pid to use for data packets. 284 */ 285 void batch_data(batch_t *instance, usb_packet_id pid) 286 { 287 assert(instance); 288 const bool low_speed = instance->speed == USB_SPEED_LOW; 289 int toggle = 290 device_keeper_get_toggle(instance->manager, instance->target); 291 assert(toggle == 0 || toggle == 1); 292 293 size_t packet = 0; 294 size_t remain_size = instance->buffer_size; 295 while (remain_size > 0) { 296 char *data = 297 instance->transport_buffer + instance->buffer_size 298 - remain_size; 299 300 const size_t packet_size = 301 (instance->max_packet_size > remain_size) ? 302 remain_size : instance->max_packet_size; 303 304 td_t *next_packet = (packet + 1 < instance->packets) 305 ? &instance->tds[packet + 1] : NULL; 306 307 assert(packet < instance->packets); 308 assert(packet_size <= remain_size); 309 310 td_init( 311 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 312 toggle, false, low_speed, instance->target, pid, data, 313 next_packet); 314 315 316 toggle = 1 - toggle; 317 remain_size -= packet_size; 318 ++packet; 319 } 320 device_keeper_set_toggle(instance->manager, instance->target, toggle); 321 } 322 /*----------------------------------------------------------------------------*/ 323 /** Prepares generic control transaction 324 * 325 * @param[in] instance Batch structure to use. 326 * @param[in] data_stage to use for data packets. 327 * @param[in] status_stage to use for data packets. 328 */ 329 void batch_control(batch_t *instance, 330 usb_packet_id data_stage, usb_packet_id status_stage) 331 { 332 assert(instance); 173 333 174 334 const bool low_speed = instance->speed == USB_SPEED_LOW; 175 335 int toggle = 0; 176 336 /* setup stage */ 177 transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT, 178 instance->setup_size, toggle, false, low_speed, 179 instance->target, USB_PID_SETUP, instance->setup_buffer, 180 &instance->tds[1]); 181 182 /* data stage */ 183 size_t i = 1; 184 for (;i < instance->packets - 1; ++i) { 185 char *data = 186 instance->transport_buffer + ((i - 1) * instance->max_packet_size); 187 toggle = 1 - toggle; 188 189 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 190 instance->max_packet_size, toggle++, false, low_speed, 191 instance->target, USB_PID_OUT, data, &instance->tds[i + 1]); 192 } 193 194 /* status stage */ 195 i = instance->packets - 1; 196 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 197 0, 1, false, low_speed, instance->target, USB_PID_IN, NULL, NULL); 198 199 instance->tds[i].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 200 usb_log_debug2("Control write last TD status: %x.\n", 201 instance->tds[i].status); 202 203 instance->next_step = batch_call_out_and_dispose; 204 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 205 batch_schedule(instance); 206 } 207 /*----------------------------------------------------------------------------*/ 208 void batch_control_read(batch_t *instance) 209 { 210 assert(instance); 211 212 const bool low_speed = instance->speed == USB_SPEED_LOW; 213 int toggle = 0; 214 /* setup stage */ 215 transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT, 337 td_init(instance->tds, DEFAULT_ERROR_COUNT, 216 338 instance->setup_size, toggle, false, low_speed, instance->target, 217 339 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]); 218 340 219 341 /* data stage */ 220 size_t i = 1; 221 for (;i < instance->packets - 1; ++i) { 342 size_t packet = 1; 343 size_t remain_size = instance->buffer_size; 344 while (remain_size > 0) { 222 345 char *data = 223 instance->transport_buffer + ((i - 1) * instance->max_packet_size); 346 instance->transport_buffer + instance->buffer_size 347 - remain_size; 348 224 349 toggle = 1 - toggle; 225 350 226 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 227 instance->max_packet_size, toggle, false, low_speed, 228 instance->target, USB_PID_IN, data, &instance->tds[i + 1]); 351 const size_t packet_size = 352 (instance->max_packet_size > remain_size) ? 353 remain_size : instance->max_packet_size; 354 355 td_init( 356 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 357 toggle, false, low_speed, instance->target, data_stage, 358 data, &instance->tds[packet + 1]); 359 360 ++packet; 361 assert(packet < instance->packets); 362 assert(packet_size <= remain_size); 363 remain_size -= packet_size; 229 364 } 230 365 231 366 /* status stage */ 232 i = instance->packets - 1; 233 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 234 0, 1, false, low_speed, instance->target, USB_PID_OUT, NULL, NULL); 235 236 instance->tds[i].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 237 usb_log_debug2("Control read last TD status: %x.\n", 238 instance->tds[i].status); 239 240 instance->next_step = batch_call_in_and_dispose; 241 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 242 batch_schedule(instance); 243 } 244 /*----------------------------------------------------------------------------*/ 245 void batch_interrupt_in(batch_t *instance) 246 { 247 assert(instance); 248 249 const bool low_speed = instance->speed == USB_SPEED_LOW; 250 int toggle = 1; 251 size_t i = 0; 252 for (;i < instance->packets; ++i) { 253 char *data = 254 instance->transport_buffer + (i * instance->max_packet_size); 255 transfer_descriptor_t *next = (i + 1) < instance->packets ? 256 &instance->tds[i + 1] : NULL; 257 toggle = 1 - toggle; 258 259 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 260 instance->max_packet_size, toggle, false, low_speed, 261 instance->target, USB_PID_IN, data, next); 262 } 263 264 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 265 266 instance->next_step = batch_call_in_and_dispose; 267 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 268 batch_schedule(instance); 269 } 270 /*----------------------------------------------------------------------------*/ 271 void batch_interrupt_out(batch_t *instance) 272 { 273 assert(instance); 274 275 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 276 277 const bool low_speed = instance->speed == USB_SPEED_LOW; 278 int toggle = 1; 279 size_t i = 0; 280 for (;i < instance->packets; ++i) { 281 char *data = 282 instance->transport_buffer + (i * instance->max_packet_size); 283 transfer_descriptor_t *next = (i + 1) < instance->packets ? 284 &instance->tds[i + 1] : NULL; 285 toggle = 1 - toggle; 286 287 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 288 instance->max_packet_size, toggle++, false, low_speed, 289 instance->target, USB_PID_OUT, data, next); 290 } 291 292 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 293 294 instance->next_step = batch_call_out_and_dispose; 295 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 296 batch_schedule(instance); 297 } 298 /*----------------------------------------------------------------------------*/ 367 assert(packet == instance->packets - 1); 368 td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT, 369 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 370 371 372 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 373 usb_log_debug2("Control last TD status: %x.\n", 374 instance->tds[packet].status); 375 } 376 /*----------------------------------------------------------------------------*/ 377 /** Prepares data, gets error status and calls callback in. 378 * 379 * @param[in] instance Batch structure to use. 380 */ 299 381 void batch_call_in(batch_t *instance) 300 382 { … … 302 384 assert(instance->callback_in); 303 385 304 memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size); 386 /* we are data in, we need data */ 387 memcpy(instance->buffer, instance->transport_buffer, 388 instance->buffer_size); 305 389 306 390 int err = instance->error; … … 309 393 instance->transfered_size); 310 394 311 instance->callback_in(instance->fun, 312 err, instance->transfered_size, 313 instance->arg); 314 } 315 /*----------------------------------------------------------------------------*/ 395 instance->callback_in( 396 instance->fun, err, instance->transfered_size, instance->arg); 397 } 398 /*----------------------------------------------------------------------------*/ 399 /** Gets error status and calls callback out. 400 * 401 * @param[in] instance Batch structure to use. 402 */ 316 403 void batch_call_out(batch_t *instance) 317 404 { … … 326 413 } 327 414 /*----------------------------------------------------------------------------*/ 415 /** Prepares data, gets error status, calls callback in and dispose. 416 * 417 * @param[in] instance Batch structure to use. 418 */ 328 419 void batch_call_in_and_dispose(batch_t *instance) 329 420 { 330 421 assert(instance); 331 422 batch_call_in(instance); 423 batch_dispose(instance); 424 } 425 /*----------------------------------------------------------------------------*/ 426 /** Gets error status, calls callback out and dispose. 427 * 428 * @param[in] instance Batch structure to use. 429 */ 430 void batch_call_out_and_dispose(batch_t *instance) 431 { 432 assert(instance); 433 batch_call_out(instance); 434 batch_dispose(instance); 435 } 436 /*----------------------------------------------------------------------------*/ 437 /** Correctly disposes all used data structures. 438 * 439 * @param[in] instance Batch structure to use. 440 */ 441 void batch_dispose(batch_t *instance) 442 { 443 assert(instance); 332 444 usb_log_debug("Batch(%p) disposing.\n", instance); 445 /* free32 is NULL safe */ 333 446 free32(instance->tds); 334 447 free32(instance->qh); … … 338 451 } 339 452 /*----------------------------------------------------------------------------*/ 340 void batch_call_out_and_dispose(batch_t *instance)341 {342 assert(instance);343 batch_call_out(instance);344 usb_log_debug("Batch(%p) disposing.\n", instance);345 free32(instance->tds);346 free32(instance->qh);347 free32(instance->setup_buffer);348 free32(instance->transport_buffer);349 free(instance);350 }351 /*----------------------------------------------------------------------------*/352 453 int batch_schedule(batch_t *instance) 353 454 {
Note:
See TracChangeset
for help on using the changeset viewer.