Changes in uspace/drv/uhci-hcd/batch.c [a7e2f0d:4abc304] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/batch.c
ra7e2f0d r4abc304 35 35 #include <str_error.h> 36 36 37 #include <usb/usb.h>38 37 #include <usb/debug.h> 39 38 … … 47 46 static int batch_schedule(batch_t *instance); 48 47 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);52 48 static void batch_call_in(batch_t *instance); 53 49 static void batch_call_out(batch_t *instance); 54 50 static void batch_call_in_and_dispose(batch_t *instance); 55 51 static void batch_call_out_and_dispose(batch_t *instance); 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 */ 52 53 76 54 batch_t * batch_get(ddf_fun_t *fun, usb_target_t target, 77 55 usb_transfer_type_t transfer_type, size_t max_packet_size, … … 79 57 char* setup_buffer, size_t setup_size, 80 58 usbhc_iface_transfer_in_callback_t func_in, 81 usbhc_iface_transfer_out_callback_t func_out, void *arg, 82 device_keeper_t *manager 83 ) 59 usbhc_iface_transfer_out_callback_t func_out, void *arg) 84 60 { 85 61 assert(func_in == NULL || func_out == NULL); 86 62 assert(func_in != NULL || func_out != NULL); 87 63 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)096 97 64 batch_t *instance = malloc(sizeof(batch_t)); 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); 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 } 106 76 107 77 instance->packets = (size + max_packet_size - 1) / max_packet_size; … … 110 80 } 111 81 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"); 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) { 129 113 memcpy(instance->setup_buffer, setup_buffer, setup_size); 130 114 } 131 115 116 instance->max_packet_size = max_packet_size; 132 117 133 118 link_initialize(&instance->link); 134 119 135 instance->max_packet_size = max_packet_size;136 120 instance->target = target; 137 121 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 138 128 instance->buffer = buffer; 139 129 instance->buffer_size = size; … … 142 132 instance->arg = arg; 143 133 instance->speed = speed; 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 134 135 queue_head_element_td(instance->qh, addr_to_phys(instance->tds)); 153 136 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 154 137 instance, target.address, target.endpoint); … … 156 139 } 157 140 /*----------------------------------------------------------------------------*/ 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 */163 141 bool batch_is_complete(batch_t *instance) 164 142 { … … 169 147 size_t i = 0; 170 148 for (;i < instance->packets; ++i) { 171 if (t d_is_active(&instance->tds[i])) {149 if (transfer_descriptor_is_active(&instance->tds[i])) { 172 150 return false; 173 151 } 174 175 instance->error = td_status(&instance->tds[i]); 152 instance->error = transfer_descriptor_status(&instance->tds[i]); 176 153 if (instance->error != EOK) { 154 if (i > 0) 155 instance->transfered_size -= instance->setup_size; 177 156 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])); 182 if (i > 0) 183 goto substract_ret; 157 instance, i, instance->tds[i].status); 184 158 return true; 185 159 } 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: 160 instance->transfered_size += 161 transfer_descriptor_actual_size(&instance->tds[i]); 162 } 192 163 instance->transfered_size -= instance->setup_size; 193 164 return true; 194 165 } 195 166 /*----------------------------------------------------------------------------*/ 196 /** Prepares control write transaction.197 *198 * @param[in] instance Batch structure to use.199 */200 167 void batch_control_write(batch_t *instance) 201 168 { 202 169 assert(instance); 170 203 171 /* 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); 172 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 173 174 const bool low_speed = instance->speed == USB_SPEED_LOW; 175 int toggle = 0; 176 /* 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 207 203 instance->next_step = batch_call_out_and_dispose; 208 204 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); … … 210 206 } 211 207 /*----------------------------------------------------------------------------*/ 212 /** Prepares control read transaction.213 *214 * @param[in] instance Batch structure to use.215 */216 208 void batch_control_read(batch_t *instance) 217 209 { 218 210 assert(instance); 219 batch_control(instance, USB_PID_IN, USB_PID_OUT); 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, 216 instance->setup_size, toggle, false, low_speed, instance->target, 217 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]); 218 219 /* data stage */ 220 size_t i = 1; 221 for (;i < instance->packets - 1; ++i) { 222 char *data = 223 instance->transport_buffer + ((i - 1) * instance->max_packet_size); 224 toggle = 1 - toggle; 225 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]); 229 } 230 231 /* 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 220 240 instance->next_step = batch_call_in_and_dispose; 221 241 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); … … 223 243 } 224 244 /*----------------------------------------------------------------------------*/ 225 /** Prepares interrupt in transaction.226 *227 * @param[in] instance Batch structure to use.228 */229 245 void batch_interrupt_in(batch_t *instance) 230 246 { 231 247 assert(instance); 232 batch_data(instance, USB_PID_IN); 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 233 266 instance->next_step = batch_call_in_and_dispose; 234 267 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); … … 236 269 } 237 270 /*----------------------------------------------------------------------------*/ 238 /** Prepares interrupt out transaction.239 *240 * @param[in] instance Batch structure to use.241 */242 271 void batch_interrupt_out(batch_t *instance) 243 272 { 244 273 assert(instance); 245 /* we are data out, we are supposed to provide data */ 274 246 275 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 247 batch_data(instance, USB_PID_OUT); 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 248 294 instance->next_step = batch_call_out_and_dispose; 249 295 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); … … 251 297 } 252 298 /*----------------------------------------------------------------------------*/ 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 transaction281 *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_size298 - 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 transaction324 *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);333 334 const bool low_speed = instance->speed == USB_SPEED_LOW;335 int toggle = 0;336 /* setup stage */337 td_init(instance->tds, DEFAULT_ERROR_COUNT,338 instance->setup_size, toggle, false, low_speed, instance->target,339 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);340 341 /* data stage */342 size_t packet = 1;343 size_t remain_size = instance->buffer_size;344 while (remain_size > 0) {345 char *data =346 instance->transport_buffer + instance->buffer_size347 - remain_size;348 349 toggle = 1 - toggle;350 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;364 }365 366 /* status stage */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 */381 299 void batch_call_in(batch_t *instance) 382 300 { … … 384 302 assert(instance->callback_in); 385 303 386 /* we are data in, we need data */ 387 memcpy(instance->buffer, instance->transport_buffer, 388 instance->buffer_size); 304 memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size); 389 305 390 306 int err = instance->error; … … 393 309 instance->transfered_size); 394 310 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 */ 311 instance->callback_in(instance->fun, 312 err, instance->transfered_size, 313 instance->arg); 314 } 315 /*----------------------------------------------------------------------------*/ 403 316 void batch_call_out(batch_t *instance) 404 317 { … … 413 326 } 414 327 /*----------------------------------------------------------------------------*/ 415 /** Prepares data, gets error status, calls callback in and dispose.416 *417 * @param[in] instance Batch structure to use.418 */419 328 void batch_call_in_and_dispose(batch_t *instance) 420 329 { 421 330 assert(instance); 422 331 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);444 332 usb_log_debug("Batch(%p) disposing.\n", instance); 445 /* free32 is NULL safe */446 333 free32(instance->tds); 447 334 free32(instance->qh); … … 451 338 } 452 339 /*----------------------------------------------------------------------------*/ 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 /*----------------------------------------------------------------------------*/ 453 352 int batch_schedule(batch_t *instance) 454 353 {
Note:
See TracChangeset
for help on using the changeset viewer.