Changeset 72af8da in mainline for uspace/drv/uhci-hcd
- Timestamp:
- 2011-03-16T18:50:17Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, 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. - Location:
- uspace/drv/uhci-hcd
- Files:
-
- 2 added
- 1 deleted
- 19 edited
- 2 moved
-
Makefile (modified) (1 diff)
-
batch.c (modified) (16 diffs)
-
batch.h (modified) (6 diffs)
-
iface.c (modified) (14 diffs)
-
iface.h (modified) (2 diffs)
-
main.c (modified) (2 diffs)
-
pci.c (modified) (6 diffs)
-
pci.h (modified) (1 diff)
-
root_hub.c (deleted)
-
transfer_list.c (modified) (5 diffs)
-
transfer_list.h (modified) (3 diffs)
-
uhci.c (modified) (3 diffs)
-
uhci.h (modified) (2 diffs)
-
uhci_hc.c (added)
-
uhci_hc.h (added)
-
uhci_rh.c (moved) (moved from uspace/lib/usb/src/hcdhubd_private.h ) (2 diffs)
-
uhci_rh.h (moved) (moved from uspace/drv/uhci-hcd/root_hub.h ) (2 diffs)
-
uhci_struct/link_pointer.h (modified) (2 diffs)
-
uhci_struct/queue_head.h (modified) (3 diffs)
-
uhci_struct/transfer_descriptor.c (modified) (5 diffs)
-
uhci_struct/transfer_descriptor.h (modified) (5 diffs)
-
utils/device_keeper.c (modified) (10 diffs)
-
utils/device_keeper.h (modified) (3 diffs)
-
utils/malloc32.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/Makefile
r3e7b7cd r72af8da 35 35 iface.c \ 36 36 main.c \ 37 root_hub.c \38 37 transfer_list.c \ 39 38 uhci.c \ 39 uhci_hc.c \ 40 uhci_rh.c \ 40 41 uhci_struct/transfer_descriptor.c \ 41 42 utils/device_keeper.c \ -
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 * @} -
uspace/drv/uhci-hcd/batch.h
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 #ifndef DRV_UHCI_BATCH_H … … 42 42 #include "uhci_struct/transfer_descriptor.h" 43 43 #include "uhci_struct/queue_head.h" 44 #include "utils/device_keeper.h" 44 45 45 46 typedef struct batch … … 49 50 usb_target_t target; 50 51 usb_transfer_type_t transfer_type; 51 union { 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 54 }; 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 55 54 void *arg; 56 55 char *transport_buffer; … … 64 63 int error; 65 64 ddf_fun_t *fun; 66 q ueue_head_t *qh;67 t ransfer_descriptor_t *tds;65 qh_t *qh; 66 td_t *tds; 68 67 void (*next_step)(struct batch*); 68 device_keeper_t *manager; 69 69 } batch_t; 70 70 … … 74 74 char *setup_buffer, size_t setup_size, 75 75 usbhc_iface_transfer_in_callback_t func_in, 76 usbhc_iface_transfer_out_callback_t func_out, void *arg); 76 usbhc_iface_transfer_out_callback_t func_out, void *arg, 77 device_keeper_t *manager 78 ); 79 80 void batch_dispose(batch_t *instance); 77 81 78 82 bool batch_is_complete(batch_t *instance); … … 86 90 void batch_interrupt_out(batch_t *instance); 87 91 88 /* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */ 89 void batch_control_setup_old(batch_t *instance); 92 void batch_bulk_in(batch_t *instance); 90 93 91 void batch_control_write_data_old(batch_t *instance); 92 93 void batch_control_read_data_old(batch_t *instance); 94 95 void batch_control_write_status_old(batch_t *instance); 96 97 void batch_control_read_status_old(batch_t *instance); 94 void batch_bulk_out(batch_t *instance); 98 95 #endif 99 96 /** -
uspace/drv/uhci-hcd/iface.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 hc interface implementation 33 33 */ 34 34 #include <ddf/driver.h> … … 40 40 41 41 #include "iface.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/device_keeper.h" 44 44 45 /** Reserve default address interface function 46 * 47 * @param[in] fun DDF function that was called. 48 * @param[in] speed Speed to associate with the new default address. 49 * @return Error code. 50 */ 45 51 /*----------------------------------------------------------------------------*/ 46 52 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 47 53 { 48 54 assert(fun); 49 uhci_ t *hc = fun_to_uhci(fun);55 uhci_hc_t *hc = fun_to_uhci_hc(fun); 50 56 assert(hc); 51 57 usb_log_debug("Default address request with speed %d.\n", speed); … … 54 60 } 55 61 /*----------------------------------------------------------------------------*/ 62 /** Release default address interface function 63 * 64 * @param[in] fun DDF function that was called. 65 * @return Error code. 66 */ 56 67 static int release_default_address(ddf_fun_t *fun) 57 68 { 58 69 assert(fun); 59 uhci_ t *hc = fun_to_uhci(fun);70 uhci_hc_t *hc = fun_to_uhci_hc(fun); 60 71 assert(hc); 61 72 usb_log_debug("Default address release.\n"); … … 64 75 } 65 76 /*----------------------------------------------------------------------------*/ 77 /** Request address interface function 78 * 79 * @param[in] fun DDF function that was called. 80 * @param[in] speed Speed to associate with the new default address. 81 * @param[out] address Place to write a new address. 82 * @return Error code. 83 */ 66 84 static int request_address(ddf_fun_t *fun, usb_speed_t speed, 67 85 usb_address_t *address) 68 86 { 69 87 assert(fun); 70 uhci_ t *hc = fun_to_uhci(fun);88 uhci_hc_t *hc = fun_to_uhci_hc(fun); 71 89 assert(hc); 72 90 assert(address); … … 80 98 } 81 99 /*----------------------------------------------------------------------------*/ 100 /** Bind address interface function 101 * 102 * @param[in] fun DDF function that was called. 103 * @param[in] address Address of the device 104 * @param[in] handle Devman handle of the device driver. 105 * @return Error code. 106 */ 82 107 static int bind_address( 83 108 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle) 84 109 { 85 110 assert(fun); 86 uhci_ t *hc = fun_to_uhci(fun);111 uhci_hc_t *hc = fun_to_uhci_hc(fun); 87 112 assert(hc); 88 113 usb_log_debug("Address bind %d-%d.\n", address, handle); … … 91 116 } 92 117 /*----------------------------------------------------------------------------*/ 118 /** Release address interface function 119 * 120 * @param[in] fun DDF function that was called. 121 * @param[in] address USB address to be released. 122 * @return Error code. 123 */ 93 124 static int release_address(ddf_fun_t *fun, usb_address_t address) 94 125 { 95 126 assert(fun); 96 uhci_ t *hc = fun_to_uhci(fun);127 uhci_hc_t *hc = fun_to_uhci_hc(fun); 97 128 assert(hc); 98 129 usb_log_debug("Address release %d.\n", address); … … 101 132 } 102 133 /*----------------------------------------------------------------------------*/ 134 /** Interrupt out transaction interface function 135 * 136 * @param[in] fun DDF function that was called. 137 * @param[in] target USB device to write to. 138 * @param[in] max_packet_size maximum size of data packet the device accepts 139 * @param[in] data Source of data. 140 * @param[in] size Size of data source. 141 * @param[in] callback Function to call on transaction completion 142 * @param[in] arg Additional for callback function. 143 * @return Error code. 144 */ 103 145 static int interrupt_out(ddf_fun_t *fun, usb_target_t target, 104 146 size_t max_packet_size, void *data, size_t size, … … 106 148 { 107 149 assert(fun); 108 uhci_ t *hc = fun_to_uhci(fun);150 uhci_hc_t *hc = fun_to_uhci_hc(fun); 109 151 assert(hc); 110 152 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 114 156 115 157 batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT, 116 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg); 158 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg, 159 &hc->device_manager); 117 160 if (!batch) 118 161 return ENOMEM; 119 162 batch_interrupt_out(batch); 120 return EOK; 121 } 122 /*----------------------------------------------------------------------------*/ 163 const int ret = uhci_hc_schedule(hc, batch); 164 if (ret != EOK) { 165 batch_dispose(batch); 166 return ret; 167 } 168 return EOK; 169 } 170 /*----------------------------------------------------------------------------*/ 171 /** Interrupt in transaction interface function 172 * 173 * @param[in] fun DDF function that was called. 174 * @param[in] target USB device to write to. 175 * @param[in] max_packet_size maximum size of data packet the device accepts 176 * @param[out] data Data destination. 177 * @param[in] size Size of data source. 178 * @param[in] callback Function to call on transaction completion 179 * @param[in] arg Additional for callback function. 180 * @return Error code. 181 */ 123 182 static int interrupt_in(ddf_fun_t *fun, usb_target_t target, 124 183 size_t max_packet_size, void *data, size_t size, … … 126 185 { 127 186 assert(fun); 128 uhci_ t *hc = fun_to_uhci(fun);187 uhci_hc_t *hc = fun_to_uhci_hc(fun); 129 188 assert(hc); 130 189 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 133 192 134 193 batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT, 135 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg); 194 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg, 195 &hc->device_manager); 136 196 if (!batch) 137 197 return ENOMEM; 138 198 batch_interrupt_in(batch); 139 return EOK; 140 } 141 /*----------------------------------------------------------------------------*/ 199 const int ret = uhci_hc_schedule(hc, batch); 200 if (ret != EOK) { 201 batch_dispose(batch); 202 return ret; 203 } 204 return EOK; 205 } 206 /*----------------------------------------------------------------------------*/ 207 /** Bulk out transaction interface function 208 * 209 * @param[in] fun DDF function that was called. 210 * @param[in] target USB device to write to. 211 * @param[in] max_packet_size maximum size of data packet the device accepts 212 * @param[in] data Source of data. 213 * @param[in] size Size of data source. 214 * @param[in] callback Function to call on transaction completion 215 * @param[in] arg Additional for callback function. 216 * @return Error code. 217 */ 218 static int bulk_out(ddf_fun_t *fun, usb_target_t target, 219 size_t max_packet_size, void *data, size_t size, 220 usbhc_iface_transfer_out_callback_t callback, void *arg) 221 { 222 assert(fun); 223 uhci_hc_t *hc = fun_to_uhci_hc(fun); 224 assert(hc); 225 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 226 227 usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n", 228 target.address, target.endpoint, size, max_packet_size); 229 230 batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK, 231 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg, 232 &hc->device_manager); 233 if (!batch) 234 return ENOMEM; 235 batch_bulk_out(batch); 236 const int ret = uhci_hc_schedule(hc, batch); 237 if (ret != EOK) { 238 batch_dispose(batch); 239 return ret; 240 } 241 return EOK; 242 } 243 /*----------------------------------------------------------------------------*/ 244 /** Bulk in transaction interface function 245 * 246 * @param[in] fun DDF function that was called. 247 * @param[in] target USB device to write to. 248 * @param[in] max_packet_size maximum size of data packet the device accepts 249 * @param[out] data Data destination. 250 * @param[in] size Size of data source. 251 * @param[in] callback Function to call on transaction completion 252 * @param[in] arg Additional for callback function. 253 * @return Error code. 254 */ 255 static int bulk_in(ddf_fun_t *fun, usb_target_t target, 256 size_t max_packet_size, void *data, size_t size, 257 usbhc_iface_transfer_in_callback_t callback, void *arg) 258 { 259 assert(fun); 260 uhci_hc_t *hc = fun_to_uhci_hc(fun); 261 assert(hc); 262 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 263 usb_log_debug("Bulk IN %d:%d %zu(%zu).\n", 264 target.address, target.endpoint, size, max_packet_size); 265 266 batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK, 267 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg, 268 &hc->device_manager); 269 if (!batch) 270 return ENOMEM; 271 batch_bulk_in(batch); 272 const int ret = uhci_hc_schedule(hc, batch); 273 if (ret != EOK) { 274 batch_dispose(batch); 275 return ret; 276 } 277 return EOK; 278 } 279 /*----------------------------------------------------------------------------*/ 280 /** Control write transaction interface function 281 * 282 * @param[in] fun DDF function that was called. 283 * @param[in] target USB device to write to. 284 * @param[in] max_packet_size maximum size of data packet the device accepts. 285 * @param[in] setup_data Data to send with SETUP packet. 286 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B). 287 * @param[in] data Source of data. 288 * @param[in] size Size of data source. 289 * @param[in] callback Function to call on transaction completion. 290 * @param[in] arg Additional for callback function. 291 * @return Error code. 292 */ 142 293 static int control_write(ddf_fun_t *fun, usb_target_t target, 143 294 size_t max_packet_size, … … 146 297 { 147 298 assert(fun); 148 uhci_t *hc = fun_to_uhci(fun); 149 assert(hc); 150 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 151 usb_log_debug("Control WRITE %d:%d %zu(%zu).\n", 152 target.address, target.endpoint, size, max_packet_size); 299 uhci_hc_t *hc = fun_to_uhci_hc(fun); 300 assert(hc); 301 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 302 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n", 303 speed, target.address, target.endpoint, size, max_packet_size); 304 305 if (setup_size != 8) 306 return EINVAL; 153 307 154 308 batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL, 155 309 max_packet_size, speed, data, size, setup_data, setup_size, 156 NULL, callback, arg); 157 if (!batch) 158 return ENOMEM; 310 NULL, callback, arg, &hc->device_manager); 311 if (!batch) 312 return ENOMEM; 313 device_keeper_reset_if_need(&hc->device_manager, target, setup_data); 159 314 batch_control_write(batch); 160 return EOK; 161 } 162 /*----------------------------------------------------------------------------*/ 315 const int ret = uhci_hc_schedule(hc, batch); 316 if (ret != EOK) { 317 batch_dispose(batch); 318 return ret; 319 } 320 return EOK; 321 } 322 /*----------------------------------------------------------------------------*/ 323 /** Control read transaction interface function 324 * 325 * @param[in] fun DDF function that was called. 326 * @param[in] target USB device to write to. 327 * @param[in] max_packet_size maximum size of data packet the device accepts. 328 * @param[in] setup_data Data to send with SETUP packet. 329 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B). 330 * @param[out] data Source of data. 331 * @param[in] size Size of data source. 332 * @param[in] callback Function to call on transaction completion. 333 * @param[in] arg Additional for callback function. 334 * @return Error code. 335 */ 163 336 static int control_read(ddf_fun_t *fun, usb_target_t target, 164 337 size_t max_packet_size, … … 167 340 { 168 341 assert(fun); 169 uhci_ t *hc = fun_to_uhci(fun);170 assert(hc); 171 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 172 173 usb_log_debug("Control READ %d:%d %zu(%zu).\n",174 target.address, target.endpoint, size, max_packet_size);342 uhci_hc_t *hc = fun_to_uhci_hc(fun); 343 assert(hc); 344 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 345 346 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n", 347 speed, target.address, target.endpoint, size, max_packet_size); 175 348 batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL, 176 349 max_packet_size, speed, data, size, setup_data, setup_size, callback, 177 NULL, arg );350 NULL, arg, &hc->device_manager); 178 351 if (!batch) 179 352 return ENOMEM; 180 353 batch_control_read(batch); 181 return EOK; 182 } 183 184 185 /*----------------------------------------------------------------------------*/ 186 usbhc_iface_t uhci_iface = { 354 const int ret = uhci_hc_schedule(hc, batch); 355 if (ret != EOK) { 356 batch_dispose(batch); 357 return ret; 358 } 359 return EOK; 360 } 361 /*----------------------------------------------------------------------------*/ 362 usbhc_iface_t uhci_hc_iface = { 187 363 .reserve_default_address = reserve_default_address, 188 364 .release_default_address = release_default_address, … … 194 370 .interrupt_in = interrupt_in, 195 371 372 .bulk_in = bulk_in, 373 .bulk_out = bulk_out, 374 196 375 .control_read = control_read, 197 376 .control_write = control_write, -
uspace/drv/uhci-hcd/iface.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup usb29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver iface 34 34 */ 35 35 #ifndef DRV_UHCI_IFACE_H … … 38 38 #include <usbhc_iface.h> 39 39 40 extern usbhc_iface_t uhci_ iface;40 extern usbhc_iface_t uhci_hc_iface; 41 41 42 42 #endif -
uspace/drv/uhci-hcd/main.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 initialization 33 33 */ 34 34 #include <ddf/driver.h> 35 #include <ddf/interrupt.h>36 #include <device/hw_res.h>37 35 #include <errno.h> 38 36 #include <str_error.h> 39 37 40 #include <usb_iface.h>41 38 #include <usb/ddfiface.h> 42 39 #include <usb/debug.h> 43 40 44 41 #include "iface.h" 45 #include "pci.h"46 #include "root_hub.h"47 42 #include "uhci.h" 48 43 … … 60 55 }; 61 56 /*----------------------------------------------------------------------------*/ 62 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 57 /** Initialize a new ddf driver instance for uhci hc and hub. 58 * 59 * @param[in] device DDF instance of the device to initialize. 60 * @return Error code. 61 */ 62 int uhci_add_device(ddf_dev_t *device) 63 63 { 64 assert(dev); 65 uhci_t *hc = dev_to_uhci(dev); 66 uint16_t status = IPC_GET_ARG1(*call); 67 assert(hc); 68 uhci_interrupt(hc, status); 64 usb_log_info("uhci_add_device() called\n"); 65 assert(device); 66 uhci_t *uhci = malloc(sizeof(uhci_t)); 67 if (uhci == NULL) { 68 usb_log_error("Failed to allocate UHCI driver.\n"); 69 return ENOMEM; 70 } 71 72 int ret = uhci_init(uhci, device); 73 if (ret != EOK) { 74 usb_log_error("Failed to initialzie UHCI driver.\n"); 75 return ret; 76 } 77 device->driver_data = uhci; 78 return EOK; 69 79 } 70 80 /*----------------------------------------------------------------------------*/ 71 static int uhci_add_device(ddf_dev_t *device) 72 { 73 assert(device); 74 uhci_t *hcd = NULL; 75 #define CHECK_RET_FREE_HC_RETURN(ret, message...) \ 76 if (ret != EOK) { \ 77 usb_log_error(message); \ 78 if (hcd != NULL) \ 79 free(hcd); \ 80 return ret; \ 81 } 82 83 usb_log_info("uhci_add_device() called\n"); 84 85 uintptr_t io_reg_base = 0; 86 size_t io_reg_size = 0; 87 int irq = 0; 88 89 int ret = 90 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 91 CHECK_RET_FREE_HC_RETURN(ret, 92 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 93 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 94 io_reg_base, io_reg_size, irq); 95 96 ret = pci_disable_legacy(device); 97 CHECK_RET_FREE_HC_RETURN(ret, 98 "Failed(%d) disable legacy USB: %s.\n", ret, str_error(ret)); 99 100 #if 0 101 ret = pci_enable_interrupts(device); 102 if (ret != EOK) { 103 usb_log_warning( 104 "Failed(%d) to enable interrupts, fall back to polling.\n", 105 ret); 106 } 107 #endif 108 109 hcd = malloc(sizeof(uhci_t)); 110 ret = (hcd != NULL) ? EOK : ENOMEM; 111 CHECK_RET_FREE_HC_RETURN(ret, 112 "Failed(%d) to allocate memory for uhci hcd.\n", ret); 113 114 ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size); 115 CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", 116 ret); 117 #undef CHECK_RET_FREE_HC_RETURN 118 119 /* 120 * We might free hcd, but that does not matter since no one 121 * else would access driver_data anyway. 122 */ 123 device->driver_data = hcd; 124 125 ddf_fun_t *rh = NULL; 126 #define CHECK_RET_FINI_FREE_RETURN(ret, message...) \ 127 if (ret != EOK) { \ 128 usb_log_error(message); \ 129 if (hcd != NULL) {\ 130 uhci_fini(hcd); \ 131 free(hcd); \ 132 } \ 133 if (rh != NULL) \ 134 free(rh); \ 135 return ret; \ 136 } 137 138 /* It does no harm if we register this on polling */ 139 ret = register_interrupt_handler(device, irq, irq_handler, 140 &hcd->interrupt_code); 141 CHECK_RET_FINI_FREE_RETURN(ret, 142 "Failed(%d) to register interrupt handler.\n", ret); 143 144 ret = setup_root_hub(&rh, device); 145 CHECK_RET_FINI_FREE_RETURN(ret, 146 "Failed(%d) to setup UHCI root hub.\n", ret); 147 rh->driver_data = hcd->ddf_instance; 148 149 ret = ddf_fun_bind(rh); 150 CHECK_RET_FINI_FREE_RETURN(ret, 151 "Failed(%d) to register UHCI root hub.\n", ret); 152 153 return EOK; 154 #undef CHECK_RET_FINI_FREE_RETURN 155 } 156 /*----------------------------------------------------------------------------*/ 81 /** Initialize global driver structures (NONE). 82 * 83 * @param[in] argc Nmber of arguments in argv vector (ignored). 84 * @param[in] argv Cmdline argument vector (ignored). 85 * @return Error code. 86 * 87 * Driver debug level is set here. 88 */ 157 89 int main(int argc, char *argv[]) 158 90 { 159 sleep(3); 91 sleep(3); /* TODO: remove in final version */ 160 92 usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME); 161 93 -
uspace/drv/uhci-hcd/pci.c
r3e7b7cd r72af8da 27 27 */ 28 28 /** 29 * @addtogroup drvusbuhci 29 * @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 65 65 66 66 int rc; 67 68 67 hw_resource_list_t hw_resources; 69 68 rc = hw_res_get_resource_list(parent_phone, &hw_resources); … … 82 81 for (i = 0; i < hw_resources.count; i++) { 83 82 hw_resource_t *res = &hw_resources.resources[i]; 84 switch (res->type) { 85 case INTERRUPT: 86 irq = res->res.interrupt.irq; 87 irq_found = true; 88 usb_log_debug2("Found interrupt: %d.\n", irq); 89 break; 90 case IO_RANGE: 91 io_address = res->res.io_range.address; 92 io_size = res->res.io_range.size; 93 usb_log_debug2("Found io: %llx %zu.\n", 94 res->res.io_range.address, res->res.io_range.size); 95 io_found = true; 96 break; 97 default: 98 break; 83 switch (res->type) 84 { 85 case INTERRUPT: 86 irq = res->res.interrupt.irq; 87 irq_found = true; 88 usb_log_debug2("Found interrupt: %d.\n", irq); 89 break; 90 91 case IO_RANGE: 92 io_address = res->res.io_range.address; 93 io_size = res->res.io_range.size; 94 usb_log_debug2("Found io: %llx %zu.\n", 95 res->res.io_range.address, res->res.io_range.size); 96 io_found = true; 97 98 default: 99 break; 99 100 } 100 101 } 101 102 102 if (!io_found) { 103 rc = ENOENT; 104 goto leave; 105 } 106 107 if (!irq_found) { 103 if (!io_found || !irq_found) { 108 104 rc = ENOENT; 109 105 goto leave; … … 121 117 } 122 118 /*----------------------------------------------------------------------------*/ 119 /** Call the PCI driver with a request to enable interrupts 120 * 121 * @param[in] device Device asking for interrupts 122 * @return Error code. 123 */ 123 124 int pci_enable_interrupts(ddf_dev_t *device) 124 125 { … … 130 131 } 131 132 /*----------------------------------------------------------------------------*/ 133 /** Call the PCI driver with a request to clear legacy support register 134 * 135 * @param[in] device Device asking to disable interrupts 136 * @return Error code. 137 */ 132 138 int pci_disable_legacy(ddf_dev_t *device) 133 139 { 134 140 assert(device); 135 int parent_phone = devman_parent_device_connect(device->handle,136 IPC_FLAG_BLOCKING);141 int parent_phone = 142 devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING); 137 143 if (parent_phone < 0) { 138 144 return parent_phone; … … 144 150 sysarg_t value = 0x8f00; 145 151 146 int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),152 int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 147 153 IPC_M_CONFIG_SPACE_WRITE_16, address, value); 148 154 async_hangup(parent_phone); 149 155 150 return rc;156 return rc; 151 157 } 152 158 /*----------------------------------------------------------------------------*/ -
uspace/drv/uhci-hcd/pci.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver PCI helper functions 34 34 */ 35 35 #ifndef DRV_UHCI_PCI_H -
uspace/drv/uhci-hcd/transfer_list.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 transfer list implementation 33 33 */ 34 34 #include <errno.h> 35 36 35 #include <usb/debug.h> 37 36 38 37 #include "transfer_list.h" 39 38 39 static void transfer_list_remove_batch( 40 transfer_list_t *instance, batch_t *batch); 41 /*----------------------------------------------------------------------------*/ 42 /** Initialize transfer list structures. 43 * 44 * @param[in] instance Memory place to use. 45 * @param[in] name Name of the new list. 46 * @return Error code 47 * 48 * Allocates memory for internal qh_t structure. 49 */ 40 50 int transfer_list_init(transfer_list_t *instance, const char *name) 41 51 { 42 52 assert(instance); 43 instance->next = NULL;44 53 instance->name = name; 45 instance->queue_head = queue_head_get();54 instance->queue_head = malloc32(sizeof(qh_t)); 46 55 if (!instance->queue_head) { 47 56 usb_log_error("Failed to allocate queue head.\n"); 48 57 return ENOMEM; 49 58 } 50 instance->queue_head_pa = (uintptr_t)addr_to_phys(instance->queue_head);51 52 q ueue_head_init(instance->queue_head);59 instance->queue_head_pa = addr_to_phys(instance->queue_head); 60 61 qh_init(instance->queue_head); 53 62 list_initialize(&instance->batch_list); 54 63 fibril_mutex_initialize(&instance->guard); … … 56 65 } 57 66 /*----------------------------------------------------------------------------*/ 67 /** Set the next list in transfer list chain. 68 * 69 * @param[in] instance List to lead. 70 * @param[in] next List to append. 71 * @return Error code 72 * 73 * Does not check whether this replaces an existing list . 74 */ 58 75 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next) 59 76 { … … 62 79 if (!instance->queue_head) 63 80 return; 64 queue_head_append_qh(instance->queue_head, next->queue_head_pa); 65 instance->queue_head->element = instance->queue_head->next_queue; 66 } 67 /*----------------------------------------------------------------------------*/ 81 /* Set both next and element to point to the same QH */ 82 qh_set_next_qh(instance->queue_head, next->queue_head_pa); 83 qh_set_element_qh(instance->queue_head, next->queue_head_pa); 84 } 85 /*----------------------------------------------------------------------------*/ 86 /** Submit transfer batch to the list and queue. 87 * 88 * @param[in] instance List to use. 89 * @param[in] batch Transfer batch to submit. 90 * @return Error code 91 * 92 * The batch is added to the end of the list and queue. 93 */ 68 94 void transfer_list_add_batch(transfer_list_t *instance, batch_t *batch) 69 95 { 70 96 assert(instance); 71 97 assert(batch); 72 usb_log_debug2(" Adding batch(%p) to queue %s.\n", batch, instance->name);73 74 uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);98 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch); 99 100 const uint32_t pa = addr_to_phys(batch->qh); 75 101 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 76 pa |= LINK_POINTER_QUEUE_HEAD_FLAG; 77 78 batch->qh->next_queue = instance->queue_head->next_queue; 102 103 /* New batch will be added to the end of the current list 104 * so set the link accordingly */ 105 qh_set_next_qh(batch->qh, instance->queue_head->next); 79 106 80 107 fibril_mutex_lock(&instance->guard); 81 108 82 if (instance->queue_head->element == instance->queue_head->next_queue) { 83 /* there is nothing scheduled */ 84 list_append(&batch->link, &instance->batch_list); 85 instance->queue_head->element = pa; 86 usb_log_debug("Batch(%p) added to queue %s first.\n", 87 batch, instance->name); 88 fibril_mutex_unlock(&instance->guard); 89 return; 90 } 91 /* now we can be sure that there is someting scheduled */ 92 assert(!list_empty(&instance->batch_list)); 109 /* Add to the hardware queue. */ 110 if (list_empty(&instance->batch_list)) { 111 /* There is nothing scheduled */ 112 qh_t *qh = instance->queue_head; 113 assert(qh->element == qh->next); 114 qh_set_element_qh(qh, pa); 115 } else { 116 /* There is something scheduled */ 117 batch_t *last = list_get_instance( 118 instance->batch_list.prev, batch_t, link); 119 qh_set_next_qh(last->qh, pa); 120 } 121 /* Add to the driver list */ 122 list_append(&batch->link, &instance->batch_list); 123 93 124 batch_t *first = list_get_instance( 94 instance->batch_list.next, batch_t, link); 95 batch_t *last = list_get_instance( 96 instance->batch_list.prev, batch_t, link); 97 queue_head_append_qh(last->qh, pa); 98 list_append(&batch->link, &instance->batch_list); 99 usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n", 100 batch, instance->name, first ); 125 instance->batch_list.next, batch_t, link); 126 usb_log_debug("Batch(%p) added to queue %s, first is %p.\n", 127 batch, instance->name, first); 101 128 fibril_mutex_unlock(&instance->guard); 102 129 } 103 130 /*----------------------------------------------------------------------------*/ 104 static void transfer_list_remove_batch( 105 transfer_list_t *instance, batch_t *batch) 131 /** Remove a transfer batch from the list and queue. 132 * 133 * @param[in] instance List to use. 134 * @param[in] batch Transfer batch to remove. 135 * @return Error code 136 * 137 * Does not lock the transfer list, caller is responsible for that. 138 */ 139 void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch) 106 140 { 107 141 assert(instance); … … 109 143 assert(instance->queue_head); 110 144 assert(batch->qh); 111 usb_log_debug2("Removing batch(%p) from queue %s.\n", batch, instance->name); 112 113 /* I'm the first one here */ 145 usb_log_debug2( 146 "Queue %s: removing batch(%p).\n", instance->name, batch); 147 148 const char * pos = NULL; 149 /* Remove from the hardware queue */ 114 150 if (batch->link.prev == &instance->batch_list) { 115 usb_log_debug("Batch(%p) removed (FIRST) from queue %s, next element %x.\n",116 batch, instance->name, batch->qh->next_queue);117 instance->queue_head->element = batch->qh->next_queue;151 /* I'm the first one here */ 152 qh_set_element_qh(instance->queue_head, batch->qh->next); 153 pos = "FIRST"; 118 154 } else { 119 usb_log_debug("Batch(%p) removed (NOT FIRST) from queue, next element %x.\n", 120 batch, instance->name, batch->qh->next_queue); 121 batch_t *prev = list_get_instance(batch->link.prev, batch_t, link); 122 prev->qh->next_queue = batch->qh->next_queue; 123 } 155 batch_t *prev = 156 list_get_instance(batch->link.prev, batch_t, link); 157 qh_set_next_qh(prev->qh, batch->qh->next); 158 pos = "NOT FIRST"; 159 } 160 /* Remove from the driver list */ 124 161 list_remove(&batch->link); 125 } 126 /*----------------------------------------------------------------------------*/ 162 usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n", 163 batch, pos, instance->name, batch->qh->next); 164 } 165 /*----------------------------------------------------------------------------*/ 166 /** Check list for finished batches. 167 * 168 * @param[in] instance List to use. 169 * @return Error code 170 * 171 * Creates a local list of finished batches and calls next_step on each and 172 * every one. This is safer because next_step may theoretically access 173 * this transfer list leading to the deadlock if its done inline. 174 */ 127 175 void transfer_list_remove_finished(transfer_list_t *instance) 128 176 { … … 138 186 139 187 if (batch_is_complete(batch)) { 188 /* Save for post-processing */ 140 189 transfer_list_remove_batch(instance, batch); 141 190 list_append(current, &done); -
uspace/drv/uhci-hcd/transfer_list.h
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 transfer list structure 33 33 */ 34 34 #ifndef DRV_UHCI_TRANSFER_LIST_H … … 44 44 { 45 45 fibril_mutex_t guard; 46 q ueue_head_t *queue_head;46 qh_t *queue_head; 47 47 uint32_t queue_head_pa; 48 struct transfer_list *next;49 48 const char *name; 50 49 link_t batch_list; 51 50 } transfer_list_t; 51 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 } 52 63 53 64 int transfer_list_init(transfer_list_t *instance, const char *name); … … 55 66 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next); 56 67 57 static inline void transfer_list_fini(transfer_list_t *instance)58 {59 assert(instance);60 queue_head_dispose(instance->queue_head);61 }62 68 void transfer_list_remove_finished(transfer_list_t *instance); 63 69 -
uspace/drv/uhci-hcd/uhci.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb 28 29 /** @addtogroup drvusbuhci 29 30 * @{ 30 31 */ … … 34 35 #include <errno.h> 35 36 #include <str_error.h> 36 #include < adt/list.h>37 #include < libarch/ddi.h>38 37 #include <ddf/interrupt.h> 38 #include <usb_iface.h> 39 #include <usb/ddfiface.h> 39 40 #include <usb/debug.h> 40 #include <usb/usb.h>41 #include <usb/ddfiface.h>42 #include <usb_iface.h>43 41 44 42 #include "uhci.h" 45 43 #include "iface.h" 46 47 static irq_cmd_t uhci_cmds[] = { 48 { 49 .cmd = CMD_PIO_READ_16, 50 .addr = NULL, /* patched for every instance */ 51 .dstarg = 1 52 }, 53 { 54 .cmd = CMD_PIO_WRITE_16, 55 .addr = NULL, /* pathed for every instance */ 56 .value = 0x1f 57 }, 58 { 59 .cmd = CMD_ACCEPT 60 } 61 }; 62 63 static int usb_iface_get_address(ddf_fun_t *fun, devman_handle_t handle, 64 usb_address_t *address) 44 #include "pci.h" 45 46 47 /** IRQ handling callback, identifies device 48 * 49 * @param[in] dev DDF instance of the device to use. 50 * @param[in] iid (Unused). 51 * @param[in] call Pointer to the call that represents interrupt. 52 */ 53 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 54 { 55 assert(dev); 56 uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc; 57 uint16_t status = IPC_GET_ARG1(*call); 58 assert(hc); 59 uhci_hc_interrupt(hc, status); 60 } 61 /*----------------------------------------------------------------------------*/ 62 /** Get address of the device identified by handle. 63 * 64 * @param[in] dev DDF instance of the device to use. 65 * @param[in] iid (Unused). 66 * @param[in] call Pointer to the call that represents interrupt. 67 */ 68 static int usb_iface_get_address( 69 ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address) 65 70 { 66 71 assert(fun); 67 uhci_t *hc = fun_to_uhci(fun); 68 assert(hc); 69 70 usb_address_t addr = device_keeper_find(&hc->device_manager, 71 handle); 72 device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager; 73 74 usb_address_t addr = device_keeper_find(manager, handle); 72 75 if (addr < 0) { 73 76 return addr; … … 81 84 } 82 85 /*----------------------------------------------------------------------------*/ 83 static usb_iface_t hc_usb_iface = { 84 .get_hc_handle = usb_iface_get_hc_handle_hc_impl, 86 /** Gets handle of the respective hc (this or parent device). 87 * 88 * @param[in] root_hub_fun Root hub function seeking hc handle. 89 * @param[out] handle Place to write the handle. 90 * @return Error code. 91 */ 92 static int usb_iface_get_hc_handle( 93 ddf_fun_t *fun, devman_handle_t *handle) 94 { 95 assert(handle); 96 ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun; 97 assert(hc_fun != NULL); 98 99 *handle = hc_fun->handle; 100 return EOK; 101 } 102 /*----------------------------------------------------------------------------*/ 103 /** This iface is generic for both RH and HC. */ 104 static usb_iface_t usb_iface = { 105 .get_hc_handle = usb_iface_get_hc_handle, 85 106 .get_address = usb_iface_get_address 86 107 }; 87 108 /*----------------------------------------------------------------------------*/ 88 static ddf_dev_ops_t uhci_ops = { 89 .interfaces[USB_DEV_IFACE] = &hc_usb_iface, 90 .interfaces[USBHC_DEV_IFACE] = &uhci_iface, 91 }; 92 /*----------------------------------------------------------------------------*/ 93 static int uhci_init_transfer_lists(uhci_t *instance); 94 static int uhci_init_mem_structures(uhci_t *instance); 95 static void uhci_init_hw(uhci_t *instance); 96 97 static int uhci_interrupt_emulator(void *arg); 98 static int uhci_debug_checker(void *arg); 99 100 static bool allowed_usb_packet( 101 bool low_speed, usb_transfer_type_t, size_t size); 102 103 104 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size) 105 { 106 assert(reg_size >= sizeof(regs_t)); 107 int ret; 108 109 static ddf_dev_ops_t uhci_hc_ops = { 110 .interfaces[USB_DEV_IFACE] = &usb_iface, 111 .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */ 112 }; 113 /*----------------------------------------------------------------------------*/ 114 /** Get root hub hw resources (I/O registers). 115 * 116 * @param[in] fun Root hub function. 117 * @return Pointer to the resource list used by the root hub. 118 */ 119 static hw_resource_list_t *get_resource_list(ddf_fun_t *fun) 120 { 121 assert(fun); 122 return &((uhci_rh_t*)fun->driver_data)->resource_list; 123 } 124 /*----------------------------------------------------------------------------*/ 125 static hw_res_ops_t hw_res_iface = { 126 .get_resource_list = get_resource_list, 127 .enable_interrupt = NULL 128 }; 129 /*----------------------------------------------------------------------------*/ 130 static ddf_dev_ops_t uhci_rh_ops = { 131 .interfaces[USB_DEV_IFACE] = &usb_iface, 132 .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface 133 }; 134 /*----------------------------------------------------------------------------*/ 135 /** Initialize hc and rh ddf structures and their respective drivers. 136 * 137 * @param[in] instance UHCI structure to use. 138 * @param[in] device DDF instance of the device to use. 139 * 140 * This function does all the preparatory work for hc and rh drivers: 141 * - gets device hw resources 142 * - disables UHCI legacy support 143 * - asks for interrupt 144 * - registers interrupt handler 145 */ 146 int uhci_init(uhci_t *instance, ddf_dev_t *device) 147 { 148 assert(instance); 149 instance->hc_fun = NULL; 150 instance->rh_fun = NULL; 109 151 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \ 110 if (ret != EOK) { \ 111 usb_log_error(message); \ 112 if (instance->ddf_instance) \ 113 ddf_fun_destroy(instance->ddf_instance); \ 114 return ret; \ 115 } else (void) 0 116 117 /* Create UHCI function. */ 118 instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci"); 119 ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK; 120 CHECK_RET_DEST_FUN_RETURN(ret, 121 "Failed to create UHCI device function.\n"); 122 123 instance->ddf_instance->ops = &uhci_ops; 124 instance->ddf_instance->driver_data = instance; 125 126 ret = ddf_fun_bind(instance->ddf_instance); 152 if (ret != EOK) { \ 153 usb_log_error(message); \ 154 if (instance->hc_fun) \ 155 ddf_fun_destroy(instance->hc_fun); \ 156 if (instance->rh_fun) \ 157 ddf_fun_destroy(instance->rh_fun); \ 158 return ret; \ 159 } 160 161 uintptr_t io_reg_base = 0; 162 size_t io_reg_size = 0; 163 int irq = 0; 164 165 int ret = 166 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 167 CHECK_RET_DEST_FUN_RETURN(ret, 168 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 169 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 170 io_reg_base, io_reg_size, irq); 171 172 ret = pci_disable_legacy(device); 173 CHECK_RET_DEST_FUN_RETURN(ret, 174 "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret)); 175 176 bool interrupts = false; 177 ret = pci_enable_interrupts(device); 178 if (ret != EOK) { 179 usb_log_warning( 180 "Failed(%d) to enable interrupts, fall back to polling.\n", 181 ret); 182 } else { 183 usb_log_debug("Hw interrupts enabled.\n"); 184 interrupts = true; 185 } 186 187 instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc"); 188 ret = (instance->hc_fun == NULL) ? ENOMEM : EOK; 189 CHECK_RET_DEST_FUN_RETURN(ret, 190 "Failed(%d) to create HC function.\n", ret); 191 192 ret = uhci_hc_init(&instance->hc, instance->hc_fun, 193 (void*)io_reg_base, io_reg_size, interrupts); 194 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 195 instance->hc_fun->ops = &uhci_hc_ops; 196 instance->hc_fun->driver_data = &instance->hc; 197 ret = ddf_fun_bind(instance->hc_fun); 127 198 CHECK_RET_DEST_FUN_RETURN(ret, 128 199 "Failed(%d) to bind UHCI device function: %s.\n", 129 200 ret, str_error(ret)); 130 131 /* allow access to hc control registers */ 132 regs_t *io; 133 ret = pio_enable(regs, reg_size, (void**)&io); 134 CHECK_RET_DEST_FUN_RETURN(ret, 135 "Failed(%d) to gain access to registers at %p: %s.\n", 136 ret, str_error(ret), io); 137 instance->registers = io; 138 usb_log_debug("Device registers at %p(%u) accessible.\n", 139 io, reg_size); 140 141 ret = uhci_init_mem_structures(instance); 142 CHECK_RET_DEST_FUN_RETURN(ret, 143 "Failed to initialize UHCI memory structures.\n"); 144 145 uhci_init_hw(instance); 146 instance->cleaner = 147 fibril_create(uhci_interrupt_emulator, instance); 148 fibril_add_ready(instance->cleaner); 149 150 instance->debug_checker = fibril_create(uhci_debug_checker, instance); 151 fibril_add_ready(instance->debug_checker); 152 153 usb_log_info("Started UHCI driver.\n"); 201 #undef CHECK_RET_HC_RETURN 202 203 #define CHECK_RET_FINI_RETURN(ret, message...) \ 204 if (ret != EOK) { \ 205 usb_log_error(message); \ 206 if (instance->hc_fun) \ 207 ddf_fun_destroy(instance->hc_fun); \ 208 if (instance->rh_fun) \ 209 ddf_fun_destroy(instance->rh_fun); \ 210 uhci_hc_fini(&instance->hc); \ 211 return ret; \ 212 } 213 214 /* It does no harm if we register this on polling */ 215 ret = register_interrupt_handler(device, irq, irq_handler, 216 &instance->hc.interrupt_code); 217 CHECK_RET_FINI_RETURN(ret, 218 "Failed(%d) to register interrupt handler.\n", ret); 219 220 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh"); 221 ret = (instance->rh_fun == NULL) ? ENOMEM : EOK; 222 CHECK_RET_FINI_RETURN(ret, 223 "Failed(%d) to create root hub function.\n", ret); 224 225 ret = uhci_rh_init(&instance->rh, instance->rh_fun, 226 (uintptr_t)instance->hc.registers + 0x10, 4); 227 CHECK_RET_FINI_RETURN(ret, 228 "Failed(%d) to setup UHCI root hub.\n", ret); 229 230 instance->rh_fun->ops = &uhci_rh_ops; 231 instance->rh_fun->driver_data = &instance->rh; 232 ret = ddf_fun_bind(instance->rh_fun); 233 CHECK_RET_FINI_RETURN(ret, 234 "Failed(%d) to register UHCI root hub.\n", ret); 235 154 236 return EOK; 155 #undef CHECK_RET_DEST_FUN_RETURN 156 } 157 /*----------------------------------------------------------------------------*/ 158 void uhci_init_hw(uhci_t *instance) 159 { 160 assert(instance); 161 162 /* reset everything, who knows what touched it before us */ 163 pio_write_16(&instance->registers->usbcmd, UHCI_CMD_GLOBAL_RESET); 164 async_usleep(10000); /* 10ms according to USB spec */ 165 pio_write_16(&instance->registers->usbcmd, 0); 166 167 /* reset hc, all states and counters */ 168 pio_write_16(&instance->registers->usbcmd, UHCI_CMD_HCRESET); 169 while ((pio_read_16(&instance->registers->usbcmd) & UHCI_CMD_HCRESET) != 0) 170 { async_usleep(10); } 171 172 /* set framelist pointer */ 173 const uint32_t pa = addr_to_phys(instance->frame_list); 174 pio_write_32(&instance->registers->flbaseadd, pa); 175 176 /* enable all interrupts, but resume interrupt */ 177 pio_write_16(&instance->registers->usbintr, 178 UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET); 179 180 /* Start the hc with large(64B) packet FSBR */ 181 pio_write_16(&instance->registers->usbcmd, 182 UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE); 183 } 184 /*----------------------------------------------------------------------------*/ 185 int uhci_init_mem_structures(uhci_t *instance) 186 { 187 assert(instance); 188 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \ 189 if (ret != EOK) { \ 190 usb_log_error(message); \ 191 if (instance->interrupt_code.cmds != NULL) \ 192 free(instance->interrupt_code.cmds); \ 193 return ret; \ 194 } else (void) 0 195 196 /* init interrupt code */ 197 instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds)); 198 int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK; 199 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to allocate interrupt cmds space.\n"); 200 201 { 202 irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds; 203 memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds)); 204 interrupt_commands[0].addr = (void*)&instance->registers->usbsts; 205 interrupt_commands[1].addr = (void*)&instance->registers->usbsts; 206 instance->interrupt_code.cmdcount = 207 sizeof(uhci_cmds) / sizeof(irq_cmd_t); 208 } 209 210 /* init transfer lists */ 211 ret = uhci_init_transfer_lists(instance); 212 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to initialize transfer lists.\n"); 213 usb_log_debug("Initialized transfer lists.\n"); 214 215 /* frame list initialization */ 216 instance->frame_list = get_page(); 217 ret = instance ? EOK : ENOMEM; 218 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n"); 219 usb_log_debug("Initialized frame list.\n"); 220 221 /* initialize all frames to point to the first queue head */ 222 const uint32_t queue = 223 instance->transfers_interrupt.queue_head_pa 224 | LINK_POINTER_QUEUE_HEAD_FLAG; 225 226 unsigned i = 0; 227 for(; i < UHCI_FRAME_LIST_COUNT; ++i) { 228 instance->frame_list[i] = queue; 229 } 230 231 /* init address keeper(libusb) */ 232 device_keeper_init(&instance->device_manager); 233 usb_log_debug("Initialized device manager.\n"); 234 235 return EOK; 236 #undef CHECK_RET_DEST_CMDS_RETURN 237 } 238 /*----------------------------------------------------------------------------*/ 239 int uhci_init_transfer_lists(uhci_t *instance) 240 { 241 assert(instance); 242 #define CHECK_RET_CLEAR_RETURN(ret, message...) \ 243 if (ret != EOK) { \ 244 usb_log_error(message); \ 245 transfer_list_fini(&instance->transfers_bulk_full); \ 246 transfer_list_fini(&instance->transfers_control_full); \ 247 transfer_list_fini(&instance->transfers_control_slow); \ 248 transfer_list_fini(&instance->transfers_interrupt); \ 249 return ret; \ 250 } else (void) 0 251 252 /* initialize TODO: check errors */ 253 int ret; 254 ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL"); 255 CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list."); 256 257 ret = transfer_list_init(&instance->transfers_control_full, "CONTROL_FULL"); 258 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list."); 259 260 ret = transfer_list_init(&instance->transfers_control_slow, "CONTROL_SLOW"); 261 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list."); 262 263 ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT"); 264 CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list."); 265 266 transfer_list_set_next(&instance->transfers_control_full, 267 &instance->transfers_bulk_full); 268 transfer_list_set_next(&instance->transfers_control_slow, 269 &instance->transfers_control_full); 270 transfer_list_set_next(&instance->transfers_interrupt, 271 &instance->transfers_control_slow); 272 273 /*FSBR*/ 274 #ifdef FSBR 275 transfer_list_set_next(&instance->transfers_bulk_full, 276 &instance->transfers_control_full); 277 #endif 278 279 instance->transfers[0][USB_TRANSFER_INTERRUPT] = 280 &instance->transfers_interrupt; 281 instance->transfers[1][USB_TRANSFER_INTERRUPT] = 282 &instance->transfers_interrupt; 283 instance->transfers[0][USB_TRANSFER_CONTROL] = 284 &instance->transfers_control_full; 285 instance->transfers[1][USB_TRANSFER_CONTROL] = 286 &instance->transfers_control_slow; 287 instance->transfers[0][USB_TRANSFER_BULK] = 288 &instance->transfers_bulk_full; 289 290 return EOK; 291 #undef CHECK_RET_CLEAR_RETURN 292 } 293 /*----------------------------------------------------------------------------*/ 294 int uhci_schedule(uhci_t *instance, batch_t *batch) 295 { 296 assert(instance); 297 assert(batch); 298 const int low_speed = (batch->speed == USB_SPEED_LOW); 299 if (!allowed_usb_packet( 300 low_speed, batch->transfer_type, batch->max_packet_size)) { 301 usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n", 302 low_speed ? "LOW" : "FULL" , batch->transfer_type, 303 batch->max_packet_size); 304 return ENOTSUP; 305 } 306 /* TODO: check available bandwith here */ 307 308 transfer_list_t *list = 309 instance->transfers[low_speed][batch->transfer_type]; 310 assert(list); 311 transfer_list_add_batch(list, batch); 312 313 return EOK; 314 } 315 /*----------------------------------------------------------------------------*/ 316 void uhci_interrupt(uhci_t *instance, uint16_t status) 317 { 318 assert(instance); 319 transfer_list_remove_finished(&instance->transfers_interrupt); 320 transfer_list_remove_finished(&instance->transfers_control_slow); 321 transfer_list_remove_finished(&instance->transfers_control_full); 322 transfer_list_remove_finished(&instance->transfers_bulk_full); 323 } 324 /*----------------------------------------------------------------------------*/ 325 int uhci_interrupt_emulator(void* arg) 326 { 327 usb_log_debug("Started interrupt emulator.\n"); 328 uhci_t *instance = (uhci_t*)arg; 329 assert(instance); 330 331 while (1) { 332 uint16_t status = pio_read_16(&instance->registers->usbsts); 333 if (status != 0) 334 usb_log_debug2("UHCI status: %x.\n", status); 335 status |= 1; 336 uhci_interrupt(instance, status); 337 pio_write_16(&instance->registers->usbsts, 0x1f); 338 async_usleep(UHCI_CLEANER_TIMEOUT * 5); 339 } 340 return EOK; 341 } 342 /*---------------------------------------------------------------------------*/ 343 int uhci_debug_checker(void *arg) 344 { 345 uhci_t *instance = (uhci_t*)arg; 346 assert(instance); 347 348 #define QH(queue) \ 349 instance->transfers_##queue.queue_head 350 351 while (1) { 352 const uint16_t cmd = pio_read_16(&instance->registers->usbcmd); 353 const uint16_t sts = pio_read_16(&instance->registers->usbsts); 354 const uint16_t intr = 355 pio_read_16(&instance->registers->usbintr); 356 357 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 358 usb_log_debug2("Command: %X Status: %X Intr: %x\n", 359 cmd, sts, intr); 360 } 361 362 uintptr_t frame_list = 363 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 364 if (frame_list != addr_to_phys(instance->frame_list)) { 365 usb_log_debug("Framelist address: %p vs. %p.\n", 366 frame_list, addr_to_phys(instance->frame_list)); 367 } 368 369 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff; 370 usb_log_debug2("Framelist item: %d \n", frnum ); 371 372 uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf); 373 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 374 if (expected_pa != real_pa) { 375 usb_log_debug("Interrupt QH: %p vs. %p.\n", 376 expected_pa, real_pa); 377 } 378 379 expected_pa = QH(interrupt)->next_queue & (~0xf); 380 real_pa = addr_to_phys(QH(control_slow)); 381 if (expected_pa != real_pa) { 382 usb_log_debug("Control Slow QH: %p vs. %p.\n", 383 expected_pa, real_pa); 384 } 385 386 expected_pa = QH(control_slow)->next_queue & (~0xf); 387 real_pa = addr_to_phys(QH(control_full)); 388 if (expected_pa != real_pa) { 389 usb_log_debug("Control Full QH: %p vs. %p.\n", 390 expected_pa, real_pa); 391 } 392 393 expected_pa = QH(control_full)->next_queue & (~0xf); 394 real_pa = addr_to_phys(QH(bulk_full)); 395 if (expected_pa != real_pa ) { 396 usb_log_debug("Bulk QH: %p vs. %p.\n", 397 expected_pa, real_pa); 398 } 399 async_usleep(UHCI_DEBUGER_TIMEOUT); 400 } 401 return 0; 402 #undef QH 403 } 404 /*----------------------------------------------------------------------------*/ 405 bool allowed_usb_packet( 406 bool low_speed, usb_transfer_type_t transfer, size_t size) 407 { 408 /* see USB specification chapter 5.5-5.8 for magic numbers used here */ 409 switch(transfer) 410 { 411 case USB_TRANSFER_ISOCHRONOUS: 412 return (!low_speed && size < 1024); 413 case USB_TRANSFER_INTERRUPT: 414 return size <= (low_speed ? 8 : 64); 415 case USB_TRANSFER_CONTROL: /* device specifies its own max size */ 416 return (size <= (low_speed ? 8 : 64)); 417 case USB_TRANSFER_BULK: /* device specifies its own max size */ 418 return (!low_speed && size <= 64); 419 } 420 return false; 237 #undef CHECK_RET_FINI_RETURN 421 238 } 422 239 /** -
uspace/drv/uhci-hcd/uhci.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver main structure for both host controller and root-hub. 34 34 */ 35 35 #ifndef DRV_UHCI_UHCI_H 36 36 #define DRV_UHCI_UHCI_H 37 #include <ddi.h> 38 #include <ddf/driver.h> 37 39 38 #include <fibril.h> 39 #include <fibril_synch.h> 40 #include <adt/list.h> 41 #include <ddi.h> 42 43 #include <usbhc_iface.h> 44 45 #include "batch.h" 46 #include "transfer_list.h" 47 #include "utils/device_keeper.h" 48 49 typedef struct uhci_regs { 50 uint16_t usbcmd; 51 #define UHCI_CMD_MAX_PACKET (1 << 7) 52 #define UHCI_CMD_CONFIGURE (1 << 6) 53 #define UHCI_CMD_DEBUG (1 << 5) 54 #define UHCI_CMD_FORCE_GLOBAL_RESUME (1 << 4) 55 #define UHCI_CMD_FORCE_GLOBAL_SUSPEND (1 << 3) 56 #define UHCI_CMD_GLOBAL_RESET (1 << 2) 57 #define UHCI_CMD_HCRESET (1 << 1) 58 #define UHCI_CMD_RUN_STOP (1 << 0) 59 60 uint16_t usbsts; 61 #define UHCI_STATUS_HALTED (1 << 5) 62 #define UHCI_STATUS_PROCESS_ERROR (1 << 4) 63 #define UHCI_STATUS_SYSTEM_ERROR (1 << 3) 64 #define UHCI_STATUS_RESUME (1 << 2) 65 #define UHCI_STATUS_ERROR_INTERRUPT (1 << 1) 66 #define UHCI_STATUS_INTERRUPT (1 << 0) 67 68 uint16_t usbintr; 69 #define UHCI_INTR_SHORT_PACKET (1 << 3) 70 #define UHCI_INTR_COMPLETE (1 << 2) 71 #define UHCI_INTR_RESUME (1 << 1) 72 #define UHCI_INTR_CRC (1 << 0) 73 74 uint16_t frnum; 75 uint32_t flbaseadd; 76 uint8_t sofmod; 77 } regs_t; 78 79 #define UHCI_FRAME_LIST_COUNT 1024 80 #define UHCI_CLEANER_TIMEOUT 10000 81 #define UHCI_DEBUGER_TIMEOUT 5000000 40 #include "uhci_hc.h" 41 #include "uhci_rh.h" 82 42 83 43 typedef struct uhci { 84 device_keeper_t device_manager; 44 ddf_fun_t *hc_fun; 45 ddf_fun_t *rh_fun; 85 46 86 volatile regs_t *registers; 87 88 link_pointer_t *frame_list; 89 90 transfer_list_t transfers_bulk_full; 91 transfer_list_t transfers_control_full; 92 transfer_list_t transfers_control_slow; 93 transfer_list_t transfers_interrupt; 94 95 transfer_list_t *transfers[2][4]; 96 97 irq_code_t interrupt_code; 98 99 fid_t cleaner; 100 fid_t debug_checker; 101 102 ddf_fun_t *ddf_instance; 47 uhci_hc_t hc; 48 uhci_rh_t rh; 103 49 } uhci_t; 104 50 105 /* init uhci specifics in device.driver_data */ 106 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size); 107 108 static inline void uhci_fini(uhci_t *instance) {}; 109 110 int uhci_schedule(uhci_t *instance, batch_t *batch); 111 112 void uhci_interrupt(uhci_t *instance, uint16_t status); 113 114 static inline uhci_t * dev_to_uhci(ddf_dev_t *dev) 115 { return (uhci_t*)dev->driver_data; } 116 117 static inline uhci_t * fun_to_uhci(ddf_fun_t *fun) 118 { return (uhci_t*)fun->driver_data; } 119 51 int uhci_init(uhci_t *instance, ddf_dev_t *device); 120 52 121 53 #endif -
uspace/drv/uhci-hcd/uhci_rh.c
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0 Vojtech Horky2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup libusb 28 /** @addtogroup drvusbuhci 30 29 * @{ 31 30 */ 32 31 /** @file 33 * @brief Common definitions for both HC driver and hub driver.32 * @brief UHCI driver 34 33 */ 35 #ifndef LIBUSB_HCDHUBD_PRIVATE_H_ 36 #define LIBUSB_HCDHUBD_PRIVATE_H_ 34 #include <assert.h> 35 #include <errno.h> 36 #include <str_error.h> 37 #include <stdio.h> 37 38 38 #define USB_HUB_DEVICE_NAME "usbhub" 39 #define USB_KBD_DEVICE_NAME "hid" 39 #include <usb/debug.h> 40 40 41 extern link_t hc_list; 42 extern usb_hc_driver_t *hc_driver; 41 #include "uhci_rh.h" 42 #include "uhci_hc.h" 43 43 44 extern usbhc_iface_t usbhc_interface; 44 /** Root hub initialization 45 * @param[in] instance RH structure to initialize 46 * @param[in] fun DDF function representing UHCI root hub 47 * @param[in] reg_addr Address of root hub status and control registers. 48 * @param[in] reg_size Size of accessible address space. 49 * @return Error code. 50 */ 51 int uhci_rh_init( 52 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size) 53 { 54 assert(fun); 45 55 46 usb_address_t usb_get_address_by_handle(devman_handle_t); 47 int usb_add_hc_device(device_t *); 56 char *match_str = NULL; 57 int ret = asprintf(&match_str, "usb&uhci&root-hub"); 58 if (ret < 0) { 59 usb_log_error("Failed to create root hub match string.\n"); 60 return ENOMEM; 61 } 48 62 49 /** lowest allowed usb address */ 50 extern int usb_lowest_address; 63 ret = ddf_fun_add_match_id(fun, match_str, 100); 64 if (ret != EOK) { 65 usb_log_error("Failed(%d) to add root hub match id: %s\n", 66 ret, str_error(ret)); 67 return ret; 68 } 51 69 52 /** highest allowed usb address */ 53 extern int usb_highest_address; 70 hw_resource_list_t *resource_list = &instance->resource_list; 71 resource_list->count = 1; 72 resource_list->resources = &instance->io_regs; 73 assert(resource_list->resources); 74 instance->io_regs.type = IO_RANGE; 75 instance->io_regs.res.io_range.address = reg_addr; 76 instance->io_regs.res.io_range.size = reg_size; 77 instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN; 54 78 55 /** 56 * @brief initialize address list of given hcd 57 * 58 * This function should be used only for hcd initialization. 59 * It creates interval list of free addresses, thus it is initialized as 60 * list with one interval with whole address space. Using an address shrinks 61 * the interval, freeing an address extends an interval or creates a 62 * new one. 63 * 64 * @param hcd 65 * @return 66 */ 67 void usb_create_address_list(usb_hc_device_t * hcd); 68 69 70 71 72 73 74 #endif 79 return EOK; 80 } 75 81 /** 76 82 * @} -
uspace/drv/uhci-hcd/uhci_rh.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 33 33 * @brief UHCI driver 34 34 */ 35 #ifndef DRV_UHCI_ ROOT_HUB_H36 #define DRV_UHCI_ ROOT_HUB_H35 #ifndef DRV_UHCI_UHCI_RH_H 36 #define DRV_UHCI_UHCI_RH_H 37 37 38 38 #include <ddf/driver.h> 39 #include <ops/hw_res.h> 39 40 40 int setup_root_hub(ddf_fun_t **device, ddf_dev_t *hc); 41 typedef struct uhci_rh { 42 hw_resource_list_t resource_list; 43 hw_resource_t io_regs; 44 } uhci_rh_t; 45 46 int uhci_rh_init( 47 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size); 41 48 42 49 #endif -
uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
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 */ … … 46 46 #define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */ 47 47 48 #define LINK_POINTER_QH(address) \ 49 ((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG) 50 48 51 #endif 49 52 /** -
uspace/drv/uhci-hcd/uhci_struct/queue_head.h
r3e7b7cd r72af8da 1 2 1 /* 3 2 * Copyright (c) 2010 Jan Vesely … … 27 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 27 */ 29 /** @addtogroup usb28 /** @addtogroup drv usbuhcihc 30 29 * @{ 31 30 */ … … 43 42 44 43 typedef struct queue_head { 45 volatile link_pointer_t next _queue;44 volatile link_pointer_t next; 46 45 volatile link_pointer_t element; 47 } __attribute__((packed)) queue_head_t; 48 49 static inline void queue_head_init(queue_head_t *instance) 46 } __attribute__((packed)) qh_t; 47 /*----------------------------------------------------------------------------*/ 48 /** Initialize queue head structure 49 * 50 * @param[in] instance qh_t structure to initialize. 51 * 52 * Sets both pointer to terminal NULL. 53 */ 54 static inline void qh_init(qh_t *instance) 50 55 { 51 56 assert(instance); 52 57 53 58 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 54 instance->next _queue= 0 | LINK_POINTER_TERMINATE_FLAG;59 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 55 60 } 56 57 static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa) 61 /*----------------------------------------------------------------------------*/ 62 /** Set queue head next pointer 63 * 64 * @param[in] instance qh_t structure to use. 65 * @param[in] pa Physical address of the next queue head. 66 * 67 * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal 68 * NULL. 69 */ 70 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa) 58 71 { 59 if (pa) { 60 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 72 /* Address is valid and not terminal */ 73 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 74 instance->next = (pa & LINK_POINTER_ADDRESS_MASK) 61 75 | LINK_POINTER_QUEUE_HEAD_FLAG; 76 } else { 77 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 62 78 } 63 79 } 64 65 static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa) 80 /*----------------------------------------------------------------------------*/ 81 /** Set queue head element pointer 82 * 83 * @param[in] instance qh_t structure to initialize. 84 * @param[in] pa Physical address of the next queue head. 85 * 86 * Adds proper flag. If the pointer is NULL or terminal, sets element 87 * to terminal NULL. 88 */ 89 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa) 66 90 { 67 if (pa) { 68 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 91 /* Address is valid and not terminal */ 92 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 93 instance->element = (pa & LINK_POINTER_ADDRESS_MASK) 69 94 | LINK_POINTER_QUEUE_HEAD_FLAG; 95 } else { 96 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 70 97 } 71 98 } 72 73 static inline void queue_head_element_td(queue_head_t *instance, uint32_t pa) 99 /*----------------------------------------------------------------------------*/ 100 /** Set queue head element pointer 101 * 102 * @param[in] instance qh_t structure to initialize. 103 * @param[in] pa Physical address of the TD structure. 104 * 105 * Adds proper flag. If the pointer is NULL or terminal, sets element 106 * to terminal NULL. 107 */ 108 static inline void qh_set_element_td(qh_t *instance, uint32_t pa) 74 109 { 75 if (pa ) {110 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 76 111 instance->element = (pa & LINK_POINTER_ADDRESS_MASK); 112 } else { 113 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 77 114 } 78 115 } 79 80 static inline queue_head_t * queue_head_get() {81 queue_head_t *ret = malloc32(sizeof(queue_head_t));82 if (ret)83 queue_head_init(ret);84 return ret;85 }86 87 static inline void queue_head_dispose(queue_head_t *head)88 { free32(head); }89 90 116 91 117 #endif -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.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 */ … … 38 38 #include "utils/malloc32.h" 39 39 40 void transfer_descriptor_init(transfer_descriptor_t *instance, 41 int error_count, size_t size, bool toggle, bool isochronous, bool low_speed, 42 usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next) 40 /** Initialize Transfer Descriptor 41 * 42 * @param[in] instance Memory place to initialize. 43 * @param[in] err_count Number of retries hc should attempt. 44 * @param[in] size Size of data source. 45 * @param[in] toggle Value of toggle bit. 46 * @param[in] iso True if TD represents Isochronous transfer. 47 * @param[in] low_speed Target device's speed. 48 * @param[in] target Address and endpoint receiving the transfer. 49 * @param[in] pid Packet identification (SETUP, IN or OUT). 50 * @param[in] buffer Source of data. 51 * @param[in] next Net TD in transaction. 52 * @return Error code. 53 * 54 * Uses a mix of supplied and default values. 55 * Implicit values: 56 * - all TDs have vertical flag set (makes transfers to endpoints atomic) 57 * - in the error field only active it is set 58 * - if the packet uses PID_IN and is not isochronous SPD is set 59 * 60 * Dumps 8 bytes of buffer if PID_SETUP is used. 61 */ 62 void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso, 63 bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer, 64 td_t *next) 43 65 { 44 66 assert(instance); 67 assert(size < 1024); 68 assert((pid == USB_PID_SETUP) || (pid == USB_PID_IN) 69 || (pid == USB_PID_OUT)); 45 70 46 71 instance->next = 0 … … 49 74 50 75 instance->status = 0 51 | ((error_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 52 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 53 | TD_STATUS_ERROR_ACTIVE; 76 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 77 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 78 | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0) 79 | TD_STATUS_ERROR_ACTIVE; 54 80 55 assert(size < 1024); 81 if (pid == USB_PID_IN && !iso) { 82 instance->status |= TD_STATUS_SPD_FLAG; 83 } 84 56 85 instance->device = 0 57 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)58 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)59 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)60 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)61 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);86 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS) 87 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0) 88 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS) 89 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS) 90 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS); 62 91 63 92 instance->buffer_ptr = 0; … … 67 96 } 68 97 69 usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n", 70 instance->next, instance->status, instance->device, 71 instance->buffer_ptr, buffer); 98 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n", 99 instance, instance->next, instance->status, instance->device, 100 instance->buffer_ptr, buffer); 101 td_print_status(instance); 102 if (pid == USB_PID_SETUP) { 103 usb_log_debug("SETUP BUFFER: %s\n", 104 usb_debug_str_buffer(buffer, 8, 8)); 105 } 72 106 } 73 107 /*----------------------------------------------------------------------------*/ 74 int transfer_descriptor_status(transfer_descriptor_t *instance) 108 /** Convert TD status into standard error code 109 * 110 * @param[in] instance TD structure to use. 111 * @return Error code. 112 */ 113 int td_status(td_t *instance) 75 114 { 76 115 assert(instance); … … 96 135 return EOK; 97 136 } 137 /*----------------------------------------------------------------------------*/ 138 /** Print values in status field (dw1) in a human readable way. 139 * 140 * @param[in] instance TD structure to use. 141 */ 142 void td_print_status(td_t *instance) 143 { 144 assert(instance); 145 const uint32_t s = instance->status; 146 usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n", 147 instance, instance->status, 148 (s & TD_STATUS_SPD_FLAG) ? " SPD," : "", 149 (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK, 150 (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "", 151 (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "", 152 (s & TD_STATUS_IOC_FLAG) ? " IOC," : "", 153 (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "", 154 (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "", 155 (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "", 156 (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "", 157 (s & TD_STATUS_ERROR_NAK) ? " NAK," : "", 158 (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "", 159 (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "", 160 (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "", 161 (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK 162 ); 163 } 98 164 /** 99 165 * @} -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ … … 45 45 46 46 volatile uint32_t status; 47 48 47 #define TD_STATUS_RESERVED_MASK 0xc000f800 49 48 #define TD_STATUS_SPD_FLAG ( 1 << 29 ) 50 49 #define TD_STATUS_ERROR_COUNT_POS ( 27 ) 51 50 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 ) 52 #define TD_STATUS_ERROR_COUNT_DEFAULT 353 51 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 ) 54 52 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 ) 55 #define TD_STATUS_ COMPLETE_INTERRUPT_FLAG ( 1 << 24 )53 #define TD_STATUS_IOC_FLAG ( 1 << 24 ) 56 54 57 55 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23 ) … … 70 68 71 69 volatile uint32_t device; 72 73 70 #define TD_DEVICE_MAXLEN_POS 21 74 71 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff ) … … 85 82 86 83 /* there is 16 bytes of data available here, according to UHCI 87 * Design guide, according to linux kernel the hardware does not care 88 * we don't use it anyway84 * Design guide, according to linux kernel the hardware does not care, 85 * it just needs to be aligned, we don't use it anyway 89 86 */ 90 } __attribute__((packed)) t ransfer_descriptor_t;87 } __attribute__((packed)) td_t; 91 88 92 89 93 void t ransfer_descriptor_init(transfer_descriptor_t *instance,94 int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,95 usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next);90 void td_init(td_t *instance, int error_count, size_t size, bool toggle, 91 bool iso, bool low_speed, usb_target_t target, usb_packet_id pid, 92 void *buffer, td_t *next); 96 93 97 int t ransfer_descriptor_status(transfer_descriptor_t *instance);94 int td_status(td_t *instance); 98 95 99 static inline size_t transfer_descriptor_actual_size( 100 transfer_descriptor_t *instance) 96 void td_print_status(td_t *instance); 97 /*----------------------------------------------------------------------------*/ 98 /** Helper function for parsing actual size out of TD. 99 * 100 * @param[in] instance TD structure to use. 101 * @return Parsed actual size. 102 */ 103 static inline size_t td_act_size(td_t *instance) 101 104 { 102 105 assert(instance); 106 const uint32_t s = instance->status; 107 return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK; 108 } 109 /*----------------------------------------------------------------------------*/ 110 /** Check whether less than max data were recieved and packet is marked as SPD. 111 * 112 * @param[in] instance TD structure to use. 113 * @return True if packet is short (less than max bytes and SPD set), false 114 * otherwise. 115 */ 116 static inline bool td_is_short(td_t *instance) 117 { 118 const size_t act_size = td_act_size(instance); 119 const size_t max_size = 120 ((instance->device >> TD_DEVICE_MAXLEN_POS) + 1) 121 & TD_DEVICE_MAXLEN_MASK; 103 122 return 104 ( (instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;123 (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size; 105 124 } 106 107 static inline bool transfer_descriptor_is_active( 108 transfer_descriptor_t *instance) 125 /*----------------------------------------------------------------------------*/ 126 /** Helper function for parsing value of toggle bit. 127 * 128 * @param[in] instance TD structure to use. 129 * @return Toggle bit value. 130 */ 131 static inline int td_toggle(td_t *instance) 132 { 133 assert(instance); 134 return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0; 135 } 136 /*----------------------------------------------------------------------------*/ 137 /** Helper function for parsing value of active bit 138 * 139 * @param[in] instance TD structure to use. 140 * @return Active bit value. 141 */ 142 static inline bool td_is_active(td_t *instance) 109 143 { 110 144 assert(instance); 111 145 return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0; 112 146 } 147 /*----------------------------------------------------------------------------*/ 148 /** Helper function for setting IOC bit. 149 * 150 * @param[in] instance TD structure to use. 151 */ 152 static inline void td_set_ioc(td_t *instance) 153 { 154 assert(instance); 155 instance->status |= TD_STATUS_IOC_FLAG; 156 } 157 /*----------------------------------------------------------------------------*/ 113 158 #endif 114 159 /** -
uspace/drv/uhci-hcd/utils/device_keeper.c
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 35 35 #include <assert.h> 36 36 #include <errno.h> 37 #include <usb/debug.h> 37 38 38 39 #include "device_keeper.h" 39 40 40 41 /*----------------------------------------------------------------------------*/ 42 /** Initialize device keeper structure. 43 * 44 * @param[in] instance Memory place to initialize. 45 * 46 * Set all values to false/0. 47 */ 41 48 void device_keeper_init(device_keeper_t *instance) 42 49 { … … 49 56 instance->devices[i].occupied = false; 50 57 instance->devices[i].handle = 0; 51 } 52 } 53 /*----------------------------------------------------------------------------*/ 54 void device_keeper_reserve_default( 55 device_keeper_t *instance, usb_speed_t speed) 58 instance->devices[i].toggle_status = 0; 59 } 60 } 61 /*----------------------------------------------------------------------------*/ 62 /** Attempt to obtain address 0, blocks. 63 * 64 * @param[in] instance Device keeper structure to use. 65 * @param[in] speed Speed of the device requesting default address. 66 */ 67 void device_keeper_reserve_default(device_keeper_t *instance, usb_speed_t speed) 56 68 { 57 69 assert(instance); … … 66 78 } 67 79 /*----------------------------------------------------------------------------*/ 80 /** Attempt to obtain address 0, blocks. 81 * 82 * @param[in] instance Device keeper structure to use. 83 * @param[in] speed Speed of the device requesting default address. 84 */ 68 85 void device_keeper_release_default(device_keeper_t *instance) 69 86 { … … 75 92 } 76 93 /*----------------------------------------------------------------------------*/ 94 /** Check setup packet data for signs of toggle reset. 95 * 96 * @param[in] instance Device keeper structure to use. 97 * @param[in] target Device to receive setup packet. 98 * @param[in] data Setup packet data. 99 * 100 * Really ugly one. 101 */ 102 void device_keeper_reset_if_need( 103 device_keeper_t *instance, usb_target_t target, const unsigned char *data) 104 { 105 assert(instance); 106 fibril_mutex_lock(&instance->guard); 107 if (target.endpoint > 15 || target.endpoint < 0 108 || target.address >= USB_ADDRESS_COUNT || target.address < 0 109 || !instance->devices[target.address].occupied) { 110 fibril_mutex_unlock(&instance->guard); 111 usb_log_error("Invalid data when checking for toggle reset.\n"); 112 return; 113 } 114 115 switch (data[1]) 116 { 117 case 0x01: /*clear feature*/ 118 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */ 119 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) { 120 /* endpoint number is < 16, thus first byte is enough */ 121 instance->devices[target.address].toggle_status &= 122 ~(1 << data[4]); 123 } 124 break; 125 126 case 0x9: /* set configuration */ 127 case 0x11: /* set interface */ 128 /* target must be device */ 129 if ((data[0] & 0xf) == 0) { 130 instance->devices[target.address].toggle_status = 0; 131 } 132 break; 133 } 134 fibril_mutex_unlock(&instance->guard); 135 } 136 /*----------------------------------------------------------------------------*/ 137 /** Get current value of endpoint toggle. 138 * 139 * @param[in] instance Device keeper structure to use. 140 * @param[in] target Device and endpoint used. 141 * @return Error code 142 */ 143 int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target) 144 { 145 assert(instance); 146 int ret; 147 fibril_mutex_lock(&instance->guard); 148 if (target.endpoint > 15 || target.endpoint < 0 149 || target.address >= USB_ADDRESS_COUNT || target.address < 0 150 || !instance->devices[target.address].occupied) { 151 usb_log_error("Invalid data when asking for toggle value.\n"); 152 ret = EINVAL; 153 } else { 154 ret = (instance->devices[target.address].toggle_status 155 >> target.endpoint) & 1; 156 } 157 fibril_mutex_unlock(&instance->guard); 158 return ret; 159 } 160 /*----------------------------------------------------------------------------*/ 161 /** Set current value of endpoint toggle. 162 * 163 * @param[in] instance Device keeper structure to use. 164 * @param[in] target Device and endpoint used. 165 * @param[in] toggle Toggle value. 166 * @return Error code. 167 */ 168 int device_keeper_set_toggle( 169 device_keeper_t *instance, usb_target_t target, bool toggle) 170 { 171 assert(instance); 172 int ret; 173 fibril_mutex_lock(&instance->guard); 174 if (target.endpoint > 15 || target.endpoint < 0 175 || target.address >= USB_ADDRESS_COUNT || target.address < 0 176 || !instance->devices[target.address].occupied) { 177 usb_log_error("Invalid data when setting toggle value.\n"); 178 ret = EINVAL; 179 } else { 180 if (toggle) { 181 instance->devices[target.address].toggle_status |= (1 << target.endpoint); 182 } else { 183 instance->devices[target.address].toggle_status &= ~(1 << target.endpoint); 184 } 185 ret = EOK; 186 } 187 fibril_mutex_unlock(&instance->guard); 188 return ret; 189 } 190 /*----------------------------------------------------------------------------*/ 191 /** Get a free USB address 192 * 193 * @param[in] instance Device keeper structure to use. 194 * @param[in] speed Speed of the device requiring address. 195 * @return Free address, or error code. 196 */ 77 197 usb_address_t device_keeper_request( 78 198 device_keeper_t *instance, usb_speed_t speed) … … 96 216 instance->devices[new_address].occupied = true; 97 217 instance->devices[new_address].speed = speed; 218 instance->devices[new_address].toggle_status = 0; 98 219 instance->last_address = new_address; 99 220 fibril_mutex_unlock(&instance->guard); … … 101 222 } 102 223 /*----------------------------------------------------------------------------*/ 224 /** Bind USB address to devman handle. 225 * 226 * @param[in] instance Device keeper structure to use. 227 * @param[in] address Device address 228 * @param[in] handle Devman handle of the device. 229 */ 103 230 void device_keeper_bind( 104 231 device_keeper_t *instance, usb_address_t address, devman_handle_t handle) … … 113 240 } 114 241 /*----------------------------------------------------------------------------*/ 242 /** Release used USB address. 243 * 244 * @param[in] instance Device keeper structure to use. 245 * @param[in] address Device address 246 */ 115 247 void device_keeper_release(device_keeper_t *instance, usb_address_t address) 116 248 { … … 125 257 } 126 258 /*----------------------------------------------------------------------------*/ 259 /** Find USB address associated with the device 260 * 261 * @param[in] instance Device keeper structure to use. 262 * @param[in] handle Devman handle of the device seeking its address. 263 * @return USB Address, or error code. 264 */ 127 265 usb_address_t device_keeper_find( 128 266 device_keeper_t *instance, devman_handle_t handle) … … 142 280 } 143 281 /*----------------------------------------------------------------------------*/ 282 /** Get speed associated with the address 283 * 284 * @param[in] instance Device keeper structure to use. 285 * @param[in] address Address of the device. 286 * @return USB speed. 287 */ 144 288 usb_speed_t device_keeper_speed( 145 289 device_keeper_t *instance, usb_address_t address) -
uspace/drv/uhci-hcd/utils/device_keeper.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 44 44 usb_speed_t speed; 45 45 bool occupied; 46 uint16_t toggle_status; 46 47 devman_handle_t handle; 47 48 }; … … 55 56 56 57 void device_keeper_init(device_keeper_t *instance); 58 57 59 void device_keeper_reserve_default( 58 60 device_keeper_t *instance, usb_speed_t speed); 61 59 62 void device_keeper_release_default(device_keeper_t *instance); 63 64 void device_keeper_reset_if_need( 65 device_keeper_t *instance, usb_target_t target, const unsigned char *setup_data); 66 67 int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target); 68 69 int device_keeper_set_toggle( 70 device_keeper_t *instance, usb_target_t target, bool toggle); 60 71 61 72 usb_address_t device_keeper_request( 62 73 device_keeper_t *instance, usb_speed_t speed); 74 63 75 void device_keeper_bind( 64 76 device_keeper_t *instance, usb_address_t address, devman_handle_t handle); 77 65 78 void device_keeper_release(device_keeper_t *instance, usb_address_t address); 79 66 80 usb_address_t device_keeper_find( 67 81 device_keeper_t *instance, devman_handle_t handle); -
uspace/drv/uhci-hcd/utils/malloc32.h
r3e7b7cd r72af8da 35 35 #define DRV_UHCI_TRANSLATOR_H 36 36 37 #include <usb/usbmem.h>38 39 37 #include <assert.h> 40 38 #include <malloc.h> … … 45 43 #define UHCI_REQUIRED_PAGE_SIZE 4096 46 44 45 /** Get physical address translation 46 * 47 * @param[in] addr Virtual address to translate 48 * @return Physical address if exists, NULL otherwise. 49 */ 47 50 static inline uintptr_t addr_to_phys(void *addr) 48 51 { … … 50 53 int ret = as_get_physical_mapping(addr, &result); 51 54 52 assert(ret == 0); 55 if (ret != EOK) 56 return 0; 53 57 return (result | ((uintptr_t)addr & 0xfff)); 54 58 } 55 59 /*----------------------------------------------------------------------------*/ 60 /** Physical mallocator simulator 61 * 62 * @param[in] size Size of the required memory space 63 * @return Address of the alligned and big enough memory place, NULL on failure. 64 */ 56 65 static inline void * malloc32(size_t size) 57 66 { return memalign(UHCI_STRCUTURES_ALIGNMENT, size); } 58 59 static inline void * get_page() 67 /*----------------------------------------------------------------------------*/ 68 /** Physical mallocator simulator 69 * 70 * @param[in] addr Address of the place allocated by malloc32 71 */ 72 static inline void free32(void *addr) 73 { if (addr) free(addr); } 74 /*----------------------------------------------------------------------------*/ 75 /** Create 4KB page mapping 76 * 77 * @return Address of the mapped page, NULL on failure. 78 */ 79 static inline void * get_page(void) 60 80 { 61 81 void * free_address = as_get_mappable_page(UHCI_REQUIRED_PAGE_SIZE); 62 82 assert(free_address); 63 83 if (free_address == 0) 64 return 0;84 return NULL; 65 85 void* ret = 66 86 as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE, 67 87 AS_AREA_READ | AS_AREA_WRITE); 68 88 if (ret != free_address) 69 return 0;89 return NULL; 70 90 return ret; 71 91 } 72 73 static inline void free32(void *addr)74 { if (addr) free(addr); }75 92 76 93 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
