Changeset df6ded8 in mainline for uspace/drv/bus/usb/ehci
- Timestamp:
- 2018-02-28T16:37:50Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1b20da0
- Parents:
- f5e5f73 (diff), b2dca8de (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. - git-author:
- Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
- git-committer:
- Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
- Location:
- uspace/drv/bus/usb/ehci
- Files:
-
- 1 added
- 1 deleted
- 18 edited
- 1 moved
-
Makefile (modified) (1 diff)
-
ehci_batch.c (modified) (17 diffs)
-
ehci_batch.h (modified) (3 diffs)
-
ehci_bus.c (added)
-
ehci_bus.h (moved) (moved from uspace/drv/bus/usb/ehci/ehci_endpoint.h ) (3 diffs)
-
ehci_endpoint.c (deleted)
-
ehci_rh.c (modified) (13 diffs)
-
ehci_rh.h (modified) (2 diffs)
-
endpoint_list.c (modified) (7 diffs)
-
endpoint_list.h (modified) (3 diffs)
-
hc.c (modified) (21 diffs)
-
hc.h (modified) (5 diffs)
-
hw_struct/iso_transfer_descriptor.h (modified) (1 diff)
-
hw_struct/queue_head.c (modified) (4 diffs)
-
hw_struct/queue_head.h (modified) (2 diffs)
-
hw_struct/split_iso_transfer_descriptor.h (modified) (1 diff)
-
hw_struct/transfer_descriptor.c (modified) (5 diffs)
-
hw_struct/transfer_descriptor.h (modified) (3 diffs)
-
main.c (modified) (3 diffs)
-
res.c (modified) (10 diffs)
-
res.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ehci/Makefile
rf5e5f73 rdf6ded8 35 35 SOURCES = \ 36 36 ehci_batch.c \ 37 ehci_ endpoint.c \37 ehci_bus.c \ 38 38 ehci_rh.c \ 39 39 endpoint_list.c \ -
uspace/drv/bus/usb/ehci/ehci_batch.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2014 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 42 43 #include <usb/usb.h> 43 44 #include <usb/debug.h> 44 #include <usb/host/utils/malloc32.h>45 45 46 46 #include "ehci_batch.h" 47 #include "ehci_ endpoint.h"47 #include "ehci_bus.h" 48 48 49 49 /* The buffer pointer list in the qTD is long enough to support a maximum … … 53 53 #define EHCI_TD_MAX_TRANSFER (16 * 1024) 54 54 55 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t);55 static void (*const batch_setup[])(ehci_transfer_batch_t*); 56 56 57 57 /** Safely destructs ehci_transfer_batch_t structure … … 59 59 * @param[in] ehci_batch Instance to destroy. 60 60 */ 61 static void ehci_transfer_batch_dispose(ehci_transfer_batch_t *ehci_batch) 62 { 63 if (!ehci_batch) 64 return; 65 if (ehci_batch->tds) { 66 for (size_t i = 0; i < ehci_batch->td_count; ++i) { 67 free32(ehci_batch->tds[i]); 68 } 69 free(ehci_batch->tds); 70 } 71 usb_transfer_batch_destroy(ehci_batch->usb_batch); 72 free32(ehci_batch->device_buffer); 61 void ehci_transfer_batch_destroy(ehci_transfer_batch_t *ehci_batch) 62 { 63 assert(ehci_batch); 64 dma_buffer_free(&ehci_batch->ehci_dma_buffer); 65 usb_log_debug2("Batch(%p): disposed", ehci_batch); 73 66 free(ehci_batch); 74 usb_log_debug2("Batch(%p): disposed", ehci_batch);75 }76 77 /** Finishes usb_transfer_batch and destroys the structure.78 *79 * @param[in] uhci_batch Instance to finish and destroy.80 */81 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *ehci_batch)82 {83 assert(ehci_batch);84 assert(ehci_batch->usb_batch);85 usb_transfer_batch_finish(ehci_batch->usb_batch,86 ehci_batch->device_buffer + ehci_batch->usb_batch->setup_size);87 ehci_transfer_batch_dispose(ehci_batch);88 67 } 89 68 … … 94 73 * NULL otherwise. 95 74 * 75 */ 76 ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep) 77 { 78 assert(ep); 79 80 ehci_transfer_batch_t *ehci_batch = calloc(1, sizeof(ehci_transfer_batch_t)); 81 if (!ehci_batch) { 82 usb_log_error("Failed to allocate EHCI batch data."); 83 return NULL; 84 } 85 86 usb_transfer_batch_init(&ehci_batch->base, ep); 87 88 return ehci_batch; 89 } 90 91 /** Prepares a batch to be sent. 92 * 96 93 * Determines the number of needed transfer descriptors (TDs). 97 94 * Prepares a transport buffer (that is accessible by the hardware). 98 95 * Initializes parameters needed for the transfer and callback. 99 96 */ 100 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 101 { 102 assert(usb_batch); 103 104 ehci_transfer_batch_t *ehci_batch = 105 calloc(1, sizeof(ehci_transfer_batch_t)); 106 if (!ehci_batch) { 107 usb_log_error("Batch %p: Failed to allocate EHCI batch data.", 108 usb_batch); 109 goto dispose; 110 } 111 link_initialize(&ehci_batch->link); 112 ehci_batch->td_count = 113 (usb_batch->buffer_size + EHCI_TD_MAX_TRANSFER - 1) 114 / EHCI_TD_MAX_TRANSFER; 97 int ehci_transfer_batch_prepare(ehci_transfer_batch_t *ehci_batch) 98 { 99 assert(ehci_batch); 100 101 const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) 102 ? USB_SETUP_PACKET_SIZE 103 : 0; 104 105 const size_t size = ehci_batch->base.size; 106 107 /* Add TD left over by the previous transfer */ 108 ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh; 109 110 /* Determine number of TDs needed */ 111 ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1) 112 / EHCI_TD_MAX_TRANSFER; 115 113 116 114 /* Control transfer need Setup and Status stage */ 117 if ( usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {115 if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) { 118 116 ehci_batch->td_count += 2; 119 117 } 120 118 121 ehci_batch->tds = calloc(ehci_batch->td_count, sizeof(td_t*)); 122 if (!ehci_batch->tds) { 123 usb_log_error("Batch %p: Failed to allocate EHCI transfer " 124 "descriptors.", usb_batch); 125 goto dispose; 126 } 127 128 /* Add TD left over by the previous transfer */ 129 ehci_batch->qh = ehci_endpoint_get(usb_batch->ep)->qh; 130 131 for (unsigned i = 0; i < ehci_batch->td_count; ++i) { 132 ehci_batch->tds[i] = malloc32(sizeof(td_t)); 133 if (!ehci_batch->tds[i]) { 134 usb_log_error("Batch %p: Failed to allocate TD %d.", 135 usb_batch, i); 136 goto dispose; 137 } 138 memset(ehci_batch->tds[i], 0, sizeof(td_t)); 139 } 140 141 142 /* Mix setup stage and data together, we have enough space */ 143 if (usb_batch->setup_size + usb_batch->buffer_size > 0) { 144 /* Use one buffer for setup and data stage */ 145 ehci_batch->device_buffer = 146 malloc32(usb_batch->setup_size + usb_batch->buffer_size); 147 if (!ehci_batch->device_buffer) { 148 usb_log_error("Batch %p: Failed to allocate device " 149 "buffer", usb_batch); 150 goto dispose; 151 } 152 /* Copy setup data */ 153 memcpy(ehci_batch->device_buffer, usb_batch->setup_buffer, 154 usb_batch->setup_size); 155 /* Copy generic data */ 156 if (usb_batch->ep->direction != USB_DIRECTION_IN) 157 memcpy( 158 ehci_batch->device_buffer + usb_batch->setup_size, 159 usb_batch->buffer, usb_batch->buffer_size); 160 } 161 ehci_batch->usb_batch = usb_batch; 162 163 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch); 164 assert(batch_setup[usb_batch->ep->transfer_type]); 165 batch_setup[usb_batch->ep->transfer_type](ehci_batch, dir); 166 167 usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.\n", 168 usb_batch, usb_str_direction(dir), 169 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 170 171 return ehci_batch; 172 dispose: 173 ehci_transfer_batch_dispose(ehci_batch); 174 return NULL; 119 assert(ehci_batch->td_count > 0); 120 121 const size_t tds_size = ehci_batch->td_count * sizeof(td_t); 122 123 /* Mix setup stage and TDs together, we have enough space */ 124 if (dma_buffer_alloc(&ehci_batch->ehci_dma_buffer, tds_size + setup_size)) { 125 usb_log_error("Batch %p: Failed to allocate device buffer", 126 ehci_batch); 127 return ENOMEM; 128 } 129 130 /* Clean TDs */ 131 ehci_batch->tds = ehci_batch->ehci_dma_buffer.virt; 132 memset(ehci_batch->tds, 0, tds_size); 133 134 /* Copy setup data */ 135 ehci_batch->setup_buffer = ehci_batch->ehci_dma_buffer.virt + tds_size; 136 memcpy(ehci_batch->setup_buffer, ehci_batch->base.setup.buffer, setup_size); 137 138 /* Generic data already prepared*/ 139 ehci_batch->data_buffer = ehci_batch->base.dma_buffer.virt; 140 141 if (!batch_setup[ehci_batch->base.ep->transfer_type]) 142 return ENOTSUP; 143 144 batch_setup[ehci_batch->base.ep->transfer_type](ehci_batch); 145 146 usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.", 147 ehci_batch, usb_str_direction(ehci_batch->base.dir), 148 USB_TRANSFER_BATCH_ARGS(ehci_batch->base)); 149 150 return EOK; 175 151 } 176 152 … … 184 160 * completes with the last TD. 185 161 */ 186 bool ehci_transfer_batch_is_complete(const ehci_transfer_batch_t *ehci_batch) 187 { 188 assert(ehci_batch); 189 assert(ehci_batch->usb_batch); 190 191 usb_log_debug("Batch %p: checking %zu td(s) for completion.\n", 192 ehci_batch->usb_batch, ehci_batch->td_count); 193 194 usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.\n", 195 ehci_batch->usb_batch, 162 bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *ehci_batch) 163 { 164 assert(ehci_batch); 165 166 usb_log_debug("Batch %p: checking %zu td(s) for completion.", 167 ehci_batch, ehci_batch->td_count); 168 169 usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.", 170 ehci_batch, 196 171 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 197 172 ehci_batch->qh->status, ehci_batch->qh->current, … … 206 181 207 182 /* Assume all data got through */ 208 ehci_batch->usb_batch->transfered_size = 209 ehci_batch->usb_batch->buffer_size; 183 ehci_batch->base.transferred_size = ehci_batch->base.size; 210 184 211 185 /* Check all TDs */ 212 186 for (size_t i = 0; i < ehci_batch->td_count; ++i) { 213 assert(ehci_batch->tds[i] != NULL);214 187 usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.", 215 ehci_batch ->usb_batch, i,216 ehci_batch->tds[i] ->status, ehci_batch->tds[i]->next,217 ehci_batch->tds[i] ->alternate);218 219 ehci_batch-> usb_batch->error = td_error(ehci_batch->tds[i]);220 if (ehci_batch-> usb_batch->error == EOK) {188 ehci_batch, i, 189 ehci_batch->tds[i].status, ehci_batch->tds[i].next, 190 ehci_batch->tds[i].alternate); 191 192 ehci_batch->base.error = td_error(&ehci_batch->tds[i]); 193 if (ehci_batch->base.error == EOK) { 221 194 /* If the TD got all its data through, it will report 222 195 * 0 bytes remain, the sole exception is INPUT with … … 231 204 * we leave the very last(unused) TD behind. 232 205 */ 233 ehci_batch-> usb_batch->transfered_size234 -= td_remain_size( ehci_batch->tds[i]);206 ehci_batch->base.transferred_size 207 -= td_remain_size(&ehci_batch->tds[i]); 235 208 } else { 236 209 usb_log_debug("Batch %p found error TD(%zu):%08x: %s.", 237 ehci_batch ->usb_batch, i,238 ehci_batch->tds[i] ->status,239 str_error_name(ehci_batch-> usb_batch->error));210 ehci_batch, i, 211 ehci_batch->tds[i].status, 212 str_error_name(ehci_batch->base.error)); 240 213 /* Clear possible ED HALT */ 241 214 qh_clear_halt(ehci_batch->qh); … … 244 217 } 245 218 246 assert(ehci_batch-> usb_batch->transfered_size <=247 ehci_batch->usb_batch->buffer_size); 219 assert(ehci_batch->base.transferred_size <= ehci_batch->base.size); 220 248 221 /* Clear TD pointers */ 249 222 ehci_batch->qh->next = LINK_POINTER_TERM; 250 223 ehci_batch->qh->current = LINK_POINTER_TERM; 251 usb_log_debug("Batch %p complete: %s", ehci_batch ->usb_batch,252 str_error(ehci_batch-> usb_batch->error));224 usb_log_debug("Batch %p complete: %s", ehci_batch, 225 str_error(ehci_batch->base.error)); 253 226 254 227 return true; … … 262 235 { 263 236 assert(ehci_batch); 264 qh_set_next_td(ehci_batch->qh, ehci_batch->tds[0]); 237 qh_set_next_td(ehci_batch->qh, 238 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0])); 265 239 } 266 240 … … 268 242 * 269 243 * @param[in] ehci_batch Batch structure to use. 270 * @param[in] dir Communication direction271 244 * 272 245 * Setup stage with toggle 0 and direction BOTH(SETUP_PID) 273 * Data stage with alternating toggle and direction supplied by parameter. 274 * Status stage with toggle 1 and direction supplied by parameter. 275 */ 276 static void batch_control(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 277 { 278 assert(ehci_batch); 279 assert(ehci_batch->usb_batch); 246 * Data stage with alternating toggle and direction 247 * Status stage with toggle 1 and direction 248 */ 249 static void batch_control(ehci_transfer_batch_t *ehci_batch) 250 { 251 assert(ehci_batch); 252 253 usb_direction_t dir = ehci_batch->base.dir; 280 254 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 281 255 282 usb_log_debug2("Batch %p: Control QH(% "PRIxn"): "283 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch ->usb_batch,284 addr_to_phys(ehci_batch->qh),256 usb_log_debug2("Batch %p: Control QH(%p): " 257 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 258 ehci_batch->qh, 285 259 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 286 260 ehci_batch->qh->status, ehci_batch->qh->current, … … 292 266 293 267 int toggle = 0; 294 const char* buffer = ehci_batch->device_buffer;295 268 const usb_direction_t data_dir = dir; 296 269 const usb_direction_t status_dir = reverse_dir[dir]; 297 270 298 271 /* Setup stage */ 299 td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH, 300 buffer, ehci_batch->usb_batch->setup_size, toggle, false); 272 td_init(&ehci_batch->tds[0], 273 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[1]), 274 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, ehci_batch->setup_buffer), 275 USB_DIRECTION_BOTH, USB_SETUP_PACKET_SIZE, toggle, false); 301 276 usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): " 302 "%08x:%08x:%08x", ehci_batch->usb_batch, 303 addr_to_phys(ehci_batch->tds[0]), 304 ehci_batch->tds[0]->status, ehci_batch->tds[0]->next, 305 ehci_batch->tds[0]->alternate); 306 buffer += ehci_batch->usb_batch->setup_size; 277 "%08x:%08x:%08x", ehci_batch, 278 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0]), 279 ehci_batch->tds[0].status, ehci_batch->tds[0].next, 280 ehci_batch->tds[0].alternate); 307 281 308 282 /* Data stage */ 309 size_t td_current = 1; 310 size_t remain_size = ehci_batch->usb_batch->buffer_size; 283 unsigned td_current = 1; 284 size_t remain_size = ehci_batch->base.size; 285 uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer, 286 ehci_batch->data_buffer); 311 287 while (remain_size > 0) { 312 const size_t transfer_size = 313 min(remain_size, EHCI_TD_MAX_TRANSFER); 288 const size_t transfer_size = min(remain_size, EHCI_TD_MAX_TRANSFER); 314 289 toggle = 1 - toggle; 315 290 316 td_init( ehci_batch->tds[td_current],317 ehci_batch->tds[td_current + 1], data_dir, buffer,318 transfer_size, toggle, false);291 td_init(&ehci_batch->tds[td_current], 292 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current + 1]), 293 buffer, data_dir, transfer_size, toggle, false); 319 294 usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): " 320 "%08x:%08x:%08x", ehci_batch ->usb_batch,321 addr_to_phys(ehci_batch->tds[td_current]),322 ehci_batch->tds[td_current] ->status,323 ehci_batch->tds[td_current] ->next,324 ehci_batch->tds[td_current] ->alternate);295 "%08x:%08x:%08x", ehci_batch, 296 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]), 297 ehci_batch->tds[td_current].status, 298 ehci_batch->tds[td_current].next, 299 ehci_batch->tds[td_current].alternate); 325 300 326 301 buffer += transfer_size; … … 332 307 /* Status stage */ 333 308 assert(td_current == ehci_batch->td_count - 1); 334 td_init( ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true);335 usb_log_debug2("Batch %p: Created CONTROL STATUS TD (%"PRIxn"): "336 "%08x:%08x:%08x", ehci_batch ->usb_batch,337 addr_to_phys(ehci_batch->tds[td_current]),338 ehci_batch->tds[td_current] ->status,339 ehci_batch->tds[td_current] ->next,340 ehci_batch->tds[td_current] ->alternate);309 td_init(&ehci_batch->tds[td_current], 0, 0, status_dir, 0, 1, true); 310 usb_log_debug2("Batch %p: Created CONTROL STATUS TD %d(%"PRIxn"): " 311 "%08x:%08x:%08x", ehci_batch, td_current, 312 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]), 313 ehci_batch->tds[td_current].status, 314 ehci_batch->tds[td_current].next, 315 ehci_batch->tds[td_current].alternate); 341 316 } 342 317 … … 349 324 * EHCI hw in ED. 350 325 */ 351 static void batch_data(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir) 352 { 353 assert(ehci_batch); 354 assert(ehci_batch->usb_batch); 355 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 356 357 usb_log_debug2("Batch %p: Data QH(%"PRIxn"): " 358 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch, 359 addr_to_phys(ehci_batch->qh), 326 static void batch_data(ehci_transfer_batch_t *ehci_batch) 327 { 328 assert(ehci_batch); 329 330 usb_log_debug2("Batch %p: Data QH(%p): " 331 "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch, 332 ehci_batch->qh, 360 333 ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap, 361 334 ehci_batch->qh->status, ehci_batch->qh->current, … … 363 336 364 337 size_t td_current = 0; 365 size_t remain_size = ehci_batch->usb_batch->buffer_size; 366 char *buffer = ehci_batch->device_buffer; 338 size_t remain_size = ehci_batch->base.size; 339 uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer, 340 ehci_batch->data_buffer); 367 341 while (remain_size > 0) { 368 342 const size_t transfer_size = remain_size > EHCI_TD_MAX_TRANSFER … … 370 344 371 345 const bool last = (remain_size == transfer_size); 372 td_init( 373 ehci_batch->tds[td_current],374 last ? NULL : ehci_batch->tds[td_current + 1],375 dir, buffer, transfer_size, -1, last);346 td_init(&ehci_batch->tds[td_current], 347 last ? 0 : dma_buffer_phys(&ehci_batch->ehci_dma_buffer, 348 &ehci_batch->tds[td_current + 1]), 349 buffer, ehci_batch->base.dir, transfer_size, -1, last); 376 350 377 351 usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x", 378 ehci_batch->usb_batch, 379 addr_to_phys(ehci_batch->tds[td_current]), 380 ehci_batch->tds[td_current]->status, 381 ehci_batch->tds[td_current]->next, 382 ehci_batch->tds[td_current]->alternate); 352 ehci_batch, 353 dma_buffer_phys(&ehci_batch->ehci_dma_buffer, 354 &ehci_batch->tds[td_current]), 355 ehci_batch->tds[td_current].status, 356 ehci_batch->tds[td_current].next, 357 ehci_batch->tds[td_current].alternate); 383 358 384 359 buffer += transfer_size; … … 390 365 391 366 /** Transfer setup table. */ 392 static void (*const batch_setup[])(ehci_transfer_batch_t* , usb_direction_t) =367 static void (*const batch_setup[])(ehci_transfer_batch_t*) = 393 368 { 394 369 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/ehci/ehci_batch.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2014 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 39 40 #include <stdbool.h> 40 41 #include <usb/host/usb_transfer_batch.h> 42 #include <usb/dma_buffer.h> 41 43 42 44 #include "hw_struct/queue_head.h" … … 45 47 /** EHCI specific data required for USB transfer */ 46 48 typedef struct ehci_transfer_batch { 47 /** Link */ 48 link_t link; 49 usb_transfer_batch_t base; 50 /** Number of TDs used by the transfer */ 51 size_t td_count; 49 52 /** Endpoint descriptor of the target endpoint. */ 50 53 qh_t *qh; 51 /** List of TDs needed for the transfer */ 52 td_t **tds; 53 /** Number of TDs used by the transfer */ 54 size_t td_count; 55 /** Data buffer, must be accessible by the EHCI hw. */ 56 char *device_buffer; 54 /** Backend for TDs and setup data. */ 55 dma_buffer_t ehci_dma_buffer; 56 /** List of TDs needed for the transfer - backed by dma_buffer */ 57 td_t *tds; 58 /** Data buffers - backed by dma_buffer */ 59 void *setup_buffer; 60 void *data_buffer; 57 61 /** Generic USB transfer structure */ 58 62 usb_transfer_batch_t *usb_batch; 59 63 } ehci_transfer_batch_t; 60 64 61 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *batch);62 bool ehci_transfer_batch_is_complete(constehci_transfer_batch_t *batch);65 ehci_transfer_batch_t *ehci_transfer_batch_create(endpoint_t *ep); 66 int ehci_transfer_batch_prepare(ehci_transfer_batch_t *batch); 63 67 void ehci_transfer_batch_commit(const ehci_transfer_batch_t *batch); 64 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *batch); 68 bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *batch); 69 void ehci_transfer_batch_destroy(ehci_transfer_batch_t *batch); 65 70 66 static inline ehci_transfer_batch_t *ehci_transfer_batch_from_link(link_t *l) 71 static inline ehci_transfer_batch_t *ehci_transfer_batch_get( 72 usb_transfer_batch_t *usb_batch) 67 73 { 68 assert(l); 69 return list_get_instance(l, ehci_transfer_batch_t, link); 74 assert(usb_batch); 75 76 return (ehci_transfer_batch_t *) usb_batch; 70 77 } 78 71 79 #endif 72 80 /** -
uspace/drv/bus/usb/ehci/ehci_bus.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 32 33 * @brief EHCI driver 33 34 */ 34 #ifndef DRV_EHCI_HCD_ ENDPOINT_H35 #define DRV_EHCI_HCD_ ENDPOINT_H35 #ifndef DRV_EHCI_HCD_BUS_H 36 #define DRV_EHCI_HCD_BUS_H 36 37 37 38 #include <assert.h> 38 39 #include <adt/list.h> 40 #include <usb/host/usb2_bus.h> 39 41 #include <usb/host/endpoint.h> 40 #include <usb/ host/hcd.h>42 #include <usb/dma_buffer.h> 41 43 42 44 #include "hw_struct/queue_head.h" 43 #include "hw_struct/transfer_descriptor.h"44 45 45 46 /** Connector structure linking ED to to prepared TD. */ 46 47 typedef struct ehci_endpoint { 47 /** EHCI endpoint descriptor */ 48 /* Inheritance */ 49 endpoint_t base; 50 51 /** EHCI endpoint descriptor, backed by dma_buffer */ 48 52 qh_t *qh; 49 /** Linked list used by driver software */ 50 link_t link; 53 54 dma_buffer_t dma_buffer; 55 56 /** Link in endpoint_list */ 57 link_t eplist_link; 58 59 /** Link in pending_endpoints */ 60 link_t pending_link; 51 61 } ehci_endpoint_t; 52 62 53 errno_t ehci_endpoint_init(hcd_t *hcd, endpoint_t *ep); 54 void ehci_endpoint_fini(hcd_t *hcd, endpoint_t *ep); 63 typedef struct hc hc_t; 64 65 typedef struct { 66 bus_t base; 67 usb2_bus_helper_t helper; 68 hc_t *hc; 69 } ehci_bus_t; 70 71 void ehci_ep_toggle_reset(endpoint_t *); 72 void ehci_bus_prepare_ops(void); 73 74 errno_t ehci_bus_init(ehci_bus_t *, hc_t *); 55 75 56 76 /** Get and convert assigned ehci_endpoint_t structure 57 77 * @param[in] ep USBD endpoint structure. 58 * @return Pointer to assigned hcdendpoint structure78 * @return Pointer to assigned ehci endpoint structure 59 79 */ 60 static inline ehci_endpoint_t * ehci_endpoint_get(const endpoint_t *ep)80 static inline ehci_endpoint_t *ehci_endpoint_get(const endpoint_t *ep) 61 81 { 62 82 assert(ep); 63 return ep->hc_data.data;83 return (ehci_endpoint_t *) ep; 64 84 } 65 85 66 static inline ehci_endpoint_t * ehci_endpoint_list_instance(link_t *l)86 static inline ehci_endpoint_t *ehci_endpoint_list_instance(link_t *l) 67 87 { 68 return list_get_instance(l, ehci_endpoint_t, link);88 return list_get_instance(l, ehci_endpoint_t, eplist_link); 69 89 } 70 90 … … 73 93 * @} 74 94 */ 75 -
uspace/drv/bus/usb/ehci/ehci_rh.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 100 101 */ 101 102 errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs, 102 const char *name)103 fibril_mutex_t *guard, const char *name) 103 104 { 104 105 assert(instance); … … 107 108 (EHCI_RD(caps->hcsparams) >> EHCI_CAPS_HCS_N_PORTS_SHIFT) & 108 109 EHCI_CAPS_HCS_N_PORTS_MASK; 109 usb_log_debug2("RH(%p): hcsparams: %x. \n", instance,110 usb_log_debug2("RH(%p): hcsparams: %x.", instance, 110 111 EHCI_RD(caps->hcsparams)); 111 usb_log_info("RH(%p): Found %u ports. \n", instance,112 usb_log_info("RH(%p): Found %u ports.", instance, 112 113 instance->port_count); 113 114 … … 127 128 128 129 ehci_rh_hub_desc_init(instance, EHCI_RD(caps->hcsparams)); 129 instance->unfinished_interrupt_transfer = NULL; 130 instance->guard = guard; 131 instance->status_change_endpoint = NULL; 130 132 131 133 return virthub_base_init(&instance->base, name, &ops, instance, … … 144 146 assert(instance); 145 147 assert(batch); 146 const usb_target_t target = {{ 147 .address = batch->ep->address, 148 .endpoint = batch->ep->endpoint, 149 }}; 150 batch->error = virthub_base_request(&instance->base, target, 151 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer, 152 batch->buffer, batch->buffer_size, &batch->transfered_size); 148 batch->error = virthub_base_request(&instance->base, batch->target, 149 batch->dir, (void*) batch->setup.buffer, 150 batch->dma_buffer.virt, batch->size, 151 &batch->transferred_size); 153 152 if (batch->error == ENAK) { 154 153 usb_log_debug("RH(%p): BATCH(%p) adding as unfinished", 155 154 instance, batch); 156 /* This is safe because only status change interrupt transfers 157 * return NAK. The assertion holds true because the batch 158 * existence prevents communication with that ep */ 159 assert(instance->unfinished_interrupt_transfer == NULL); 160 instance->unfinished_interrupt_transfer = batch; 155 156 /* Lock the HC guard */ 157 fibril_mutex_lock(instance->guard); 158 const int err = endpoint_activate_locked(batch->ep, batch); 159 if (err) { 160 fibril_mutex_unlock(batch->ep->guard); 161 return err; 162 } 163 164 /* 165 * Asserting that the HC do not run two instances of the status 166 * change endpoint - shall be true. 167 */ 168 assert(!instance->status_change_endpoint); 169 170 endpoint_add_ref(batch->ep); 171 instance->status_change_endpoint = batch->ep; 172 fibril_mutex_unlock(instance->guard); 161 173 } else { 162 usb_transfer_batch_finish(batch, NULL);163 usb_transfer_batch_destroy(batch);164 174 usb_log_debug("RH(%p): BATCH(%p) virtual request complete: %s", 165 175 instance, batch, str_error(batch->error)); 176 usb_transfer_batch_finish(batch); 166 177 } 167 178 return EOK; … … 177 188 errno_t ehci_rh_interrupt(ehci_rh_t *instance) 178 189 { 179 //TODO atomic swap needed 180 usb_transfer_batch_t *batch = instance->unfinished_interrupt_transfer; 181 instance->unfinished_interrupt_transfer = NULL; 182 usb_log_debug2("RH(%p): Interrupt. Processing batch: %p", 183 instance, batch); 190 fibril_mutex_lock(instance->guard); 191 endpoint_t *ep = instance->status_change_endpoint; 192 if (!ep) { 193 fibril_mutex_unlock(instance->guard); 194 return EOK; 195 } 196 197 usb_transfer_batch_t * const batch = ep->active_batch; 198 endpoint_deactivate_locked(ep); 199 instance->status_change_endpoint = NULL; 200 fibril_mutex_unlock(instance->guard); 201 202 endpoint_del_ref(ep); 203 184 204 if (batch) { 185 const usb_target_t target = {{ 186 .address = batch->ep->address, 187 .endpoint = batch->ep->endpoint, 188 }}; 189 batch->error = virthub_base_request(&instance->base, target, 190 usb_transfer_batch_direction(batch), 191 (void*)batch->setup_buffer, 192 batch->buffer, batch->buffer_size, &batch->transfered_size); 193 usb_transfer_batch_finish(batch, NULL); 194 usb_transfer_batch_destroy(batch); 205 usb_log_debug2("RH(%p): Interrupt. Processing batch: %p", 206 instance, batch); 207 batch->error = virthub_base_request(&instance->base, batch->target, 208 batch->dir, (void*) batch->setup.buffer, 209 batch->dma_buffer.virt, batch->size, 210 &batch->transferred_size); 211 usb_transfer_batch_finish(batch); 195 212 } 196 213 return EOK; … … 258 275 259 276 #define BIT_VAL(val, bit) ((val & bit) ? 1 : 0) 260 #define EHCI2USB(val, bit, feat) (BIT_VAL(val, bit) << feat)277 #define EHCI2USB(val, bit, mask) (BIT_VAL(val, bit) ? mask : 0) 261 278 262 279 /** Port status request handler. … … 280 297 const uint32_t reg = EHCI_RD(hub->registers->portsc[port]); 281 298 const uint32_t status = uint32_host2usb( 282 EHCI2USB(reg, USB_PORTSC_CONNECT_FLAG, USB_HUB_ FEATURE_PORT_CONNECTION) |283 EHCI2USB(reg, USB_PORTSC_ENABLED_FLAG, USB_HUB_ FEATURE_PORT_ENABLE) |284 EHCI2USB(reg, USB_PORTSC_SUSPEND_FLAG, USB _HUB_FEATURE_PORT_SUSPEND) |285 EHCI2USB(reg, USB_PORTSC_OC_ACTIVE_FLAG, USB_HUB_ FEATURE_PORT_OVER_CURRENT) |286 EHCI2USB(reg, USB_PORTSC_PORT_RESET_FLAG, USB_HUB_ FEATURE_PORT_RESET) |287 EHCI2USB(reg, USB_PORTSC_PORT_POWER_FLAG, USB _HUB_FEATURE_PORT_POWER) |299 EHCI2USB(reg, USB_PORTSC_CONNECT_FLAG, USB_HUB_PORT_STATUS_CONNECTION) | 300 EHCI2USB(reg, USB_PORTSC_ENABLED_FLAG, USB_HUB_PORT_STATUS_ENABLE) | 301 EHCI2USB(reg, USB_PORTSC_SUSPEND_FLAG, USB2_HUB_PORT_STATUS_SUSPEND) | 302 EHCI2USB(reg, USB_PORTSC_OC_ACTIVE_FLAG, USB_HUB_PORT_STATUS_OC) | 303 EHCI2USB(reg, USB_PORTSC_PORT_RESET_FLAG, USB_HUB_PORT_STATUS_RESET) | 304 EHCI2USB(reg, USB_PORTSC_PORT_POWER_FLAG, USB2_HUB_PORT_STATUS_POWER) | 288 305 (((reg & USB_PORTSC_LINE_STATUS_MASK) == USB_PORTSC_LINE_STATUS_K) ? 289 ( 1 << USB_HUB_FEATURE_PORT_LOW_SPEED) : 0) |290 ((reg & USB_PORTSC_PORT_OWNER_FLAG) ? 0 : (1 << USB_HUB_FEATURE_PORT_HIGH_SPEED)) |291 EHCI2USB(reg, USB_PORTSC_PORT_TEST_MASK, 11) |292 EHCI2USB(reg, USB_PORTSC_INDICATOR_MASK, 12) |293 EHCI2USB(reg, USB_PORTSC_CONNECT_CH_FLAG, USB_HUB_ FEATURE_C_PORT_CONNECTION) |294 EHCI2USB(reg, USB_PORTSC_EN_CHANGE_FLAG, USB _HUB_FEATURE_C_PORT_ENABLE) |295 (hub->resume_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_SUSPEND): 0) |296 EHCI2USB(reg, USB_PORTSC_OC_CHANGE_FLAG, USB_HUB_ FEATURE_C_PORT_OVER_CURRENT) |297 (hub->reset_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_RESET): 0)306 (USB2_HUB_PORT_STATUS_LOW_SPEED) : 0) | 307 ((reg & USB_PORTSC_PORT_OWNER_FLAG) ? 0 : USB2_HUB_PORT_STATUS_HIGH_SPEED) | 308 EHCI2USB(reg, USB_PORTSC_PORT_TEST_MASK, USB2_HUB_PORT_STATUS_TEST) | 309 EHCI2USB(reg, USB_PORTSC_INDICATOR_MASK, USB2_HUB_PORT_STATUS_INDICATOR) | 310 EHCI2USB(reg, USB_PORTSC_CONNECT_CH_FLAG, USB_HUB_PORT_STATUS_C_CONNECTION) | 311 EHCI2USB(reg, USB_PORTSC_EN_CHANGE_FLAG, USB2_HUB_PORT_STATUS_C_ENABLE) | 312 (hub->resume_flag[port] ? USB2_HUB_PORT_STATUS_C_SUSPEND : 0) | 313 EHCI2USB(reg, USB_PORTSC_OC_CHANGE_FLAG, USB_HUB_PORT_STATUS_C_OC) | 314 (hub->reset_flag[port] ? USB_HUB_PORT_STATUS_C_RESET: 0) 298 315 ); 299 316 /* Note feature numbers for test and indicator feature do not … … 396 413 return EOK; 397 414 398 case USB _HUB_FEATURE_PORT_ENABLE: /*1*/415 case USB2_HUB_FEATURE_PORT_ENABLE: /*1*/ 399 416 usb_log_debug2("RH(%p-%u): Clear port enable.", hub, port); 400 417 EHCI_CLR(hub->registers->portsc[port], … … 402 419 return EOK; 403 420 404 case USB _HUB_FEATURE_PORT_SUSPEND: /*2*/421 case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/ 405 422 usb_log_debug2("RH(%p-%u): Clear port suspend.", hub, port); 406 423 /* If not in suspend it's noop */ … … 420 437 USB_PORTSC_CONNECT_CH_FLAG); 421 438 return EOK; 422 case USB _HUB_FEATURE_C_PORT_ENABLE: /*17*/439 case USB2_HUB_FEATURE_C_PORT_ENABLE: /*17*/ 423 440 usb_log_debug2("RH(%p-%u): Clear port enable change.", 424 441 hub, port); … … 432 449 USB_PORTSC_OC_CHANGE_FLAG); 433 450 return EOK; 434 case USB _HUB_FEATURE_C_PORT_SUSPEND: /*18*/451 case USB2_HUB_FEATURE_C_PORT_SUSPEND: /*18*/ 435 452 usb_log_debug2("RH(%p-%u): Clear port suspend change.", 436 453 hub, port); … … 467 484 const unsigned feature = uint16_usb2host(setup_packet->value); 468 485 switch (feature) { 469 case USB _HUB_FEATURE_PORT_ENABLE: /*1*/486 case USB2_HUB_FEATURE_PORT_ENABLE: /*1*/ 470 487 usb_log_debug2("RH(%p-%u): Set port enable.", hub, port); 471 488 EHCI_SET(hub->registers->portsc[port], 472 489 USB_PORTSC_ENABLED_FLAG); 473 490 return EOK; 474 case USB _HUB_FEATURE_PORT_SUSPEND: /*2*/491 case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/ 475 492 usb_log_debug2("RH(%p-%u): Set port suspend.", hub, port); 476 493 EHCI_SET(hub->registers->portsc[port], -
uspace/drv/bus/usb/ehci/ehci_rh.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 61 62 uint8_t rempow[STATUS_BYTES(EHCI_MAX_PORTS) * 2]; 62 63 } __attribute__((packed)) hub_descriptor; 63 /** interrupt transfer waiting for an actual interrupt to occur */64 usb_transfer_batch_t *unfinished_interrupt_transfer;65 64 bool reset_flag[EHCI_MAX_PORTS]; 66 65 bool resume_flag[EHCI_MAX_PORTS]; 66 67 /* HC guard */ 68 fibril_mutex_t *guard; 69 70 /* 71 * This is sort of hacky, but better than duplicating functionality. 72 * We cannot simply store a pointer to a transfer in-progress, in order 73 * to allow it to be aborted. We can however store a reference to the 74 * Status Change Endpoint. Note that this is mixing two worlds together 75 * - otherwise, the RH is "a device" and have no clue about HC, apart 76 * from accessing its registers. 77 */ 78 endpoint_t *status_change_endpoint; 79 67 80 } ehci_rh_t; 68 81 69 errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs,70 const char *name);82 errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, 83 ehci_regs_t *regs, fibril_mutex_t *guard, const char *name); 71 84 errno_t ehci_rh_schedule(ehci_rh_t *instance, usb_transfer_batch_t *batch); 72 85 errno_t ehci_rh_interrupt(ehci_rh_t *instance); -
uspace/drv/bus/usb/ehci/endpoint_list.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2014 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 54 55 assert(instance); 55 56 instance->name = name; 56 instance->list_head = malloc32(sizeof(qh_t)); 57 if (!instance->list_head) { 57 if (dma_buffer_alloc(&instance->dma_buffer, sizeof(qh_t))) { 58 58 usb_log_error("EPL(%p-%s): Failed to allocate list head.", 59 59 instance, name); 60 60 return ENOMEM; 61 61 } 62 instance->list_head = instance->dma_buffer.virt; 62 63 qh_init(instance->list_head, NULL); 63 64 … … 95 96 { 96 97 assert(instance); 98 assert(instance->list_head); 97 99 assert(ep); 98 100 assert(ep->qh); 99 usb_log_debug2("EPL(%p-%s): Append endpoint(%p). \n",101 usb_log_debug2("EPL(%p-%s): Append endpoint(%p).", 100 102 instance, instance->name, ep); 101 103 … … 124 126 write_barrier(); 125 127 /* Add to the sw list */ 126 list_append(&ep-> link, &instance->endpoint_list);128 list_append(&ep->eplist_link, &instance->endpoint_list); 127 129 128 130 ehci_endpoint_t *first = ehci_endpoint_list_instance( 129 131 list_first(&instance->endpoint_list)); 130 usb_log_debug("EPL(%p-%s): EP(%p) added to list, first is %p(%p). \n",132 usb_log_debug("EPL(%p-%s): EP(%p) added to list, first is %p(%p).", 131 133 instance, instance->name, ep, first, first->qh); 132 134 if (last_qh == instance->list_head) { 133 usb_log_debug2("EPL(%p-%s): head EP(%p-%"PRIxn"): %x:%x. \n",135 usb_log_debug2("EPL(%p-%s): head EP(%p-%"PRIxn"): %x:%x.", 134 136 instance, instance->name, last_qh, 135 137 addr_to_phys(instance->list_head), … … 153 155 fibril_mutex_lock(&instance->guard); 154 156 155 usb_log_debug2("EPL(%p-%s): removing EP(%p). \n",157 usb_log_debug2("EPL(%p-%s): removing EP(%p).", 156 158 instance, instance->name, ep); 157 159 … … 159 161 qh_t *prev_qh; 160 162 /* Remove from the hardware queue */ 161 if (list_first(&instance->endpoint_list) == &ep-> link) {163 if (list_first(&instance->endpoint_list) == &ep->eplist_link) { 162 164 /* I'm the first one here */ 163 165 prev_qh = instance->list_head; 164 166 qpos = "FIRST"; 165 167 } else { 166 prev_qh = ehci_endpoint_list_instance(ep-> link.prev)->qh;168 prev_qh = ehci_endpoint_list_instance(ep->eplist_link.prev)->qh; 167 169 qpos = "NOT FIRST"; 168 170 } … … 172 174 write_barrier(); 173 175 174 usb_log_debug("EPL(%p-%s): EP(%p) removed (%s), horizontal %x. \n",176 usb_log_debug("EPL(%p-%s): EP(%p) removed (%s), horizontal %x.", 175 177 instance, instance->name, ep, qpos, ep->qh->horizontal); 176 178 177 179 /* Remove from the endpoint list */ 178 list_remove(&ep-> link);180 list_remove(&ep->eplist_link); 179 181 fibril_mutex_unlock(&instance->guard); 180 182 } -
uspace/drv/bus/usb/ehci/endpoint_list.h
rf5e5f73 rdf6ded8 38 38 #include <assert.h> 39 39 #include <fibril_synch.h> 40 #include <usb/host/utils/malloc32.h>41 40 42 #include "ehci_ endpoint.h"41 #include "ehci_bus.h" 43 42 #include "hw_struct/queue_head.h" 44 43 … … 49 48 /** EHCI hw structure at the beginning of the queue */ 50 49 qh_t *list_head; 50 dma_buffer_t dma_buffer; 51 51 /** Assigned name, provides nicer debug output */ 52 52 const char *name; … … 64 64 { 65 65 assert(instance); 66 free32(instance->list_head);66 dma_buffer_free(&instance->dma_buffer); 67 67 instance->list_head = NULL; 68 68 } -
uspace/drv/bus/usb/ehci/hc.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 45 46 #include <usb/debug.h> 46 47 #include <usb/usb.h> 47 #include <usb/host/util s/malloc32.h>48 #include <usb/host/utility.h> 48 49 49 50 #include "ehci_batch.h" … … 89 90 }; 90 91 91 static void hc_start(hc_t *instance);92 92 static errno_t hc_init_memory(hc_t *instance); 93 93 … … 100 100 * @return Error code. 101 101 */ 102 errno_t ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)102 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq) 103 103 { 104 104 assert(code); 105 105 assert(hw_res); 106 hc_t *instance = hcd_to_hc(hcd); 106 107 107 108 if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1) … … 130 131 131 132 memcpy(code->cmds, ehci_irq_commands, sizeof(ehci_irq_commands)); 132 ehci_caps_regs_t *caps = NULL;133 134 errno_t ret = pio_enable_range(®s, (void**)&caps);135 if (ret != EOK) {136 free(code->ranges);137 free(code->cmds);138 return ret;139 }140 133 141 134 ehci_regs_t *registers = 142 (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(caps->caplength));135 (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(instance->caps->caplength)); 143 136 code->cmds[0].addr = (void *) ®isters->usbsts; 144 137 code->cmds[3].addr = (void *) ®isters->usbsts; 145 138 EHCI_WR(code->cmds[1].value, EHCI_USED_INTERRUPTS); 146 139 147 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d. \n",140 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.", 148 141 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 149 142 … … 159 152 * @return Error code 160 153 */ 161 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)162 { 163 assert(instance);154 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 155 { 156 hc_t *instance = hcd_to_hc(hcd); 164 157 assert(hw_res); 165 158 if (hw_res->mem_ranges.count != 1 || … … 172 165 if (ret != EOK) { 173 166 usb_log_error("HC(%p): Failed to gain access to device " 174 "registers: %s. \n", instance, str_error(ret));167 "registers: %s.", instance, str_error(ret)); 175 168 return ret; 176 169 } 170 177 171 usb_log_info("HC(%p): Device registers at %"PRIx64" (%zuB) accessible.", 178 172 instance, hw_res->mem_ranges.ranges[0].address.absolute, … … 184 178 + EHCI_RD8(instance->caps->caplength)); 185 179 186 list_initialize(&instance->pending_ batches);180 list_initialize(&instance->pending_endpoints); 187 181 fibril_mutex_initialize(&instance->guard); 188 182 fibril_condvar_initialize(&instance->async_doorbell); … … 197 191 usb_log_info("HC(%p): Initializing RH(%p).", instance, &instance->rh); 198 192 ehci_rh_init( 199 &instance->rh, instance->caps, instance->registers, "ehci rh"); 200 usb_log_debug("HC(%p): Starting HW.", instance); 201 hc_start(instance); 202 193 &instance->rh, instance->caps, instance->registers, &instance->guard, 194 "ehci rh"); 195 196 ehci_bus_init(&instance->bus, instance); 197 hc_device_setup(hcd, (bus_t *) &instance->bus); 203 198 return EOK; 204 199 } … … 208 203 * @param[in] instance Host controller structure to use. 209 204 */ 210 void hc_fini(hc_t *instance) 211 { 212 assert(instance); 213 //TODO: stop the hw 214 #if 0 215 endpoint_list_fini(&instance->async_list); 216 endpoint_list_fini(&instance->int_list); 217 return_page(instance->periodic_list_base); 218 #endif 205 int hc_gone(hc_device_t *hcd) 206 { 207 hc_t *hc = hcd_to_hc(hcd); 208 endpoint_list_fini(&hc->async_list); 209 endpoint_list_fini(&hc->int_list); 210 dma_buffer_free(&hc->dma_buffer); 211 return EOK; 219 212 }; 220 213 … … 224 217 assert(ep); 225 218 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 226 usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s) \n", instance,227 ep-> address, ep->endpoint,219 usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)", instance, 220 ep->device->address, ep->endpoint, 228 221 usb_str_transfer_type_short(ep->transfer_type), 229 222 usb_str_direction(ep->direction)); … … 248 241 assert(ep); 249 242 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 250 usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s) \n", instance,251 ep-> address, ep->endpoint,243 usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)", instance, 244 ep->device->address, ep->endpoint, 252 245 usb_str_transfer_type_short(ep->transfer_type), 253 246 usb_str_direction(ep->direction)); … … 273 266 } 274 267 275 errno_t ehci_hc_status(hcd_t *hcd, uint32_t *status) 276 { 277 assert(hcd); 278 hc_t *instance = hcd_get_driver_data(hcd); 279 assert(instance); 268 errno_t ehci_hc_status(bus_t *bus_base, uint32_t *status) 269 { 270 assert(bus_base); 280 271 assert(status); 272 273 ehci_bus_t *bus = (ehci_bus_t *) bus_base; 274 hc_t *hc = bus->hc; 275 assert(hc); 276 281 277 *status = 0; 282 if ( instance->registers) {283 *status = EHCI_RD( instance->registers->usbsts);284 EHCI_WR( instance->registers->usbsts, *status);285 } 286 usb_log_debug2("HC(%p): Read status: %x", instance, *status);278 if (hc->registers) { 279 *status = EHCI_RD(hc->registers->usbsts); 280 EHCI_WR(hc->registers->usbsts, *status); 281 } 282 usb_log_debug2("HC(%p): Read status: %x", hc, *status); 287 283 return EOK; 288 284 } … … 294 290 * @return Error code. 295 291 */ 296 errno_t ehci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 297 { 298 assert(hcd); 299 hc_t *instance = hcd_get_driver_data(hcd); 300 assert(instance); 292 errno_t ehci_hc_schedule(usb_transfer_batch_t *batch) 293 { 294 assert(batch); 295 296 ehci_bus_t *bus = (ehci_bus_t *) endpoint_get_bus(batch->ep); 297 hc_t *hc = bus->hc; 298 assert(hc); 301 299 302 300 /* Check for root hub communication */ 303 if (batch-> ep->address == ehci_rh_get_address(&instance->rh)) {301 if (batch->target.address == ehci_rh_get_address(&hc->rh)) { 304 302 usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)", 305 instance, batch, &instance->rh); 306 return ehci_rh_schedule(&instance->rh, batch); 307 } 303 hc, batch, &hc->rh); 304 return ehci_rh_schedule(&hc->rh, batch); 305 } 306 307 endpoint_t * const ep = batch->ep; 308 ehci_endpoint_t * const ehci_ep = ehci_endpoint_get(ep); 308 309 ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch); 309 if (!ehci_batch) 310 return ENOMEM; 311 312 fibril_mutex_lock(&instance->guard); 313 usb_log_debug2("HC(%p): Appending BATCH(%p)", instance, batch); 314 list_append(&ehci_batch->link, &instance->pending_batches); 315 usb_log_debug("HC(%p): Committing BATCH(%p)", instance, batch); 310 311 int err; 312 313 if ((err = ehci_transfer_batch_prepare(ehci_batch))) 314 return err; 315 316 fibril_mutex_lock(&hc->guard); 317 318 if ((err = endpoint_activate_locked(ep, batch))) { 319 fibril_mutex_unlock(&hc->guard); 320 return err; 321 } 322 323 usb_log_debug("HC(%p): Committing BATCH(%p)", hc, batch); 316 324 ehci_transfer_batch_commit(ehci_batch); 317 325 318 fibril_mutex_unlock(&instance->guard); 326 /* Enqueue endpoint to the checked list */ 327 usb_log_debug2("HC(%p): Appending BATCH(%p)", hc, batch); 328 list_append(&ehci_ep->pending_link, &hc->pending_endpoints); 329 330 fibril_mutex_unlock(&hc->guard); 319 331 return EOK; 320 332 } … … 325 337 * @param[in] status Value of the status register at the time of interrupt. 326 338 */ 327 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status) 328 { 329 assert(hcd); 330 hc_t *instance = hcd_get_driver_data(hcd); 331 status = EHCI_RD(status); 332 assert(instance); 333 334 usb_log_debug2("HC(%p): Interrupt: %"PRIx32, instance, status); 339 void ehci_hc_interrupt(bus_t *bus_base, uint32_t status) 340 { 341 assert(bus_base); 342 343 ehci_bus_t *bus = (ehci_bus_t *) bus_base; 344 hc_t *hc = bus->hc; 345 assert(hc); 346 347 usb_log_debug2("HC(%p): Interrupt: %"PRIx32, hc, status); 335 348 if (status & USB_STS_PORT_CHANGE_FLAG) { 336 ehci_rh_interrupt(& instance->rh);349 ehci_rh_interrupt(&hc->rh); 337 350 } 338 351 339 352 if (status & USB_STS_IRQ_ASYNC_ADVANCE_FLAG) { 340 fibril_mutex_lock(& instance->guard);341 usb_log_debug2("HC(%p): Signaling doorbell", instance);342 fibril_condvar_broadcast(& instance->async_doorbell);343 fibril_mutex_unlock(& instance->guard);353 fibril_mutex_lock(&hc->guard); 354 usb_log_debug2("HC(%p): Signaling doorbell", hc); 355 fibril_condvar_broadcast(&hc->async_doorbell); 356 fibril_mutex_unlock(&hc->guard); 344 357 } 345 358 346 359 if (status & (USB_STS_IRQ_FLAG | USB_STS_ERR_IRQ_FLAG)) { 347 fibril_mutex_lock(&instance->guard); 348 349 usb_log_debug2("HC(%p): Scanning %lu pending batches", instance, 350 list_count(&instance->pending_batches)); 351 list_foreach_safe(instance->pending_batches, current, next) { 352 ehci_transfer_batch_t *batch = 353 ehci_transfer_batch_from_link(current); 354 355 if (ehci_transfer_batch_is_complete(batch)) { 360 fibril_mutex_lock(&hc->guard); 361 362 usb_log_debug2("HC(%p): Scanning %lu pending endpoints", hc, 363 list_count(&hc->pending_endpoints)); 364 list_foreach_safe(hc->pending_endpoints, current, next) { 365 ehci_endpoint_t *ep 366 = list_get_instance(current, ehci_endpoint_t, pending_link); 367 368 ehci_transfer_batch_t *batch 369 = ehci_transfer_batch_get(ep->base.active_batch); 370 assert(batch); 371 372 if (ehci_transfer_batch_check_completed(batch)) { 373 endpoint_deactivate_locked(&ep->base); 356 374 list_remove(current); 357 ehci_transfer_batch_finish_dispose(batch); 375 hc_reset_toggles(&batch->base, &ehci_ep_toggle_reset); 376 usb_transfer_batch_finish(&batch->base); 358 377 } 359 378 } 360 fibril_mutex_unlock(&instance->guard); 379 fibril_mutex_unlock(&hc->guard); 380 381 361 382 } 362 383 363 384 if (status & USB_STS_HOST_ERROR_FLAG) { 364 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", instance);385 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", hc); 365 386 //TODO do something here 366 387 } … … 371 392 * @param[in] instance EHCI hc driver structure. 372 393 */ 373 void hc_start(hc_t *instance) 374 { 375 assert(instance); 394 int hc_start(hc_device_t *hcd) 395 { 396 hc_t *instance = hcd_to_hc(hcd); 397 usb_log_debug("HC(%p): Starting HW.", instance); 398 376 399 /* Turn off the HC if it's running, Reseting a running device is 377 400 * undefined */ … … 404 427 405 428 /* Enable periodic list */ 406 assert(instance->periodic_list _base);429 assert(instance->periodic_list); 407 430 uintptr_t phys_base = 408 addr_to_phys((void*)instance->periodic_list _base);431 addr_to_phys((void*)instance->periodic_list); 409 432 assert((phys_base & USB_PERIODIC_LIST_BASE_MASK) == phys_base); 410 433 EHCI_WR(instance->registers->periodiclistbase, phys_base); … … 425 448 usb_log_debug("HC(%p): HW started.", instance); 426 449 427 usb_log_debug2("HC(%p): Registers: \n"428 "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts) \n"429 "\tUSBSTS(%p): %x(0x00001000 = HC halted) \n"430 "\tUSBINT(%p): %x(0x0 = no interrupts). \n"431 "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc). \n",450 usb_log_debug2("HC(%p): Registers: " 451 "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)" 452 "\tUSBSTS(%p): %x(0x00001000 = HC halted)" 453 "\tUSBINT(%p): %x(0x0 = no interrupts)." 454 "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc).", 432 455 instance, 433 456 &instance->registers->usbcmd, EHCI_RD(instance->registers->usbcmd), … … 438 461 EHCI_WR(instance->registers->usbsts, EHCI_RD(instance->registers->usbsts)); 439 462 EHCI_WR(instance->registers->usbintr, EHCI_USED_INTERRUPTS); 463 464 return EOK; 465 } 466 467 /** 468 * Setup roothub as a virtual hub. 469 */ 470 int hc_setup_roothub(hc_device_t *hcd) 471 { 472 return hc_setup_virtual_root_hub(hcd, USB_SPEED_HIGH); 440 473 } 441 474 … … 473 506 474 507 /* Take 1024 periodic list heads, we ignore low mem options */ 475 instance->periodic_list_base = get_page(); 476 if (!instance->periodic_list_base) { 508 if (dma_buffer_alloc(&instance->dma_buffer, PAGE_SIZE)) { 477 509 usb_log_error("HC(%p): Failed to get ISO schedule page.", 478 510 instance); … … 481 513 return ENOMEM; 482 514 } 515 instance->periodic_list = instance->dma_buffer.virt; 483 516 484 517 usb_log_debug2("HC(%p): Initializing Periodic list.", instance); 485 for (unsigned i = 0; 486 i < PAGE_SIZE/sizeof(instance->periodic_list_base[0]); ++i) 518 for (unsigned i = 0; i < PAGE_SIZE/sizeof(link_pointer_t); ++i) 487 519 { 488 520 /* Disable everything for now */ 489 instance->periodic_list _base[i] =521 instance->periodic_list[i] = 490 522 LINK_POINTER_QH(addr_to_phys(instance->int_list.list_head)); 491 523 } -
uspace/drv/bus/usb/ehci/hc.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 55 56 /** Main EHCI driver structure */ 56 57 typedef struct hc { 58 /* Common device header */ 59 hc_device_t base; 60 57 61 /** Memory mapped CAPS register area */ 58 62 ehci_caps_regs_t *caps; … … 60 64 ehci_regs_t *registers; 61 65 62 /** Iso transfer list */ 63 link_pointer_t *periodic_list_base; 66 /** Iso transfer list, backed by dma_buffer */ 67 link_pointer_t *periodic_list; 68 69 dma_buffer_t dma_buffer; 64 70 65 71 /** CONTROL and BULK schedules */ … … 70 76 71 77 /** List of active transfers */ 72 list_t pending_ batches;78 list_t pending_endpoints; 73 79 74 80 /** Guards schedule and endpoint manipulation */ … … 80 86 /** USB hub emulation structure */ 81 87 ehci_rh_t rh; 88 89 /** USB bookkeeping */ 90 ehci_bus_t bus; 82 91 } hc_t; 83 92 84 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts); 85 void hc_fini(hc_t *instance); 93 static inline hc_t *hcd_to_hc(hc_device_t *hcd) 94 { 95 assert(hcd); 96 return (hc_t *) hcd; 97 } 86 98 87 void hc_enqueue_endpoint(hc_t * instance, const endpoint_t *ep);88 void hc_dequeue_endpoint(hc_t * instance, const endpoint_t *ep);99 void hc_enqueue_endpoint(hc_t *, const endpoint_t *); 100 void hc_dequeue_endpoint(hc_t *, const endpoint_t *); 89 101 90 errno_t ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq); 102 /* Boottime operations */ 103 extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *); 104 extern errno_t hc_start(hc_device_t *); 105 extern errno_t hc_setup_roothub(hc_device_t *); 106 extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *, 107 const hw_res_list_parsed_t *, int *); 108 extern errno_t hc_gone(hc_device_t *); 91 109 92 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status); 93 errno_t ehci_hc_status(hcd_t *hcd, uint32_t *status); 94 errno_t ehci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 110 /** Runtime operations */ 111 extern void ehci_hc_interrupt(bus_t *, uint32_t); 112 extern errno_t ehci_hc_status(bus_t *, uint32_t *); 113 extern errno_t ehci_hc_schedule(usb_transfer_batch_t *); 114 95 115 #endif 96 116 /** -
uspace/drv/bus/usb/ehci/hw_struct/iso_transfer_descriptor.h
rf5e5f73 rdf6ded8 72 72 /* 64 bit struct only */ 73 73 volatile uint32_t extended_bp[7]; 74 } itd_t;74 } __attribute__((packed, aligned(32))) itd_t; 75 75 #endif 76 76 /** -
uspace/drv/bus/usb/ehci/hw_struct/queue_head.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2013 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 37 38 #include <mem.h> 38 39 #include <macros.h> 40 #include <usb/host/bus.h> 39 41 40 42 #include "mem_access.h" … … 63 65 return; 64 66 } 65 assert(ep-> speed < ARRAY_SIZE(speed));67 assert(ep->device->speed < ARRAY_SIZE(speed)); 66 68 EHCI_MEM32_WR(instance->ep_char, 67 QH_EP_CHAR_ADDR_SET(ep-> address) |69 QH_EP_CHAR_ADDR_SET(ep->device->address) | 68 70 QH_EP_CHAR_EP_SET(ep->endpoint) | 69 speed[ep->speed] | 70 QH_EP_CHAR_MAX_LENGTH_SET(ep->max_packet_size) 71 ); 71 speed[ep->device->speed] | 72 QH_EP_CHAR_MAX_LENGTH_SET(ep->max_packet_size)); 72 73 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 73 if (ep-> speed != USB_SPEED_HIGH)74 if (ep->device->speed != USB_SPEED_HIGH) 74 75 EHCI_MEM32_SET(instance->ep_char, QH_EP_CHAR_C_FLAG); 75 76 /* Let BULK and INT use queue head managed toggle, … … 78 79 } 79 80 uint32_t ep_cap = QH_EP_CAP_C_MASK_SET(3 << 2) | 80 QH_EP_CAP_MULTI_SET(ep->packets); 81 if (ep->speed != USB_SPEED_HIGH) { 81 QH_EP_CAP_MULTI_SET(ep->packets_per_uframe); 82 if (usb_speed_is_11(ep->device->speed)) { 83 assert(ep->device->tt.dev != NULL); 82 84 ep_cap |= 83 QH_EP_CAP_TT_PORT_SET(ep-> tt.port) |84 QH_EP_CAP_TT_ADDR_SET(ep-> tt.address);85 QH_EP_CAP_TT_PORT_SET(ep->device->tt.port) | 86 QH_EP_CAP_TT_ADDR_SET(ep->device->tt.dev->address); 85 87 } 86 88 if (ep->transfer_type == USB_TRANSFER_INTERRUPT) { -
uspace/drv/bus/usb/ehci/hw_struct/queue_head.h
rf5e5f73 rdf6ded8 143 143 /* 64 bit struct only */ 144 144 volatile uint32_t extended_bp[5]; 145 } qh_t;145 } __attribute__((packed, aligned(32))) qh_t; 146 146 147 147 static inline void qh_append_qh(qh_t *qh, const qh_t *next) … … 193 193 } 194 194 195 static inline void qh_set_next_td(qh_t *qh, td_t *td)195 static inline void qh_set_next_td(qh_t *qh, uintptr_t td) 196 196 { 197 197 assert(qh); 198 198 assert(td); 199 EHCI_MEM32_WR(qh->next, LINK_POINTER_TD( addr_to_phys(td)));199 EHCI_MEM32_WR(qh->next, LINK_POINTER_TD(td)); 200 200 } 201 201 -
uspace/drv/bus/usb/ehci/hw_struct/split_iso_transfer_descriptor.h
rf5e5f73 rdf6ded8 89 89 /* 64 bit struct only */ 90 90 volatile uint32_t extended_bp[2]; 91 } sitd_t;91 } __attribute__((packed, aligned(32))) sitd_t; 92 92 #endif 93 93 /** -
uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2014 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 39 40 40 41 #include <usb/usb.h> 41 #include <usb/host/utils/malloc32.h>42 42 43 43 #include "mem_access.h" … … 70 70 }; 71 71 72 #include <usb/debug.h> 73 72 74 /** 73 75 * Initialize EHCI TD. 74 76 * @param instance TD structure to initialize. 75 * @param next Next TD in ED list.77 * @param next_phys Next TD in ED list. 76 78 * @param direction Used to determine PID, BOTH means setup PID. 77 79 * @param buffer Pointer to the first byte of transferred data. … … 80 82 * any other value means that ED toggle will be used. 81 83 */ 82 void td_init(td_t *instance, const td_t *next, 83 usb_direction_t direction, const void *buffer, size_t size, int toggle, 84 bool ioc) 84 void td_init(td_t *instance, uintptr_t next_phys, uintptr_t buffer, 85 usb_direction_t direction, size_t size, int toggle, bool ioc) 85 86 { 86 87 assert(instance); … … 98 99 } 99 100 100 if (buffer != NULL) {101 if (buffer != 0) { 101 102 assert(size != 0); 102 103 for (unsigned i = 0; (i < ARRAY_SIZE(instance->buffer_pointer)) 103 104 && size; ++i) { 104 const uintptr_t page = 105 (addr_to_phys(buffer) & TD_BUFFER_POINTER_MASK); 106 const size_t offset = 107 ((uintptr_t)buffer & TD_BUFFER_POINTER_OFFSET_MASK); 105 const uintptr_t offset = buffer & TD_BUFFER_POINTER_OFFSET_MASK; 108 106 assert(offset == 0 || i == 0); 109 size -= min((4096 - offset), size);110 buffer += min((4096 - offset), size);111 EHCI_MEM32_WR(instance->buffer_pointer[i],112 page | offset);107 const size_t this_size = min(size, 4096 - offset); 108 EHCI_MEM32_WR(instance->buffer_pointer[i], buffer); 109 size -= this_size; 110 buffer += this_size; 113 111 } 114 112 } 115 113 116 EHCI_MEM32_WR(instance->next, next ?117 LINK_POINTER_TD( addr_to_phys(next)) : LINK_POINTER_TERM);114 EHCI_MEM32_WR(instance->next, next_phys ? 115 LINK_POINTER_TD(next_phys) : LINK_POINTER_TERM); 118 116 119 117 EHCI_MEM32_WR(instance->alternate, LINK_POINTER_TERM); -
uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h
rf5e5f73 rdf6ded8 37 37 #include <stddef.h> 38 38 #include <stdint.h> 39 #include <macros.h> 39 40 #include "link_pointer.h" 40 41 #include "mem_access.h" … … 75 76 /* 64 bit struct only */ 76 77 volatile uint32_t extended_bp[5]; 77 } td_t; 78 79 } __attribute__((packed,aligned(32))) td_t; 80 81 static_assert(sizeof(td_t) % 32 == 0); 78 82 79 83 static inline bool td_active(const td_t *td) … … 92 96 errno_t td_error(const td_t *td); 93 97 94 void td_init(td_t *td, const td_t *next, usb_direction_t dir, const void * buf,98 void td_init(td_t *td, uintptr_t next_phys, uintptr_t buf, usb_direction_t dir, 95 99 size_t buf_size, int toggle, bool ioc); 96 100 -
uspace/drv/bus/usb/ehci/main.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Jan Vesely 3 3 * Copyright (c) 2011 Vojtech Horky 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 4 5 * All rights reserved. 5 6 * … … 35 36 */ 36 37 37 #include <ddf/driver.h>38 #include <ddf/interrupt.h>39 #include <device/hw_res.h>40 #include <errno.h>41 #include <str_error.h>42 38 #include <io/logctl.h> 43 44 #include <usb_iface.h> 45 #include <usb/debug.h> 46 #include <usb/host/ddf_helpers.h> 39 #include <usb/host/hcd.h> 47 40 48 41 #include "res.h" 49 42 #include "hc.h" 50 #include "ehci_endpoint.h"51 43 52 44 #define NAME "ehci" 53 45 54 static errno_t ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 55 static void ehci_driver_fini(hcd_t *); 46 static const hc_driver_t ehci_driver = { 47 .name = NAME, 48 .hc_device_size = sizeof(hc_t), 56 49 57 static const ddf_hc_driver_t ehci_hc_driver = { 50 .hc_add = hc_add, 51 .irq_code_gen = hc_gen_irq_code, 58 52 .claim = disable_legacy, 59 .hc_speed = USB_SPEED_HIGH, 60 .irq_code_gen = ehci_hc_gen_irq_code, 61 .init = ehci_driver_init, 62 .fini = ehci_driver_fini, 63 .name = "EHCI-PCI", 64 .ops = { 65 .schedule = ehci_hc_schedule, 66 .ep_add_hook = ehci_endpoint_init, 67 .ep_remove_hook = ehci_endpoint_fini, 68 .irq_hook = ehci_hc_interrupt, 69 .status_hook = ehci_hc_status, 70 } 53 .start = hc_start, 54 .setup_root_hub = hc_setup_roothub, 55 .hc_gone = hc_gone, 71 56 }; 72 73 74 static errno_t ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res,75 bool irq)76 {77 assert(hcd);78 assert(hcd_get_driver_data(hcd) == NULL);79 80 hc_t *instance = malloc(sizeof(hc_t));81 if (!instance)82 return ENOMEM;83 84 const errno_t ret = hc_init(instance, res, irq);85 if (ret == EOK) {86 hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops);87 } else {88 free(instance);89 }90 return ret;91 }92 93 static void ehci_driver_fini(hcd_t *hcd)94 {95 assert(hcd);96 hc_t *hc = hcd_get_driver_data(hcd);97 if (hc)98 hc_fini(hc);99 100 free(hc);101 hcd_set_implementation(hcd, NULL, NULL);102 }103 104 /** Initializes a new ddf driver instance of EHCI hcd.105 *106 * @param[in] device DDF instance of the device to initialize.107 * @return Error code.108 */109 static errno_t ehci_dev_add(ddf_dev_t *device)110 {111 usb_log_debug("ehci_dev_add() called\n");112 assert(device);113 114 return hcd_ddf_add_hc(device, &ehci_hc_driver);115 116 }117 118 119 static const driver_ops_t ehci_driver_ops = {120 .dev_add = ehci_dev_add,121 };122 123 static const driver_t ehci_driver = {124 .name = NAME,125 .driver_ops = &ehci_driver_ops126 };127 128 57 129 58 /** Initializes global driver structures (NONE). … … 139 68 log_init(NAME); 140 69 logctl_set_log_level(NAME, LVL_NOTE); 141 return ddf_driver_main(&ehci_driver);70 return hc_driver_main(&ehci_driver); 142 71 } 143 72 -
uspace/drv/bus/usb/ehci/res.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 45 46 #include <pci_dev_iface.h> 46 47 48 #include "hc.h" 47 49 #include "res.h" 48 50 #include "ehci_regs.h" … … 73 75 eecp + USBLEGSUP_OFFSET, &usblegsup); 74 76 if (ret != EOK) { 75 usb_log_error("Failed to read USBLEGSUP: %s. \n", str_error(ret));76 return ret; 77 } 78 usb_log_debug2("USBLEGSUP: %" PRIx32 ". \n", usblegsup);77 usb_log_error("Failed to read USBLEGSUP: %s.", str_error(ret)); 78 return ret; 79 } 80 usb_log_debug2("USBLEGSUP: %" PRIx32 ".", usblegsup); 79 81 80 82 /* Request control from firmware/BIOS by writing 1 to highest 81 83 * byte. (OS Control semaphore)*/ 82 usb_log_debug("Requesting OS control. \n");84 usb_log_debug("Requesting OS control."); 83 85 ret = pci_config_space_write_8(parent_sess, 84 86 eecp + USBLEGSUP_OFFSET + 3, 1); 85 87 if (ret != EOK) { 86 usb_log_error("Failed to request OS EHCI control: %s. \n",88 usb_log_error("Failed to request OS EHCI control: %s.", 87 89 str_error(ret)); 88 90 return ret; … … 102 104 103 105 if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) { 104 usb_log_info("BIOS released control after %zu usec. \n", wait);106 usb_log_info("BIOS released control after %zu usec.", wait); 105 107 return EOK; 106 108 } … … 108 110 /* BIOS failed to hand over control, this should not happen. */ 109 111 usb_log_warning( "BIOS failed to release control after " 110 "%zu usecs, force it. \n", wait);112 "%zu usecs, force it.", wait); 111 113 ret = pci_config_space_write_32(parent_sess, 112 114 eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL); 113 115 if (ret != EOK) { 114 usb_log_error("Failed to force OS control: %s. \n",116 usb_log_error("Failed to force OS control: %s.", 115 117 str_error(ret)); 116 118 return ret; … … 129 131 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts); 130 132 if (ret != EOK) { 131 usb_log_error("Failed to get USBLEGCTLSTS: %s. \n",133 usb_log_error("Failed to get USBLEGCTLSTS: %s.", 132 134 str_error(ret)); 133 135 return ret; 134 136 } 135 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ". \n", usblegctlsts);137 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".", usblegctlsts); 136 138 /* 137 139 * Zero SMI enables in legacy control register. … … 142 144 eecp + USBLEGCTLSTS_OFFSET, 0xe0000000); 143 145 if (ret != EOK) { 144 usb_log_error("Failed to zero USBLEGCTLSTS: %s \n",146 usb_log_error("Failed to zero USBLEGCTLSTS: %s", 145 147 str_error(ret)); 146 148 return ret; … … 152 154 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts); 153 155 if (ret != EOK) { 154 usb_log_error("Failed to get USBLEGCTLSTS 2: %s. \n",156 usb_log_error("Failed to get USBLEGCTLSTS 2: %s.", 155 157 str_error(ret)); 156 158 return ret; 157 159 } 158 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ". \n",160 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".", 159 161 usblegctlsts); 160 162 } … … 164 166 eecp + USBLEGSUP_OFFSET, &usblegsup); 165 167 if (ret != EOK) { 166 usb_log_error("Failed to read USBLEGSUP: %s. \n",167 str_error(ret)); 168 return ret; 169 } 170 usb_log_debug2("USBLEGSUP: %" PRIx32 ". \n", usblegsup);168 usb_log_error("Failed to read USBLEGSUP: %s.", 169 str_error(ret)); 170 return ret; 171 } 172 usb_log_debug2("USBLEGSUP: %" PRIx32 ".", usblegsup); 171 173 return ret; 172 174 } 173 175 174 errno_t disable_legacy( ddf_dev_t *device)176 errno_t disable_legacy(hc_device_t *hcd) 175 177 { 176 assert(device);177 178 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);178 hc_t *hc = hcd_to_hc(hcd); 179 180 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 179 181 if (parent_sess == NULL) 180 182 return ENOMEM; 181 183 182 usb_log_debug("Disabling EHCI legacy support.\n"); 183 184 hw_res_list_parsed_t res; 185 hw_res_list_parsed_init(&res); 186 errno_t ret = hw_res_get_list_parsed(parent_sess, &res, 0); 187 if (ret != EOK) { 188 usb_log_error("Failed to get resource list: %s\n", 189 str_error(ret)); 190 goto clean; 191 } 192 193 if (res.mem_ranges.count < 1) { 194 usb_log_error("Incorrect mem range count: %zu", 195 res.mem_ranges.count); 196 ret = EINVAL; 197 goto clean; 198 } 199 200 /* Map EHCI registers */ 201 void *regs = NULL; 202 ret = pio_enable_range(&res.mem_ranges.ranges[0], ®s); 203 if (ret != EOK) { 204 usb_log_error("Failed to map registers %p: %s.\n", 205 RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret)); 206 goto clean; 207 } 208 209 usb_log_debug("Registers mapped at: %p.\n", regs); 210 211 ehci_caps_regs_t *ehci_caps = regs; 212 213 const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams); 214 usb_log_debug2("Value of hcc params register: %x.\n", hcc_params); 184 usb_log_debug("Disabling EHCI legacy support."); 185 186 const uint32_t hcc_params = EHCI_RD(hc->caps->hccparams); 187 usb_log_debug2("Value of hcc params register: %x.", hcc_params); 215 188 216 189 /* Read value of EHCI Extended Capabilities Pointer … … 218 191 const uint32_t eecp = 219 192 (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK; 220 usb_log_debug2("Value of EECP: %x. \n", eecp);221 222 ret = disable_extended_caps(parent_sess, eecp);223 if (ret != EOK) { 224 usb_log_error("Failed to disable extended capabilities: %s. \n",193 usb_log_debug2("Value of EECP: %x.", eecp); 194 195 int ret = disable_extended_caps(parent_sess, eecp); 196 if (ret != EOK) { 197 usb_log_error("Failed to disable extended capabilities: %s.", 225 198 str_error(ret)); 226 199 goto clean; 227 200 } 228 201 clean: 229 //TODO unmap registers 230 hw_res_list_parsed_clean(&res); 202 async_hangup(parent_sess); 231 203 return ret; 232 204 } -
uspace/drv/bus/usb/ehci/res.h
rf5e5f73 rdf6ded8 36 36 #define DRV_EHCI_PCI_H 37 37 38 #include <ddf/driver.h> 39 #include <device/hw_res_parsed.h> 38 typedef struct hc_device hc_device_t; 40 39 41 extern errno_t disable_legacy( ddf_dev_t *);40 extern errno_t disable_legacy(hc_device_t *); 42 41 43 42 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
