Changeset d8b275d in mainline for uspace/drv/uhci-hcd
- Timestamp:
- 2011-04-14T08:24:29Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5e07e2b5
- Parents:
- 3f2af64 (diff), 34e8bab (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. - Location:
- uspace/drv/uhci-hcd
- Files:
-
- 16 edited
-
batch.c (modified) (13 diffs)
-
batch.h (modified) (1 diff)
-
hc.c (modified) (8 diffs)
-
hc.h (modified) (5 diffs)
-
hw_struct/queue_head.h (modified) (4 diffs)
-
hw_struct/transfer_descriptor.c (modified) (4 diffs)
-
hw_struct/transfer_descriptor.h (modified) (1 diff)
-
iface.c (modified) (9 diffs)
-
main.c (modified) (5 diffs)
-
pci.c (modified) (5 diffs)
-
root_hub.c (modified) (2 diffs)
-
root_hub.h (modified) (1 diff)
-
transfer_list.c (modified) (11 diffs)
-
transfer_list.h (modified) (1 diff)
-
uhci.c (modified) (13 diffs)
-
uhci.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/batch.c
r3f2af64 rd8b275d 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 transfer s (TDs). Prepares a transport buffer79 * (that is accessible by the hardware). Initializes parameters needed for the80 * transactionand callback.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. 81 84 */ 82 85 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, … … 92 95 if (ptr == NULL) { \ 93 96 usb_log_error(message); \ 94 if ( instance) { \95 batch_dispose(instance); \97 if (uhci_data) { \ 98 uhci_transfer_batch_dispose(uhci_data); \ 96 99 } \ 97 100 return NULL; \ 98 101 } else (void)0 99 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 100 130 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 101 131 CHECK_NULL_DISPOSE_RETURN(instance, 102 132 "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; 103 137 usb_target_t target = 104 138 { .address = ep->address, .endpoint = ep->endpoint }; 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 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); 145 144 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 146 145 instance, target.address, target.endpoint); … … 154 153 * 155 154 * Walk all TDs. Stop with false if there is an active one (it is to be 156 * 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 157 156 * is reached. 158 157 */ … … 160 159 { 161 160 assert(instance); 162 uhci_ batch_t *data = instance->private_data;161 uhci_transfer_batch_t *data = instance->private_data; 163 162 assert(data); 164 163 165 164 usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n", 166 instance, data->t ransfers);165 instance, data->td_count); 167 166 instance->transfered_size = 0; 168 167 size_t i = 0; 169 for (;i < data->t ransfers; ++i) {168 for (;i < data->td_count; ++i) { 170 169 if (td_is_active(&data->tds[i])) { 171 170 return false; … … 177 176 instance, i, data->tds[i].status); 178 177 td_print_status(&data->tds[i]); 178 179 179 assert(instance->ep != NULL); 180 181 180 endpoint_toggle_set(instance->ep, 182 181 td_toggle(&data->tds[i])); … … 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 * @} -
uspace/drv/uhci-hcd/batch.h
r3f2af64 rd8b275d 30 30 */ 31 31 /** @file 32 * @brief UHCI driver USB tran saction structure32 * @brief UHCI driver USB tranfer helper functions 33 33 */ 34 34 #ifndef DRV_UHCI_BATCH_H -
uspace/drv/uhci-hcd/hc.c
r3f2af64 rd8b275d 66 66 static int hc_interrupt_emulator(void *arg); 67 67 static int hc_debug_checker(void *arg); 68 #if 069 static bool usb_is_allowed(70 bool low_speed, usb_transfer_type_t transfer, size_t size);71 #endif72 68 /*----------------------------------------------------------------------------*/ 73 69 /** Initialize UHCI hcd driver structure … … 89 85 int ret; 90 86 91 #define CHECK_RET_ DEST_FUN_RETURN(ret, message...) \87 #define CHECK_RET_RETURN(ret, message...) \ 92 88 if (ret != EOK) { \ 93 89 usb_log_error(message); \ 94 if (instance->ddf_instance) \95 ddf_fun_destroy(instance->ddf_instance); \96 90 return ret; \ 97 91 } else (void) 0 … … 99 93 instance->hw_interrupts = interrupts; 100 94 instance->hw_failures = 0; 101 102 /* Setup UHCI function. */103 instance->ddf_instance = fun;104 95 105 96 /* allow access to hc control registers */ 106 97 regs_t *io; 107 98 ret = pio_enable(regs, reg_size, (void**)&io); 108 CHECK_RET_ DEST_FUN_RETURN(ret,99 CHECK_RET_RETURN(ret, 109 100 "Failed(%d) to gain access to registers at %p: %s.\n", 110 ret, str_error(ret), io);101 ret, io, str_error(ret)); 111 102 instance->registers = io; 112 103 usb_log_debug("Device registers at %p(%u) accessible.\n", … … 114 105 115 106 ret = hc_init_mem_structures(instance); 116 CHECK_RET_DEST_FUN_RETURN(ret, 117 "Failed to initialize UHCI memory structures.\n"); 107 CHECK_RET_RETURN(ret, 108 "Failed(%d) to initialize UHCI memory structures: %s.\n", 109 ret, str_error(ret)); 118 110 119 111 hc_init_hw(instance); 120 112 if (!interrupts) { 121 instance-> cleaner =113 instance->interrupt_emulator = 122 114 fibril_create(hc_interrupt_emulator, instance); 123 fibril_add_ready(instance->cleaner); 124 } else { 125 /* TODO: enable interrupts here */ 126 } 127 128 instance->debug_checker = 129 fibril_create(hc_debug_checker, instance); 130 // fibril_add_ready(instance->debug_checker); 115 fibril_add_ready(instance->interrupt_emulator); 116 } 117 (void)hc_debug_checker; 131 118 132 119 return EOK; … … 228 215 /* Set all frames to point to the first queue head */ 229 216 const uint32_t queue = 230 instance->transfers_interrupt.queue_head_pa231 | LINK_POINTER_QUEUE_HEAD_FLAG;217 LINK_POINTER_QH(addr_to_phys( 218 instance->transfers_interrupt.queue_head)); 232 219 233 220 unsigned i = 0; … … 236 223 } 237 224 238 /* Init device keeper */225 /* Init device keeper */ 239 226 usb_device_keeper_init(&instance->manager); 240 227 usb_log_debug("Initialized device manager.\n"); … … 329 316 330 317 transfer_list_t *list = 331 instance->transfers[batch-> speed][batch->transfer_type];318 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 332 319 assert(list); 333 320 transfer_list_add_batch(list, batch); … … 479 466 #undef QH 480 467 } 481 /*----------------------------------------------------------------------------*/482 /** Check transfers for USB validity483 *484 * @param[in] low_speed Transfer speed.485 * @param[in] transfer Transer type486 * @param[in] size Size of data packets487 * @return True if transaction is allowed by USB specs, false otherwise488 */489 #if 0490 bool usb_is_allowed(491 bool low_speed, usb_transfer_type_t transfer, size_t size)492 {493 /* see USB specification chapter 5.5-5.8 for magic numbers used here */494 switch(transfer)495 {496 case USB_TRANSFER_ISOCHRONOUS:497 return (!low_speed && size < 1024);498 case USB_TRANSFER_INTERRUPT:499 return size <= (low_speed ? 8 : 64);500 case USB_TRANSFER_CONTROL: /* device specifies its own max size */501 return (size <= (low_speed ? 8 : 64));502 case USB_TRANSFER_BULK: /* device specifies its own max size */503 return (!low_speed && size <= 64);504 }505 return false;506 }507 #endif508 468 /** 509 469 * @} -
uspace/drv/uhci-hcd/hc.h
r3f2af64 rd8b275d 48 48 #include "transfer_list.h" 49 49 50 /** UHCI I/O registers layout */ 50 51 typedef struct uhci_regs { 52 /** Command register, controls HC behaviour */ 51 53 uint16_t usbcmd; 52 54 #define UHCI_CMD_MAX_PACKET (1 << 7) … … 59 61 #define UHCI_CMD_RUN_STOP (1 << 0) 60 62 63 /** Status register, 1 means interrupt is asserted (if enabled) */ 61 64 uint16_t usbsts; 62 65 #define UHCI_STATUS_HALTED (1 << 5) … … 67 70 #define UHCI_STATUS_INTERRUPT (1 << 0) 68 71 72 /** Interrupt enabled registers */ 69 73 uint16_t usbintr; 70 74 #define UHCI_INTR_SHORT_PACKET (1 << 3) … … 73 77 #define UHCI_INTR_CRC (1 << 0) 74 78 79 /** Register stores frame number used in SOF packet */ 75 80 uint16_t frnum; 81 82 /** Pointer(physical) to the Frame List */ 76 83 uint32_t flbaseadd; 84 85 /** SOF modification to match external timers */ 77 86 uint8_t sofmod; 78 87 } regs_t; … … 83 92 #define UHCI_ALLOWED_HW_FAIL 5 84 93 94 /* Main HC driver structure */ 85 95 typedef struct hc { 96 /** USB bus driver, devices and addresses */ 86 97 usb_device_keeper_t manager; 98 /** USB bus driver, endpoints */ 87 99 usb_endpoint_manager_t ep_manager; 88 100 101 /** Addresses of I/O registers */ 89 102 regs_t *registers; 90 103 104 /** Frame List contains 1024 link pointers */ 91 105 link_pointer_t *frame_list; 92 106 107 /** List and queue of interrupt transfers */ 108 transfer_list_t transfers_interrupt; 109 /** List and queue of low speed control transfers */ 110 transfer_list_t transfers_control_slow; 111 /** List and queue of full speed bulk transfers */ 93 112 transfer_list_t transfers_bulk_full; 113 /** List and queue of full speed control transfers */ 94 114 transfer_list_t transfers_control_full; 95 transfer_list_t transfers_control_slow;96 transfer_list_t transfers_interrupt;97 115 116 /** Pointer table to the above lists, helps during scheduling */ 98 117 transfer_list_t *transfers[2][4]; 99 118 119 /** Code to be executed in kernel interrupt handler */ 100 120 irq_code_t interrupt_code; 101 121 102 fid_t cleaner; 103 fid_t debug_checker; 122 /** Fibril periodically checking status register*/ 123 fid_t interrupt_emulator; 124 125 /** Indicator of hw interrupts availability */ 104 126 bool hw_interrupts; 127 128 /** Number of hw failures detected. */ 105 129 unsigned hw_failures; 106 107 ddf_fun_t *ddf_instance;108 130 } hc_t; 109 131 -
uspace/drv/uhci-hcd/hw_struct/queue_head.h
r3f2af64 rd8b275d 34 34 #ifndef DRV_UHCI_QH_H 35 35 #define DRV_UHCI_QH_H 36 37 /* libc */38 36 #include <assert.h> 39 37 40 38 #include "link_pointer.h" 39 #include "transfer_descriptor.h" 40 #include "utils/malloc32.h" 41 41 42 /** This structure is defined in UHCI design guide p. 31 */ 42 43 typedef struct queue_head { 44 /** Pointer to the next entity (another QH or TD */ 43 45 volatile link_pointer_t next; 46 /** Pointer to the contained entities (execution controlled by vertical flag*/ 44 47 volatile link_pointer_t element; 45 48 } __attribute__((packed)) qh_t; … … 64 67 * @param[in] pa Physical address of the next queue head. 65 68 * 66 * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal 67 * NULL. 69 * Adds proper flag. If the pointer is NULL, sets next to terminal NULL. 68 70 */ 69 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)71 static inline void qh_set_next_qh(qh_t *instance, qh_t *next) 70 72 { 71 /* Address is valid and not terminal */72 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {73 uint32_t pa = addr_to_phys(next); 74 if (pa) { 73 75 instance->next = LINK_POINTER_QH(pa); 74 76 } else { … … 80 82 * 81 83 * @param[in] instance qh_t structure to initialize. 82 * @param[in] pa Physical address of the next queue head.83 *84 * Adds proper flag. If the pointer is NULL or terminal, sets element85 * to terminal NULL.86 */87 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)88 {89 /* Address is valid and not terminal */90 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {91 instance->element = LINK_POINTER_QH(pa);92 } else {93 instance->element = LINK_POINTER_TERM;94 }95 }96 /*----------------------------------------------------------------------------*/97 /** Set queue head element pointer98 *99 * @param[in] instance qh_t structure to initialize.100 84 * @param[in] pa Physical address of the TD structure. 101 85 * 102 * Adds proper flag. If the pointer is NULL or terminal, sets element 103 * to terminal NULL. 86 * Adds proper flag. If the pointer is NULL, sets element to terminal NULL. 104 87 */ 105 static inline void qh_set_element_td(qh_t *instance, uint32_t pa)88 static inline void qh_set_element_td(qh_t *instance, td_t *td) 106 89 { 107 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 90 uint32_t pa = addr_to_phys(td); 91 if (pa) { 108 92 instance->element = LINK_POINTER_TD(pa); 109 93 } else { … … 111 95 } 112 96 } 113 114 97 #endif 115 98 /** -
uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.c
r3f2af64 rd8b275d 77 77 78 78 instance->status = 0 79 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 79 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) 80 << TD_STATUS_ERROR_COUNT_POS) 80 81 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 81 82 | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0) … … 89 90 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS) 90 91 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0) 91 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS) 92 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS) 92 | ((target.address & TD_DEVICE_ADDRESS_MASK) 93 << TD_DEVICE_ADDRESS_POS) 94 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) 95 << TD_DEVICE_ENDPOINT_POS) 93 96 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS); 94 97 … … 114 117 assert(instance); 115 118 116 /* this is hc internal error it should never be reported*/119 /* This is hc internal error it should never be reported. */ 117 120 if ((instance->status & TD_STATUS_ERROR_BIT_STUFF) != 0) 118 121 return EAGAIN; … … 123 126 return EBADCHECKSUM; 124 127 125 /* hc does not end transactionon these, it should never be reported */128 /* HC does not end transactions on these, it should never be reported */ 126 129 if ((instance->status & TD_STATUS_ERROR_NAK) != 0) 127 130 return EAGAIN; 128 131 129 /* buffer overrun or underrun */132 /* Buffer overrun or underrun */ 130 133 if ((instance->status & TD_STATUS_ERROR_BUFFER) != 0) 131 134 return ERANGE; 132 135 133 /* device babble is something serious */136 /* Device babble is something serious */ 134 137 if ((instance->status & TD_STATUS_ERROR_BABBLE) != 0) 135 138 return EIO; 136 139 137 /* stall might represent err count reaching zero or stall response from138 * the device , iserr count reached zero, one of the above is reported*/140 /* Stall might represent err count reaching zero or stall response from 141 * the device. If err count reached zero, one of the above is reported*/ 139 142 if ((instance->status & TD_STATUS_ERROR_STALLED) != 0) 140 143 return ESTALL; -
uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.h
r3f2af64 rd8b275d 40 40 #include "link_pointer.h" 41 41 42 /** UHCI Transfer Descriptor*/42 /** Transfer Descriptor, defined in UHCI design guide p. 26 */ 43 43 typedef struct transfer_descriptor { 44 /** Pointer to the next entity (TD or QH) */ 44 45 link_pointer_t next; 45 46 47 /** Status doubleword */ 46 48 volatile uint32_t status; 47 49 #define TD_STATUS_RESERVED_MASK 0xc000f800 48 #define TD_STATUS_SPD_FLAG ( 1 << 29)49 #define TD_STATUS_ERROR_COUNT_POS ( 27 )50 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )51 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26)52 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25)53 #define TD_STATUS_IOC_FLAG ( 1 << 24)50 #define TD_STATUS_SPD_FLAG (1 << 29) 51 #define TD_STATUS_ERROR_COUNT_POS 27 52 #define TD_STATUS_ERROR_COUNT_MASK 0x3 53 #define TD_STATUS_LOW_SPEED_FLAG (1 << 26) 54 #define TD_STATUS_ISOCHRONOUS_FLAG (1 << 25) 55 #define TD_STATUS_IOC_FLAG (1 << 24) 54 56 55 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23)56 #define TD_STATUS_ERROR_STALLED ( 1 << 22)57 #define TD_STATUS_ERROR_BUFFER ( 1 << 21)58 #define TD_STATUS_ERROR_BABBLE ( 1 << 20)59 #define TD_STATUS_ERROR_NAK ( 1 << 19)60 #define TD_STATUS_ERROR_CRC ( 1 << 18)61 #define TD_STATUS_ERROR_BIT_STUFF ( 1 << 17)62 #define TD_STATUS_ERROR_RESERVED ( 1 << 16)57 #define TD_STATUS_ERROR_ACTIVE (1 << 23) 58 #define TD_STATUS_ERROR_STALLED (1 << 22) 59 #define TD_STATUS_ERROR_BUFFER (1 << 21) 60 #define TD_STATUS_ERROR_BABBLE (1 << 20) 61 #define TD_STATUS_ERROR_NAK (1 << 19) 62 #define TD_STATUS_ERROR_CRC (1 << 18) 63 #define TD_STATUS_ERROR_BIT_STUFF (1 << 17) 64 #define TD_STATUS_ERROR_RESERVED (1 << 16) 63 65 #define TD_STATUS_ERROR_POS 16 64 #define TD_STATUS_ERROR_MASK ( 0xff )66 #define TD_STATUS_ERROR_MASK 0xff 65 67 66 68 #define TD_STATUS_ACTLEN_POS 0 67 69 #define TD_STATUS_ACTLEN_MASK 0x7ff 68 70 71 /* double word with USB device specific info */ 69 72 volatile uint32_t device; 70 73 #define TD_DEVICE_MAXLEN_POS 21 71 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff )72 #define TD_DEVICE_RESERVED_FLAG ( 1 << 20)73 #define TD_DEVICE_DATA_TOGGLE_ONE_FLAG ( 1 << 19)74 #define TD_DEVICE_MAXLEN_MASK 0x7ff 75 #define TD_DEVICE_RESERVED_FLAG (1 << 20) 76 #define TD_DEVICE_DATA_TOGGLE_ONE_FLAG (1 << 19) 74 77 #define TD_DEVICE_ENDPOINT_POS 15 75 #define TD_DEVICE_ENDPOINT_MASK ( 0xf )78 #define TD_DEVICE_ENDPOINT_MASK 0xf 76 79 #define TD_DEVICE_ADDRESS_POS 8 77 #define TD_DEVICE_ADDRESS_MASK ( 0x7f )80 #define TD_DEVICE_ADDRESS_MASK 0x7f 78 81 #define TD_DEVICE_PID_POS 0 79 #define TD_DEVICE_PID_MASK ( 0xff )82 #define TD_DEVICE_PID_MASK 0xff 80 83 84 /** Pointer(physical) to the beginning of the transaction's buffer */ 81 85 volatile uint32_t buffer_ptr; 82 86 83 /* there is 16 bytes of data available here, according to UHCI 84 * Design guide, according to linux kernel the hardware does not care, 85 * it just needs to be aligned, we don't use it anyway 87 /* According to UHCI design guide, there is 16 bytes of 88 * data available here. 89 * According to linux kernel the hardware does not care, 90 * it just needs to be aligned. We don't use it anyway. 86 91 */ 87 92 } __attribute__((packed)) td_t; -
uspace/drv/uhci-hcd/iface.c
r3f2af64 rd8b275d 63 63 } 64 64 65 usb_log_debug("%s %d:%d %zu(%zu).\n", 66 name, target.address, target.endpoint, size, ep->max_packet_size); 67 65 68 const size_t bw = bandwidth_count_usb11( 66 69 ep->speed, ep->transfer_type, size, ep->max_packet_size); … … 68 71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 69 72 "but only %zu is reserved.\n", 70 name, target.address, target.endpoint, bw, res_bw);73 target.address, target.endpoint, name, bw, res_bw); 71 74 return ENOSPC; 72 75 } 73 usb_log_debug("%s %d:%d %zu(%zu).\n",74 name, target.address, target.endpoint, size, ep->max_packet_size);75 76 76 77 *batch = batch_get( … … 146 147 hc_t *hc = fun_to_hc(fun); 147 148 assert(hc); 149 const size_t size = max_packet_size; 148 150 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address); 149 151 if (speed >= USB_SPEED_MAX) { 150 152 speed = ep_speed; 151 153 } 152 const size_t size =153 (transfer_type == USB_TRANSFER_INTERRUPT154 || transfer_type == USB_TRANSFER_ISOCHRONOUS) ?155 max_packet_size : 0;156 int ret;157 158 endpoint_t *ep = malloc(sizeof(endpoint_t));159 if (ep == NULL)160 return ENOMEM;161 ret = endpoint_init(ep, address, endpoint, direction,162 transfer_type, speed, max_packet_size);163 if (ret != EOK) {164 free(ep);165 return ret;166 }167 168 154 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n", 169 155 address, endpoint, usb_str_transfer_type(transfer_type), 170 156 usb_str_speed(speed), direction, size, max_packet_size, interval); 171 157 172 ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size); 173 if (ret != EOK) { 174 endpoint_destroy(ep); 175 } 176 return ret; 158 return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint, 159 direction, transfer_type, speed, max_packet_size, size); 177 160 } 178 161 /*----------------------------------------------------------------------------*/ … … 212 195 ret = hc_schedule(hc, batch); 213 196 if (ret != EOK) { 214 batch_dispose(batch);197 usb_transfer_batch_dispose(batch); 215 198 } 216 199 return ret; … … 240 223 ret = hc_schedule(hc, batch); 241 224 if (ret != EOK) { 242 batch_dispose(batch);225 usb_transfer_batch_dispose(batch); 243 226 } 244 227 return ret; … … 268 251 ret = hc_schedule(hc, batch); 269 252 if (ret != EOK) { 270 batch_dispose(batch);253 usb_transfer_batch_dispose(batch); 271 254 } 272 255 return ret; … … 296 279 ret = hc_schedule(hc, batch); 297 280 if (ret != EOK) { 298 batch_dispose(batch);281 usb_transfer_batch_dispose(batch); 299 282 } 300 283 return ret; … … 329 312 ret = hc_schedule(hc, batch); 330 313 if (ret != EOK) { 331 batch_dispose(batch);314 usb_transfer_batch_dispose(batch); 332 315 } 333 316 return ret; … … 361 344 ret = hc_schedule(hc, batch); 362 345 if (ret != EOK) { 363 batch_dispose(batch);346 usb_transfer_batch_dispose(batch); 364 347 } 365 348 return ret; -
uspace/drv/uhci-hcd/main.c
r3f2af64 rd8b275d 39 39 #include <usb/debug.h> 40 40 41 #include "iface.h"42 41 #include "uhci.h" 43 42 … … 62 61 int uhci_add_device(ddf_dev_t *device) 63 62 { 64 usb_log_debug ("uhci_add_device() called\n");63 usb_log_debug2("uhci_add_device() called\n"); 65 64 assert(device); 65 66 66 uhci_t *uhci = malloc(sizeof(uhci_t)); 67 67 if (uhci == NULL) { … … 72 72 int ret = uhci_init(uhci, device); 73 73 if (ret != EOK) { 74 usb_log_error("Failed to initialize UHCI driver: %s.\n",75 str_error(ret));74 usb_log_error("Failed(%d) to initialize UHCI driver: %s.\n", 75 ret, str_error(ret)); 76 76 return ret; 77 77 } … … 85 85 /** Initialize global driver structures (NONE). 86 86 * 87 * @param[in] argc N mber of arguments in argv vector (ignored).87 * @param[in] argc Number of arguments in argv vector (ignored). 88 88 * @param[in] argv Cmdline argument vector (ignored). 89 89 * @return Error code. … … 94 94 { 95 95 printf(NAME ": HelenOS UHCI driver.\n"); 96 97 sleep(3); /* TODO: remove in final version */98 96 usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME); 99 97 -
uspace/drv/uhci-hcd/pci.c
r3f2af64 rd8b275d 44 44 #include "pci.h" 45 45 46 /** Get address of registers and IRQ for given device.46 /** Get I/O address of registers and IRQ for given device. 47 47 * 48 48 * @param[in] dev Device asking for the addresses. … … 53 53 */ 54 54 int pci_get_my_registers(ddf_dev_t *dev, 55 uintptr_t *io_reg_address, size_t *io_reg_size, 56 int *irq_no) 55 uintptr_t *io_reg_address, size_t *io_reg_size, int *irq_no) 57 56 { 58 57 assert(dev != NULL); 59 58 60 int parent_phone = devman_parent_device_connect(dev->handle,61 IPC_FLAG_BLOCKING);59 int parent_phone = 60 devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING); 62 61 if (parent_phone < 0) { 63 62 return parent_phone; 64 63 } 65 64 66 int rc;67 65 hw_resource_list_t hw_resources; 68 rc = hw_res_get_resource_list(parent_phone, &hw_resources);66 int rc = hw_res_get_resource_list(parent_phone, &hw_resources); 69 67 if (rc != EOK) { 70 68 goto leave; … … 95 93 res->res.io_range.address, res->res.io_range.size); 96 94 io_found = true; 95 break; 97 96 98 97 default: … … 113 112 leave: 114 113 async_hangup(parent_phone); 115 116 114 return rc; 117 115 } … … 145 143 } 146 144 147 /* See UHCI design guide for these values ,145 /* See UHCI design guide for these values p.45, 148 146 * write all WC bits in USB legacy register */ 149 147 sysarg_t address = 0xc0; -
uspace/drv/uhci-hcd/root_hub.c
r3f2af64 rd8b275d 55 55 int ret = asprintf(&match_str, "usb&uhci&root-hub"); 56 56 if (ret < 0) { 57 usb_log_error("Failed to create root hub match string.\n"); 58 return ENOMEM; 57 usb_log_error( 58 "Failed(%d) to create root hub match string: %s.\n", 59 ret, str_error(ret)); 60 return ret; 59 61 } 60 62 61 63 ret = ddf_fun_add_match_id(fun, match_str, 100); 62 64 if (ret != EOK) { 65 free(match_str); 63 66 usb_log_error("Failed(%d) to add root hub match id: %s\n", 64 67 ret, str_error(ret)); … … 66 69 } 67 70 68 hw_resource_list_t *resource_list = &instance->resource_list;69 resource_list->count = 1;70 resource_list->resources = &instance->io_regs;71 assert(resource_list->resources); 71 /* Initialize resource structure */ 72 instance->resource_list.count = 1; 73 instance->resource_list.resources = &instance->io_regs; 74 72 75 instance->io_regs.type = IO_RANGE; 73 76 instance->io_regs.res.io_range.address = reg_addr; -
uspace/drv/uhci-hcd/root_hub.h
r3f2af64 rd8b275d 39 39 #include <ops/hw_res.h> 40 40 41 /** DDF support structure for uhci-rhd driver, provides I/O resources */ 41 42 typedef struct rh { 43 /** List of resources available to the root hub. */ 42 44 hw_resource_list_t resource_list; 45 /** The only resource in the above list */ 43 46 hw_resource_t io_regs; 44 47 } rh_t; -
uspace/drv/uhci-hcd/transfer_list.c
r3f2af64 rd8b275d 57 57 return ENOMEM; 58 58 } 59 instance->queue_head_pa = addr_to_phys(instance->queue_head);59 uint32_t queue_head_pa = addr_to_phys(instance->queue_head); 60 60 usb_log_debug2("Transfer list %s setup with QH: %p(%p).\n", 61 name, instance->queue_head, instance->queue_head_pa);61 name, instance->queue_head, queue_head_pa); 62 62 63 63 qh_init(instance->queue_head); … … 67 67 } 68 68 /*----------------------------------------------------------------------------*/ 69 /** Dispose transfer list structures. 70 * 71 * @param[in] instance Memory place to use. 72 * 73 * Frees memory for internal qh_t structure. 74 */ 75 void transfer_list_fini(transfer_list_t *instance) 76 { 77 assert(instance); 78 free32(instance->queue_head); 79 } 69 80 /** Set the next list in transfer list chain. 70 81 * … … 81 92 if (!instance->queue_head) 82 93 return; 83 /* Set bothqueue_head.next to point to the follower */84 qh_set_next_qh(instance->queue_head, next->queue_head _pa);85 } 86 /*----------------------------------------------------------------------------*/ 87 /** Submittransfer batch to the list and queue.94 /* Set queue_head.next to point to the follower */ 95 qh_set_next_qh(instance->queue_head, next->queue_head); 96 } 97 /*----------------------------------------------------------------------------*/ 98 /** Add transfer batch to the list and queue. 88 99 * 89 100 * @param[in] instance List to use. 90 101 * @param[in] batch Transfer batch to submit. 91 * @return Error code92 102 * 93 103 * The batch is added to the end of the list and queue. … … 109 119 } else { 110 120 /* There is something scheduled */ 111 usb_transfer_batch_t *last = list_get_instance(112 instance->batch_list.prev, usb_transfer_batch_t, link);121 usb_transfer_batch_t *last = 122 usb_transfer_batch_from_link(instance->batch_list.prev); 113 123 last_qh = batch_qh(last); 114 124 } … … 118 128 /* keep link */ 119 129 batch_qh(batch)->next = last_qh->next; 120 qh_set_next_qh(last_qh, pa);130 qh_set_next_qh(last_qh, batch_qh(batch)); 121 131 122 132 asm volatile ("": : :"memory"); … … 132 142 } 133 143 /*----------------------------------------------------------------------------*/ 134 /** Create list for finished batches.144 /** Add completed bantches to the provided list. 135 145 * 136 146 * @param[in] instance List to use. … … 147 157 link_t *next = current->next; 148 158 usb_transfer_batch_t *batch = 149 list_get_instance(current, usb_transfer_batch_t, link);159 usb_transfer_batch_from_link(current); 150 160 151 161 if (batch_is_complete(batch)) { 152 /* Save for p ost-processing */162 /* Save for processing */ 153 163 transfer_list_remove_batch(instance, batch); 154 164 list_append(current, done); … … 159 169 } 160 170 /*----------------------------------------------------------------------------*/ 161 /** Walk the list and abort all batches.171 /** Walk the list and finish all batches with EINTR. 162 172 * 163 173 * @param[in] instance List to use. … … 169 179 link_t *current = instance->batch_list.next; 170 180 usb_transfer_batch_t *batch = 171 list_get_instance(current, usb_transfer_batch_t, link);181 usb_transfer_batch_from_link(current); 172 182 transfer_list_remove_batch(instance, batch); 173 usb_transfer_batch_finish_error(batch, EI O);183 usb_transfer_batch_finish_error(batch, EINTR); 174 184 } 175 185 fibril_mutex_unlock(&instance->guard); … … 180 190 * @param[in] instance List to use. 181 191 * @param[in] batch Transfer batch to remove. 182 * @return Error code183 192 * 184 193 * Does not lock the transfer list, caller is responsible for that. … … 197 206 198 207 const char *qpos = NULL; 208 qh_t *prev_qh = NULL; 199 209 /* Remove from the hardware queue */ 200 210 if (instance->batch_list.next == &batch->link) { 201 211 /* I'm the first one here */ 202 assert((instance->queue_head->next & LINK_POINTER_ADDRESS_MASK) 203 == addr_to_phys(batch_qh(batch))); 204 instance->queue_head->next = batch_qh(batch)->next; 212 prev_qh = instance->queue_head; 205 213 qpos = "FIRST"; 206 214 } else { 215 /* The thing before me is a batch too */ 207 216 usb_transfer_batch_t *prev = 208 list_get_instance( 209 batch->link.prev, usb_transfer_batch_t, link); 210 assert((batch_qh(prev)->next & LINK_POINTER_ADDRESS_MASK) 211 == addr_to_phys(batch_qh(batch))); 212 batch_qh(prev)->next = batch_qh(batch)->next; 217 usb_transfer_batch_from_link(batch->link.prev); 218 prev_qh = batch_qh(prev); 213 219 qpos = "NOT FIRST"; 214 220 } 221 assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK) 222 == addr_to_phys(batch_qh(batch))); 223 prev_qh->next = batch_qh(batch)->next; 215 224 asm volatile ("": : :"memory"); 216 225 /* Remove from the batch list */ 217 226 list_remove(&batch->link); 218 usb_log_debug("Batch(%p) removed (%s) from %s, next %x.\n",227 usb_log_debug("Batch(%p) removed (%s) from %s, next: %x.\n", 219 228 batch, qpos, instance->name, batch_qh(batch)->next); 220 229 } -
uspace/drv/uhci-hcd/transfer_list.h
r3f2af64 rd8b275d 39 39 #include "batch.h" 40 40 #include "hw_struct/queue_head.h" 41 #include "utils/malloc32.h"42 41 42 /** Structure maintaining both hw queue and software list 43 * of currently executed transfers 44 */ 43 45 typedef struct transfer_list 44 46 { 47 /** Guard against multiple add/remove races */ 45 48 fibril_mutex_t guard; 49 /** UHCI hw structure represeting this queue */ 46 50 qh_t *queue_head; 47 uint32_t queue_head_pa;51 /** Assigned name, for nicer debug output */ 48 52 const char *name; 53 /** List of all batches in this list */ 49 54 link_t batch_list; 50 55 } transfer_list_t; 51 56 52 /** Dispose transfer list structures. 53 * 54 * @param[in] instance Memory place to use. 55 * 56 * Frees memory for internal qh_t structure. 57 */ 58 static inline void transfer_list_fini(transfer_list_t *instance) 59 { 60 assert(instance); 61 free32(instance->queue_head); 62 } 63 57 void transfer_list_fini(transfer_list_t *instance); 64 58 int transfer_list_init(transfer_list_t *instance, const char *name); 65 66 59 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next); 67 68 void transfer_list_add_batch(transfer_list_t *instance, usb_transfer_batch_t *batch); 69 60 void transfer_list_add_batch( 61 transfer_list_t *instance, usb_transfer_batch_t *batch); 70 62 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done); 71 72 63 void transfer_list_abort_all(transfer_list_t *instance); 73 64 #endif -
uspace/drv/uhci-hcd/uhci.c
r3f2af64 rd8b275d 44 44 #include "pci.h" 45 45 46 /** IRQ handling callback, identifies device46 /** IRQ handling callback, forward status from call to diver structure. 47 47 * 48 48 * @param[in] dev DDF instance of the device to use. 49 49 * @param[in] iid (Unused). 50 * @param[in] call Pointer to the call that represents interrupt.50 * @param[in] call Pointer to the call from kernel. 51 51 */ 52 52 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) … … 61 61 /** Get address of the device identified by handle. 62 62 * 63 * @param[in] dev DDF instance of the deviceto use.64 * @param[in] iid (Unused).65 * @param[ in] call Pointer to the call that represents interrupt.63 * @param[in] fun DDF instance of the function to use. 64 * @param[in] handle DDF handle of the driver seeking its USB address. 65 * @param[out] address Found address. 66 66 */ 67 67 static int usb_iface_get_address( … … 69 69 { 70 70 assert(fun); 71 usb_device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.manager; 71 usb_device_keeper_t *manager = 72 &((uhci_t*)fun->dev->driver_data)->hc.manager; 72 73 73 74 usb_address_t addr = usb_device_keeper_find(manager, handle); … … 83 84 } 84 85 /*----------------------------------------------------------------------------*/ 85 /** Gets handle of the respective hc (this or parent device).86 * 87 * @param[in] root_hub_fun Root hub function seeking hc handle.88 * @param[out] handle Place to write thehandle.86 /** Gets handle of the respective hc. 87 * 88 * @param[in] fun DDF function of uhci device. 89 * @param[out] handle Host cotnroller handle. 89 90 * @return Error code. 90 91 */ … … 100 101 } 101 102 /*----------------------------------------------------------------------------*/ 102 /** This iface is generic for both RH and HC.*/103 /** USB interface implementation used by RH */ 103 104 static usb_iface_t usb_iface = { 104 105 .get_hc_handle = usb_iface_get_hc_handle, … … 106 107 }; 107 108 /*----------------------------------------------------------------------------*/ 109 /** Operations supported by the HC driver */ 108 110 static ddf_dev_ops_t hc_ops = { 109 // .interfaces[USB_DEV_IFACE] = &usb_iface,110 111 .interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */ 111 112 }; … … 122 123 } 123 124 /*----------------------------------------------------------------------------*/ 125 /** Interface to provide the root hub driver with hw info */ 124 126 static hw_res_ops_t hw_res_iface = { 125 127 .get_resource_list = get_resource_list, … … 127 129 }; 128 130 /*----------------------------------------------------------------------------*/ 131 /** RH function support for uhci-rhd */ 129 132 static ddf_dev_ops_t rh_ops = { 130 133 .interfaces[USB_DEV_IFACE] = &usb_iface, … … 132 135 }; 133 136 /*----------------------------------------------------------------------------*/ 134 /** Initialize hc and rh ddfstructures and their respective drivers.137 /** Initialize hc and rh DDF structures and their respective drivers. 135 138 * 136 139 * @param[in] instance UHCI structure to use. … … 138 141 * 139 142 * This function does all the preparatory work for hc and rh drivers: 140 * - gets device hw resources141 * - disables UHCI legacy support 143 * - gets device's hw resources 144 * - disables UHCI legacy support (PCI config space) 142 145 * - asks for interrupt 143 146 * - registers interrupt handler … … 193 196 ret = (instance->hc_fun == NULL) ? ENOMEM : EOK; 194 197 CHECK_RET_DEST_FUN_RETURN(ret, 195 "Failed(%d) to create HC function .\n", ret);198 "Failed(%d) to create HC function: %s.\n", ret, str_error(ret)); 196 199 197 200 ret = hc_init(&instance->hc, instance->hc_fun, 198 201 (void*)io_reg_base, io_reg_size, interrupts); 199 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 202 CHECK_RET_DEST_FUN_RETURN(ret, 203 "Failed(%d) to init uhci-hcd: %s.\n", ret, str_error(ret)); 204 200 205 instance->hc_fun->ops = &hc_ops; 201 206 instance->hc_fun->driver_data = &instance->hc; … … 221 226 &instance->hc.interrupt_code); 222 227 CHECK_RET_FINI_RETURN(ret, 223 "Failed(%d) to register interrupt handler.\n", ret); 228 "Failed(%d) to register interrupt handler: %s.\n", 229 ret, str_error(ret)); 224 230 225 231 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh"); 226 232 ret = (instance->rh_fun == NULL) ? ENOMEM : EOK; 227 233 CHECK_RET_FINI_RETURN(ret, 228 "Failed(%d) to create root hub function.\n", ret); 234 "Failed(%d) to create root hub function: %s.\n", 235 ret, str_error(ret)); 229 236 230 237 ret = rh_init(&instance->rh, instance->rh_fun, 231 238 (uintptr_t)instance->hc.registers + 0x10, 4); 232 239 CHECK_RET_FINI_RETURN(ret, 233 "Failed(%d) to setup UHCI root hub .\n", ret);240 "Failed(%d) to setup UHCI root hub: %s.\n", ret, str_error(ret)); 234 241 235 242 instance->rh_fun->ops = &rh_ops; … … 237 244 ret = ddf_fun_bind(instance->rh_fun); 238 245 CHECK_RET_FINI_RETURN(ret, 239 "Failed(%d) to register UHCI root hub .\n", ret);246 "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret)); 240 247 241 248 return EOK; -
uspace/drv/uhci-hcd/uhci.h
r3f2af64 rd8b275d 41 41 #include "root_hub.h" 42 42 43 /** Structure representing both functions of UHCI hc, USB host controller 44 * and USB root hub */ 43 45 typedef struct uhci { 46 /** Pointer to DDF represenation of UHCI host controller */ 44 47 ddf_fun_t *hc_fun; 48 /** Pointer to DDF represenation of UHCI root hub */ 45 49 ddf_fun_t *rh_fun; 46 50 51 /** Internal driver's represenation of UHCI host controller */ 47 52 hc_t hc; 53 /** Internal driver's represenation of UHCI root hub */ 48 54 rh_t rh; 49 55 } uhci_t; 50 56 51 57 int uhci_init(uhci_t *instance, ddf_dev_t *device); 52 53 58 #endif 54 59 /**
Note:
See TracChangeset
for help on using the changeset viewer.
