Changeset 72af8da in mainline for uspace/drv/uhci-hcd/batch.c
- Timestamp:
- 2011-03-16T18:50:17Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 42a3a57
- Parents:
- 3e7b7cd (diff), fcf07e6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/batch.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver USB transaction structure 33 33 */ 34 34 #include <errno.h> … … 40 40 #include "batch.h" 41 41 #include "transfer_list.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/malloc32.h" 44 44 45 45 #define DEFAULT_ERROR_COUNT 3 46 46 47 static int batch_schedule(batch_t *instance); 48 49 static void batch_control( 50 batch_t *instance, int data_stage, int status_stage); 47 static void batch_control(batch_t *instance, 48 usb_packet_id data_stage, usb_packet_id status_stage); 49 static void batch_data(batch_t *instance, usb_packet_id pid); 51 50 static void batch_call_in(batch_t *instance); 52 51 static void batch_call_out(batch_t *instance); … … 55 54 56 55 56 /** Allocate memory and initialize internal data structure. 57 * 58 * @param[in] fun DDF function to pass to callback. 59 * @param[in] target Device and endpoint target of the transaction. 60 * @param[in] transfer_type Interrupt, Control or Bulk. 61 * @param[in] max_packet_size maximum allowed size of data packets. 62 * @param[in] speed Speed of the transaction. 63 * @param[in] buffer Data source/destination. 64 * @param[in] size Size of the buffer. 65 * @param[in] setup_buffer Setup data source (if not NULL) 66 * @param[in] setup_size Size of setup_buffer (should be always 8) 67 * @param[in] func_in function to call on inbound transaction completion 68 * @param[in] func_out function to call on outbound transaction completion 69 * @param[in] arg additional parameter to func_in or func_out 70 * @param[in] manager Pointer to toggle management structure. 71 * @return Valid pointer if all substructures were successfully created, 72 * NULL otherwise. 73 * 74 * Determines the number of needed packets (TDs). Prepares a transport buffer 75 * (that is accessible by the hardware). Initializes parameters needed for the 76 * transaction and callback. 77 */ 57 78 batch_t * batch_get(ddf_fun_t *fun, usb_target_t target, 58 79 usb_transfer_type_t transfer_type, size_t max_packet_size, … … 60 81 char* setup_buffer, size_t setup_size, 61 82 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, void *arg) 83 usbhc_iface_transfer_out_callback_t func_out, void *arg, 84 device_keeper_t *manager 85 ) 63 86 { 64 87 assert(func_in == NULL || func_out == NULL); 65 88 assert(func_in != NULL || func_out != NULL); 66 89 90 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 91 if (ptr == NULL) { \ 92 usb_log_error(message); \ 93 if (instance) { \ 94 batch_dispose(instance); \ 95 } \ 96 return NULL; \ 97 } else (void)0 98 67 99 batch_t *instance = malloc(sizeof(batch_t)); 68 if (instance == NULL) { 69 usb_log_error("Failed to allocate batch instance.\n"); 70 return NULL; 71 } 72 73 instance->qh = queue_head_get(); 74 if (instance->qh == NULL) { 75 usb_log_error("Failed to allocate queue head.\n"); 76 free(instance); 77 return NULL; 78 } 100 CHECK_NULL_DISPOSE_RETURN(instance, 101 "Failed to allocate batch instance.\n"); 102 bzero(instance, sizeof(batch_t)); 103 104 instance->qh = malloc32(sizeof(qh_t)); 105 CHECK_NULL_DISPOSE_RETURN(instance->qh, 106 "Failed to allocate batch queue head.\n"); 107 qh_init(instance->qh); 79 108 80 109 instance->packets = (size + max_packet_size - 1) / max_packet_size; … … 83 112 } 84 113 85 instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets); 86 if (instance->tds == NULL) { 87 usb_log_error("Failed to allocate transfer descriptors.\n"); 88 queue_head_dispose(instance->qh); 89 free(instance); 90 return NULL; 91 } 92 bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets); 93 94 const size_t transport_size = max_packet_size * instance->packets; 95 96 instance->transport_buffer = 97 (size > 0) ? malloc32(transport_size) : NULL; 98 99 if ((size > 0) && (instance->transport_buffer == NULL)) { 100 usb_log_error("Failed to allocate device accessible buffer.\n"); 101 queue_head_dispose(instance->qh); 102 free32(instance->tds); 103 free(instance); 104 return NULL; 105 } 106 107 instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL; 108 if ((setup_size > 0) && (instance->setup_buffer == NULL)) { 109 usb_log_error("Failed to allocate device accessible setup buffer.\n"); 110 queue_head_dispose(instance->qh); 111 free32(instance->tds); 112 free32(instance->transport_buffer); 113 free(instance); 114 return NULL; 115 } 116 if (instance->setup_buffer) { 114 instance->tds = malloc32(sizeof(td_t) * instance->packets); 115 CHECK_NULL_DISPOSE_RETURN( 116 instance->tds, "Failed to allocate transfer descriptors.\n"); 117 bzero(instance->tds, sizeof(td_t) * 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"); 117 129 memcpy(instance->setup_buffer, setup_buffer, setup_size); 118 130 } 119 131 132 133 link_initialize(&instance->link); 134 120 135 instance->max_packet_size = max_packet_size; 121 122 link_initialize(&instance->link);123 124 136 instance->target = target; 125 137 instance->transfer_type = transfer_type; 126 127 if (func_out)128 instance->callback_out = func_out;129 if (func_in)130 instance->callback_in = func_in;131 132 138 instance->buffer = buffer; 133 139 instance->buffer_size = size; … … 136 142 instance->arg = arg; 137 143 instance->speed = speed; 138 139 queue_head_element_td(instance->qh, addr_to_phys(instance->tds)); 144 instance->manager = manager; 145 instance->callback_out = func_out; 146 instance->callback_in = func_in; 147 148 qh_set_element_td(instance->qh, addr_to_phys(instance->tds)); 149 140 150 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 141 151 instance, target.address, target.endpoint); … … 143 153 } 144 154 /*----------------------------------------------------------------------------*/ 155 /** Check batch TDs for activity. 156 * 157 * @param[in] instance Batch structure to use. 158 * @return False, if there is an active TD, true otherwise. 159 * 160 * Walk all TDs. Stop with false if there is an active one (it is to be 161 * processed). Stop with true if an error is found. Return true if the last TS 162 * is reached. 163 */ 145 164 bool batch_is_complete(batch_t *instance) 146 165 { … … 151 170 size_t i = 0; 152 171 for (;i < instance->packets; ++i) { 153 if (t ransfer_descriptor_is_active(&instance->tds[i])) {172 if (td_is_active(&instance->tds[i])) { 154 173 return false; 155 174 } 156 instance->error = transfer_descriptor_status(&instance->tds[i]); 175 176 instance->error = td_status(&instance->tds[i]); 157 177 if (instance->error != EOK) { 178 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 179 instance, i, instance->tds[i].status); 180 td_print_status(&instance->tds[i]); 181 182 device_keeper_set_toggle(instance->manager, 183 instance->target, td_toggle(&instance->tds[i])); 158 184 if (i > 0) 159 instance->transfered_size -= instance->setup_size; 160 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 161 instance, i, instance->tds[i].status); 185 goto substract_ret; 162 186 return true; 163 187 } 164 instance->transfered_size += 165 transfer_descriptor_actual_size(&instance->tds[i]); 166 } 188 189 instance->transfered_size += td_act_size(&instance->tds[i]); 190 if (td_is_short(&instance->tds[i])) 191 goto substract_ret; 192 } 193 substract_ret: 167 194 instance->transfered_size -= instance->setup_size; 168 195 return true; 169 196 } 170 197 /*----------------------------------------------------------------------------*/ 198 /** Prepares control write transaction. 199 * 200 * @param[in] instance Batch structure to use. 201 * 202 * Uses genercir control function with pids OUT and IN. 203 */ 171 204 void batch_control_write(batch_t *instance) 172 205 { 173 206 assert(instance); 174 /* we are data out, we are supposed to provide data */ 175 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 207 /* We are data out, we are supposed to provide data */ 208 memcpy(instance->transport_buffer, instance->buffer, 209 instance->buffer_size); 176 210 batch_control(instance, USB_PID_OUT, USB_PID_IN); 177 211 instance->next_step = batch_call_out_and_dispose; 178 212 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 179 batch_schedule(instance); 180 } 181 /*----------------------------------------------------------------------------*/ 213 } 214 /*----------------------------------------------------------------------------*/ 215 /** Prepares control read transaction. 216 * 217 * @param[in] instance Batch structure to use. 218 * 219 * Uses generic control with pids IN and OUT. 220 */ 182 221 void batch_control_read(batch_t *instance) 183 222 { … … 186 225 instance->next_step = batch_call_in_and_dispose; 187 226 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 188 batch_schedule(instance); 189 } 190 /*----------------------------------------------------------------------------*/ 227 } 228 /*----------------------------------------------------------------------------*/ 229 /** Prepare interrupt in transaction. 230 * 231 * @param[in] instance Batch structure to use. 232 * 233 * Data transaction with PID_IN. 234 */ 191 235 void batch_interrupt_in(batch_t *instance) 192 236 { 193 237 assert(instance); 194 195 const bool low_speed = instance->speed == USB_SPEED_LOW; 196 int toggle = 1; 197 size_t i = 0; 198 for (;i < instance->packets; ++i) { 199 char *data = 200 instance->transport_buffer + (i * instance->max_packet_size); 201 transfer_descriptor_t *next = (i + 1) < instance->packets ? 202 &instance->tds[i + 1] : NULL; 203 toggle = 1 - toggle; 204 205 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 206 instance->max_packet_size, toggle, false, low_speed, 207 instance->target, USB_PID_IN, data, next); 208 } 209 210 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 211 238 batch_data(instance, USB_PID_IN); 212 239 instance->next_step = batch_call_in_and_dispose; 213 240 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 214 batch_schedule(instance); 215 } 216 /*----------------------------------------------------------------------------*/ 241 } 242 /*----------------------------------------------------------------------------*/ 243 /** Prepare interrupt out transaction. 244 * 245 * @param[in] instance Batch structure to use. 246 * 247 * Data transaction with PID_OUT. 248 */ 217 249 void batch_interrupt_out(batch_t *instance) 218 250 { 219 251 assert(instance); 252 /* We are data out, we are supposed to provide data */ 220 253 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 221 222 const bool low_speed = instance->speed == USB_SPEED_LOW; 223 int toggle = 1; 224 size_t i = 0; 225 for (;i < instance->packets; ++i) { 226 char *data = 227 instance->transport_buffer + (i * instance->max_packet_size); 228 transfer_descriptor_t *next = (i + 1) < instance->packets ? 229 &instance->tds[i + 1] : NULL; 230 toggle = 1 - toggle; 231 232 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 233 instance->max_packet_size, toggle++, false, low_speed, 234 instance->target, USB_PID_OUT, data, next); 235 } 236 237 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 238 254 batch_data(instance, USB_PID_OUT); 239 255 instance->next_step = batch_call_out_and_dispose; 240 256 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 241 batch_schedule(instance); 242 } 243 /*----------------------------------------------------------------------------*/ 244 static void batch_control( 245 batch_t *instance, int data_stage, int status_stage) 257 } 258 /*----------------------------------------------------------------------------*/ 259 /** Prepare bulk in transaction. 260 * 261 * @param[in] instance Batch structure to use. 262 * 263 * Data transaction with PID_IN. 264 */ 265 void batch_bulk_in(batch_t *instance) 266 { 267 assert(instance); 268 batch_data(instance, USB_PID_IN); 269 instance->next_step = batch_call_in_and_dispose; 270 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 271 } 272 /*----------------------------------------------------------------------------*/ 273 /** Prepare bulk out transaction. 274 * 275 * @param[in] instance Batch structure to use. 276 * 277 * Data transaction with PID_OUT. 278 */ 279 void batch_bulk_out(batch_t *instance) 280 { 281 assert(instance); 282 /* We are data out, we are supposed to provide data */ 283 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 284 batch_data(instance, USB_PID_OUT); 285 instance->next_step = batch_call_out_and_dispose; 286 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 287 } 288 /*----------------------------------------------------------------------------*/ 289 /** Prepare generic data transaction 290 * 291 * @param[in] instance Batch structure to use. 292 * @param[in] pid to use for data packets. 293 * 294 * Packets with alternating toggle bit and supplied pid value. 295 * The last packet is marked with IOC flag. 296 */ 297 void batch_data(batch_t *instance, usb_packet_id pid) 298 { 299 assert(instance); 300 const bool low_speed = instance->speed == USB_SPEED_LOW; 301 int toggle = 302 device_keeper_get_toggle(instance->manager, instance->target); 303 assert(toggle == 0 || toggle == 1); 304 305 size_t packet = 0; 306 size_t remain_size = instance->buffer_size; 307 while (remain_size > 0) { 308 char *data = 309 instance->transport_buffer + instance->buffer_size 310 - remain_size; 311 312 const size_t packet_size = 313 (instance->max_packet_size > remain_size) ? 314 remain_size : instance->max_packet_size; 315 316 td_t *next_packet = (packet + 1 < instance->packets) 317 ? &instance->tds[packet + 1] : NULL; 318 319 assert(packet < instance->packets); 320 assert(packet_size <= remain_size); 321 322 td_init( 323 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 324 toggle, false, low_speed, instance->target, pid, data, 325 next_packet); 326 327 328 toggle = 1 - toggle; 329 remain_size -= packet_size; 330 ++packet; 331 } 332 td_set_ioc(&instance->tds[packet - 1]); 333 device_keeper_set_toggle(instance->manager, instance->target, toggle); 334 } 335 /*----------------------------------------------------------------------------*/ 336 /** Prepare generic control transaction 337 * 338 * @param[in] instance Batch structure to use. 339 * @param[in] data_stage to use for data packets. 340 * @param[in] status_stage to use for data packets. 341 * 342 * Setup stage with toggle 0 and USB_PID_SETUP. 343 * Data stage with alternating toggle and pid supplied by parameter. 344 * Status stage with toggle 1 and pid supplied by parameter. 345 * The last packet is marked with IOC. 346 */ 347 void batch_control(batch_t *instance, 348 usb_packet_id data_stage, usb_packet_id status_stage) 246 349 { 247 350 assert(instance); … … 250 353 int toggle = 0; 251 354 /* setup stage */ 252 t ransfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,355 td_init(instance->tds, DEFAULT_ERROR_COUNT, 253 356 instance->setup_size, toggle, false, low_speed, instance->target, 254 357 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]); … … 268 371 remain_size : instance->max_packet_size; 269 372 270 t ransfer_descriptor_init(&instance->tds[packet],271 DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,272 instance->target, data_stage, data,273 &instance->tds[packet + 1]);373 td_init( 374 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 375 toggle, false, low_speed, instance->target, data_stage, 376 data, &instance->tds[packet + 1]); 274 377 275 378 ++packet; … … 281 384 /* status stage */ 282 385 assert(packet == instance->packets - 1); 283 t ransfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,386 td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT, 284 387 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 285 388 286 287 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 389 td_set_ioc(&instance->tds[packet]); 288 390 usb_log_debug2("Control last TD status: %x.\n", 289 391 instance->tds[packet].status); 290 392 } 291 393 /*----------------------------------------------------------------------------*/ 394 /** Prepare data, get error status and call callback in. 395 * 396 * @param[in] instance Batch structure to use. 397 * Copies data from transport buffer, and calls callback with appropriate 398 * parameters. 399 */ 292 400 void batch_call_in(batch_t *instance) 293 401 { … … 295 403 assert(instance->callback_in); 296 404 297 memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size); 405 /* We are data in, we need data */ 406 memcpy(instance->buffer, instance->transport_buffer, 407 instance->buffer_size); 298 408 299 409 int err = instance->error; … … 302 412 instance->transfered_size); 303 413 304 instance->callback_in(instance->fun, 305 err, instance->transfered_size, 306 instance->arg); 307 } 308 /*----------------------------------------------------------------------------*/ 414 instance->callback_in( 415 instance->fun, err, instance->transfered_size, instance->arg); 416 } 417 /*----------------------------------------------------------------------------*/ 418 /** Get error status and call callback out. 419 * 420 * @param[in] instance Batch structure to use. 421 */ 309 422 void batch_call_out(batch_t *instance) 310 423 { … … 319 432 } 320 433 /*----------------------------------------------------------------------------*/ 434 /** Helper function calls callback and correctly disposes of batch structure. 435 * 436 * @param[in] instance Batch structure to use. 437 */ 321 438 void batch_call_in_and_dispose(batch_t *instance) 322 439 { 323 440 assert(instance); 324 441 batch_call_in(instance); 442 batch_dispose(instance); 443 } 444 /*----------------------------------------------------------------------------*/ 445 /** Helper function calls callback and correctly disposes of batch structure. 446 * 447 * @param[in] instance Batch structure to use. 448 */ 449 void batch_call_out_and_dispose(batch_t *instance) 450 { 451 assert(instance); 452 batch_call_out(instance); 453 batch_dispose(instance); 454 } 455 /*----------------------------------------------------------------------------*/ 456 /** Correctly dispose all used data structures. 457 * 458 * @param[in] instance Batch structure to use. 459 */ 460 void batch_dispose(batch_t *instance) 461 { 462 assert(instance); 325 463 usb_log_debug("Batch(%p) disposing.\n", instance); 464 /* free32 is NULL safe */ 326 465 free32(instance->tds); 327 466 free32(instance->qh); … … 330 469 free(instance); 331 470 } 332 /*----------------------------------------------------------------------------*/333 void batch_call_out_and_dispose(batch_t *instance)334 {335 assert(instance);336 batch_call_out(instance);337 usb_log_debug("Batch(%p) disposing.\n", instance);338 free32(instance->tds);339 free32(instance->qh);340 free32(instance->setup_buffer);341 free32(instance->transport_buffer);342 free(instance);343 }344 /*----------------------------------------------------------------------------*/345 int batch_schedule(batch_t *instance)346 {347 assert(instance);348 uhci_t *hc = fun_to_uhci(instance->fun);349 assert(hc);350 return uhci_schedule(hc, instance);351 }352 471 /** 353 472 * @}
Note:
See TracChangeset
for help on using the changeset viewer.