Changeset df6ded8 in mainline for uspace/drv/bus
- Timestamp:
- 2018-02-28T16:37:50Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, 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
- Files:
-
- 42 added
- 2 deleted
- 61 edited
- 2 moved
-
ehci/Makefile (modified) (1 diff)
-
ehci/ehci_batch.c (modified) (17 diffs)
-
ehci/ehci_batch.h (modified) (3 diffs)
-
ehci/ehci_bus.c (added)
-
ehci/ehci_bus.h (moved) (moved from uspace/drv/bus/usb/ehci/ehci_endpoint.h ) (3 diffs)
-
ehci/ehci_endpoint.c (deleted)
-
ehci/ehci_rh.c (modified) (13 diffs)
-
ehci/ehci_rh.h (modified) (2 diffs)
-
ehci/endpoint_list.c (modified) (7 diffs)
-
ehci/endpoint_list.h (modified) (3 diffs)
-
ehci/hc.c (modified) (21 diffs)
-
ehci/hc.h (modified) (5 diffs)
-
ehci/hw_struct/iso_transfer_descriptor.h (modified) (1 diff)
-
ehci/hw_struct/queue_head.c (modified) (4 diffs)
-
ehci/hw_struct/queue_head.h (modified) (2 diffs)
-
ehci/hw_struct/split_iso_transfer_descriptor.h (modified) (1 diff)
-
ehci/hw_struct/transfer_descriptor.c (modified) (5 diffs)
-
ehci/hw_struct/transfer_descriptor.h (modified) (3 diffs)
-
ehci/main.c (modified) (3 diffs)
-
ehci/res.c (modified) (10 diffs)
-
ehci/res.h (modified) (1 diff)
-
ohci/Makefile (modified) (1 diff)
-
ohci/endpoint_list.c (modified) (8 diffs)
-
ohci/endpoint_list.h (modified) (1 diff)
-
ohci/hc.c (modified) (30 diffs)
-
ohci/hc.h (modified) (4 diffs)
-
ohci/hw_struct/endpoint_descriptor.c (modified) (3 diffs)
-
ohci/hw_struct/endpoint_descriptor.h (modified) (4 diffs)
-
ohci/hw_struct/iso_transfer_descriptor.h (modified) (1 diff)
-
ohci/hw_struct/transfer_descriptor.c (modified) (1 diff)
-
ohci/hw_struct/transfer_descriptor.h (modified) (2 diffs)
-
ohci/main.c (modified) (3 diffs)
-
ohci/ohci_batch.c (modified) (18 diffs)
-
ohci/ohci_batch.h (modified) (3 diffs)
-
ohci/ohci_bus.c (added)
-
ohci/ohci_bus.h (moved) (moved from uspace/drv/bus/usb/ohci/ohci_endpoint.h ) (3 diffs)
-
ohci/ohci_endpoint.c (deleted)
-
ohci/ohci_rh.c (modified) (11 diffs)
-
ohci/ohci_rh.h (modified) (1 diff)
-
uhci/hc.c (modified) (26 diffs)
-
uhci/hc.h (modified) (5 diffs)
-
uhci/hw_struct/queue_head.h (modified) (1 diff)
-
uhci/hw_struct/transfer_descriptor.c (modified) (2 diffs)
-
uhci/hw_struct/transfer_descriptor.h (modified) (1 diff)
-
uhci/main.c (modified) (6 diffs)
-
uhci/transfer_list.c (modified) (9 diffs)
-
uhci/transfer_list.h (modified) (1 diff)
-
uhci/uhci_batch.c (modified) (15 diffs)
-
uhci/uhci_batch.h (modified) (7 diffs)
-
uhci/uhci_rh.c (modified) (12 diffs)
-
usbdiag/Makefile (added)
-
usbdiag/device.c (added)
-
usbdiag/device.h (added)
-
usbdiag/main.c (added)
-
usbdiag/tests.c (added)
-
usbdiag/tests.h (added)
-
usbdiag/usbdiag.ma (added)
-
usbflbk/main.c (modified) (4 diffs)
-
usbhub/main.c (modified) (1 diff)
-
usbhub/port.c (modified) (4 diffs)
-
usbhub/port.h (modified) (4 diffs)
-
usbhub/status.h (modified) (2 diffs)
-
usbhub/usbhub.c (modified) (15 diffs)
-
usbhub/usbhub.h (modified) (4 diffs)
-
usbmid/dump.c (modified) (1 diff)
-
usbmid/explore.c (modified) (6 diffs)
-
usbmid/main.c (modified) (7 diffs)
-
usbmid/usbmid.c (modified) (4 diffs)
-
vhc/conndev.c (modified) (2 diffs)
-
vhc/hub/hub.c (modified) (10 diffs)
-
vhc/hub/virthubops.c (modified) (4 diffs)
-
vhc/main.c (modified) (4 diffs)
-
vhc/transfer.c (modified) (16 diffs)
-
vhc/vhcd.h (modified) (5 diffs)
-
xhci/Makefile (added)
-
xhci/bus.c (added)
-
xhci/bus.h (added)
-
xhci/commands.c (added)
-
xhci/commands.h (added)
-
xhci/debug.c (added)
-
xhci/debug.h (added)
-
xhci/device.c (added)
-
xhci/device.h (added)
-
xhci/endpoint.c (added)
-
xhci/endpoint.h (added)
-
xhci/hc.c (added)
-
xhci/hc.h (added)
-
xhci/hw_struct/README (added)
-
xhci/hw_struct/common.h (added)
-
xhci/hw_struct/context.h (added)
-
xhci/hw_struct/regs.h (added)
-
xhci/hw_struct/trb.h (added)
-
xhci/isoch.c (added)
-
xhci/isoch.h (added)
-
xhci/main.c (added)
-
xhci/rh.c (added)
-
xhci/rh.h (added)
-
xhci/scratchpad.c (added)
-
xhci/scratchpad.h (added)
-
xhci/streams.c (added)
-
xhci/streams.h (added)
-
xhci/test/reg-ops.c (added)
-
xhci/transfers.c (added)
-
xhci/transfers.h (added)
-
xhci/trb_ring.c (added)
-
xhci/trb_ring.h (added)
-
xhci/xhci.ma (added)
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 -
uspace/drv/bus/usb/ohci/Makefile
rf5e5f73 rdf6ded8 38 38 main.c \ 39 39 ohci_batch.c \ 40 ohci_ endpoint.c \40 ohci_bus.c \ 41 41 ohci_rh.c \ 42 42 hw_struct/endpoint_descriptor.c \ -
uspace/drv/bus/usb/ohci/endpoint_list.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 * … … 57 58 instance->list_head = malloc32(sizeof(ed_t)); 58 59 if (!instance->list_head) { 59 usb_log_error("Failed to allocate list head. \n");60 usb_log_error("Failed to allocate list head."); 60 61 return ENOMEM; 61 62 } 62 63 instance->list_head_pa = addr_to_phys(instance->list_head); 63 usb_log_debug2("Transfer list %s setup with ED: %p(0x%0" PRIx32 ")). \n",64 usb_log_debug2("Transfer list %s setup with ED: %p(0x%0" PRIx32 ")).", 64 65 name, instance->list_head, instance->list_head_pa); 65 66 … … 96 97 assert(instance); 97 98 assert(ep); 98 usb_log_debug2("Queue %s: Adding endpoint(%p). \n", instance->name, ep);99 usb_log_debug2("Queue %s: Adding endpoint(%p).", instance->name, ep); 99 100 100 101 fibril_mutex_lock(&instance->guard); … … 108 109 /* There are active EDs, get the last one */ 109 110 ohci_endpoint_t *last = list_get_instance( 110 list_last(&instance->endpoint_list), ohci_endpoint_t, link);111 list_last(&instance->endpoint_list), ohci_endpoint_t, eplist_link); 111 112 last_ed = last->ed; 112 113 } … … 122 123 123 124 /* Add to the sw list */ 124 list_append(&ep-> link, &instance->endpoint_list);125 list_append(&ep->eplist_link, &instance->endpoint_list); 125 126 126 127 ohci_endpoint_t *first = list_get_instance( 127 list_first(&instance->endpoint_list), ohci_endpoint_t, link);128 usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p). \n",128 list_first(&instance->endpoint_list), ohci_endpoint_t, eplist_link); 129 usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).", 129 130 ep, instance->name, first, first->ed); 130 131 if (last_ed == instance->list_head) { 131 usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x. \n",132 usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.", 132 133 instance->name, last_ed, instance->list_head_pa, 133 134 last_ed->status, last_ed->td_tail, last_ed->td_head, … … 151 152 fibril_mutex_lock(&instance->guard); 152 153 153 usb_log_debug2("Queue %s: removing endpoint(%p). \n", instance->name, ep);154 usb_log_debug2("Queue %s: removing endpoint(%p).", instance->name, ep); 154 155 155 156 const char *qpos = NULL; 156 157 ed_t *prev_ed; 157 158 /* Remove from the hardware queue */ 158 if (list_first(&instance->endpoint_list) == &ep-> link) {159 if (list_first(&instance->endpoint_list) == &ep->eplist_link) { 159 160 /* I'm the first one here */ 160 161 prev_ed = instance->list_head; … … 162 163 } else { 163 164 ohci_endpoint_t *prev = 164 list_get_instance(ep-> link.prev, ohci_endpoint_t,link);165 list_get_instance(ep->eplist_link.prev, ohci_endpoint_t, eplist_link); 165 166 prev_ed = prev->ed; 166 167 qpos = "NOT FIRST"; … … 171 172 write_barrier(); 172 173 173 usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x. \n",174 usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.", 174 175 ep, qpos, instance->name, ep->ed->next); 175 176 176 177 /* Remove from the endpoint list */ 177 list_remove(&ep-> link);178 list_remove(&ep->eplist_link); 178 179 fibril_mutex_unlock(&instance->guard); 179 180 } -
uspace/drv/bus/usb/ohci/endpoint_list.h
rf5e5f73 rdf6ded8 41 41 #include <usb/host/utils/malloc32.h> 42 42 43 #include "ohci_ endpoint.h"43 #include "ohci_bus.h" 44 44 #include "hw_struct/endpoint_descriptor.h" 45 45 -
uspace/drv/bus/usb/ohci/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 46 47 #include <usb/debug.h> 48 #include <usb/host/utility.h> 47 49 #include <usb/usb.h> 48 50 49 #include "ohci_ endpoint.h"51 #include "ohci_bus.h" 50 52 #include "ohci_batch.h" 51 53 … … 89 91 }; 90 92 91 static void hc_gain_control(hc_t *instance);92 static void hc_start(hc_t *instance);93 93 static errno_t hc_init_transfer_lists(hc_t *instance); 94 94 static errno_t hc_init_memory(hc_t *instance); … … 103 103 * @return Error code. 104 104 */ 105 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)105 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq) 106 106 { 107 107 assert(code); … … 138 138 OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS); 139 139 140 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.", 141 141 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 142 142 … … 152 152 * @return Error code 153 153 */ 154 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)155 { 156 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); 157 157 assert(hw_res); 158 158 if (hw_res->mem_ranges.count != 1 || … … 163 163 (void **) &instance->registers); 164 164 if (ret != EOK) { 165 usb_log_error("Failed to gain access to registers: %s. \n",165 usb_log_error("Failed to gain access to registers: %s.", 166 166 str_error(ret)); 167 167 return ret; 168 168 } 169 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",169 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 170 170 hw_res->mem_ranges.ranges[0].address.absolute, 171 171 hw_res->mem_ranges.ranges[0].size); 172 172 173 list_initialize(&instance->pending_ batches);173 list_initialize(&instance->pending_endpoints); 174 174 fibril_mutex_initialize(&instance->guard); 175 instance->hw_interrupts = interrupts;176 175 177 176 ret = hc_init_memory(instance); 178 177 if (ret != EOK) { 179 usb_log_error("Failed to create OHCI memory structures: %s. \n",178 usb_log_error("Failed to create OHCI memory structures: %s.", 180 179 str_error(ret)); 181 180 // TODO: We should disable pio access here … … 183 182 } 184 183 185 hc_gain_control(instance);186 187 ohci_rh_init(&instance->rh, instance->registers, "ohci rh");188 hc_start(instance);189 190 184 return EOK; 191 185 } … … 195 189 * @param[in] instance Host controller structure to use. 196 190 */ 197 void hc_fini(hc_t *instance)191 int hc_gone(hc_device_t *instance) 198 192 { 199 193 assert(instance); 200 194 /* TODO: implement*/ 201 }; 195 return ENOTSUP; 196 } 202 197 203 198 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) … … 269 264 } 270 265 271 errno_t ohci_hc_status( hcd_t *hcd, uint32_t *status)272 { 273 assert( hcd);266 errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status) 267 { 268 assert(bus_base); 274 269 assert(status); 275 hc_t *instance = hcd_get_driver_data(hcd); 276 assert(instance); 277 278 if (instance->registers){ 279 *status = OHCI_RD(instance->registers->interrupt_status); 280 OHCI_WR(instance->registers->interrupt_status, *status); 270 271 ohci_bus_t *bus = (ohci_bus_t *) bus_base; 272 hc_t *hc = bus->hc; 273 assert(hc); 274 275 if (hc->registers){ 276 *status = OHCI_RD(hc->registers->interrupt_status); 277 OHCI_WR(hc->registers->interrupt_status, *status); 281 278 } 282 279 return EOK; … … 289 286 * @return Error code. 290 287 */ 291 errno_t ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 292 { 293 assert(hcd); 294 hc_t *instance = hcd_get_driver_data(hcd); 295 assert(instance); 288 errno_t ohci_hc_schedule(usb_transfer_batch_t *batch) 289 { 290 assert(batch); 291 292 ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep); 293 hc_t *hc = bus->hc; 294 assert(hc); 296 295 297 296 /* Check for root hub communication */ 298 if (batch->ep->address == ohci_rh_get_address(&instance->rh)) { 299 usb_log_debug("OHCI root hub request.\n"); 300 return ohci_rh_schedule(&instance->rh, batch); 301 } 297 if (batch->target.address == ohci_rh_get_address(&hc->rh)) { 298 usb_log_debug("OHCI root hub request."); 299 return ohci_rh_schedule(&hc->rh, batch); 300 } 301 302 endpoint_t *ep = batch->ep; 303 ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep); 302 304 ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch); 303 if (!ohci_batch) 304 return ENOMEM; 305 306 fibril_mutex_lock(&instance->guard); 307 list_append(&ohci_batch->link, &instance->pending_batches); 305 int err; 306 307 if ((err = ohci_transfer_batch_prepare(ohci_batch))) 308 return err; 309 310 fibril_mutex_lock(&hc->guard); 311 if ((err = endpoint_activate_locked(ep, batch))) { 312 fibril_mutex_unlock(&hc->guard); 313 return err; 314 } 315 308 316 ohci_transfer_batch_commit(ohci_batch); 317 list_append(&ohci_ep->pending_link, &hc->pending_endpoints); 318 fibril_mutex_unlock(&hc->guard); 309 319 310 320 /* Control and bulk schedules need a kick to start working */ … … 312 322 { 313 323 case USB_TRANSFER_CONTROL: 314 OHCI_SET( instance->registers->command_status, CS_CLF);324 OHCI_SET(hc->registers->command_status, CS_CLF); 315 325 break; 316 326 case USB_TRANSFER_BULK: 317 OHCI_SET( instance->registers->command_status, CS_BLF);327 OHCI_SET(hc->registers->command_status, CS_BLF); 318 328 break; 319 329 default: 320 330 break; 321 331 } 322 fibril_mutex_unlock(&instance->guard); 332 323 333 return EOK; 324 334 } … … 329 339 * @param[in] status Value of the status register at the time of interrupt. 330 340 */ 331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status) 332 { 333 assert(hcd); 334 hc_t *instance = hcd_get_driver_data(hcd); 341 void ohci_hc_interrupt(bus_t *bus_base, uint32_t status) 342 { 343 assert(bus_base); 344 345 ohci_bus_t *bus = (ohci_bus_t *) bus_base; 346 hc_t *hc = bus->hc; 347 assert(hc); 348 335 349 status = OHCI_RD(status); 336 assert( instance);350 assert(hc); 337 351 if ((status & ~I_SF) == 0) /* ignore sof status */ 338 352 return; 339 usb_log_debug2("OHCI(%p) interrupt: %x. \n", instance, status);353 usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status); 340 354 if (status & I_RHSC) 341 ohci_rh_interrupt(& instance->rh);355 ohci_rh_interrupt(&hc->rh); 342 356 343 357 if (status & I_WDH) { 344 fibril_mutex_lock(&instance->guard); 345 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca, 346 OHCI_RD(instance->registers->hcca), 347 (void *) addr_to_phys(instance->hcca)); 348 usb_log_debug2("Periodic current: %#" PRIx32 ".\n", 349 OHCI_RD(instance->registers->periodic_current)); 350 351 link_t *current = list_first(&instance->pending_batches); 352 while (current && current != &instance->pending_batches.head) { 353 link_t *next = current->next; 354 ohci_transfer_batch_t *batch = 355 ohci_transfer_batch_from_link(current); 356 357 if (ohci_transfer_batch_is_complete(batch)) { 358 fibril_mutex_lock(&hc->guard); 359 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca, 360 OHCI_RD(hc->registers->hcca), 361 (void *) addr_to_phys(hc->hcca)); 362 usb_log_debug2("Periodic current: %#" PRIx32 ".", 363 OHCI_RD(hc->registers->periodic_current)); 364 365 list_foreach_safe(hc->pending_endpoints, current, next) { 366 ohci_endpoint_t *ep 367 = list_get_instance(current, ohci_endpoint_t, pending_link); 368 369 ohci_transfer_batch_t *batch 370 = ohci_transfer_batch_get(ep->base.active_batch); 371 assert(batch); 372 373 if (ohci_transfer_batch_check_completed(batch)) { 374 endpoint_deactivate_locked(&ep->base); 358 375 list_remove(current); 359 ohci_transfer_batch_finish_dispose(batch); 376 hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset); 377 usb_transfer_batch_finish(&batch->base); 360 378 } 361 362 current = next;363 379 } 364 fibril_mutex_unlock(& instance->guard);380 fibril_mutex_unlock(&hc->guard); 365 381 } 366 382 367 383 if (status & I_UE) { 368 usb_log_fatal("Error like no other! \n");369 hc_start( instance);384 usb_log_fatal("Error like no other!"); 385 hc_start(&hc->base); 370 386 } 371 387 … … 379 395 * @param[in] instance OHCI hc driver structure. 380 396 */ 381 void hc_gain_control(hc_t *instance)382 { 383 assert(instance);384 385 usb_log_debug("Requesting OHCI control. \n");397 int hc_gain_control(hc_device_t *hcd) 398 { 399 hc_t *instance = hcd_to_hc(hcd); 400 401 usb_log_debug("Requesting OHCI control."); 386 402 if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) { 387 403 /* Turn off legacy emulation, it should be enough to zero … … 392 408 volatile uint32_t *ohci_emulation_reg = 393 409 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET); 394 usb_log_debug("OHCI legacy register %p: %x. \n",410 usb_log_debug("OHCI legacy register %p: %x.", 395 411 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 396 412 /* Zero everything but A20State */ … … 398 414 OHCI_CLR(*ohci_emulation_reg, ~0x100); 399 415 usb_log_debug( 400 "OHCI legacy register (should be 0 or 0x100) %p: %x. \n",416 "OHCI legacy register (should be 0 or 0x100) %p: %x.", 401 417 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 402 418 } … … 404 420 /* Interrupt routing enabled => smm driver is active */ 405 421 if (OHCI_RD(instance->registers->control) & C_IR) { 406 usb_log_debug("SMM driver: request ownership change. \n");422 usb_log_debug("SMM driver: request ownership change."); 407 423 // TODO: should we ack interrupts before doing this? 408 424 OHCI_SET(instance->registers->command_status, CS_OCR); … … 411 427 async_usleep(1000); 412 428 } 413 usb_log_info("SMM driver: Ownership taken. \n");429 usb_log_info("SMM driver: Ownership taken."); 414 430 C_HCFS_SET(instance->registers->control, C_HCFS_RESET); 415 431 async_usleep(50000); 416 return ;432 return EOK; 417 433 } 418 434 … … 420 436 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 421 437 if (hc_status != C_HCFS_RESET) { 422 usb_log_debug("BIOS driver found. \n");438 usb_log_debug("BIOS driver found."); 423 439 if (hc_status == C_HCFS_OPERATIONAL) { 424 usb_log_info("BIOS driver: HC operational. \n");425 return ;440 usb_log_info("BIOS driver: HC operational."); 441 return EOK; 426 442 } 427 443 /* HC is suspended assert resume for 20ms */ 428 444 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME); 429 445 async_usleep(20000); 430 usb_log_info("BIOS driver: HC resumed. \n");431 return ;446 usb_log_info("BIOS driver: HC resumed."); 447 return EOK; 432 448 } 433 449 434 450 /* HC is in reset (hw startup) => no other driver 435 451 * maintain reset for at least the time specified in USB spec (50 ms)*/ 436 usb_log_debug("Host controller found in reset state. \n");452 usb_log_debug("Host controller found in reset state."); 437 453 async_usleep(50000); 454 return EOK; 438 455 } 439 456 … … 442 459 * @param[in] instance OHCI hc driver structure. 443 460 */ 444 void hc_start(hc_t *instance) 445 { 461 int hc_start(hc_device_t *hcd) 462 { 463 hc_t *instance = hcd_to_hc(hcd); 464 ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh"); 465 446 466 /* OHCI guide page 42 */ 447 467 assert(instance); 448 usb_log_debug2("Started hc initialization routine. \n");468 usb_log_debug2("Started hc initialization routine."); 449 469 450 470 /* Save contents of fm_interval register */ 451 471 const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval); 452 usb_log_debug2("Old value of HcFmInterval: %x. \n", fm_interval);472 usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval); 453 473 454 474 /* Reset hc */ 455 usb_log_debug2("HC reset. \n");475 usb_log_debug2("HC reset."); 456 476 size_t time = 0; 457 477 OHCI_WR(instance->registers->command_status, CS_HCR); … … 460 480 time += 10; 461 481 } 462 usb_log_debug2("HC reset complete in %zu us. \n", time);482 usb_log_debug2("HC reset complete in %zu us.", time); 463 483 464 484 /* Restore fm_interval */ … … 467 487 468 488 /* hc is now in suspend state */ 469 usb_log_debug2("HC should be in suspend state(%x). \n",489 usb_log_debug2("HC should be in suspend state(%x).", 470 490 OHCI_RD(instance->registers->control)); 471 491 … … 476 496 OHCI_WR(instance->registers->bulk_head, 477 497 instance->lists[USB_TRANSFER_BULK].list_head_pa); 478 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 "). \n",498 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").", 479 499 instance->lists[USB_TRANSFER_BULK].list_head, 480 500 instance->lists[USB_TRANSFER_BULK].list_head_pa); … … 482 502 OHCI_WR(instance->registers->control_head, 483 503 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); 484 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 "). \n",504 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").", 485 505 instance->lists[USB_TRANSFER_CONTROL].list_head, 486 506 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); … … 488 508 /* Enable queues */ 489 509 OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE)); 490 usb_log_debug("Queues enabled(%x). \n",510 usb_log_debug("Queues enabled(%x).", 491 511 OHCI_RD(instance->registers->control)); 492 512 493 513 /* Enable interrupts */ 494 if (instance-> hw_interrupts) {514 if (instance->base.irq_cap >= 0) { 495 515 OHCI_WR(instance->registers->interrupt_enable, 496 516 OHCI_USED_INTERRUPTS); 497 usb_log_debug("Enabled interrupts: %x. \n",517 usb_log_debug("Enabled interrupts: %x.", 498 518 OHCI_RD(instance->registers->interrupt_enable)); 499 519 OHCI_WR(instance->registers->interrupt_enable, I_MI); … … 505 525 OHCI_WR(instance->registers->periodic_start, 506 526 ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT); 507 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d). \n",527 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).", 508 528 OHCI_RD(instance->registers->periodic_start), 509 529 OHCI_RD(instance->registers->periodic_start), frame_length); 510 530 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL); 511 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x). \n",531 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).", 512 532 OHCI_RD(instance->registers->control)); 533 534 return EOK; 535 } 536 537 /** 538 * Setup roothub as a virtual hub. 539 */ 540 int hc_setup_roothub(hc_device_t *hcd) 541 { 542 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 513 543 } 514 544 … … 526 556 const errno_t ret = endpoint_list_init(&instance->lists[type], name); \ 527 557 if (ret != EOK) { \ 528 usb_log_error("Failed to setup %s endpoint list: %s. \n", \558 usb_log_error("Failed to setup %s endpoint list: %s.", \ 529 559 name, str_error(ret)); \ 530 560 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\ … … 558 588 memset(&instance->rh, 0, sizeof(instance->rh)); 559 589 /* Init queues */ 560 consterrno_t ret = hc_init_transfer_lists(instance);590 errno_t ret = hc_init_transfer_lists(instance); 561 591 if (ret != EOK) { 562 592 return ret; … … 567 597 if (instance->hcca == NULL) 568 598 return ENOMEM; 569 usb_log_debug2("OHCI HCCA initialized at %p. \n", instance->hcca);599 usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca); 570 600 571 601 for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) { … … 573 603 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 574 604 } 575 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 "). \n",605 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").", 576 606 instance->lists[USB_TRANSFER_INTERRUPT].list_head, 577 607 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 578 608 609 if ((ret = ohci_bus_init(&instance->bus, instance))) { 610 usb_log_error("HC(%p): Failed to setup bus : %s", 611 instance, str_error(ret)); 612 return ret; 613 } 614 615 hc_device_setup(&instance->base, (bus_t *) &instance->bus); 616 579 617 return EOK; 580 618 } -
uspace/drv/bus/usb/ohci/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 * … … 52 53 #include "ohci_regs.h" 53 54 #include "ohci_rh.h" 55 #include "ohci_bus.h" 54 56 #include "endpoint_list.h" 55 57 #include "hw_struct/hcca.h" … … 57 59 /** Main OHCI driver structure */ 58 60 typedef struct hc { 61 /** Common hcd header */ 62 hc_device_t base; 63 59 64 /** Memory mapped I/O registers area */ 60 65 ohci_regs_t *registers; 66 61 67 /** Host controller communication area structure */ 62 68 hcca_t *hcca; … … 64 70 /** Transfer schedules */ 65 71 endpoint_list_t lists[4]; 66 /** List of active transfers */67 list_t pending_batches;68 72 69 /** Fibril for periodic checks if interrupts can't be used*/70 fid_t interrupt_emulator;73 /** List of active endpoints */ 74 list_t pending_endpoints; 71 75 72 76 /** Guards schedule and endpoint manipulation */ 73 77 fibril_mutex_t guard; 74 78 75 /** interrupts available */76 bool hw_interrupts;77 78 79 /** USB hub emulation structure */ 79 80 ohci_rh_t rh; 81 82 /** USB bookkeeping */ 83 ohci_bus_t bus; 80 84 } hc_t; 81 85 82 extern errno_t hc_init(hc_t *, const hw_res_list_parsed_t *, bool); 83 extern void hc_fini(hc_t *); 86 static inline hc_t *hcd_to_hc(hc_device_t *hcd) 87 { 88 assert(hcd); 89 return (hc_t *) hcd; 90 } 91 92 extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *); 93 extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *, 94 const hw_res_list_parsed_t *, int *); 95 extern errno_t hc_gain_control(hc_device_t *); 96 extern errno_t hc_start(hc_device_t *); 97 extern errno_t hc_setup_roothub(hc_device_t *); 98 extern errno_t hc_gone(hc_device_t *); 84 99 85 100 extern void hc_enqueue_endpoint(hc_t *, const endpoint_t *); 86 101 extern void hc_dequeue_endpoint(hc_t *, const endpoint_t *); 87 102 88 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq); 89 90 extern void ohci_hc_interrupt(hcd_t *, uint32_t); 91 extern errno_t ohci_hc_status(hcd_t *, uint32_t *); 92 extern errno_t ohci_hc_schedule(hcd_t *, usb_transfer_batch_t *); 103 extern errno_t ohci_hc_schedule(usb_transfer_batch_t *); 104 extern errno_t ohci_hc_status(bus_t *, uint32_t *); 105 extern void ohci_hc_interrupt(bus_t *, uint32_t); 93 106 94 107 #endif -
uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c
rf5e5f73 rdf6ded8 40 40 #include <usb/usb.h> 41 41 #include <usb/host/utils/malloc32.h> 42 #include <usb/host/endpoint.h> 43 #include <usb/host/bus.h> 42 44 43 45 #include "mem_access.h" … … 79 81 /* Status: address, endpoint nr, direction mask and max packet size. */ 80 82 OHCI_MEM32_WR(instance->status, 81 ((ep-> address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)83 ((ep->device->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT) 82 84 | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT) 83 85 | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT) 84 | ((ep->max_packet_size & ED_STATUS_MPS_MASK) 85 << ED_STATUS_MPS_SHIFT)); 86 | ((ep->max_packet_size & ED_STATUS_MPS_MASK) << ED_STATUS_MPS_SHIFT)); 86 87 87 88 /* Low speed flag */ 88 if (ep-> speed == USB_SPEED_LOW)89 if (ep->device->speed == USB_SPEED_LOW) 89 90 OHCI_MEM32_SET(instance->status, ED_STATUS_S_FLAG); 90 91 … … 98 99 OHCI_MEM32_WR(instance->td_head, pa & ED_TDHEAD_PTR_MASK); 99 100 OHCI_MEM32_WR(instance->td_tail, pa & ED_TDTAIL_PTR_MASK); 100 101 /* Set toggle bit */102 if (ep->toggle)103 OHCI_MEM32_SET(instance->td_head, ED_TDHEAD_TOGGLE_CARRY);104 105 101 } 106 102 /** -
uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.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 * … … 106 107 #define ED_NEXT_PTR_MASK (0xfffffff0) 107 108 #define ED_NEXT_PTR_SHIFT (0) 108 } __attribute__((packed )) ed_t;109 } __attribute__((packed, aligned(32))) ed_t; 109 110 110 111 void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td); … … 162 163 assert(instance); 163 164 return OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_PTR_MASK; 165 } 166 167 /** 168 * Set the HeadP of ED. Do not call unless the ED is Halted. 169 * @param instance ED 170 */ 171 static inline void ed_set_head_td(ed_t *instance, const td_t *td) 172 { 173 assert(instance); 174 const uintptr_t pa = addr_to_phys(td); 175 OHCI_MEM32_WR(instance->td_head, pa & ED_TDHEAD_PTR_MASK); 164 176 } 165 177 … … 192 204 { 193 205 assert(instance); 194 return (OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_TOGGLE_CARRY) ? 1 : 0;206 return !!(OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_TOGGLE_CARRY); 195 207 } 196 208 -
uspace/drv/bus/usb/ohci/hw_struct/iso_transfer_descriptor.h
rf5e5f73 rdf6ded8 69 69 #define ITD_OFFSET_CC_SHIFT (12) 70 70 71 } __attribute__((packed )) itd_t;71 } __attribute__((packed, aligned(32))) itd_t; 72 72 73 73 #endif -
uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
rf5e5f73 rdf6ded8 88 88 } 89 89 90 td_set_next(instance, next); 91 } 92 93 void td_set_next(td_t *instance, const td_t *next) 94 { 90 95 OHCI_MEM32_WR(instance->next, addr_to_phys(next) & TD_NEXT_PTR_MASK); 96 } 91 97 92 }93 98 /** 94 99 * @} -
uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
rf5e5f73 rdf6ded8 90 90 */ 91 91 volatile uint32_t be; 92 } __attribute__((packed )) td_t;92 } __attribute__((packed, aligned(32))) td_t; 93 93 94 void td_init(td_t * instance, const td_t *next,95 usb_direction_t dir, const void *buffer, size_t size, int toggle);94 void td_init(td_t *, const td_t *, usb_direction_t, const void *, size_t, int); 95 void td_set_next(td_t *, const td_t *); 96 96 97 97 /** … … 103 103 { 104 104 assert(instance); 105 const int cc = (OHCI_MEM32_RD(instance->status)106 >> TD_STATUS_CC_SHIFT)& TD_STATUS_CC_MASK;105 const int cc = (OHCI_MEM32_RD(instance->status) >> TD_STATUS_CC_SHIFT) 106 & TD_STATUS_CC_MASK; 107 107 /* This value is changed on transfer completion, 108 108 * either to CC_NOERROR or and error code. -
uspace/drv/bus/usb/ohci/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 * … … 39 40 #include <errno.h> 40 41 #include <io/log.h> 42 #include <io/logctl.h> 41 43 #include <str_error.h> 42 44 43 45 #include <usb/debug.h> 44 #include <usb/host/ddf_helpers.h>45 46 46 47 #include "hc.h" 48 #include "ohci_bus.h" 47 49 48 50 #define NAME "ohci" 49 static errno_t ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);50 static void ohci_driver_fini(hcd_t *);51 51 52 static const ddf_hc_driver_t ohci_hc_driver = { 53 .hc_speed = USB_SPEED_FULL, 54 .irq_code_gen = ohci_hc_gen_irq_code, 55 .init = ohci_driver_init, 56 .fini = ohci_driver_fini, 57 .name = "OHCI", 58 .ops = { 59 .schedule = ohci_hc_schedule, 60 .ep_add_hook = ohci_endpoint_init, 61 .ep_remove_hook = ohci_endpoint_fini, 62 .irq_hook = ohci_hc_interrupt, 63 .status_hook = ohci_hc_status, 64 }, 65 }; 52 static const hc_driver_t ohci_driver = { 53 .name = NAME, 54 .hc_device_size = sizeof(hc_t), 66 55 67 68 static errno_t ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq) 69 { 70 assert(hcd); 71 assert(hcd_get_driver_data(hcd) == NULL); 72 73 hc_t *instance = malloc(sizeof(hc_t)); 74 if (!instance) 75 return ENOMEM; 76 77 const errno_t ret = hc_init(instance, res, irq); 78 if (ret == EOK) { 79 hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops); 80 } else { 81 free(instance); 82 } 83 return ret; 84 } 85 86 static void ohci_driver_fini(hcd_t *hcd) 87 { 88 assert(hcd); 89 hc_t *hc = hcd_get_driver_data(hcd); 90 if (hc) 91 hc_fini(hc); 92 93 hcd_set_implementation(hcd, NULL, NULL); 94 free(hc); 95 } 96 97 /** Initializes a new ddf driver instance of OHCI hcd. 98 * 99 * @param[in] device DDF instance of the device to initialize. 100 * @return Error code. 101 */ 102 static errno_t ohci_dev_add(ddf_dev_t *device) 103 { 104 usb_log_debug("ohci_dev_add() called\n"); 105 assert(device); 106 return hcd_ddf_add_hc(device, &ohci_hc_driver); 107 } 108 109 static const driver_ops_t ohci_driver_ops = { 110 .dev_add = ohci_dev_add, 111 }; 112 113 static const driver_t ohci_driver = { 114 .name = NAME, 115 .driver_ops = &ohci_driver_ops 56 .hc_add = hc_add, 57 .irq_code_gen = hc_gen_irq_code, 58 .claim = hc_gain_control, 59 .start = hc_start, 60 .setup_root_hub = hc_setup_roothub, 61 .hc_gone = hc_gone, 116 62 }; 117 63 … … 127 73 { 128 74 log_init(NAME); 129 return ddf_driver_main(&ohci_driver); 75 logctl_set_log_level(NAME, LVL_NOTE); 76 return hc_driver_main(&ohci_driver); 130 77 } 131 78 -
uspace/drv/bus/usb/ohci/ohci_batch.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 46 47 #include "ohci_batch.h" 47 #include "ohci_ endpoint.h"48 49 static void (*const batch_setup[])(ohci_transfer_batch_t* , usb_direction_t);48 #include "ohci_bus.h" 49 50 static void (*const batch_setup[])(ohci_transfer_batch_t*); 50 51 51 52 /** Safely destructs ohci_transfer_batch_t structure … … 53 54 * @param[in] ohci_batch Instance to destroy. 54 55 */ 55 static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch) 56 { 57 if (!ohci_batch) 58 return; 59 if (ohci_batch->tds) { 60 const ohci_endpoint_t *ohci_ep = 61 ohci_endpoint_get(ohci_batch->usb_batch->ep); 62 assert(ohci_ep); 63 for (unsigned i = 0; i < ohci_batch->td_count; ++i) { 64 if (ohci_batch->tds[i] != ohci_ep->td) 65 free32(ohci_batch->tds[i]); 66 } 67 free(ohci_batch->tds); 68 } 69 usb_transfer_batch_destroy(ohci_batch->usb_batch); 70 free32(ohci_batch->device_buffer); 56 void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch) 57 { 58 assert(ohci_batch); 59 dma_buffer_free(&ohci_batch->ohci_dma_buffer); 71 60 free(ohci_batch); 72 61 } 73 62 74 /** Finishes usb_transfer_batch and destroys the structure.75 *76 * @param[in] uhci_batch Instance to finish and destroy.77 */78 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)79 {80 assert(ohci_batch);81 assert(ohci_batch->usb_batch);82 usb_transfer_batch_finish(ohci_batch->usb_batch,83 ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);84 ohci_transfer_batch_dispose(ohci_batch);85 }86 87 63 /** Allocate memory and initialize internal data structure. 88 64 * 89 * @param[in] usb_batch Pointer to generic USB batch structure.65 * @param[in] ep Endpoint for which the batch will be created 90 66 * @return Valid pointer if all structures were successfully created, 91 67 * NULL otherwise. 92 * 93 * Determines the number of needed transfer descriptors (TDs). 94 * Prepares a transport buffer (that is accessible by the hardware). 95 * Initializes parameters needed for the transfer and callback. 96 */ 97 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch) 98 { 99 assert(usb_batch); 68 */ 69 ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *ep) 70 { 71 assert(ep); 100 72 101 73 ohci_transfer_batch_t *ohci_batch = … … 103 75 if (!ohci_batch) { 104 76 usb_log_error("Failed to allocate OHCI batch data."); 105 goto dispose; 106 } 107 link_initialize(&ohci_batch->link); 108 ohci_batch->td_count = 109 (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1) 77 return NULL; 78 } 79 80 usb_transfer_batch_init(&ohci_batch->base, ep); 81 82 return ohci_batch; 83 } 84 85 /** Prepares a batch to be sent. 86 * 87 * Determines the number of needed transfer descriptors (TDs). 88 * Prepares a transport buffer (that is accessible by the hardware). 89 * Initializes parameters needed for the transfer and callback. 90 */ 91 int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch) 92 { 93 assert(ohci_batch); 94 usb_transfer_batch_t *usb_batch = &ohci_batch->base; 95 96 if (!batch_setup[usb_batch->ep->transfer_type]) 97 return ENOTSUP; 98 99 ohci_batch->td_count = (usb_batch->size + OHCI_TD_MAX_TRANSFER - 1) 110 100 / OHCI_TD_MAX_TRANSFER; 111 101 /* Control transfer need Setup and Status stage */ … … 114 104 } 115 105 116 /* We need an extra place for TD that was left at ED */ 117 ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t*)); 118 if (!ohci_batch->tds) { 119 usb_log_error("Failed to allocate OHCI transfer descriptors."); 120 goto dispose; 121 } 122 123 /* Add TD left over by the previous transfer */ 124 ohci_batch->ed = ohci_endpoint_get(usb_batch->ep)->ed; 125 ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td; 126 127 for (unsigned i = 1; i <= ohci_batch->td_count; ++i) { 128 ohci_batch->tds[i] = malloc32(sizeof(td_t)); 129 if (!ohci_batch->tds[i]) { 130 usb_log_error("Failed to allocate TD %d.", i); 131 goto dispose; 132 } 133 } 134 135 136 /* NOTE: OHCI is capable of handling buffer that crosses page boundaries 137 * it is, however, not capable of handling buffer that occupies more 138 * than two pages (the first page is computed using start pointer, the 139 * other using the end pointer) */ 140 if (usb_batch->setup_size + usb_batch->buffer_size > 0) { 141 /* Use one buffer for setup and data stage */ 142 ohci_batch->device_buffer = 143 malloc32(usb_batch->setup_size + usb_batch->buffer_size); 144 if (!ohci_batch->device_buffer) { 145 usb_log_error("Failed to allocate device buffer"); 146 goto dispose; 147 } 148 /* Copy setup data */ 149 memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer, 150 usb_batch->setup_size); 151 /* Copy generic data */ 152 if (usb_batch->ep->direction != USB_DIRECTION_IN) 153 memcpy( 154 ohci_batch->device_buffer + usb_batch->setup_size, 155 usb_batch->buffer, usb_batch->buffer_size); 156 } 157 ohci_batch->usb_batch = usb_batch; 158 159 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch); 160 assert(batch_setup[usb_batch->ep->transfer_type]); 161 batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir); 162 163 return ohci_batch; 164 dispose: 165 ohci_transfer_batch_dispose(ohci_batch); 166 return NULL; 106 /* Alloc one more to NULL terminate */ 107 ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t *)); 108 if (!ohci_batch->tds) 109 return ENOMEM; 110 111 const size_t td_size = ohci_batch->td_count * sizeof(td_t); 112 const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) 113 ? USB_SETUP_PACKET_SIZE 114 : 0; 115 116 if (dma_buffer_alloc(&ohci_batch->ohci_dma_buffer, td_size + setup_size)) { 117 usb_log_error("Failed to allocate OHCI DMA buffer."); 118 return ENOMEM; 119 } 120 121 td_t *tds = ohci_batch->ohci_dma_buffer.virt; 122 123 for (size_t i = 0; i < ohci_batch->td_count; i++) 124 ohci_batch->tds[i] = &tds[i]; 125 126 /* Presence of this terminator makes TD initialization easier */ 127 ohci_batch->tds[ohci_batch->td_count] = NULL; 128 129 ohci_batch->setup_buffer = (void *) (&tds[ohci_batch->td_count]); 130 memcpy(ohci_batch->setup_buffer, usb_batch->setup.buffer, setup_size); 131 132 ohci_batch->data_buffer = usb_batch->dma_buffer.virt; 133 134 batch_setup[usb_batch->ep->transfer_type](ohci_batch); 135 136 return EOK; 167 137 } 168 138 … … 176 146 * completes with the last TD. 177 147 */ 178 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch) 179 { 180 assert(ohci_batch); 181 assert(ohci_batch->usb_batch); 182 183 usb_log_debug("Batch %p checking %zu td(s) for completion.\n", 184 ohci_batch->usb_batch, ohci_batch->td_count); 185 usb_log_debug2("ED: %08x:%08x:%08x:%08x.\n", 186 ohci_batch->ed->status, ohci_batch->ed->td_head, 187 ohci_batch->ed->td_tail, ohci_batch->ed->next); 188 189 if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed)) 148 bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *ohci_batch) 149 { 150 assert(ohci_batch); 151 152 usb_transfer_batch_t *usb_batch = &ohci_batch->base; 153 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(usb_batch->ep); 154 assert(ohci_ep); 155 156 usb_log_debug("Batch %p checking %zu td(s) for completion.", 157 ohci_batch, ohci_batch->td_count); 158 usb_log_debug2("ED: %08x:%08x:%08x:%08x.", 159 ohci_ep->ed->status, ohci_ep->ed->td_head, 160 ohci_ep->ed->td_tail, ohci_ep->ed->next); 161 162 if (!ed_inactive(ohci_ep->ed) && ed_transfer_pending(ohci_ep->ed)) 190 163 return false; 191 164 … … 194 167 195 168 /* Assume all data got through */ 196 ohci_batch->usb_batch->transfered_size = 197 ohci_batch->usb_batch->buffer_size; 198 199 /* Assume we will leave the last(unused) TD behind */ 200 unsigned leave_td = ohci_batch->td_count; 169 usb_batch->transferred_size = usb_batch->size; 201 170 202 171 /* Check all TDs */ 203 172 for (size_t i = 0; i < ohci_batch->td_count; ++i) { 204 173 assert(ohci_batch->tds[i] != NULL); 205 usb_log_debug("TD %zu: %08x:%08x:%08x:%08x. \n", i,174 usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.", i, 206 175 ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp, 207 176 ohci_batch->tds[i]->next, ohci_batch->tds[i]->be); 208 177 209 ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);210 if ( ohci_batch->usb_batch->error == EOK) {178 usb_batch->error = td_error(ohci_batch->tds[i]); 179 if (usb_batch->error == EOK) { 211 180 /* If the TD got all its data through, it will report 212 181 * 0 bytes remain, the sole exception is INPUT with … … 221 190 * we leave the very last(unused) TD behind. 222 191 */ 223 ohci_batch->usb_batch->transfered_size192 usb_batch->transferred_size 224 193 -= td_remain_size(ohci_batch->tds[i]); 225 194 } else { 226 usb_log_debug("Batch %p found error TD(%zu):%08x.\n", 227 ohci_batch->usb_batch, i, 228 ohci_batch->tds[i]->status); 195 usb_log_debug("Batch %p found error TD(%zu):%08x.", 196 ohci_batch, i, ohci_batch->tds[i]->status); 229 197 230 198 /* ED should be stopped because of errors */ 231 assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0); 232 233 /* Now we have a problem: we don't know what TD 234 * the head pointer points to, the retiring rules 235 * described in specs say it should be the one after 236 * the failed one so set the tail pointer accordingly. 237 * It will be the one TD we leave behind. 199 assert((ohci_ep->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0); 200 201 /* We don't care where the processing stopped, we just 202 * need to make sure it's not using any of the TDs owned 203 * by the transfer. 204 * 205 * As the chain is terminated by a TD in ownership of 206 * the EP, set it. 238 207 */ 239 leave_td = i + 1; 240 241 /* Check TD assumption */ 242 assert(ed_head_td(ohci_batch->ed) == 243 addr_to_phys(ohci_batch->tds[leave_td])); 244 245 /* Set tail to the same TD */ 246 ed_set_tail_td(ohci_batch->ed, 247 ohci_batch->tds[leave_td]); 248 249 /* Clear possible ED HALT */ 250 ed_clear_halt(ohci_batch->ed); 208 ed_set_head_td(ohci_ep->ed, ohci_ep->tds[0]); 209 210 /* Clear the halted condition for the next transfer */ 211 ed_clear_halt(ohci_ep->ed); 251 212 break; 252 213 } 253 214 } 254 assert(ohci_batch->usb_batch->transfered_size <= 255 ohci_batch->usb_batch->buffer_size); 256 257 /* Store the remaining TD */ 258 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep); 259 assert(ohci_ep); 260 ohci_ep->td = ohci_batch->tds[leave_td]; 215 assert(usb_batch->transferred_size <= usb_batch->size); 261 216 262 217 /* Make sure that we are leaving the right TD behind */ 263 assert(addr_to_phys(ohci_ep->td ) == ed_head_td(ohci_batch->ed));264 assert( addr_to_phys(ohci_ep->td) == ed_tail_td(ohci_batch->ed));218 assert(addr_to_phys(ohci_ep->tds[0]) == ed_tail_td(ohci_ep->ed)); 219 assert(ed_tail_td(ohci_ep->ed) == ed_head_td(ohci_ep->ed)); 265 220 266 221 return true; … … 274 229 { 275 230 assert(ohci_batch); 276 ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]); 231 232 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep); 233 234 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.", ohci_ep->ed, 235 ohci_ep->ed->status, ohci_ep->ed->td_tail, 236 ohci_ep->ed->td_head, ohci_ep->ed->next); 237 238 /* 239 * According to spec, we need to copy the first TD to the currently 240 * enqueued one. 241 */ 242 memcpy(ohci_ep->tds[0], ohci_batch->tds[0], sizeof(td_t)); 243 ohci_batch->tds[0] = ohci_ep->tds[0]; 244 245 td_t *last = ohci_batch->tds[ohci_batch->td_count - 1]; 246 td_set_next(last, ohci_ep->tds[1]); 247 248 ed_set_tail_td(ohci_ep->ed, ohci_ep->tds[1]); 249 250 /* Swap the EP TDs for the next transfer */ 251 td_t *tmp = ohci_ep->tds[0]; 252 ohci_ep->tds[0] = ohci_ep->tds[1]; 253 ohci_ep->tds[1] = tmp; 277 254 } 278 255 … … 286 263 * Status stage with toggle 1 and direction supplied by parameter. 287 264 */ 288 static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir) 289 { 290 assert(ohci_batch); 291 assert(ohci_batch->usb_batch); 265 static void batch_control(ohci_transfer_batch_t *ohci_batch) 266 { 267 assert(ohci_batch); 268 269 usb_direction_t dir = ohci_batch->base.dir; 292 270 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 293 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed, 294 ohci_batch->ed->status, ohci_batch->ed->td_tail, 295 ohci_batch->ed->td_head, ohci_batch->ed->next); 271 296 272 static const usb_direction_t reverse_dir[] = { 297 273 [USB_DIRECTION_IN] = USB_DIRECTION_OUT, … … 300 276 301 277 int toggle = 0; 302 const char* buffer = ohci_batch->device_buffer;303 278 const usb_direction_t data_dir = dir; 304 279 const usb_direction_t status_dir = reverse_dir[dir]; … … 307 282 td_init( 308 283 ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH, 309 buffer, ohci_batch->usb_batch->setup_size, toggle);310 usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x. \n",284 ohci_batch->setup_buffer, USB_SETUP_PACKET_SIZE, toggle); 285 usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.", 311 286 ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp, 312 287 ohci_batch->tds[0]->next, ohci_batch->tds[0]->be); 313 buffer += ohci_batch->usb_batch->setup_size;314 288 315 289 /* Data stage */ 316 290 size_t td_current = 1; 317 size_t remain_size = ohci_batch->usb_batch->buffer_size; 291 const char* buffer = ohci_batch->data_buffer; 292 size_t remain_size = ohci_batch->base.size; 318 293 while (remain_size > 0) { 319 294 const size_t transfer_size = … … 324 299 ohci_batch->tds[td_current + 1], 325 300 data_dir, buffer, transfer_size, toggle); 326 usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x. \n",301 usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.", 327 302 ohci_batch->tds[td_current]->status, 328 303 ohci_batch->tds[td_current]->cbp, … … 340 315 td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1], 341 316 status_dir, NULL, 0, 1); 342 usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x. \n",317 usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.", 343 318 ohci_batch->tds[td_current]->status, 344 319 ohci_batch->tds[td_current]->cbp, … … 346 321 ohci_batch->tds[td_current]->be); 347 322 usb_log_debug2( 348 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized. \n", \349 ohci_batch->usb_batch,350 usb_str_transfer_type(ohci_batch-> usb_batch->ep->transfer_type),323 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \ 324 &ohci_batch->base, 325 usb_str_transfer_type(ohci_batch->base.ep->transfer_type), 351 326 usb_str_direction(dir), 352 USB_TRANSFER_BATCH_ARGS( *ohci_batch->usb_batch));327 USB_TRANSFER_BATCH_ARGS(ohci_batch->base)); 353 328 } 354 329 … … 361 336 * OHCI hw in ED. 362 337 */ 363 static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir) 364 { 365 assert(ohci_batch); 366 assert(ohci_batch->usb_batch); 338 static void batch_data(ohci_transfer_batch_t *ohci_batch) 339 { 340 assert(ohci_batch); 341 342 usb_direction_t dir = ohci_batch->base.dir; 367 343 assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT); 368 usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,369 ohci_batch->ed->status, ohci_batch->ed->td_tail,370 ohci_batch->ed->td_head, ohci_batch->ed->next);371 344 372 345 size_t td_current = 0; 373 size_t remain_size = ohci_batch-> usb_batch->buffer_size;374 char *buffer = ohci_batch->d evice_buffer;346 size_t remain_size = ohci_batch->base.size; 347 char *buffer = ohci_batch->data_buffer; 375 348 while (remain_size > 0) { 376 349 const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER … … 381 354 dir, buffer, transfer_size, -1); 382 355 383 usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x. \n",356 usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.", 384 357 ohci_batch->tds[td_current]->status, 385 358 ohci_batch->tds[td_current]->cbp, … … 393 366 } 394 367 usb_log_debug2( 395 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized. \n", \396 ohci_batch->usb_batch,397 usb_str_transfer_type(ohci_batch-> usb_batch->ep->transfer_type),368 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \ 369 &ohci_batch->base, 370 usb_str_transfer_type(ohci_batch->base.ep->transfer_type), 398 371 usb_str_direction(dir), 399 USB_TRANSFER_BATCH_ARGS( *ohci_batch->usb_batch));372 USB_TRANSFER_BATCH_ARGS(ohci_batch->base)); 400 373 } 401 374 402 375 /** Transfer setup table. */ 403 static void (*const batch_setup[])(ohci_transfer_batch_t* , usb_direction_t) =376 static void (*const batch_setup[])(ohci_transfer_batch_t*) = 404 377 { 405 378 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/ohci/ohci_batch.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 * … … 38 39 #include <assert.h> 39 40 #include <stdbool.h> 41 #include <usb/dma_buffer.h> 40 42 #include <usb/host/usb_transfer_batch.h> 41 43 … … 45 47 /** OHCI specific data required for USB transfer */ 46 48 typedef struct ohci_transfer_batch { 47 /** Link */ 48 link_t link; 49 /** Endpoint descriptor of the target endpoint. */ 50 ed_t *ed; 51 /** List of TDs needed for the transfer */ 52 td_t **tds; 49 usb_transfer_batch_t base; 50 53 51 /** Number of TDs used by the transfer */ 54 52 size_t td_count; 55 /** Data buffer, must be accessible by the OHCI hw. */ 56 char *device_buffer; 57 /** Generic USB transfer structure */ 58 usb_transfer_batch_t *usb_batch; 53 54 /** 55 * List of TDs needed for the transfer - together with setup data 56 * backed by the dma buffer. Note that the TD pointers are pointing to 57 * the DMA buffer initially, but as the scheduling must use the first TD 58 * from EP, it is replaced. 59 */ 60 td_t **tds; 61 char *setup_buffer; 62 char *data_buffer; 63 64 dma_buffer_t ohci_dma_buffer; 59 65 } ohci_transfer_batch_t; 60 66 61 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);62 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);67 ohci_transfer_batch_t *ohci_transfer_batch_create(endpoint_t *batch); 68 int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch); 63 69 void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch); 64 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch); 70 bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *batch); 71 void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch); 65 72 66 static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l) 73 static inline ohci_transfer_batch_t *ohci_transfer_batch_get( 74 usb_transfer_batch_t *usb_batch) 67 75 { 68 assert(l); 69 return list_get_instance(l, ohci_transfer_batch_t, link); 76 assert(usb_batch); 77 78 return (ohci_transfer_batch_t *) usb_batch; 70 79 } 80 71 81 #endif 72 82 /** -
uspace/drv/bus/usb/ohci/ohci_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 OHCI driver 33 34 */ 34 #ifndef DRV_OHCI_HCD_ ENDPOINT_H35 #define DRV_OHCI_HCD_ ENDPOINT_H35 #ifndef DRV_OHCI_HCD_BUS_H 36 #define DRV_OHCI_HCD_BUS_H 36 37 37 38 #include <assert.h> 38 39 #include <adt/list.h> 39 #include <usb/ host/endpoint.h>40 #include <usb/host/ hcd.h>40 #include <usb/dma_buffer.h> 41 #include <usb/host/usb2_bus.h> 41 42 42 43 #include "hw_struct/endpoint_descriptor.h" 43 44 #include "hw_struct/transfer_descriptor.h" 44 45 45 /** Connector structure linking ED to to prepared TD. */ 46 /** 47 * Connector structure linking ED to to prepared TD. 48 * 49 * OHCI requires new transfers to be appended at the end of a queue. But it has 50 * a weird semantics of a leftover TD, which serves as a placeholder. This left 51 * TD is overwritten with first TD of a new transfer, and the spare one is used 52 * as the next placeholder. Then the two are swapped for the next transaction. 53 */ 46 54 typedef struct ohci_endpoint { 55 endpoint_t base; 56 47 57 /** OHCI endpoint descriptor */ 48 58 ed_t *ed; 49 /** Currently enqueued transfer descriptor */ 50 td_t *td; 51 /** Linked list used by driver software */ 52 link_t link; 59 /** TDs to be used at the beginning and end of transaction */ 60 td_t *tds [2]; 61 62 /** Buffer to back ED + 2 TD */ 63 dma_buffer_t dma_buffer; 64 65 /** Link in endpoint_list*/ 66 link_t eplist_link; 67 /** Link in pending_endpoints */ 68 link_t pending_link; 53 69 } ohci_endpoint_t; 54 70 55 errno_t ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep); 56 void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep); 71 typedef struct hc hc_t; 72 73 typedef struct { 74 bus_t base; 75 usb2_bus_helper_t helper; 76 hc_t *hc; 77 } ohci_bus_t; 78 79 errno_t ohci_bus_init(ohci_bus_t *, hc_t *); 80 void ohci_ep_toggle_reset(endpoint_t *); 57 81 58 82 /** Get and convert assigned ohci_endpoint_t structure … … 63 87 { 64 88 assert(ep); 65 return ep->hc_data.data;89 return (ohci_endpoint_t *) ep; 66 90 } 67 91 -
uspace/drv/bus/usb/ohci/ohci_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 * … … 109 110 * initializes internal virtual hub. 110 111 */ 111 errno_t ohci_rh_init(ohci_rh_t *instance, ohci_regs_t *regs, const char *name) 112 errno_t ohci_rh_init(ohci_rh_t *instance, ohci_regs_t *regs, 113 fibril_mutex_t *guard, const char *name) 112 114 { 113 115 assert(instance); 114 116 instance->registers = regs; 115 117 instance->port_count = OHCI_RD(regs->rh_desc_a) & RHDA_NDS_MASK; 116 usb_log_debug2("rh_desc_a: %x. \n", OHCI_RD(regs->rh_desc_a));118 usb_log_debug2("rh_desc_a: %x.", OHCI_RD(regs->rh_desc_a)); 117 119 if (instance->port_count > OHCI_MAX_PORTS) { 118 120 usb_log_warning("OHCI specification does not allow %d ports. " 119 "Max %d ports will be used. \n", instance->port_count,121 "Max %d ports will be used.", instance->port_count, 120 122 OHCI_MAX_PORTS); 121 123 instance->port_count = OHCI_MAX_PORTS; 122 124 } 123 usb_log_info("%s: Found %u ports. \n", name, instance->port_count);125 usb_log_info("%s: Found %u ports.", name, instance->port_count); 124 126 125 127 #if defined OHCI_POWER_SWITCH_no 126 usb_log_info("%s: Set power mode to no power switching. \n", name);128 usb_log_info("%s: Set power mode to no power switching.", name); 127 129 /* Set port power mode to no power-switching. (always on) */ 128 130 OHCI_SET(regs->rh_desc_a, RHDA_NPS_FLAG); … … 132 134 133 135 #elif defined OHCI_POWER_SWITCH_ganged 134 usb_log_info("%s: Set power mode to ganged power switching. \n", name);136 usb_log_info("%s: Set power mode to ganged power switching.", name); 135 137 /* Set port power mode to ganged power-switching. */ 136 138 OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG); … … 144 146 OHCI_CLR(regs->rh_desc_a, RHDA_OCPM_FLAG); 145 147 #else 146 usb_log_info("%s: Set power mode to per-port power switching. \n", name);148 usb_log_info("%s: Set power mode to per-port power switching.", name); 147 149 /* Set port power mode to per port power-switching. */ 148 150 OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG); … … 162 164 163 165 ohci_rh_hub_desc_init(instance); 164 instance->unfinished_interrupt_transfer = NULL; 166 instance->status_change_endpoint = NULL; 167 instance->guard = guard; 165 168 return virthub_base_init(&instance->base, name, &ops, instance, 166 169 NULL, &instance->hub_descriptor.header, HUB_STATUS_CHANGE_PIPE); … … 178 181 assert(instance); 179 182 assert(batch); 180 const usb_target_t target = {{ 181 .address = batch->ep->address, 182 .endpoint = batch->ep->endpoint, 183 }}; 184 batch->error = virthub_base_request(&instance->base, target, 185 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer, 186 batch->buffer, batch->buffer_size, &batch->transfered_size); 183 batch->error = virthub_base_request(&instance->base, batch->target, 184 batch->dir, &batch->setup.packet, 185 batch->dma_buffer.virt, batch->size, &batch->transferred_size); 187 186 if (batch->error == ENAK) { 188 /* This is safe because only status change interrupt transfers 189 * return NAK. The assertion holds true because the batch 190 * existence prevents communication with that ep */ 191 assert(instance->unfinished_interrupt_transfer == NULL); 192 instance->unfinished_interrupt_transfer = batch; 187 /* Lock the HC guard */ 188 fibril_mutex_lock(instance->guard); 189 const int err = endpoint_activate_locked(batch->ep, batch); 190 if (err) { 191 fibril_mutex_unlock(batch->ep->guard); 192 return err; 193 } 194 195 /* 196 * Asserting that the HC do not run two instances of the status 197 * change endpoint - shall be true. 198 */ 199 assert(!instance->status_change_endpoint); 200 201 endpoint_add_ref(batch->ep); 202 instance->status_change_endpoint = batch->ep; 203 fibril_mutex_unlock(instance->guard); 193 204 } else { 194 usb_transfer_batch_finish(batch, NULL); 195 usb_transfer_batch_destroy(batch); 205 usb_transfer_batch_finish(batch); 196 206 } 197 207 return EOK; … … 207 217 errno_t ohci_rh_interrupt(ohci_rh_t *instance) 208 218 { 209 //TODO atomic swap needed 210 usb_transfer_batch_t *batch = instance->unfinished_interrupt_transfer; 211 instance->unfinished_interrupt_transfer = NULL; 219 fibril_mutex_lock(instance->guard); 220 endpoint_t *ep = instance->status_change_endpoint; 221 if (!ep) { 222 fibril_mutex_unlock(instance->guard); 223 return EOK; 224 } 225 226 usb_transfer_batch_t * const batch = ep->active_batch; 227 endpoint_deactivate_locked(ep); 228 instance->status_change_endpoint = NULL; 229 fibril_mutex_unlock(instance->guard); 230 231 endpoint_del_ref(ep); 232 212 233 if (batch) { 213 const usb_target_t target = {{ 214 .address = batch->ep->address, 215 .endpoint = batch->ep->endpoint, 216 }}; 217 batch->error = virthub_base_request(&instance->base, target, 218 usb_transfer_batch_direction(batch), 219 (void*)batch->setup_buffer, 220 batch->buffer, batch->buffer_size, &batch->transfered_size); 221 usb_transfer_batch_finish(batch, NULL); 222 usb_transfer_batch_destroy(batch); 234 batch->error = virthub_base_request(&instance->base, batch->target, 235 batch->dir, &batch->setup.packet, 236 batch->dma_buffer.virt, batch->size, &batch->transferred_size); 237 usb_transfer_batch_finish(batch); 223 238 } 224 239 return EOK; … … 351 366 } 352 367 353 case USB _HUB_FEATURE_PORT_ENABLE: /*1*/368 case USB2_HUB_FEATURE_PORT_ENABLE: /*1*/ 354 369 OHCI_WR(hub->registers->rh_port_status[port], 355 370 RHPS_CLEAR_PORT_ENABLE); 356 371 return EOK; 357 372 358 case USB _HUB_FEATURE_PORT_SUSPEND: /*2*/373 case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/ 359 374 OHCI_WR(hub->registers->rh_port_status[port], 360 375 RHPS_CLEAR_PORT_SUSPEND); … … 362 377 363 378 case USB_HUB_FEATURE_C_PORT_CONNECTION: /*16*/ 364 case USB _HUB_FEATURE_C_PORT_ENABLE: /*17*/365 case USB _HUB_FEATURE_C_PORT_SUSPEND: /*18*/379 case USB2_HUB_FEATURE_C_PORT_ENABLE: /*17*/ 380 case USB2_HUB_FEATURE_C_PORT_SUSPEND: /*18*/ 366 381 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: /*19*/ 367 382 case USB_HUB_FEATURE_C_PORT_RESET: /*20*/ 368 383 usb_log_debug2("Clearing port C_CONNECTION, C_ENABLE, " 369 "C_SUSPEND, C_OC or C_RESET on port %u. \n", port);384 "C_SUSPEND, C_OC or C_RESET on port %u.", port); 370 385 /* Bit offsets correspond to the feature number */ 371 386 OHCI_WR(hub->registers->rh_port_status[port], … … 412 427 /* Fall through, for per port power */ 413 428 /* Fallthrough */ 414 case USB _HUB_FEATURE_PORT_ENABLE: /*1*/415 case USB _HUB_FEATURE_PORT_SUSPEND: /*2*/429 case USB2_HUB_FEATURE_PORT_ENABLE: /*1*/ 430 case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/ 416 431 case USB_HUB_FEATURE_PORT_RESET: /*4*/ 417 432 usb_log_debug2("Setting port POWER, ENABLE, SUSPEND or RESET " 418 "on port %u. \n", port);433 "on port %u.", port); 419 434 /* Bit offsets correspond to the feature number */ 420 435 OHCI_WR(hub->registers->rh_port_status[port], 1 << feature); … … 462 477 } 463 478 464 usb_log_debug2("OHCI root hub interrupt mask: %hx. \n", mask);479 usb_log_debug2("OHCI root hub interrupt mask: %hx.", mask); 465 480 466 481 if (mask == 0) -
uspace/drv/bus/usb/ohci/ohci_rh.h
rf5e5f73 rdf6ded8 61 61 uint8_t rempow[STATUS_BYTES(OHCI_MAX_PORTS) * 2]; 62 62 } __attribute__((packed)) hub_descriptor; 63 /** interrupt transfer waiting for an actual interrupt to occur */ 64 usb_transfer_batch_t *unfinished_interrupt_transfer; 63 /** A hacky way to emulate interrupts over polling. See ehci_rh. */ 64 endpoint_t *status_change_endpoint; 65 fibril_mutex_t *guard; 65 66 } ohci_rh_t; 66 67 67 errno_t ohci_rh_init(ohci_rh_t * instance, ohci_regs_t *regs, const char *name);68 errno_t ohci_rh_init(ohci_rh_t *, ohci_regs_t *, fibril_mutex_t *, const char *); 68 69 errno_t ohci_rh_schedule(ohci_rh_t *instance, usb_transfer_batch_t *batch); 69 70 errno_t ohci_rh_interrupt(ohci_rh_t *instance); -
uspace/drv/bus/usb/uhci/hc.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 50 51 #include <usb/usb.h> 51 52 #include <usb/host/utils/malloc32.h> 53 #include <usb/host/bandwidth.h> 54 #include <usb/host/utility.h> 52 55 53 56 #include "uhci_batch.h" 57 #include "transfer_list.h" 54 58 #include "hc.h" 55 59 … … 107 111 * @return Error code. 108 112 */ 109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)113 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq) 110 114 { 111 115 assert(code); … … 140 144 code->cmds[3].addr = (void*)®isters->usbsts; 141 145 142 usb_log_debug("I/O regs at %p (size %zu), IRQ %d. \n",146 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.", 143 147 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 144 148 … … 157 161 * - resume from suspend state (not implemented) 158 162 */ 159 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status) 160 { 161 assert(hcd); 162 hc_t *instance = hcd_get_driver_data(hcd); 163 assert(instance); 163 static void hc_interrupt(bus_t *bus, uint32_t status) 164 { 165 hc_t *instance = bus_to_hc(bus); 166 164 167 /* Lower 2 bits are transaction error and transaction complete */ 165 168 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 166 LIST_INITIALIZE(done); 167 transfer_list_remove_finished( 168 &instance->transfers_interrupt, &done); 169 transfer_list_remove_finished( 170 &instance->transfers_control_slow, &done); 171 transfer_list_remove_finished( 172 &instance->transfers_control_full, &done); 173 transfer_list_remove_finished( 174 &instance->transfers_bulk_full, &done); 175 176 list_foreach_safe(done, current, next) { 177 list_remove(current); 178 uhci_transfer_batch_t *batch = 179 uhci_transfer_batch_from_link(current); 180 uhci_transfer_batch_finish_dispose(batch); 181 } 182 } 169 transfer_list_check_finished(&instance->transfers_interrupt); 170 transfer_list_check_finished(&instance->transfers_control_slow); 171 transfer_list_check_finished(&instance->transfers_control_full); 172 transfer_list_check_finished(&instance->transfers_bulk_full); 173 } 174 183 175 /* Resume interrupts are not supported */ 184 176 if (status & UHCI_STATUS_RESUME) { 185 usb_log_error("Resume interrupt! \n");177 usb_log_error("Resume interrupt!"); 186 178 } 187 179 188 180 /* Bits 4 and 5 indicate hc error */ 189 181 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 190 usb_log_error("UHCI hardware failure!. \n");182 usb_log_error("UHCI hardware failure!."); 191 183 ++instance->hw_failures; 192 184 transfer_list_abort_all(&instance->transfers_interrupt); … … 199 191 hc_init_hw(instance); 200 192 } else { 201 usb_log_fatal("Too many UHCI hardware failures!. \n");202 hc_ fini(instance);193 usb_log_fatal("Too many UHCI hardware failures!."); 194 hc_gone(&instance->base); 203 195 } 204 196 } … … 216 208 * interrupt fibrils. 217 209 */ 218 errno_t hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)219 { 220 assert(instance);210 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 211 { 212 hc_t *instance = hcd_to_hc(hcd); 221 213 assert(hw_res); 222 214 if (hw_res->io_ranges.count != 1 || … … 224 216 return EINVAL; 225 217 226 instance->hw_interrupts = interrupts;227 218 instance->hw_failures = 0; 228 219 … … 231 222 (void **) &instance->registers); 232 223 if (ret != EOK) { 233 usb_log_error("Failed to gain access to registers: %s. \n",224 usb_log_error("Failed to gain access to registers: %s.", 234 225 str_error(ret)); 235 226 return ret; 236 227 } 237 228 238 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",229 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 239 230 hw_res->io_ranges.ranges[0].address.absolute, 240 231 hw_res->io_ranges.ranges[0].size); … … 242 233 ret = hc_init_mem_structures(instance); 243 234 if (ret != EOK) { 244 usb_log_error("Failed to init UHCI memory structures: %s. \n",235 usb_log_error("Failed to init UHCI memory structures: %s.", 245 236 str_error(ret)); 246 237 // TODO: we should disable pio here … … 248 239 } 249 240 241 return EOK; 242 } 243 244 int hc_start(hc_device_t *hcd) 245 { 246 hc_t *instance = hcd_to_hc(hcd); 250 247 hc_init_hw(instance); 251 248 (void)hc_debug_checker; 252 249 253 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 254 255 return EOK; 250 return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 251 } 252 253 int hc_setup_roothub(hc_device_t *hcd) 254 { 255 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 256 256 } 257 257 … … 260 260 * @param[in] instance Host controller structure to use. 261 261 */ 262 void hc_fini(hc_t *instance)262 int hc_gone(hc_device_t *instance) 263 263 { 264 264 assert(instance); 265 265 //TODO Implement 266 return ENOTSUP; 266 267 } 267 268 … … 293 294 pio_write_32(®isters->flbaseadd, pa); 294 295 295 if (instance-> hw_interrupts) {296 if (instance->base.irq_cap >= 0) { 296 297 /* Enable all interrupts, but resume interrupt */ 297 298 pio_write_16(&instance->registers->usbintr, … … 301 302 const uint16_t cmd = pio_read_16(®isters->usbcmd); 302 303 if (cmd != 0) 303 usb_log_warning("Previous command value: %x. \n", cmd);304 usb_log_warning("Previous command value: %x.", cmd); 304 305 305 306 /* Start the hc with large(64B) packet FSBR */ … … 308 309 } 309 310 311 static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep) 312 { 313 uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep); 314 return &batch->base; 315 } 316 317 static void destroy_transfer_batch(usb_transfer_batch_t *batch) 318 { 319 uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch)); 320 } 321 322 static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc) 323 { 324 endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t)); 325 if (ep) 326 endpoint_init(ep, device, desc); 327 return ep; 328 } 329 330 static errno_t endpoint_register(endpoint_t *ep) 331 { 332 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 333 334 const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep); 335 if (err) 336 return err; 337 338 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 339 if (!list) 340 /* 341 * We don't support this combination (e.g. isochronous). Do not 342 * fail early, because that would block any device with these 343 * endpoints from connecting. Instead, make sure these transfers 344 * are denied soon enough with ENOTSUP not to fail on asserts. 345 */ 346 return EOK; 347 348 endpoint_set_online(ep, &list->guard); 349 return EOK; 350 } 351 352 static void endpoint_unregister(endpoint_t *ep) 353 { 354 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 355 usb2_bus_endpoint_unregister(&hc->bus_helper, ep); 356 357 // Check for the roothub, as it does not schedule into lists 358 if (ep->device->address == uhci_rh_get_address(&hc->rh)) { 359 // FIXME: We shall check the roothub for active transfer. But 360 // as it is polling, there is no way to make it stop doing so. 361 // Return after rewriting uhci rh. 362 return; 363 } 364 365 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 366 if (!list) 367 /* 368 * We don't support this combination (e.g. isochronous), 369 * so no transfer can be active. 370 */ 371 return; 372 373 fibril_mutex_lock(&list->guard); 374 375 endpoint_set_offline_locked(ep); 376 /* From now on, no other transfer will be scheduled. */ 377 378 if (!ep->active_batch) { 379 fibril_mutex_unlock(&list->guard); 380 return; 381 } 382 383 /* First, offer the batch a short chance to be finished. */ 384 endpoint_wait_timeout_locked(ep, 10000); 385 386 if (!ep->active_batch) { 387 fibril_mutex_unlock(&list->guard); 388 return; 389 } 390 391 uhci_transfer_batch_t * const batch = 392 uhci_transfer_batch_get(ep->active_batch); 393 394 /* Remove the batch from the schedule to stop it from being finished. */ 395 endpoint_deactivate_locked(ep); 396 transfer_list_remove_batch(list, batch); 397 398 fibril_mutex_unlock(&list->guard); 399 400 /* 401 * We removed the batch from software schedule only, it's still possible 402 * that HC has it in its caches. Better wait a while before we release 403 * the buffers. 404 */ 405 async_usleep(20000); 406 batch->base.error = EINTR; 407 batch->base.transferred_size = 0; 408 usb_transfer_batch_finish(&batch->base); 409 } 410 411 static int device_enumerate(device_t *dev) 412 { 413 hc_t * const hc = bus_to_hc(dev->bus); 414 return usb2_bus_device_enumerate(&hc->bus_helper, dev); 415 } 416 417 static void device_gone(device_t *dev) 418 { 419 hc_t * const hc = bus_to_hc(dev->bus); 420 usb2_bus_device_gone(&hc->bus_helper, dev); 421 } 422 423 static int hc_status(bus_t *, uint32_t *); 424 static int hc_schedule(usb_transfer_batch_t *); 425 426 static const bus_ops_t uhci_bus_ops = { 427 .interrupt = hc_interrupt, 428 .status = hc_status, 429 430 .device_enumerate = device_enumerate, 431 .device_gone = device_gone, 432 433 .endpoint_create = endpoint_create, 434 .endpoint_register = endpoint_register, 435 .endpoint_unregister = endpoint_unregister, 436 437 .batch_create = create_transfer_batch, 438 .batch_schedule = hc_schedule, 439 .batch_destroy = destroy_transfer_batch, 440 }; 441 310 442 /** Initialize UHCI hc memory structures. 311 443 * … … 321 453 { 322 454 assert(instance); 455 456 usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11); 457 458 bus_init(&instance->bus, sizeof(device_t)); 459 instance->bus.ops = &uhci_bus_ops; 460 461 hc_device_setup(&instance->base, &instance->bus); 323 462 324 463 /* Init USB frame list page */ … … 327 466 return ENOMEM; 328 467 } 329 usb_log_debug("Initialized frame list at %p. \n", instance->frame_list);468 usb_log_debug("Initialized frame list at %p.", instance->frame_list); 330 469 331 470 /* Init transfer lists */ 332 471 errno_t ret = hc_init_transfer_lists(instance); 333 472 if (ret != EOK) { 334 usb_log_error("Failed to initialize transfer lists. \n");473 usb_log_error("Failed to initialize transfer lists."); 335 474 return_page(instance->frame_list); 336 475 return ENOMEM; 337 476 } 338 usb_log_debug("Initialized transfer lists.\n"); 477 list_initialize(&instance->pending_endpoints); 478 usb_log_debug("Initialized transfer lists."); 339 479 340 480 … … 366 506 errno_t ret = transfer_list_init(&instance->transfers_##type, name); \ 367 507 if (ret != EOK) { \ 368 usb_log_error("Failed to setup %s transfer list: %s. \n", \508 usb_log_error("Failed to setup %s transfer list: %s.", \ 369 509 name, str_error(ret)); \ 370 510 transfer_list_fini(&instance->transfers_bulk_full); \ … … 411 551 } 412 552 413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)414 { 415 assert(hcd);553 static errno_t hc_status(bus_t *bus, uint32_t *status) 554 { 555 hc_t *instance = bus_to_hc(bus); 416 556 assert(status); 417 hc_t *instance = hcd_get_driver_data(hcd);418 assert(instance);419 557 420 558 *status = 0; … … 427 565 } 428 566 429 /** Schedule batch for execution. 567 /** 568 * Schedule batch for execution. 430 569 * 431 570 * @param[in] instance UHCI structure to use. 432 571 * @param[in] batch Transfer batch to schedule. 433 572 * @return Error code 434 * 435 * Checks for bandwidth availability and appends the batch to the proper queue. 436 */ 437 errno_t uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 438 { 439 assert(hcd); 440 hc_t *instance = hcd_get_driver_data(hcd); 441 assert(instance); 442 assert(batch); 443 444 if (batch->ep->address == uhci_rh_get_address(&instance->rh)) 445 return uhci_rh_schedule(&instance->rh, batch); 446 573 */ 574 static errno_t hc_schedule(usb_transfer_batch_t *batch) 575 { 447 576 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 448 if (!uhci_batch) { 449 usb_log_error("Failed to create UHCI transfer structures.\n"); 450 return ENOMEM; 451 } 452 453 transfer_list_t *list = 454 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 455 assert(list); 456 transfer_list_add_batch(list, uhci_batch); 457 458 return EOK; 577 endpoint_t *ep = batch->ep; 578 hc_t *hc = bus_to_hc(endpoint_get_bus(ep)); 579 580 if (batch->target.address == uhci_rh_get_address(&hc->rh)) 581 return uhci_rh_schedule(&hc->rh, batch); 582 583 transfer_list_t * const list = 584 hc->transfers[ep->device->speed][ep->transfer_type]; 585 586 if (!list) 587 return ENOTSUP; 588 589 errno_t err; 590 if ((err = uhci_transfer_batch_prepare(uhci_batch))) 591 return err; 592 593 return transfer_list_add_batch(list, uhci_batch); 459 594 } 460 595 … … 479 614 480 615 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 481 usb_log_debug2("Command: %X Status: %X Intr: %x \n",616 usb_log_debug2("Command: %X Status: %X Intr: %x", 482 617 cmd, sts, intr); 483 618 } … … 486 621 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 487 622 if (frame_list != addr_to_phys(instance->frame_list)) { 488 usb_log_debug("Framelist address: %p vs. %p. \n",623 usb_log_debug("Framelist address: %p vs. %p.", 489 624 (void *) frame_list, 490 625 (void *) addr_to_phys(instance->frame_list)); … … 497 632 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 498 633 if (expected_pa != real_pa) { 499 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p. \n",634 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.", 500 635 (void *) expected_pa, frnum, (void *) real_pa); 501 636 } … … 504 639 real_pa = addr_to_phys(QH(control_slow)); 505 640 if (expected_pa != real_pa) { 506 usb_log_debug("Control Slow QH: %p vs. %p. \n",641 usb_log_debug("Control Slow QH: %p vs. %p.", 507 642 (void *) expected_pa, (void *) real_pa); 508 643 } … … 511 646 real_pa = addr_to_phys(QH(control_full)); 512 647 if (expected_pa != real_pa) { 513 usb_log_debug("Control Full QH: %p vs. %p. \n",648 usb_log_debug("Control Full QH: %p vs. %p.", 514 649 (void *) expected_pa, (void *) real_pa); 515 650 } … … 518 653 real_pa = addr_to_phys(QH(bulk_full)); 519 654 if (expected_pa != real_pa ) { 520 usb_log_debug("Bulk QH: %p vs. %p. \n",655 usb_log_debug("Bulk QH: %p vs. %p.", 521 656 (void *) expected_pa, (void *) real_pa); 522 657 } -
uspace/drv/bus/usb/uhci/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 * … … 43 44 #include <ddi.h> 44 45 #include <usb/host/hcd.h> 46 #include <usb/host/usb2_bus.h> 45 47 #include <usb/host/usb_transfer_batch.h> 46 48 … … 99 101 /** Main UHCI driver structure */ 100 102 typedef struct hc { 103 /* Common hc_device header */ 104 hc_device_t base; 105 101 106 uhci_rh_t rh; 107 bus_t bus; 108 usb2_bus_helper_t bus_helper; 109 102 110 /** Addresses of I/O registers */ 103 111 uhci_regs_t *registers; … … 117 125 /** Pointer table to the above lists, helps during scheduling */ 118 126 transfer_list_t *transfers[2][4]; 119 /** Indicator of hw interrupts availability */ 120 bool hw_interrupts; 127 128 /** 129 * Guard for the pending list. Can be locked under EP guard, but not 130 * vice versa. 131 */ 132 fibril_mutex_t guard; 133 /** List of endpoints with a transfer scheduled */ 134 list_t pending_endpoints; 121 135 122 136 /** Number of hw failures detected. */ … … 124 138 } hc_t; 125 139 126 extern errno_t hc_init(hc_t *, const hw_res_list_parsed_t *, bool); 127 extern void hc_fini(hc_t *);140 typedef struct uhci_endpoint { 141 endpoint_t base; 128 142 129 extern errno_t uhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *, int *); 143 bool toggle; 144 } uhci_endpoint_t; 130 145 131 extern void uhci_hc_interrupt(hcd_t *, uint32_t); 132 extern errno_t uhci_hc_status(hcd_t *, uint32_t *); 133 extern errno_t uhci_hc_schedule(hcd_t *, usb_transfer_batch_t *); 146 static inline hc_t *hcd_to_hc(hc_device_t *hcd) 147 { 148 assert(hcd); 149 return (hc_t *) hcd; 150 } 151 152 static inline hc_t *bus_to_hc(bus_t *bus) 153 { 154 assert(bus); 155 return member_to_inst(bus, hc_t, bus); 156 } 157 158 int hc_unschedule_batch(usb_transfer_batch_t *); 159 160 extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *); 161 extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *); 162 extern errno_t hc_start(hc_device_t *); 163 extern errno_t hc_setup_roothub(hc_device_t *); 164 extern errno_t hc_gone(hc_device_t *); 134 165 135 166 #endif -
uspace/drv/bus/usb/uhci/hw_struct/queue_head.h
rf5e5f73 rdf6ded8 48 48 /** Pointer to the next entity (another QH or TD */ 49 49 volatile link_pointer_t next; 50 /** Pointer to the contained entities (execution controlled by vertical flag*/ 50 /** 51 * Pointer to the contained entities 52 * (execution controlled by vertical flag) 53 */ 51 54 volatile link_pointer_t element; 52 } __attribute__((packed )) qh_t;55 } __attribute__((packed, aligned(16))) qh_t; 53 56 54 57 /** Initialize queue head structure -
uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c
rf5e5f73 rdf6ded8 104 104 instance->buffer_ptr = addr_to_phys(buffer); 105 105 106 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p). \n",106 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).", 107 107 instance, instance->next, instance->status, instance->device, 108 108 instance->buffer_ptr, buffer); 109 109 td_print_status(instance); 110 110 if (pid == USB_PID_SETUP) { 111 usb_log_debug2("SETUP BUFFER: %s \n",111 usb_log_debug2("SETUP BUFFER: %s", 112 112 usb_debug_str_buffer(buffer, 8, 8)); 113 113 } … … 160 160 assert(instance); 161 161 const uint32_t s = instance->status; 162 usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu. \n",162 usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu.", 163 163 instance, instance->status, 164 164 (s & TD_STATUS_SPD_FLAG) ? " SPD," : "", -
uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h
rf5e5f73 rdf6ded8 95 95 * memory just needs to be aligned. We don't use it anyway. 96 96 */ 97 } __attribute__((packed )) td_t;97 } __attribute__((packed, aligned(16))) td_t; 98 98 99 99 -
uspace/drv/bus/usb/uhci/main.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky, Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 43 44 #include <str_error.h> 44 45 #include <usb/debug.h> 45 #include <usb/host/ ddf_helpers.h>46 #include <usb/host/utility.h> 46 47 47 48 #include "hc.h" … … 49 50 #define NAME "uhci" 50 51 51 static errno_t uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 52 static void uhci_driver_fini(hcd_t *); 53 static errno_t disable_legacy(ddf_dev_t *); 52 static errno_t disable_legacy(hc_device_t *); 54 53 55 static const ddf_hc_driver_t uhci_hc_driver = { 56 .claim = disable_legacy, 57 .hc_speed = USB_SPEED_FULL, 58 .irq_code_gen = uhci_hc_gen_irq_code, 59 .init = uhci_driver_init, 60 .fini = uhci_driver_fini, 61 .name = "UHCI", 62 .ops = { 63 .schedule = uhci_hc_schedule, 64 .irq_hook = uhci_hc_interrupt, 65 .status_hook = uhci_hc_status, 66 }, 54 static const hc_driver_t uhci_driver = { 55 .name = NAME, 56 .hc_device_size = sizeof(hc_t), 57 .claim = disable_legacy, 58 .irq_code_gen = hc_gen_irq_code, 59 .hc_add = hc_add, 60 .start = hc_start, 61 .setup_root_hub = hc_setup_roothub, 62 .hc_gone = hc_gone, 67 63 }; 68 69 static errno_t uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)70 {71 assert(hcd);72 assert(hcd_get_driver_data(hcd) == NULL);73 74 hc_t *instance = malloc(sizeof(hc_t));75 if (!instance)76 return ENOMEM;77 78 const errno_t ret = hc_init(instance, res, irq);79 if (ret == EOK) {80 hcd_set_implementation(hcd, instance, &uhci_hc_driver.ops);81 } else {82 free(instance);83 }84 return ret;85 }86 87 static void uhci_driver_fini(hcd_t *hcd)88 {89 assert(hcd);90 hc_t *hc = hcd_get_driver_data(hcd);91 if (hc)92 hc_fini(hc);93 94 hcd_set_implementation(hcd, NULL, NULL);95 free(hc);96 }97 64 98 65 /** Call the PCI driver with a request to clear legacy support register … … 101 68 * @return Error code. 102 69 */ 103 static errno_t disable_legacy( ddf_dev_t *device)70 static errno_t disable_legacy(hc_device_t *hcd) 104 71 { 105 assert( device);72 assert(hcd); 106 73 107 async_sess_t *parent_sess = ddf_dev_parent_sess_get( device);74 async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev); 108 75 if (parent_sess == NULL) 109 76 return ENOMEM; … … 113 80 return pci_config_space_write_16(parent_sess, 0xc0, 0xaf00); 114 81 } 115 116 /** Initialize a new ddf driver instance for uhci hc and hub.117 *118 * @param[in] device DDF instance of the device to initialize.119 * @return Error code.120 */121 static errno_t uhci_dev_add(ddf_dev_t *device)122 {123 usb_log_debug2("uhci_dev_add() called\n");124 assert(device);125 return hcd_ddf_add_hc(device, &uhci_hc_driver);126 }127 128 static const driver_ops_t uhci_driver_ops = {129 .dev_add = uhci_dev_add,130 };131 132 static const driver_t uhci_driver = {133 .name = NAME,134 .driver_ops = &uhci_driver_ops135 };136 137 82 138 83 /** Initialize global driver structures (NONE). … … 149 94 log_init(NAME); 150 95 logctl_set_log_level(NAME, LVL_NOTE); 151 return ddf_driver_main(&uhci_driver);96 return hc_driver_main(&uhci_driver); 152 97 } 153 98 /** -
uspace/drv/bus/usb/uhci/transfer_list.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 3 4 * All rights reserved. 4 5 * … … 41 42 #include <usb/host/usb_transfer_batch.h> 42 43 #include <usb/host/utils/malloc32.h> 44 #include <usb/host/utility.h> 43 45 44 46 #include "hw_struct/link_pointer.h" 45 47 #include "transfer_list.h" 46 47 static void transfer_list_remove_batch( 48 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch); 48 #include "hc.h" 49 49 50 50 /** Initialize transfer list structures. … … 62 62 instance->queue_head = malloc32(sizeof(qh_t)); 63 63 if (!instance->queue_head) { 64 usb_log_error("Failed to allocate queue head. \n");64 usb_log_error("Failed to allocate queue head."); 65 65 return ENOMEM; 66 66 } 67 67 const uint32_t queue_head_pa = addr_to_phys(instance->queue_head); 68 usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ). \n",68 usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ).", 69 69 name, instance->queue_head, queue_head_pa); 70 70 … … 103 103 } 104 104 105 /** Add transfer batch to the list and queue. 106 * 107 * @param[in] instance List to use. 108 * @param[in] batch Transfer batch to submit. 105 /** 106 * Add transfer batch to the list and queue. 109 107 * 110 108 * The batch is added to the end of the list and queue. 111 */ 112 void transfer_list_add_batch( 109 * 110 * @param[in] instance List to use. 111 * @param[in] batch Transfer batch to submit. After return, the batch must 112 * not be used further. 113 */ 114 int transfer_list_add_batch( 113 115 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch) 114 116 { 115 117 assert(instance); 116 118 assert(uhci_batch); 117 usb_log_debug2("Batch %p adding to queue %s.\n", 118 uhci_batch->usb_batch, instance->name);119 120 endpoint_t *ep = uhci_batch->base.ep; 119 121 120 122 fibril_mutex_lock(&instance->guard); 123 124 const int err = endpoint_activate_locked(ep, &uhci_batch->base); 125 if (err) { 126 fibril_mutex_unlock(&instance->guard); 127 return err; 128 } 129 130 usb_log_debug2("Batch %p adding to queue %s.", 131 uhci_batch, instance->name); 121 132 122 133 /* Assume there is nothing scheduled */ … … 145 156 146 157 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 147 " scheduled in queue %s. \n", uhci_batch->usb_batch,148 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch), instance->name);158 " scheduled in queue %s.", uhci_batch, 159 USB_TRANSFER_BATCH_ARGS(uhci_batch->base), instance->name); 149 160 fibril_mutex_unlock(&instance->guard); 161 return EOK; 162 } 163 164 /** 165 * Reset toggle on endpoint callback. 166 */ 167 static void uhci_reset_toggle(endpoint_t *ep) 168 { 169 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) ep; 170 uhci_ep->toggle = 0; 150 171 } 151 172 … … 155 176 * @param[in] done list to fill 156 177 */ 157 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done) 158 { 159 assert(instance); 160 assert(done); 178 void transfer_list_check_finished(transfer_list_t *instance) 179 { 180 assert(instance); 161 181 162 182 fibril_mutex_lock(&instance->guard); 163 link_t *current = list_first(&instance->batch_list); 164 while (current && current != &instance->batch_list.head) { 165 link_t * const next = current->next; 166 uhci_transfer_batch_t *batch = 167 uhci_transfer_batch_from_link(current); 168 169 if (uhci_transfer_batch_is_complete(batch)) { 170 /* Save for processing */ 183 list_foreach_safe(instance->batch_list, current, next) { 184 uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current); 185 186 if (uhci_transfer_batch_check_completed(batch)) { 187 assert(batch->base.ep->active_batch == &batch->base); 188 endpoint_deactivate_locked(batch->base.ep); 189 hc_reset_toggles(&batch->base, &uhci_reset_toggle); 171 190 transfer_list_remove_batch(instance, batch); 172 list_append(current, done);191 usb_transfer_batch_finish(&batch->base); 173 192 } 174 current = next;175 193 } 176 194 fibril_mutex_unlock(&instance->guard); … … 186 204 while (!list_empty(&instance->batch_list)) { 187 205 link_t * const current = list_first(&instance->batch_list); 188 uhci_transfer_batch_t *batch = 189 uhci_transfer_batch_from_link(current); 206 uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current); 190 207 transfer_list_remove_batch(instance, batch); 191 uhci_transfer_batch_abort(batch);192 208 } 193 209 fibril_mutex_unlock(&instance->guard); … … 209 225 assert(uhci_batch->qh); 210 226 assert(fibril_mutex_is_locked(&instance->guard)); 211 212 usb_log_debug2("Batch %p removing from queue %s.\n", 213 uhci_batch->usb_batch, instance->name); 227 assert(!list_empty(&instance->batch_list)); 228 229 usb_log_debug2("Batch %p removing from queue %s.", 230 uhci_batch, instance->name); 214 231 215 232 /* Assume I'm the first */ … … 233 250 list_remove(&uhci_batch->link); 234 251 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " removed (%s) " 235 "from %s, next: %x. \n", uhci_batch->usb_batch,236 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch),252 "from %s, next: %x.", uhci_batch, 253 USB_TRANSFER_BATCH_ARGS(uhci_batch->base), 237 254 qpos, instance->name, uhci_batch->qh->next); 238 255 } -
uspace/drv/bus/usb/uhci/transfer_list.h
rf5e5f73 rdf6ded8 56 56 } transfer_list_t; 57 57 58 void transfer_list_fini(transfer_list_t * instance);59 errno_t transfer_list_init(transfer_list_t * instance, const char *name);60 void transfer_list_set_next(transfer_list_t * instance, transfer_list_t *next);61 void transfer_list_add_batch( 62 transfer_list_t *instance, uhci_transfer_batch_t *batch);63 void transfer_list_ remove_finished(transfer_list_t *instance, list_t *done);64 void transfer_list_abort_all(transfer_list_t * instance);58 void transfer_list_fini(transfer_list_t *); 59 errno_t transfer_list_init(transfer_list_t *, const char *); 60 void transfer_list_set_next(transfer_list_t *, transfer_list_t *); 61 errno_t transfer_list_add_batch(transfer_list_t *, uhci_transfer_batch_t *); 62 void transfer_list_remove_batch(transfer_list_t *, uhci_transfer_batch_t *); 63 void transfer_list_check_finished(transfer_list_t *); 64 void transfer_list_abort_all(transfer_list_t *); 65 65 66 66 #endif -
uspace/drv/bus/usb/uhci/uhci_batch.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 * … … 46 47 47 48 #include "uhci_batch.h" 49 #include "hc.h" 48 50 #include "hw_struct/transfer_descriptor.h" 49 51 50 52 #define DEFAULT_ERROR_COUNT 3 51 53 52 /** Safely destructs uhci_transfer_batch_t structure. 54 /** Transfer batch setup table. */ 55 static void (*const batch_setup[])(uhci_transfer_batch_t*); 56 57 /** Destroys uhci_transfer_batch_t structure. 53 58 * 54 59 * @param[in] uhci_batch Instance to destroy. 55 60 */ 56 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch) 57 { 58 if (uhci_batch) { 59 usb_transfer_batch_destroy(uhci_batch->usb_batch); 60 free32(uhci_batch->device_buffer); 61 free(uhci_batch); 62 } 63 } 64 65 /** Finishes usb_transfer_batch and destroys the structure. 66 * 67 * @param[in] uhci_batch Instance to finish and destroy. 68 */ 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch) 61 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch) 70 62 { 71 63 assert(uhci_batch); 72 assert(uhci_batch->usb_batch); 73 assert(!link_in_use(&uhci_batch->link)); 74 usb_transfer_batch_finish(uhci_batch->usb_batch, 75 uhci_transfer_batch_data_buffer(uhci_batch)); 76 uhci_transfer_batch_dispose(uhci_batch); 77 } 78 79 /** Transfer batch setup table. */ 80 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t); 64 dma_buffer_free(&uhci_batch->uhci_dma_buffer); 65 free(uhci_batch); 66 } 81 67 82 68 /** Allocate memory and initialize internal data structure. … … 85 71 * @return Valid pointer if all structures were successfully created, 86 72 * NULL otherwise. 73 */ 74 uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep) 75 { 76 uhci_transfer_batch_t *uhci_batch = 77 calloc(1, sizeof(uhci_transfer_batch_t)); 78 if (!uhci_batch) { 79 usb_log_error("Failed to allocate UHCI batch."); 80 return NULL; 81 } 82 83 usb_transfer_batch_init(&uhci_batch->base, ep); 84 85 link_initialize(&uhci_batch->link); 86 return uhci_batch; 87 } 88 89 /* Prepares batch for commiting. 87 90 * 88 91 * Determines the number of needed transfer descriptors (TDs). … … 90 93 * Initializes parameters needed for the transfer and callback. 91 94 */ 92 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)95 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch) 93 96 { 94 97 static_assert((sizeof(td_t) % 16) == 0); 95 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 96 if (ptr == NULL) { \ 97 usb_log_error(message); \ 98 uhci_transfer_batch_dispose(uhci_batch); \ 99 return NULL; \ 100 } else (void)0 101 102 uhci_transfer_batch_t *uhci_batch = 103 calloc(1, sizeof(uhci_transfer_batch_t)); 104 CHECK_NULL_DISPOSE_RETURN(uhci_batch, 105 "Failed to allocate UHCI batch.\n"); 106 link_initialize(&uhci_batch->link); 107 uhci_batch->td_count = 108 (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1) 109 / usb_batch->ep->max_packet_size; 98 99 usb_transfer_batch_t *usb_batch = &uhci_batch->base; 100 101 uhci_batch->td_count = (usb_batch->size + usb_batch->ep->max_packet_size - 1) 102 / usb_batch->ep->max_packet_size; 103 110 104 if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 111 105 uhci_batch->td_count += 2; 112 106 } 113 107 108 const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) 109 ? USB_SETUP_PACKET_SIZE 110 : 0; 111 114 112 const size_t total_size = (sizeof(td_t) * uhci_batch->td_count) 115 + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size; 116 uhci_batch->device_buffer = malloc32(total_size); 117 CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer, 118 "Failed to allocate UHCI buffer.\n"); 119 memset(uhci_batch->device_buffer, 0, total_size); 120 121 uhci_batch->tds = uhci_batch->device_buffer; 122 uhci_batch->qh = 123 (uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count)); 113 + sizeof(qh_t) + setup_size; 114 115 if (dma_buffer_alloc(&uhci_batch->uhci_dma_buffer, total_size)) { 116 usb_log_error("Failed to allocate UHCI buffer."); 117 return ENOMEM; 118 } 119 memset(uhci_batch->uhci_dma_buffer.virt, 0, total_size); 120 121 uhci_batch->tds = uhci_batch->uhci_dma_buffer.virt; 122 uhci_batch->qh = (qh_t *) &uhci_batch->tds[uhci_batch->td_count]; 124 123 125 124 qh_init(uhci_batch->qh); 126 125 qh_set_element_td(uhci_batch->qh, &uhci_batch->tds[0]); 127 126 128 void *dest = 129 uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count) 130 + sizeof(qh_t); 127 void *setup_buffer = uhci_transfer_batch_setup_buffer(uhci_batch); 128 assert(setup_buffer == (void *) (uhci_batch->qh + 1)); 131 129 /* Copy SETUP packet data to the device buffer */ 132 memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size); 133 dest += usb_batch->setup_size; 134 /* Copy generic data unless they are provided by the device */ 135 if (usb_batch->ep->direction != USB_DIRECTION_IN) { 136 memcpy(dest, usb_batch->buffer, usb_batch->buffer_size); 137 } 138 uhci_batch->usb_batch = usb_batch; 130 memcpy(setup_buffer, usb_batch->setup.buffer, setup_size); 131 139 132 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 140 " memory structures ready. \n", usb_batch,133 " memory structures ready.", usb_batch, 141 134 USB_TRANSFER_BATCH_ARGS(*usb_batch)); 142 135 143 const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);144 145 136 assert(batch_setup[usb_batch->ep->transfer_type]); 146 batch_setup[usb_batch->ep->transfer_type](uhci_batch , dir);147 148 return uhci_batch;137 batch_setup[usb_batch->ep->transfer_type](uhci_batch); 138 139 return EOK; 149 140 } 150 141 … … 158 149 * is reached. 159 150 */ 160 bool uhci_transfer_batch_ is_complete(constuhci_transfer_batch_t *uhci_batch)151 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch) 161 152 { 162 153 assert(uhci_batch); 163 assert(uhci_batch->usb_batch);154 usb_transfer_batch_t *batch = &uhci_batch->base; 164 155 165 156 usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT 166 " checking %zu transfer(s) for completion.\n", 167 uhci_batch->usb_batch, 168 USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), 157 " checking %zu transfer(s) for completion.", 158 uhci_batch, USB_TRANSFER_BATCH_ARGS(*batch), 169 159 uhci_batch->td_count); 170 uhci_batch->usb_batch->transfered_size = 0; 160 batch->transferred_size = 0; 161 162 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) batch->ep; 171 163 172 164 for (size_t i = 0;i < uhci_batch->td_count; ++i) { … … 175 167 } 176 168 177 uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]);178 if ( uhci_batch->usb_batch->error != EOK) {179 assert( uhci_batch->usb_batch->ep != NULL);169 batch->error = td_status(&uhci_batch->tds[i]); 170 if (batch->error != EOK) { 171 assert(batch->ep != NULL); 180 172 181 173 usb_log_debug("Batch %p found error TD(%zu->%p):%" 182 PRIx32 ". \n", uhci_batch->usb_batch, i,174 PRIx32 ".", uhci_batch, i, 183 175 &uhci_batch->tds[i], uhci_batch->tds[i].status); 184 176 td_print_status(&uhci_batch->tds[i]); 185 177 186 endpoint_toggle_set(uhci_batch->usb_batch->ep, 187 td_toggle(&uhci_batch->tds[i])); 188 if (i > 0) 189 goto substract_ret; 190 return true; 178 uhci_ep->toggle = td_toggle(&uhci_batch->tds[i]); 179 goto substract_ret; 191 180 } 192 181 193 uhci_batch->usb_batch->transfered_size182 batch->transferred_size 194 183 += td_act_size(&uhci_batch->tds[i]); 195 184 if (td_is_short(&uhci_batch->tds[i])) … … 197 186 } 198 187 substract_ret: 199 uhci_batch->usb_batch->transfered_size 200 -= uhci_batch->usb_batch->setup_size; 188 if (batch->transferred_size > 0 && batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 189 assert(batch->transferred_size >= USB_SETUP_PACKET_SIZE); 190 batch->transferred_size -= USB_SETUP_PACKET_SIZE; 191 } 192 193 assert(batch->transferred_size <= batch->size); 194 201 195 return true; 202 196 } … … 216 210 * The last transfer is marked with IOC flag. 217 211 */ 218 static void batch_data(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)212 static void batch_data(uhci_transfer_batch_t *uhci_batch) 219 213 { 220 214 assert(uhci_batch); 221 assert(uhci_batch->usb_batch); 222 assert(uhci_batch->usb_batch->ep);215 216 usb_direction_t dir = uhci_batch->base.dir; 223 217 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 224 218 … … 226 220 const usb_packet_id pid = direction_pids[dir]; 227 221 const bool low_speed = 228 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 229 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 230 const usb_target_t target = {{ 231 uhci_batch->usb_batch->ep->address, 232 uhci_batch->usb_batch->ep->endpoint }}; 233 234 int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep); 222 uhci_batch->base.ep->device->speed == USB_SPEED_LOW; 223 const size_t mps = uhci_batch->base.ep->max_packet_size; 224 225 uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) uhci_batch->base.ep; 226 227 int toggle = uhci_ep->toggle; 235 228 assert(toggle == 0 || toggle == 1); 236 229 237 230 size_t td = 0; 238 size_t remain_size = uhci_batch-> usb_batch->buffer_size;231 size_t remain_size = uhci_batch->base.size; 239 232 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 240 233 … … 248 241 td_init( 249 242 &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size, 250 toggle, false, low_speed, target, pid, buffer, next_td);243 toggle, false, low_speed, uhci_batch->base.target, pid, buffer, next_td); 251 244 252 245 ++td; … … 256 249 } 257 250 td_set_ioc(&uhci_batch->tds[td - 1]); 258 endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle);251 uhci_ep->toggle = toggle; 259 252 usb_log_debug2( 260 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized. \n", \261 uhci_batch ->usb_batch,262 usb_str_transfer_type(uhci_batch-> usb_batch->ep->transfer_type),263 usb_str_direction(uhci_batch-> usb_batch->ep->direction),264 USB_TRANSFER_BATCH_ARGS( *uhci_batch->usb_batch));253 "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \ 254 uhci_batch, 255 usb_str_transfer_type(uhci_batch->base.ep->transfer_type), 256 usb_str_direction(uhci_batch->base.ep->direction), 257 USB_TRANSFER_BATCH_ARGS(uhci_batch->base)); 265 258 } 266 259 … … 276 269 * The last transfer is marked with IOC. 277 270 */ 278 static void batch_control(uhci_transfer_batch_t *uhci_batch , usb_direction_t dir)271 static void batch_control(uhci_transfer_batch_t *uhci_batch) 279 272 { 280 273 assert(uhci_batch); 281 assert(uhci_batch->usb_batch); 282 assert(uhci_batch->usb_batch->ep);274 275 usb_direction_t dir = uhci_batch->base.dir; 283 276 assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN); 284 277 assert(uhci_batch->td_count >= 2); … … 291 284 const usb_packet_id status_stage_pid = status_stage_pids[dir]; 292 285 const bool low_speed = 293 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 294 const size_t mps = uhci_batch->usb_batch->ep->max_packet_size; 295 const usb_target_t target = {{ 296 uhci_batch->usb_batch->ep->address, 297 uhci_batch->usb_batch->ep->endpoint }}; 286 uhci_batch->base.ep->device->speed == USB_SPEED_LOW; 287 const size_t mps = uhci_batch->base.ep->max_packet_size; 288 const usb_target_t target = uhci_batch->base.target; 298 289 299 290 /* setup stage */ 300 291 td_init( 301 292 &uhci_batch->tds[0], DEFAULT_ERROR_COUNT, 302 uhci_batch->usb_batch->setup_size, 0, false,293 USB_SETUP_PACKET_SIZE, 0, false, 303 294 low_speed, target, USB_PID_SETUP, 304 295 uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]); … … 307 298 size_t td = 1; 308 299 unsigned toggle = 1; 309 size_t remain_size = uhci_batch-> usb_batch->buffer_size;300 size_t remain_size = uhci_batch->base.size; 310 301 char *buffer = uhci_transfer_batch_data_buffer(uhci_batch); 311 302 … … 333 324 td_set_ioc(&uhci_batch->tds[td]); 334 325 335 usb_log_debug2("Control last TD status: %x. \n",326 usb_log_debug2("Control last TD status: %x.", 336 327 uhci_batch->tds[td].status); 337 328 } 338 329 339 static void (*const batch_setup[])(uhci_transfer_batch_t* , usb_direction_t) =330 static void (*const batch_setup[])(uhci_transfer_batch_t*) = 340 331 { 341 332 [USB_TRANSFER_CONTROL] = batch_control, -
uspace/drv/bus/usb/uhci/uhci_batch.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 * … … 43 44 #include <stddef.h> 44 45 #include <usb/host/usb_transfer_batch.h> 46 #include <usb/host/endpoint.h> 45 47 46 48 #include "hw_struct/queue_head.h" … … 49 51 /** UHCI specific data required for USB transfer */ 50 52 typedef struct uhci_transfer_batch { 53 usb_transfer_batch_t base; 54 51 55 /** Queue head 52 56 * This QH is used to maintain UHCI schedule structure and the element … … 58 62 /** Number of TDs used by the transfer */ 59 63 size_t td_count; 60 /* * Data buffer, must be accessible by the UHCI hw*/61 void *device_buffer;62 /** Generic transfer data*/63 usb_transfer_batch_t *usb_batch;64 /* Setup data */ 65 char *setup_buffer; 66 /** Backing TDs + setup_buffer */ 67 dma_buffer_t uhci_dma_buffer; 64 68 /** List element */ 65 69 link_t link; 66 70 } uhci_transfer_batch_t; 67 71 68 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch); 69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch); 70 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch); 72 uhci_transfer_batch_t *uhci_transfer_batch_create(endpoint_t *); 73 int uhci_transfer_batch_prepare(uhci_transfer_batch_t *); 74 bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *); 75 void uhci_transfer_batch_destroy(uhci_transfer_batch_t *); 71 76 72 77 /** Get offset to setup buffer accessible to the HC hw. … … 74 79 * @return Pointer to the setup buffer. 75 80 */ 76 static inline void * uhci_transfer_batch_setup_buffer(81 static inline void *uhci_transfer_batch_setup_buffer( 77 82 const uhci_transfer_batch_t *uhci_batch) 78 83 { 79 84 assert(uhci_batch); 80 assert(uhci_batch->device_buffer); 81 return uhci_batch->device_buffer + sizeof(qh_t) + 85 return uhci_batch->uhci_dma_buffer.virt + sizeof(qh_t) + 82 86 uhci_batch->td_count * sizeof(td_t); 83 87 } … … 87 91 * @return Pointer to the data buffer. 88 92 */ 89 static inline void * uhci_transfer_batch_data_buffer(93 static inline void *uhci_transfer_batch_data_buffer( 90 94 const uhci_transfer_batch_t *uhci_batch) 91 95 { 92 96 assert(uhci_batch); 93 assert(uhci_batch->usb_batch); 94 return uhci_transfer_batch_setup_buffer(uhci_batch) + 95 uhci_batch->usb_batch->setup_size; 96 } 97 98 /** Aborts the batch. 99 * Sets error to EINTR and size off transferd data to 0, before finishing the 100 * batch. 101 * @param uhci_batch Batch to abort. 102 */ 103 static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch) 104 { 105 assert(uhci_batch); 106 assert(uhci_batch->usb_batch); 107 uhci_batch->usb_batch->error = EINTR; 108 uhci_batch->usb_batch->transfered_size = 0; 109 uhci_transfer_batch_finish_dispose(uhci_batch); 97 return uhci_batch->base.dma_buffer.virt; 110 98 } 111 99 … … 120 108 } 121 109 110 static inline uhci_transfer_batch_t *uhci_transfer_batch_get( 111 usb_transfer_batch_t *b) 112 { 113 assert(b); 114 return (uhci_transfer_batch_t *) b; 115 } 116 122 117 #endif 123 118 -
uspace/drv/bus/usb/uhci/uhci_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 * … … 39 40 #include <usb/classes/hub.h> 40 41 #include <usb/request.h> 42 #include <usb/host/endpoint.h> 41 43 #include <usb/usb.h> 42 44 … … 103 105 assert(batch); 104 106 105 const usb_target_t target = {{106 .address = batch->ep->address,107 .endpoint = batch->ep->endpoint108 }};109 107 do { 110 batch->error = virthub_base_request(&instance->base, target,111 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,112 batch-> buffer, batch->buffer_size, &batch->transfered_size);108 batch->error = virthub_base_request(&instance->base, batch->target, 109 batch->dir, (void*) batch->setup.buffer, 110 batch->dma_buffer.virt, batch->size, &batch->transferred_size); 113 111 if (batch->error == ENAK) 114 112 async_usleep(instance->base.endpoint_descriptor.poll_interval * 1000); … … 116 114 //ENAK is technically an error condition 117 115 } while (batch->error == ENAK); 118 usb_transfer_batch_finish(batch, NULL); 119 usb_transfer_batch_destroy(batch); 116 usb_transfer_batch_finish(batch); 120 117 return EOK; 121 118 } … … 206 203 data[0] = ((value & STATUS_LINE_D_MINUS) ? 1 : 0) 207 204 | ((value & STATUS_LINE_D_PLUS) ? 2 : 0); 208 RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16") \n",205 RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16")", 209 206 data[0], value); 210 207 *act_size = 1; … … 214 211 #define BIT_VAL(val, bit) \ 215 212 ((val & bit) ? 1 : 0) 216 #define UHCI2USB(val, bit, feat) \217 (BIT_VAL(val, bit) << feat)213 #define UHCI2USB(val, bit, mask) \ 214 (BIT_VAL(val, bit) ? (mask) : 0) 218 215 219 216 /** Port status request handler. … … 240 237 const uint16_t val = pio_read_16(hub->ports[port]); 241 238 const uint32_t status = uint32_host2usb( 242 UHCI2USB(val, STATUS_CONNECTED, USB_HUB_ FEATURE_PORT_CONNECTION) |243 UHCI2USB(val, STATUS_ENABLED, USB_HUB_ FEATURE_PORT_ENABLE) |244 UHCI2USB(val, STATUS_SUSPEND, USB _HUB_FEATURE_PORT_SUSPEND) |245 UHCI2USB(val, STATUS_IN_RESET, USB_HUB_ FEATURE_PORT_RESET) |246 UHCI2USB(val, STATUS_ALWAYS_ONE, USB _HUB_FEATURE_PORT_POWER) |247 UHCI2USB(val, STATUS_LOW_SPEED, USB _HUB_FEATURE_PORT_LOW_SPEED) |248 UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_ FEATURE_C_PORT_CONNECTION) |249 UHCI2USB(val, STATUS_ENABLED_CHANGED, USB _HUB_FEATURE_C_PORT_ENABLE) |250 // UHCI2USB(val, STATUS_SUSPEND, USB _HUB_FEATURE_C_PORT_SUSPEND) |251 ( (hub->reset_changed[port] ? 1 : 0) << USB_HUB_FEATURE_C_PORT_RESET)239 UHCI2USB(val, STATUS_CONNECTED, USB_HUB_PORT_STATUS_CONNECTION) | 240 UHCI2USB(val, STATUS_ENABLED, USB_HUB_PORT_STATUS_ENABLE) | 241 UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_SUSPEND) | 242 UHCI2USB(val, STATUS_IN_RESET, USB_HUB_PORT_STATUS_RESET) | 243 UHCI2USB(val, STATUS_ALWAYS_ONE, USB2_HUB_PORT_STATUS_POWER) | 244 UHCI2USB(val, STATUS_LOW_SPEED, USB2_HUB_PORT_STATUS_LOW_SPEED) | 245 UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_PORT_STATUS_C_CONNECTION) | 246 UHCI2USB(val, STATUS_ENABLED_CHANGED, USB2_HUB_PORT_STATUS_C_ENABLE) | 247 // UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_C_SUSPEND) | 248 (hub->reset_changed[port] ? USB_HUB_PORT_STATUS_C_RESET : 0) 252 249 ); 253 250 RH_DEBUG(hub, port, "Port status %" PRIx32 " (source %" PRIx16 254 "%s) \n", uint32_usb2host(status), val,251 "%s)", uint32_usb2host(status), val, 255 252 hub->reset_changed[port] ? "-reset" : ""); 256 253 memcpy(data, &status, sizeof(status)); … … 278 275 const uint16_t val = status & (~STATUS_WC_BITS); 279 276 switch (feature) { 280 case USB _HUB_FEATURE_PORT_ENABLE:277 case USB2_HUB_FEATURE_PORT_ENABLE: 281 278 RH_DEBUG(hub, port, "Clear port enable (status %" 282 PRIx16 ") \n", status);279 PRIx16 ")", status); 283 280 pio_write_16(hub->ports[port], val & ~STATUS_ENABLED); 284 281 break; 285 case USB _HUB_FEATURE_PORT_SUSPEND:282 case USB2_HUB_FEATURE_PORT_SUSPEND: 286 283 RH_DEBUG(hub, port, "Clear port suspend (status %" 287 PRIx16 ") \n", status);284 PRIx16 ")", status); 288 285 pio_write_16(hub->ports[port], val & ~STATUS_SUSPEND); 289 286 // TODO we should do resume magic 290 usb_log_warning("Resume is not implemented on port %u \n", port);287 usb_log_warning("Resume is not implemented on port %u", port); 291 288 break; 292 289 case USB_HUB_FEATURE_PORT_POWER: 293 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ") \n",290 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ")", 294 291 status); 295 292 /* We are always powered */ 296 usb_log_warning("Tried to power off port %u \n", port);293 usb_log_warning("Tried to power off port %u", port); 297 294 break; 298 295 case USB_HUB_FEATURE_C_PORT_CONNECTION: 299 296 RH_DEBUG(hub, port, "Clear port conn change (status %" 300 PRIx16 ") \n", status);297 PRIx16 ")", status); 301 298 pio_write_16(hub->ports[port], val | STATUS_CONNECTED_CHANGED); 302 299 break; 303 300 case USB_HUB_FEATURE_C_PORT_RESET: 304 301 RH_DEBUG(hub, port, "Clear port reset change (status %" 305 PRIx16 ") \n", status);302 PRIx16 ")", status); 306 303 hub->reset_changed[port] = false; 307 304 break; 308 case USB _HUB_FEATURE_C_PORT_ENABLE:305 case USB2_HUB_FEATURE_C_PORT_ENABLE: 309 306 RH_DEBUG(hub, port, "Clear port enable change (status %" 310 PRIx16 ") \n", status);307 PRIx16 ")", status); 311 308 pio_write_16(hub->ports[port], status | STATUS_ENABLED_CHANGED); 312 309 break; 313 case USB _HUB_FEATURE_C_PORT_SUSPEND:310 case USB2_HUB_FEATURE_C_PORT_SUSPEND: 314 311 RH_DEBUG(hub, port, "Clear port suspend change (status %" 315 PRIx16 ") \n", status);312 PRIx16 ")", status); 316 313 //TODO 317 314 return ENOTSUP; 318 315 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 319 316 RH_DEBUG(hub, port, "Clear port OC change (status %" 320 PRIx16 ") \n", status);317 PRIx16 ")", status); 321 318 /* UHCI Does not report over current */ 322 319 //TODO: newer chips do, but some have broken wiring … … 324 321 default: 325 322 RH_DEBUG(hub, port, "Clear unknown feature %d (status %" 326 PRIx16 ") \n", feature, status);327 usb_log_warning("Clearing feature %d is unsupported \n",323 PRIx16 ")", feature, status); 324 usb_log_warning("Clearing feature %d is unsupported", 328 325 feature); 329 326 return ESTALL; … … 352 349 case USB_HUB_FEATURE_PORT_RESET: 353 350 RH_DEBUG(hub, port, "Set port reset before (status %" PRIx16 354 ") \n", status);351 ")", status); 355 352 uhci_port_reset_enable(hub->ports[port]); 356 353 hub->reset_changed[port] = true; 357 354 RH_DEBUG(hub, port, "Set port reset after (status %" PRIx16 358 ") \n", pio_read_16(hub->ports[port]));359 break; 360 case USB _HUB_FEATURE_PORT_SUSPEND:355 ")", pio_read_16(hub->ports[port])); 356 break; 357 case USB2_HUB_FEATURE_PORT_SUSPEND: 361 358 RH_DEBUG(hub, port, "Set port suspend (status %" PRIx16 362 ") \n", status);359 ")", status); 363 360 pio_write_16(hub->ports[port], 364 361 (status & ~STATUS_WC_BITS) | STATUS_SUSPEND); 365 usb_log_warning("Suspend is not implemented on port %u \n", port);362 usb_log_warning("Suspend is not implemented on port %u", port); 366 363 break; 367 364 case USB_HUB_FEATURE_PORT_POWER: 368 365 RH_DEBUG(hub, port, "Set port power (status %" PRIx16 369 ") \n", status);366 ")", status); 370 367 /* We are always powered */ 371 usb_log_warning("Tried to power port %u \n", port);368 usb_log_warning("Tried to power port %u", port); 372 369 break; 373 370 case USB_HUB_FEATURE_C_PORT_CONNECTION: 374 case USB _HUB_FEATURE_C_PORT_ENABLE:375 case USB _HUB_FEATURE_C_PORT_SUSPEND:371 case USB2_HUB_FEATURE_C_PORT_ENABLE: 372 case USB2_HUB_FEATURE_C_PORT_SUSPEND: 376 373 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 377 374 RH_DEBUG(hub, port, "Set port change flag (status %" PRIx16 378 ") \n", status);375 ")", status); 379 376 /* These are voluntary and don't have to be set 380 377 * there is no way we could do it on UHCI anyway */ … … 382 379 default: 383 380 RH_DEBUG(hub, port, "Set unknown feature %d (status %" PRIx16 384 ") \n", feature, status);385 usb_log_warning("Setting feature %d is unsupported \n",381 ")", feature, status); 382 usb_log_warning("Setting feature %d is unsupported", 386 383 feature); 387 384 return ESTALL; … … 422 419 RH_DEBUG(hub, -1, "Event mask %" PRIx8 423 420 " (status_a %" PRIx16 "%s)," 424 " (status_b %" PRIx16 "%s) \n", status,421 " (status_b %" PRIx16 "%s)", status, 425 422 status_a, hub->reset_changed[0] ? "-reset" : "", 426 423 status_b, hub->reset_changed[1] ? "-reset" : "" ); -
uspace/drv/bus/usb/usbflbk/main.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Petr Manek 3 4 * All rights reserved. 4 5 * … … 48 49 static errno_t usbfallback_device_add(usb_device_t *dev) 49 50 { 50 usb_log_info("Pretending to control %s `%s'. \n",51 usb_log_info("Pretending to control %s `%s'.", 51 52 usb_device_get_iface_number(dev) < 0 ? "device" : "interface", 52 53 usb_device_get_name(dev)); … … 62 63 { 63 64 assert(dev); 65 usb_log_info("Device '%s' gone.", usb_device_get_name(dev)); 66 return EOK; 67 } 68 69 static errno_t usbfallback_device_remove(usb_device_t *dev) 70 { 71 assert(dev); 72 usb_log_info("Device '%s' removed.", usb_device_get_name(dev)); 64 73 return EOK; 65 74 } … … 68 77 static const usb_driver_ops_t usbfallback_driver_ops = { 69 78 .device_add = usbfallback_device_add, 70 .device_rem = usbfallback_device_gone,79 .device_remove = usbfallback_device_remove, 71 80 .device_gone = usbfallback_device_gone, 72 81 }; -
uspace/drv/bus/usb/usbhub/main.c
rf5e5f73 rdf6ded8 48 48 static const usb_driver_ops_t usb_hub_driver_ops = { 49 49 .device_add = usb_hub_device_add, 50 // .device_rem= usb_hub_device_remove,50 .device_remove = usb_hub_device_remove, 51 51 .device_gone = usb_hub_device_gone, 52 52 }; 53 53 54 /** Hub endpoints, excluding control endpoint. */55 static const usb_endpoint_description_t *usb_hub_endpoints[] = {56 &hub_status_change_endpoint_description,57 NULL,58 };59 54 /** Static usb hub driver information. */ 60 55 static const usb_driver_t usb_hub_driver = { -
uspace/drv/bus/usb/usbhub/port.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty 4 5 * All rights reserved. 5 6 * … … 40 41 #include <inttypes.h> 41 42 #include <fibril_synch.h> 43 #include <usbhc_iface.h> 42 44 43 45 #include <usb/debug.h> … … 47 49 #include "status.h" 48 50 49 /** Information for fibril for device discovery. */ 50 struct add_device_phase1 { 51 usb_hub_dev_t *hub; 52 usb_hub_port_t *port; 53 usb_speed_t speed; 54 }; 55 56 static errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub); 57 static void usb_hub_port_reset_completed(usb_hub_port_t *port, 58 usb_hub_dev_t *hub, usb_port_status_t status); 59 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status); 60 static errno_t add_device_phase1_worker_fibril(void *arg); 61 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, 62 usb_speed_t speed); 63 64 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub) 51 #define port_log(lvl, port, fmt, ...) do { \ 52 usb_log_##lvl("(%p-%u): " fmt, \ 53 (port->hub), (port->port_number), ##__VA_ARGS__); \ 54 } while (0) 55 56 /** Initialize hub port information. 57 * 58 * @param port Port to be initialized. 59 */ 60 void usb_hub_port_init(usb_hub_port_t *port, usb_hub_dev_t *hub, 61 unsigned int port_number) 65 62 { 66 63 assert(port); 67 if (port->device_attached) 68 return usb_hub_port_device_gone(port, hub); 64 memset(port, 0, sizeof(*port)); 65 port->hub = hub; 66 port->port_number = port_number; 67 usb_port_init(&port->base); 68 } 69 70 static inline usb_hub_port_t *get_hub_port(usb_port_t *port) 71 { 72 assert(port); 73 return (usb_hub_port_t *) port; 74 } 75 76 /** 77 * Inform the HC that the device on port is gone. 78 */ 79 static void remove_device(usb_port_t *port_base) 80 { 81 usb_hub_port_t *port = get_hub_port(port_base); 82 83 async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device); 84 if (!exch) { 85 port_log(error, port, "Cannot remove the device, " 86 "failed creating exchange."); 87 return; 88 } 89 90 const errno_t err = usbhc_device_remove(exch, port->port_number); 91 if (err) 92 port_log(error, port, "Failed to remove device: %s", 93 str_error(err)); 94 95 usb_device_bus_exchange_end(exch); 96 } 97 98 99 static usb_speed_t get_port_speed(usb_hub_port_t *port, uint32_t status) 100 { 101 assert(port); 102 assert(port->hub); 103 104 return usb_port_speed(port->hub->speed, status); 105 } 106 107 /** 108 * Routine for adding a new device in USB2. 109 */ 110 static errno_t enumerate_device_usb2(usb_hub_port_t *port, async_exch_t *exch) 111 { 112 errno_t err; 113 114 port_log(debug, port, "Requesting default address."); 115 err = usb_hub_reserve_default_address(port->hub, exch, &port->base); 116 if (err != EOK) { 117 port_log(error, port, "Failed to reserve default address: %s", 118 str_error(err)); 119 return err; 120 } 121 122 /* Reservation of default address could have blocked */ 123 if (port->base.state != PORT_CONNECTING) 124 goto out_address; 125 126 port_log(debug, port, "Resetting port."); 127 if ((err = usb_hub_set_port_feature(port->hub, port->port_number, 128 USB_HUB_FEATURE_PORT_RESET))) { 129 port_log(warning, port, "Port reset request failed: %s", 130 str_error(err)); 131 goto out_address; 132 } 133 134 if ((err = usb_port_wait_for_enabled(&port->base))) { 135 port_log(error, port, "Failed to reset port: %s", 136 str_error(err)); 137 goto out_address; 138 } 139 140 port_log(debug, port, "Enumerating device."); 141 if ((err = usbhc_device_enumerate(exch, port->port_number, 142 port->speed))) { 143 port_log(error, port, "Failed to enumerate device: %s", 144 str_error(err)); 145 /* Disable the port */ 146 usb_hub_clear_port_feature(port->hub, port->port_number, 147 USB2_HUB_FEATURE_PORT_ENABLE); 148 goto out_address; 149 } 150 151 port_log(debug, port, "Device enumerated"); 152 153 out_address: 154 usb_hub_release_default_address(port->hub, exch); 155 return err; 156 } 157 158 /** 159 * Routine for adding a new device in USB 3. 160 */ 161 static errno_t enumerate_device_usb3(usb_hub_port_t *port, async_exch_t *exch) 162 { 163 errno_t err; 164 165 port_log(debug, port, "Issuing a warm reset."); 166 if ((err = usb_hub_set_port_feature(port->hub, port->port_number, 167 USB3_HUB_FEATURE_BH_PORT_RESET))) { 168 port_log(warning, port, "Port reset request failed: %s", 169 str_error(err)); 170 return err; 171 } 172 173 if ((err = usb_port_wait_for_enabled(&port->base))) { 174 port_log(error, port, "Failed to reset port: %s", 175 str_error(err)); 176 return err; 177 } 178 179 port_log(debug, port, "Enumerating device."); 180 if ((err = usbhc_device_enumerate(exch, port->port_number, 181 port->speed))) { 182 port_log(error, port, "Failed to enumerate device: %s", 183 str_error(err)); 184 return err; 185 } 186 187 port_log(debug, port, "Device enumerated"); 69 188 return EOK; 70 189 } 71 190 72 /** 73 * Clear feature on hub port. 74 * 75 * @param port Port structure. 76 * @param feature Feature selector. 77 * @return Operation result 78 */ 79 errno_t usb_hub_port_clear_feature( 80 usb_hub_port_t *port, usb_hub_class_feature_t feature) 81 { 82 assert(port); 83 const usb_device_request_setup_packet_t clear_request = { 84 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE, 85 .request = USB_DEVREQ_CLEAR_FEATURE, 86 .value = feature, 87 .index = port->port_number, 88 .length = 0, 89 }; 90 return usb_pipe_control_write(port->control_pipe, &clear_request, 91 sizeof(clear_request), NULL, 0); 92 } 93 94 /** 95 * Set feature on hub port. 96 * 97 * @param port Port structure. 98 * @param feature Feature selector. 99 * @return Operation result 100 */ 101 errno_t usb_hub_port_set_feature( 102 usb_hub_port_t *port, usb_hub_class_feature_t feature) 103 { 104 assert(port); 105 const usb_device_request_setup_packet_t clear_request = { 106 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 107 .request = USB_DEVREQ_SET_FEATURE, 108 .index = port->port_number, 109 .value = feature, 110 .length = 0, 111 }; 112 return usb_pipe_control_write(port->control_pipe, &clear_request, 113 sizeof(clear_request), NULL, 0); 114 } 115 116 /** 117 * Mark reset process as failed due to external reasons 118 * 119 * @param port Port structure 120 */ 121 void usb_hub_port_reset_fail(usb_hub_port_t *port) 122 { 123 assert(port); 124 fibril_mutex_lock(&port->mutex); 125 if (port->reset_status == IN_RESET) 126 port->reset_status = RESET_FAIL; 127 fibril_condvar_broadcast(&port->reset_cv); 128 fibril_mutex_unlock(&port->mutex); 191 static errno_t enumerate_device(usb_port_t *port_base) 192 { 193 usb_hub_port_t *port = get_hub_port(port_base); 194 195 port_log(debug, port, "Setting up new device."); 196 async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device); 197 if (!exch) { 198 port_log(error, port, "Failed to create exchange."); 199 return ENOMEM; 200 } 201 202 const errno_t err = port->hub->speed == USB_SPEED_SUPER 203 ? enumerate_device_usb3(port, exch) 204 : enumerate_device_usb2(port, exch); 205 206 usb_device_bus_exchange_end(exch); 207 return err; 208 } 209 210 static void port_changed_connection(usb_hub_port_t *port, usb_port_status_t status) 211 { 212 const bool connected = !!(status & USB_HUB_PORT_STATUS_CONNECTION); 213 port_log(debug, port, "Connection change: device %s.", connected 214 ? "attached" : "removed"); 215 216 if (connected) { 217 usb_port_connected(&port->base, &enumerate_device); 218 } else { 219 usb_port_disabled(&port->base, &remove_device); 220 } 221 } 222 223 static void port_changed_enabled(usb_hub_port_t *port, usb_port_status_t status) 224 { 225 const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE); 226 if (enabled) { 227 port_log(warning, port, "Port unexpectedly changed to enabled."); 228 } else { 229 usb_port_disabled(&port->base, &remove_device); 230 } 231 } 232 233 static void port_changed_overcurrent(usb_hub_port_t *port, 234 usb_port_status_t status) 235 { 236 const bool overcurrent = !!(status & USB_HUB_PORT_STATUS_OC); 237 238 /* According to the USB specs: 239 * 11.13.5 Over-current Reporting and Recovery 240 * Hub device is responsible for putting port in power off 241 * mode. USB system software is responsible for powering port 242 * back on when the over-current condition is gone */ 243 244 usb_port_disabled(&port->base, &remove_device); 245 246 if (!overcurrent) { 247 const errno_t err = usb_hub_set_port_feature(port->hub, 248 port->port_number, USB_HUB_FEATURE_PORT_POWER); 249 if (err) 250 port_log(error, port, "Failed to set port power " 251 "after OC: %s.", str_error(err)); 252 } 253 } 254 255 static void port_changed_reset(usb_hub_port_t *port, usb_port_status_t status) 256 { 257 const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE); 258 259 if (enabled) { 260 port->speed = get_port_speed(port, status); 261 usb_port_enabled(&port->base); 262 } else 263 usb_port_disabled(&port->base, &remove_device); 264 } 265 266 typedef void (*change_handler_t)(usb_hub_port_t *, usb_port_status_t); 267 268 static void check_port_change(usb_hub_port_t *port, usb_port_status_t *status, 269 change_handler_t handler, usb_port_status_t mask, 270 usb_hub_class_feature_t feature) 271 { 272 if ((*status & mask) == 0) 273 return; 274 275 /* Clear the change so it won't come again */ 276 usb_hub_clear_port_feature(port->hub, port->port_number, feature); 277 278 if (handler) 279 handler(port, *status); 280 281 /* Mark the change as resolved */ 282 *status &= ~mask; 129 283 } 130 284 … … 136 290 * @param hub hub representation 137 291 */ 138 void usb_hub_port_process_interrupt(usb_hub_port_t *port , usb_hub_dev_t *hub)292 void usb_hub_port_process_interrupt(usb_hub_port_t *port) 139 293 { 140 294 assert(port); 141 assert(hub); 142 usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number); 295 port_log(debug2, port, "Interrupt."); 143 296 144 297 usb_port_status_t status = 0; 145 const errno_t opResult = get_port_status(port, &status); 146 if (opResult != EOK) { 147 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub, 148 port->port_number, str_error(opResult)); 298 const errno_t err = usb_hub_get_port_status(port->hub, 299 port->port_number, &status); 300 if (err != EOK) { 301 port_log(error, port, "Failed to get port status: %s.", 302 str_error(err)); 149 303 return; 150 304 } 151 305 152 /* Connection change */ 153 if (status & USB_HUB_PORT_C_STATUS_CONNECTION) { 154 const bool connected = 155 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 156 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub, 157 port->port_number, connected ? "attached" : "removed"); 158 159 /* ACK the change */ 160 const errno_t opResult = usb_hub_port_clear_feature(port, 161 USB_HUB_FEATURE_C_PORT_CONNECTION); 162 if (opResult != EOK) { 163 usb_log_warning("(%p-%u): Failed to clear " 164 "port-change-connection flag: %s.\n", hub, 165 port->port_number, str_error(opResult)); 166 } 167 168 if (connected) { 169 const errno_t opResult = create_add_device_fibril(port, hub, 170 usb_port_speed(status)); 171 if (opResult != EOK) { 172 usb_log_error("(%p-%u): Cannot handle change on" 173 " port: %s.\n", hub, port->port_number, 174 str_error(opResult)); 175 } 176 } else { 177 /* Handle the case we were in reset */ 178 // FIXME: usb_hub_port_reset_fail(port); 179 /* If enabled change was reported leave the removal 180 * to that handler, it shall ACK the change too. */ 181 if (!(status & USB_HUB_PORT_C_STATUS_ENABLED)) { 182 usb_hub_port_device_gone(port, hub); 183 } 184 } 185 } 186 187 /* Enable change, ports are automatically disabled on errors. */ 188 if (status & USB_HUB_PORT_C_STATUS_ENABLED) { 189 // TODO: maybe HS reset failed? 190 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub, 191 port->port_number); 192 usb_hub_port_device_gone(port, hub); 193 const errno_t rc = usb_hub_port_clear_feature(port, 194 USB_HUB_FEATURE_C_PORT_ENABLE); 195 if (rc != EOK) { 196 usb_log_error("(%p-%u): Failed to clear port enable " 197 "change feature: %s.", hub, port->port_number, 198 str_error(rc)); 199 } 200 201 } 202 203 /* Suspend change */ 204 if (status & USB_HUB_PORT_C_STATUS_SUSPEND) { 205 usb_log_error("(%p-%u): Port went to suspend state, this should" 206 " NOT happen as we do not support suspend state!", hub, 207 port->port_number); 208 const errno_t rc = usb_hub_port_clear_feature(port, 209 USB_HUB_FEATURE_C_PORT_SUSPEND); 210 if (rc != EOK) { 211 usb_log_error("(%p-%u): Failed to clear port suspend " 212 "change feature: %s.", hub, port->port_number, 213 str_error(rc)); 214 } 215 } 216 217 /* Over current */ 218 if (status & USB_HUB_PORT_C_STATUS_OC) { 219 usb_log_debug("(%p-%u): Port OC reported!.", hub, 220 port->port_number); 221 /* According to the USB specs: 222 * 11.13.5 Over-current Reporting and Recovery 223 * Hub device is responsible for putting port in power off 224 * mode. USB system software is responsible for powering port 225 * back on when the over-current condition is gone */ 226 const errno_t rc = usb_hub_port_clear_feature(port, 227 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 228 if (rc != EOK) { 229 usb_log_error("(%p-%u): Failed to clear port OC change " 230 "feature: %s.\n", hub, port->port_number, 231 str_error(rc)); 232 } 233 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { 234 const errno_t rc = usb_hub_port_set_feature( 235 port, USB_HUB_FEATURE_PORT_POWER); 236 if (rc != EOK) { 237 usb_log_error("(%p-%u): Failed to set port " 238 "power after OC: %s.", hub, 239 port->port_number, str_error(rc)); 240 } 241 } 242 } 243 244 /* Port reset, set on port reset complete. */ 245 if (status & USB_HUB_PORT_C_STATUS_RESET) { 246 usb_hub_port_reset_completed(port, hub, status); 247 } 248 249 usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub, 250 port->port_number, status); 251 } 252 253 /** 254 * routine called when a device on port has been removed 255 * 256 * If the device on port had default address, it releases default address. 257 * Otherwise does not do anything, because DDF does not allow to remove device 258 * from it`s device tree. 259 * @param port port structure 260 * @param hub hub representation 261 */ 262 errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub) 263 { 264 assert(port); 265 assert(hub); 266 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 267 if (!exch) 268 return ENOMEM; 269 const errno_t rc = usb_device_remove(exch, port->port_number); 270 usb_device_bus_exchange_end(exch); 271 if (rc == EOK) 272 port->device_attached = false; 273 return rc; 274 275 } 276 277 /** 278 * Process port reset change 279 * 280 * After this change port should be enabled, unless some problem occurred. 281 * This functions triggers second phase of enabling new device. 282 * @param port Port structure 283 * @param status Port status mask 284 */ 285 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub, 286 usb_port_status_t status) 287 { 288 assert(port); 289 fibril_mutex_lock(&port->mutex); 290 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0; 291 /* Finalize device adding. */ 292 293 if (enabled) { 294 port->reset_status = RESET_OK; 295 usb_log_debug("(%p-%u): Port reset complete.\n", hub, 296 port->port_number); 306 check_port_change(port, &status, &port_changed_connection, 307 USB_HUB_PORT_STATUS_C_CONNECTION, 308 USB_HUB_FEATURE_C_PORT_CONNECTION); 309 310 check_port_change(port, &status, &port_changed_overcurrent, 311 USB_HUB_PORT_STATUS_C_OC, USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 312 313 check_port_change(port, &status, &port_changed_reset, 314 USB_HUB_PORT_STATUS_C_RESET, USB_HUB_FEATURE_C_PORT_RESET); 315 316 if (port->hub->speed <= USB_SPEED_HIGH) { 317 check_port_change(port, &status, &port_changed_enabled, 318 USB2_HUB_PORT_STATUS_C_ENABLE, 319 USB2_HUB_FEATURE_C_PORT_ENABLE); 297 320 } else { 298 port->reset_status = RESET_FAIL; 299 usb_log_warning("(%p-%u): Port reset complete but port not " 300 "enabled.", hub, port->port_number); 301 } 302 fibril_condvar_broadcast(&port->reset_cv); 303 fibril_mutex_unlock(&port->mutex); 304 305 /* Clear the port reset change. */ 306 errno_t rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 307 if (rc != EOK) { 308 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 309 hub, port->port_number, str_error(rc)); 310 } 311 } 312 313 /** Retrieve port status. 314 * 315 * @param[in] port Port structure 316 * @param[out] status Where to store the port status. 317 * @return Error code. 318 */ 319 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status) 320 { 321 assert(port); 322 /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6 323 * Generic GET_STATUS request cannot be used because of the difference 324 * in status data size (2B vs. 4B)*/ 325 const usb_device_request_setup_packet_t request = { 326 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS, 327 .request = USB_HUB_REQUEST_GET_STATUS, 328 .value = 0, 329 .index = uint16_host2usb(port->port_number), 330 .length = sizeof(usb_port_status_t), 331 }; 332 size_t recv_size; 333 usb_port_status_t status_tmp; 334 335 const errno_t rc = usb_pipe_control_read(port->control_pipe, 336 &request, sizeof(usb_device_request_setup_packet_t), 337 &status_tmp, sizeof(status_tmp), &recv_size); 338 if (rc != EOK) { 339 return rc; 340 } 341 342 if (recv_size != sizeof (status_tmp)) { 343 return ELIMIT; 344 } 345 346 if (status != NULL) { 347 *status = status_tmp; 348 } 349 350 return EOK; 351 } 352 353 static errno_t port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable) 354 { 355 if (enable) { 356 errno_t rc = 357 usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET); 358 if (rc != EOK) { 359 usb_log_error("(%p-%u): Port reset request failed: %s.", 360 hub, port->port_number, str_error(rc)); 361 return rc; 362 } 363 /* Wait until reset completes. */ 364 fibril_mutex_lock(&port->mutex); 365 port->reset_status = IN_RESET; 366 while (port->reset_status == IN_RESET) 367 fibril_condvar_wait(&port->reset_cv, &port->mutex); 368 rc = port->reset_status == RESET_OK ? EOK : ESTALL; 369 fibril_mutex_unlock(&port->mutex); 370 return rc; 371 } else { 372 return usb_hub_port_clear_feature(port, 373 USB_HUB_FEATURE_PORT_ENABLE); 374 } 375 } 376 377 /** Fibril for adding a new device. 378 * 379 * Separate fibril is needed because the port reset completion is announced 380 * via interrupt pipe and thus we cannot block here. 381 * 382 * @param arg Pointer to struct add_device_phase1. 383 * @return 0 Always. 384 */ 385 errno_t add_device_phase1_worker_fibril(void *arg) 386 { 387 struct add_device_phase1 *params = arg; 388 assert(params); 389 390 errno_t ret = EOK; 391 usb_hub_dev_t *hub = params->hub; 392 usb_hub_port_t *port = params->port; 393 const usb_speed_t speed = params->speed; 394 free(arg); 395 396 usb_log_debug("(%p-%u): New device sequence.", hub, port->port_number); 397 398 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 399 if (!exch) { 400 usb_log_error("(%p-%u): Failed to begin bus exchange.", hub, 401 port->port_number); 402 ret = ENOMEM; 403 goto out; 404 } 405 406 /* Reserve default address */ 407 while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) { 408 async_usleep(1000000); 409 } 410 if (ret != EOK) { 411 usb_log_error("(%p-%u): Failed to reserve default address: %s", 412 hub, port->port_number, str_error(ret)); 413 goto out; 414 } 415 416 usb_log_debug("(%p-%u): Got default address reseting port.", hub, 417 port->port_number); 418 /* Reset port */ 419 ret = port_enable(port, hub, true); 420 if (ret != EOK) { 421 usb_log_error("(%p-%u): Failed to reset port.", hub, 422 port->port_number); 423 if (usb_release_default_address(exch) != EOK) 424 usb_log_warning("(%p-%u): Failed to release default " 425 "address.", hub, port->port_number); 426 ret = EIO; 427 goto out; 428 } 429 usb_log_debug("(%p-%u): Port reset, enumerating device", hub, 430 port->port_number); 431 432 ret = usb_device_enumerate(exch, port->port_number); 433 if (ret != EOK) { 434 usb_log_error("(%p-%u): Failed to enumerate device: %s", hub, 435 port->port_number, str_error(ret)); 436 const errno_t ret = port_enable(port, hub, false); 437 if (ret != EOK) { 438 usb_log_warning("(%p-%u)Failed to disable port (%s), " 439 "NOT releasing default address.", hub, 440 port->port_number, str_error(ret)); 441 } else { 442 const errno_t ret = usb_release_default_address(exch); 443 if (ret != EOK) 444 usb_log_warning("(%p-%u): Failed to release " 445 "default address: %s", hub, 446 port->port_number, str_error(ret)); 447 } 448 } else { 449 usb_log_debug("(%p-%u): Device enumerated", hub, 450 port->port_number); 451 port->device_attached = true; 452 if (usb_release_default_address(exch) != EOK) 453 usb_log_warning("(%p-%u): Failed to release default " 454 "address", hub, port->port_number); 455 } 456 out: 457 usb_device_bus_exchange_end(exch); 458 459 fibril_mutex_lock(&hub->pending_ops_mutex); 460 assert(hub->pending_ops_count > 0); 461 --hub->pending_ops_count; 462 fibril_condvar_signal(&hub->pending_ops_cv); 463 fibril_mutex_unlock(&hub->pending_ops_mutex); 464 465 return ret; 466 } 467 468 /** Start device adding when connection change is detected. 469 * 470 * This fires a new fibril to complete the device addition. 471 * 472 * @param hub Hub where the change occured. 473 * @param port Port index (starting at 1). 474 * @param speed Speed of the device. 475 * @return Error code. 476 */ 477 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, 478 usb_speed_t speed) 479 { 480 assert(hub); 481 assert(port); 482 struct add_device_phase1 *data 483 = malloc(sizeof(struct add_device_phase1)); 484 if (data == NULL) { 485 return ENOMEM; 486 } 487 data->hub = hub; 488 data->port = port; 489 data->speed = speed; 490 491 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 492 if (fibril == 0) { 493 free(data); 494 return ENOMEM; 495 } 496 fibril_mutex_lock(&hub->pending_ops_mutex); 497 ++hub->pending_ops_count; 498 fibril_mutex_unlock(&hub->pending_ops_mutex); 499 fibril_add_ready(fibril); 500 501 return EOK; 502 } 321 check_port_change(port, &status, &port_changed_reset, 322 USB3_HUB_PORT_STATUS_C_BH_RESET, 323 USB3_HUB_FEATURE_C_BH_PORT_RESET); 324 325 check_port_change(port, &status, NULL, 326 USB3_HUB_PORT_STATUS_C_LINK_STATE, 327 USB3_HUB_FEATURE_C_PORT_LINK_STATE); 328 } 329 330 /* Check for changes we ignored */ 331 if (status & 0xffff0000) { 332 port_log(debug, port, "Port status change igored. " 333 "Status: %#08" PRIx32, status); 334 } 335 } 336 503 337 504 338 /** -
uspace/drv/bus/usb/usbhub/port.h
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty 4 5 * All rights reserved. 5 6 * … … 32 33 */ 33 34 /** @file 34 * Hub port s related functions.35 * Hub port handling. 35 36 */ 36 37 … … 40 41 #include <usb/dev/driver.h> 41 42 #include <usb/classes/hub.h> 42 #include <usb _iface.h>43 #include <usb/port.h> 43 44 44 45 typedef struct usb_hub_dev usb_hub_dev_t; … … 46 47 /** Information about single port on a hub. */ 47 48 typedef struct { 49 usb_port_t base; 50 /* Parenting hub */ 51 usb_hub_dev_t *hub; 48 52 /** Port number as reported in descriptors. */ 49 53 unsigned int port_number; 50 /** Device communication pipe. */ 51 usb_pipe_t *control_pipe; 52 /** Mutex needed not only by CV for checking port reset. */ 53 fibril_mutex_t mutex; 54 /** CV for waiting to port reset completion. */ 55 fibril_condvar_t reset_cv; 56 /** Port reset status. 57 * Guarded by @c reset_mutex. 58 */ 59 enum { 60 NO_RESET, 61 IN_RESET, 62 RESET_OK, 63 RESET_FAIL, 64 } reset_status; 65 /** Device reported to USB bus driver */ 66 bool device_attached; 54 /** Speed at the time of enabling the port */ 55 usb_speed_t speed; 67 56 } usb_hub_port_t; 68 57 69 /** Initialize hub port information. 70 * 71 * @param port Port to be initialized. 72 */ 73 static inline void usb_hub_port_init(usb_hub_port_t *port, 74 unsigned int port_number, usb_pipe_t *control_pipe) 75 { 76 assert(port); 77 port->port_number = port_number; 78 port->control_pipe = control_pipe; 79 port->reset_status = NO_RESET; 80 port->device_attached = false; 81 fibril_mutex_initialize(&port->mutex); 82 fibril_condvar_initialize(&port->reset_cv); 83 } 58 void usb_hub_port_init(usb_hub_port_t *, usb_hub_dev_t *, unsigned int); 84 59 85 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub); 86 errno_t usb_hub_port_clear_feature( 87 usb_hub_port_t *port, usb_hub_class_feature_t feature); 88 errno_t usb_hub_port_set_feature( 89 usb_hub_port_t *port, usb_hub_class_feature_t feature); 90 void usb_hub_port_reset_fail(usb_hub_port_t *port); 91 void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub); 60 void usb_hub_port_process_interrupt(usb_hub_port_t *port); 92 61 93 62 #endif -
uspace/drv/bus/usb/usbhub/status.h
rf5e5f73 rdf6ded8 38 38 39 39 /** 40 * structure holding port status and changes flags.41 * should not be accessed directly, use supplied getter/setter methods.42 *43 * For more information refer to tables 11-15 and 11-16 in44 * "Universal Serial Bus Specification Revision 1.1" pages 274 and 27745 * (290 and 293 in pdf)46 *47 */48 typedef uint32_t usb_port_status_t;49 #define USB_HUB_PORT_STATUS_CONNECTION \50 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_CONNECTION)))51 #define USB_HUB_PORT_STATUS_ENABLED \52 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_ENABLE)))53 #define USB_HUB_PORT_STATUS_SUSPEND \54 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_SUSPEND)))55 #define USB_HUB_PORT_STATUS_OC \56 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_OVER_CURRENT)))57 #define USB_HUB_PORT_STATUS_RESET \58 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_RESET)))59 #define USB_HUB_PORT_STATUS_POWER \60 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_POWER)))61 #define USB_HUB_PORT_STATUS_LOW_SPEED \62 (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_LOW_SPEED)))63 #define USB_HUB_PORT_STATUS_HIGH_SPEED \64 (uint32_usb2host(1 << 10))65 #define USB_HUB_PORT_STATUS_TEST_MODE \66 (uint32_usb2host(1 << 11))67 #define USB_HUB_PORT_INDICATOR_CONTROL \68 (uint32_usb2host(1 << 12))69 70 #define USB_HUB_PORT_C_STATUS_CONNECTION \71 (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_CONNECTION)))72 #define USB_HUB_PORT_C_STATUS_ENABLED \73 (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_ENABLE)))74 #define USB_HUB_PORT_C_STATUS_SUSPEND \75 (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_SUSPEND)))76 #define USB_HUB_PORT_C_STATUS_OC \77 (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_OVER_CURRENT)))78 #define USB_HUB_PORT_C_STATUS_RESET \79 (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_RESET)))80 81 /**82 40 * structure holding hub status and changes flags. 83 41 * … … 97 55 (uint32_usb2host(1 << (16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER))) 98 56 99 100 /** 101 * speed getter for port status 102 * 103 * @param status 104 * @return speed of usb device (for more see usb specification) 105 */ 106 static inline usb_speed_t usb_port_speed(usb_port_status_t status) 57 static inline usb_speed_t usb_port_speed(usb_speed_t hub_speed, uint32_t status) 107 58 { 108 if ((status & USB_HUB_PORT_STATUS_LOW_SPEED) != 0) 59 if (hub_speed == USB_SPEED_SUPER) 60 return USB_SPEED_SUPER; 61 if (hub_speed == USB_SPEED_HIGH 62 && (status & USB2_HUB_PORT_STATUS_HIGH_SPEED)) 63 return USB_SPEED_HIGH; 64 if ((status & USB2_HUB_PORT_STATUS_LOW_SPEED) != 0) 109 65 return USB_SPEED_LOW; 110 if ((status & USB_HUB_PORT_STATUS_HIGH_SPEED) != 0)111 return USB_SPEED_HIGH;112 66 return USB_SPEED_FULL; 113 67 } -
uspace/drv/bus/usb/usbhub/usbhub.c
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2010 Matus Dekanek 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 4 5 * All rights reserved. 5 6 * … … 51 52 #include <usb/classes/hub.h> 52 53 #include <usb/dev/poll.h> 53 #include <usb _iface.h>54 #include <usbhc_iface.h> 54 55 55 56 #include "usbhub.h" … … 58 59 #define HUB_FNC_NAME "hub" 59 60 60 /** Hub status-change endpoint description. 61 * 62 * For more information see section 11.15.1 of USB 1.1 specification. 63 */ 64 const usb_endpoint_description_t hub_status_change_endpoint_description = 65 { 66 .transfer_type = USB_TRANSFER_INTERRUPT, 67 .direction = USB_DIRECTION_IN, 68 .interface_class = USB_CLASS_HUB, 69 .interface_subclass = 0, 70 .interface_protocol = 0, 71 .flags = 0 61 #define HUB_STATUS_CHANGE_EP(protocol) { \ 62 .transfer_type = USB_TRANSFER_INTERRUPT, \ 63 .direction = USB_DIRECTION_IN, \ 64 .interface_class = USB_CLASS_HUB, \ 65 .interface_subclass = 0, \ 66 .interface_protocol = (protocol), \ 67 .flags = 0 \ 68 } 69 70 /** 71 * Hub status-change endpoint description. 72 * 73 * According to USB 2.0 specification, there are two possible arrangements of 74 * endpoints, depending on whether the hub has a MTT or not. 75 * 76 * Under any circumstances, there shall be exactly one endpoint descriptor. 77 * Though to be sure, let's map the protocol precisely. The possible 78 * combinations are: 79 * | bDeviceProtocol | bInterfaceProtocol 80 * Only single TT | 0 | 0 81 * MTT in Single-TT mode | 2 | 1 82 * MTT in MTT mode | 2 | 2 (iface alt. 1) 83 */ 84 static const usb_endpoint_description_t 85 status_change_single_tt_only = HUB_STATUS_CHANGE_EP(0), 86 status_change_mtt_available = HUB_STATUS_CHANGE_EP(1); 87 88 const usb_endpoint_description_t *usb_hub_endpoints [] = { 89 &status_change_single_tt_only, 90 &status_change_mtt_available, 72 91 }; 73 92 … … 81 100 }; 82 101 83 static errno_t usb_set_first_configuration(usb_device_t *usb_device); 84 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 85 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 86 usb_hub_status_t status); 87 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev); 88 static void usb_hub_polling_terminated_callback(usb_device_t *device, 89 bool was_error, void *data); 102 static errno_t usb_set_first_configuration(usb_device_t *); 103 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *); 104 static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t); 105 static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *); 106 static void usb_hub_global_interrupt(const usb_hub_dev_t *); 107 108 static bool usb_hub_polling_error_callback(usb_device_t *dev, 109 errno_t err_code, void *arg) 110 { 111 assert(dev); 112 assert(arg); 113 114 usb_log_error("Device %s polling error: %s", 115 usb_device_get_name(dev), str_error(err_code)); 116 117 return true; 118 } 90 119 91 120 /** … … 99 128 errno_t usb_hub_device_add(usb_device_t *usb_dev) 100 129 { 130 errno_t err; 101 131 assert(usb_dev); 132 102 133 /* Create driver soft-state structure */ 103 134 usb_hub_dev_t *hub_dev = 104 135 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 105 136 if (hub_dev == NULL) { 106 usb_log_error("Failed to create hub driver structure. \n");137 usb_log_error("Failed to create hub driver structure."); 107 138 return ENOMEM; 108 139 } 109 140 hub_dev->usb_device = usb_dev; 110 hub_dev->pending_ops_count = 0; 111 hub_dev->running = false; 112 fibril_mutex_initialize(&hub_dev->pending_ops_mutex); 113 fibril_condvar_initialize(&hub_dev->pending_ops_cv); 141 hub_dev->speed = usb_device_get_speed(usb_dev); 114 142 115 143 /* Set hub's first configuration. (There should be only one) */ 116 errno_t opResult = usb_set_first_configuration(usb_dev); 117 if (opResult != EOK) { 118 usb_log_error("Could not set hub configuration: %s\n", 119 str_error(opResult)); 120 return opResult; 144 if ((err = usb_set_first_configuration(usb_dev))) { 145 usb_log_error("Could not set hub configuration: %s", str_error(err)); 146 return err; 121 147 } 122 148 123 149 /* Get port count and create attached_devices. */ 124 opResult = usb_hub_process_hub_specific_info(hub_dev); 125 if (opResult != EOK) { 126 usb_log_error("Could process hub specific info, %s\n", 127 str_error(opResult)); 128 return opResult; 150 if ((err = usb_hub_process_hub_specific_info(hub_dev))) { 151 usb_log_error("Could process hub specific info, %s", str_error(err)); 152 return err; 153 } 154 155 const usb_endpoint_description_t *status_change = hub_dev->mtt_available 156 ? &status_change_mtt_available 157 : &status_change_single_tt_only; 158 159 usb_endpoint_mapping_t *status_change_mapping 160 = usb_device_get_mapped_ep_desc(hub_dev->usb_device, status_change); 161 if (!status_change_mapping) { 162 usb_log_error("Failed to map the Status Change Endpoint of a hub."); 163 return EIO; 129 164 } 130 165 131 166 /* Create hub control function. */ 132 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'. \n");167 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'."); 133 168 hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device, 134 169 fun_exposed, HUB_FNC_NAME); 135 170 if (hub_dev->hub_fun == NULL) { 136 usb_log_error("Failed to create hub function. \n");171 usb_log_error("Failed to create hub function."); 137 172 return ENOMEM; 138 173 } 139 174 140 175 /* Bind hub control function. */ 141 opResult = ddf_fun_bind(hub_dev->hub_fun); 142 if (opResult != EOK) { 143 usb_log_error("Failed to bind hub function: %s.\n", 144 str_error(opResult)); 145 ddf_fun_destroy(hub_dev->hub_fun); 146 return opResult; 176 if ((err = ddf_fun_bind(hub_dev->hub_fun))) { 177 usb_log_error("Failed to bind hub function: %s.", str_error(err)); 178 goto err_ddf_fun; 147 179 } 148 180 149 181 /* Start hub operation. */ 150 opResult = usb_device_auto_poll_desc(hub_dev->usb_device, 151 &hub_status_change_endpoint_description, 152 hub_port_changes_callback, ((hub_dev->port_count + 1 + 7) / 8), 153 -1, usb_hub_polling_terminated_callback, hub_dev); 154 if (opResult != EOK) { 155 /* Function is already bound */ 156 ddf_fun_unbind(hub_dev->hub_fun); 157 ddf_fun_destroy(hub_dev->hub_fun); 158 usb_log_error("Failed to create polling fibril: %s.\n", 159 str_error(opResult)); 160 return opResult; 161 } 162 hub_dev->running = true; 163 usb_log_info("Controlling hub '%s' (%p: %zu ports).\n", 182 if ((err = usb_hub_polling_init(hub_dev, status_change_mapping))) { 183 usb_log_error("Failed to start polling: %s.", str_error(err)); 184 goto err_bound; 185 } 186 187 usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).", 188 usb_str_speed(hub_dev->speed), 164 189 usb_device_get_name(hub_dev->usb_device), hub_dev, 165 190 hub_dev->port_count); 166 191 167 192 return EOK; 168 } 169 170 /** 171 * Turn off power to all ports. 172 * 173 * @param usb_dev generic usb device information 174 * @return error code 175 */ 176 errno_t usb_hub_device_remove(usb_device_t *usb_dev) 177 { 178 return ENOTSUP; 179 } 180 181 /** 182 * Remove all attached devices 183 * @param usb_dev generic usb device information 184 * @return error code 185 */ 186 errno_t usb_hub_device_gone(usb_device_t *usb_dev) 187 { 188 assert(usb_dev); 189 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 190 assert(hub); 191 unsigned tries = 10; 192 while (hub->running) { 193 async_usleep(100000); 194 if (!tries--) { 195 usb_log_error("(%p): Can't remove hub, still running.", 196 hub); 197 return EBUSY; 198 } 199 } 200 201 assert(!hub->running); 193 194 err_bound: 195 ddf_fun_unbind(hub_dev->hub_fun); 196 err_ddf_fun: 197 ddf_fun_destroy(hub_dev->hub_fun); 198 return err; 199 } 200 201 static errno_t usb_hub_cleanup(usb_hub_dev_t *hub) 202 { 203 free(hub->polling.buffer); 204 usb_polling_fini(&hub->polling); 202 205 203 206 for (size_t port = 0; port < hub->port_count; ++port) { 204 const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub); 205 if (ret != EOK) 206 return ret; 207 usb_port_fini(&hub->ports[port].base); 207 208 } 208 209 free(hub->ports); … … 217 218 218 219 usb_log_info("(%p) USB hub driver stopped and cleaned.", hub); 220 221 /* Device data (usb_hub_dev_t) will be freed by usbdev. */ 219 222 return EOK; 220 223 } 221 224 222 /** Callback for polling hub for changes. 225 /** 226 * Turn off power to all ports. 227 * 228 * @param usb_dev generic usb device information 229 * @return error code 230 */ 231 errno_t usb_hub_device_remove(usb_device_t *usb_dev) 232 { 233 assert(usb_dev); 234 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 235 assert(hub); 236 237 usb_log_info("(%p) USB hub removed, joining polling fibril.", hub); 238 239 /* Join polling fibril (ignoring error code). */ 240 usb_polling_join(&hub->polling); 241 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 242 243 /* Destroy hub. */ 244 return usb_hub_cleanup(hub); 245 } 246 247 /** 248 * Remove all attached devices 249 * @param usb_dev generic usb device information 250 * @return error code 251 */ 252 errno_t usb_hub_device_gone(usb_device_t *usb_dev) 253 { 254 assert(usb_dev); 255 usb_hub_dev_t *hub = usb_device_data_get(usb_dev); 256 assert(hub); 257 258 usb_log_info("(%p) USB hub gone, joining polling fibril.", hub); 259 260 /* Join polling fibril (ignoring error code). */ 261 usb_polling_join(&hub->polling); 262 usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub); 263 264 /* Destroy hub. */ 265 return usb_hub_cleanup(hub); 266 } 267 268 /** 269 * Initialize and start the polling of the Status Change Endpoint. 270 * 271 * @param mapping The mapping of Status Change Endpoint 272 */ 273 static errno_t usb_hub_polling_init(usb_hub_dev_t *hub_dev, 274 usb_endpoint_mapping_t *mapping) 275 { 276 errno_t err; 277 usb_polling_t *polling = &hub_dev->polling; 278 279 if ((err = usb_polling_init(polling))) 280 return err; 281 282 polling->device = hub_dev->usb_device; 283 polling->ep_mapping = mapping; 284 polling->request_size = ((hub_dev->port_count + 1 + 7) / 8); 285 polling->buffer = malloc(polling->request_size); 286 polling->on_data = hub_port_changes_callback; 287 polling->on_error = usb_hub_polling_error_callback; 288 polling->arg = hub_dev; 289 290 if ((err = usb_polling_start(polling))) { 291 /* Polling is already initialized. */ 292 free(polling->buffer); 293 usb_polling_fini(polling); 294 return err; 295 } 296 297 return EOK; 298 } 299 300 /** 301 * Callback for polling hub for changes. 223 302 * 224 303 * @param dev Device where the change occured. … … 245 324 } 246 325 247 /* N + 1bit indicates change on port N */326 /* Nth bit indicates change on port N */ 248 327 for (size_t port = 0; port < hub->port_count; ++port) { 249 328 const size_t bit = port + 1; 250 329 const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1; 251 330 if (change) { 252 usb_hub_port_process_interrupt(&hub->ports[port] , hub);331 usb_hub_port_process_interrupt(&hub->ports[port]); 253 332 } 254 333 } 255 334 return true; 335 } 336 337 static void usb_hub_power_ports(usb_hub_dev_t *hub_dev) 338 { 339 if (!hub_dev->power_switched) { 340 usb_log_info("(%p): Power switching not supported, " 341 "ports always powered.", hub_dev); 342 return; 343 } 344 345 usb_log_info("(%p): Hub port power switching enabled (%s).", hub_dev, 346 hub_dev->per_port_power ? "per port" : "ganged"); 347 348 for (unsigned int port = 0; port < hub_dev->port_count; ++port) { 349 usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1); 350 const errno_t ret = usb_hub_set_port_feature(hub_dev, port + 1, 351 USB_HUB_FEATURE_PORT_POWER); 352 353 if (ret != EOK) { 354 usb_log_error("(%p-%u): Cannot power on port: %s.", 355 hub_dev, hub_dev->ports[port].port_number, 356 str_error(ret)); 357 /* Continue to try at least other ports */ 358 } 359 } 256 360 } 257 361 … … 270 374 assert(hub_dev); 271 375 376 usb_log_debug("(%p): Retrieving descriptor.", hub_dev); 377 usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device); 378 379 usb_descriptor_type_t desc_type = hub_dev->speed >= USB_SPEED_SUPER 380 ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB; 381 272 382 /* Get hub descriptor. */ 273 usb_log_debug("(%p): Retrieving descriptor.", hub_dev);274 usb_pipe_t *control_pipe =275 usb_device_get_default_pipe(hub_dev->usb_device);276 277 383 usb_hub_descriptor_header_t descriptor; 278 384 size_t received_size; 279 385 errno_t opResult = usb_request_get_descriptor(control_pipe, 280 386 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 281 USB_DESCTYPE_HUB, 0, 0, &descriptor,387 desc_type, 0, 0, &descriptor, 282 388 sizeof(usb_hub_descriptor_header_t), &received_size); 283 389 if (opResult != EOK) { 284 usb_log_error("(%p): Failed to receive hub descriptor: %s. \n",390 usb_log_error("(%p): Failed to receive hub descriptor: %s.", 285 391 hub_dev, str_error(opResult)); 286 392 return opResult; 287 393 } 288 394 289 usb_log_debug("(%p): Setting port count to %d. \n", hub_dev,395 usb_log_debug("(%p): Setting port count to %d.", hub_dev, 290 396 descriptor.port_count); 291 397 hub_dev->port_count = descriptor.port_count; 398 hub_dev->control_pipe = control_pipe; 399 400 usb_log_debug("(%p): Setting hub depth to %u.", hub_dev, 401 usb_device_get_depth(hub_dev->usb_device)); 402 if ((opResult = usb_hub_set_depth(hub_dev))) { 403 usb_log_error("(%p): Failed to set hub depth: %s.", 404 hub_dev, str_error(opResult)); 405 return opResult; 406 } 292 407 293 408 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); … … 297 412 298 413 for (size_t port = 0; port < hub_dev->port_count; ++port) { 299 usb_hub_port_init( 300 &hub_dev->ports[port], port + 1, control_pipe); 414 usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1); 301 415 } 302 416 … … 306 420 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 307 421 308 if (!hub_dev->power_switched) { 309 usb_log_info("(%p): Power switching not supported, " 310 "ports always powered.", hub_dev); 311 return EOK; 312 } 313 314 usb_log_info("(%p): Hub port power switching enabled (%s).\n", hub_dev, 315 hub_dev->per_port_power ? "per port" : "ganged"); 316 317 for (unsigned int port = 0; port < hub_dev->port_count; ++port) { 318 usb_log_debug("(%p): Powering port %u.", hub_dev, port); 319 const errno_t ret = usb_hub_port_set_feature( 320 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 321 322 if (ret != EOK) { 323 usb_log_error("(%p-%u): Cannot power on port: %s.\n", 324 hub_dev, hub_dev->ports[port].port_number, 325 str_error(ret)); 326 } else { 327 if (!hub_dev->per_port_power) { 328 usb_log_debug("(%p) Ganged power switching, " 329 "one port is enough.", hub_dev); 330 break; 331 } 332 } 333 } 422 const uint8_t protocol = usb_device_descriptors(hub_dev->usb_device) 423 ->device.device_protocol; 424 hub_dev->mtt_available = (protocol == 2); 425 426 usb_hub_power_ports(hub_dev); 427 334 428 return EOK; 335 429 } … … 349 443 const size_t configuration_count = 350 444 usb_device_descriptors(usb_device)->device.configuration_count; 351 usb_log_debug("Hub has %zu configurations. \n", configuration_count);445 usb_log_debug("Hub has %zu configurations.", configuration_count); 352 446 353 447 if (configuration_count < 1) { 354 usb_log_error("There are no configurations available \n");448 usb_log_error("There are no configurations available"); 355 449 return EINVAL; 356 450 } … … 369 463 /* Set configuration. Use the configuration that was in 370 464 * usb_device->descriptors.configuration i.e. The first one. */ 371 consterrno_t opResult = usb_request_set_configuration(465 errno_t opResult = usb_request_set_configuration( 372 466 usb_device_get_default_pipe(usb_device), 373 467 config_descriptor->configuration_number); 374 468 if (opResult != EOK) { 375 usb_log_error("Failed to set hub configuration: %s. \n",469 usb_log_error("Failed to set hub configuration: %s.", 376 470 str_error(opResult)); 377 471 } else { 378 usb_log_debug("\tUsed configuration %d \n",472 usb_log_debug("\tUsed configuration %d", 379 473 config_descriptor->configuration_number); 380 474 } 475 381 476 return opResult; 382 477 } … … 406 501 /* Over-current condition is gone, it is safe to turn the ports on. */ 407 502 for (size_t port = 0; port < hub_dev->port_count; ++port) { 408 const errno_t ret = usb_hub_ port_set_feature(409 &hub_dev->ports[port],USB_HUB_FEATURE_PORT_POWER);503 const errno_t ret = usb_hub_set_port_feature(hub_dev, port, 504 USB_HUB_FEATURE_PORT_POWER); 410 505 if (ret != EOK) { 411 506 usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot" … … 417 512 } 418 513 } 419 514 } 515 516 /** 517 * Set feature on the real hub port. 518 * 519 * @param port Port structure. 520 * @param feature Feature selector. 521 */ 522 errno_t usb_hub_set_depth(const usb_hub_dev_t *hub) 523 { 524 assert(hub); 525 526 /* Slower hubs do not care about depth */ 527 if (hub->speed < USB_SPEED_SUPER) 528 return EOK; 529 530 const usb_device_request_setup_packet_t set_request = { 531 .request_type = USB_HUB_REQ_TYPE_SET_HUB_DEPTH, 532 .request = USB_HUB_REQUEST_SET_HUB_DEPTH, 533 .value = uint16_host2usb(usb_device_get_depth(hub->usb_device) - 1), 534 .index = 0, 535 .length = 0, 536 }; 537 return usb_pipe_control_write(hub->control_pipe, &set_request, 538 sizeof(set_request), NULL, 0); 539 } 540 541 /** 542 * Set feature on the real hub port. 543 * 544 * @param port Port structure. 545 * @param feature Feature selector. 546 */ 547 errno_t usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number, 548 usb_hub_class_feature_t feature) 549 { 550 assert(hub); 551 const usb_device_request_setup_packet_t clear_request = { 552 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 553 .request = USB_DEVREQ_SET_FEATURE, 554 .index = uint16_host2usb(port_number), 555 .value = feature, 556 .length = 0, 557 }; 558 return usb_pipe_control_write(hub->control_pipe, &clear_request, 559 sizeof(clear_request), NULL, 0); 560 } 561 562 /** 563 * Clear feature on the real hub port. 564 * 565 * @param port Port structure. 566 * @param feature Feature selector. 567 */ 568 errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number, 569 usb_hub_class_feature_t feature) 570 { 571 assert(hub); 572 const usb_device_request_setup_packet_t clear_request = { 573 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE, 574 .request = USB_DEVREQ_CLEAR_FEATURE, 575 .value = feature, 576 .index = uint16_host2usb(port_number), 577 .length = 0, 578 }; 579 return usb_pipe_control_write(hub->control_pipe, 580 &clear_request, sizeof(clear_request), NULL, 0); 581 } 582 583 /** 584 * Retrieve port status. 585 * 586 * @param[in] port Port structure 587 * @param[out] status Where to store the port status. 588 * @return Error code. 589 */ 590 errno_t usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number, 591 usb_port_status_t *status) 592 { 593 assert(hub); 594 assert(status); 595 596 /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6 597 * Generic GET_STATUS request cannot be used because of the difference 598 * in status data size (2B vs. 4B)*/ 599 const usb_device_request_setup_packet_t request = { 600 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS, 601 .request = USB_HUB_REQUEST_GET_STATUS, 602 .value = 0, 603 .index = uint16_host2usb(port_number), 604 .length = sizeof(usb_port_status_t), 605 }; 606 size_t recv_size; 607 608 uint32_t buffer; 609 const errno_t rc = usb_pipe_control_read(hub->control_pipe, 610 &request, sizeof(usb_device_request_setup_packet_t), 611 &buffer, sizeof(buffer), &recv_size); 612 if (rc != EOK) 613 return rc; 614 615 if (recv_size != sizeof(*status)) 616 return ELIMIT; 617 618 *status = uint32_usb2host(buffer); 619 return EOK; 420 620 } 421 621 … … 492 692 493 693 /** 494 * callback called from hub polling fibril when the fibril terminates 495 * 496 * Does not perform cleanup, just marks the hub as not running. 497 * @param device usb device afected 498 * @param was_error indicates that the fibril is stoped due to an error 499 * @param data pointer to usb_hub_dev_t structure 500 */ 501 static void usb_hub_polling_terminated_callback(usb_device_t *device, 502 bool was_error, void *data) 503 { 504 usb_hub_dev_t *hub = data; 694 * Instead of just sleeping, we may as well sleep on a condition variable. 695 * This has the advantage that we may instantly wait other hub from the polling 696 * sleep, mitigating the delay of polling while still being synchronized with 697 * other devices in need of the default address (there shall not be any). 698 */ 699 static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv); 700 static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard); 701 702 /** 703 * Reserve a default address for a port across all other devices connected to 704 * the bus. We aggregate requests for ports to minimize delays between 705 * connecting multiple devices from one hub - which happens e.g. when the hub 706 * is connected with already attached devices. 707 */ 708 errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch, 709 usb_port_t *port) 710 { 505 711 assert(hub); 506 507 fibril_mutex_lock(&hub->pending_ops_mutex); 508 509 /* The device is dead. However there might be some pending operations 510 * that we need to wait for. 511 * One of them is device adding in progress. 512 * The respective fibril is probably waiting for status change 513 * in port reset (port enable) callback. 514 * Such change would never come (otherwise we would not be here). 515 * Thus, we would flush all pending port resets. 712 assert(exch); 713 assert(port); 714 assert(fibril_mutex_is_locked(&port->guard)); 715 716 errno_t err = usbhc_reserve_default_address(exch); 717 /* 718 * EINVAL signalls that its our hub (hopefully different port) that has 719 * this address reserved 516 720 */ 517 if (hub->pending_ops_count > 0) { 518 for (size_t port = 0; port < hub->port_count; ++port) { 519 usb_hub_port_reset_fail(&hub->ports[port]); 520 } 521 } 522 /* And now wait for them. */ 523 while (hub->pending_ops_count > 0) { 524 fibril_condvar_wait(&hub->pending_ops_cv, 525 &hub->pending_ops_mutex); 526 } 527 fibril_mutex_unlock(&hub->pending_ops_mutex); 528 hub->running = false; 529 } 721 while (err == EAGAIN || err == EINVAL) { 722 /* Drop the port guard, we're going to wait */ 723 fibril_mutex_unlock(&port->guard); 724 725 /* This sleeping might be disturbed by other hub */ 726 fibril_mutex_lock(&global_hub_default_address_guard); 727 fibril_condvar_wait_timeout(&global_hub_default_address_cv, 728 &global_hub_default_address_guard, 2000000); 729 fibril_mutex_unlock(&global_hub_default_address_guard); 730 731 fibril_mutex_lock(&port->guard); 732 err = usbhc_reserve_default_address(exch); 733 } 734 735 if (err) 736 return err; 737 738 /* 739 * As we dropped the port guard, we need to check whether the device is 740 * still connected. If the release fails, we still hold the default 741 * address -- but then there is probably a bigger problem with the HC 742 * anyway. 743 */ 744 if (port->state != PORT_CONNECTING) { 745 err = usb_hub_release_default_address(hub, exch); 746 return err ? err : EINTR; 747 } 748 749 return EOK; 750 } 751 752 /** 753 * Release the default address from a port. 754 */ 755 errno_t usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch) 756 { 757 const errno_t ret = usbhc_release_default_address(exch); 758 759 /* 760 * This is an optimistic optimization - it may wake 761 * one hub from polling sleep instantly. 762 */ 763 fibril_condvar_signal(&global_hub_default_address_cv); 764 765 return ret; 766 } 767 530 768 /** 531 769 * @} -
uspace/drv/bus/usb/usbhub/usbhub.h
rf5e5f73 rdf6ded8 2 2 * Copyright (c) 2010 Vojtech Horky 3 3 * Copyright (c) 2011 Vojtech Horky 4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek 4 5 * All rights reserved. 5 6 * … … 39 40 40 41 #include <ddf/driver.h> 42 #include <fibril_synch.h> 41 43 42 44 #include <usb/classes/hub.h> … … 44 46 #include <usb/dev/pipes.h> 45 47 #include <usb/dev/driver.h> 46 47 #include <fibril_synch.h> 48 #include <usb/dev/poll.h> 48 49 49 50 #define NAME "usbhub" 50 51 51 52 #include "port.h" 53 #include "status.h" 52 54 53 55 /** Information about attached hub. */ … … 57 59 /** Port structures, one for each port */ 58 60 usb_hub_port_t *ports; 61 /** Speed of the hub */ 62 usb_speed_t speed; 59 63 /** Generic usb device data*/ 60 64 usb_device_t *usb_device; 61 62 /** Number of pending operations on the mutex to prevent shooting 63 * ourselves in the foot. 64 * When the hub is disconnected but we are in the middle of some 65 * operation, we cannot destroy this structure right away because 66 * the pending operation might use it. 67 */ 68 size_t pending_ops_count; 69 /** Guard for pending_ops_count. */ 70 fibril_mutex_t pending_ops_mutex; 71 /** Condition variable for pending_ops_count. */ 72 fibril_condvar_t pending_ops_cv; 65 /** Data polling handle. */ 66 usb_polling_t polling; 73 67 /** Pointer to usbhub function. */ 74 68 ddf_fun_t *hub_fun; 75 /** Status indicator*/76 bool running;69 /** Device communication pipe. */ 70 usb_pipe_t *control_pipe; 77 71 /** Hub supports port power switching. */ 78 72 bool power_switched; 79 73 /** Each port is switched individually. */ 80 74 bool per_port_power; 75 /** Whether MTT is available */ 76 bool mtt_available; 81 77 }; 82 78 83 extern const usb_endpoint_description_t hub_status_change_endpoint_description;79 extern const usb_endpoint_description_t *usb_hub_endpoints []; 84 80 85 e xtern errno_t usb_hub_device_add(usb_device_t *);86 e xtern errno_t usb_hub_device_remove(usb_device_t *);87 e xtern errno_t usb_hub_device_gone(usb_device_t *);81 errno_t usb_hub_device_add(usb_device_t *); 82 errno_t usb_hub_device_remove(usb_device_t *); 83 errno_t usb_hub_device_gone(usb_device_t *); 88 84 89 extern bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, 90 void *); 85 errno_t usb_hub_set_depth(const usb_hub_dev_t *); 86 errno_t usb_hub_get_port_status(const usb_hub_dev_t *, size_t, 87 usb_port_status_t *); 88 errno_t usb_hub_set_port_feature(const usb_hub_dev_t *, size_t, 89 usb_hub_class_feature_t); 90 errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *, size_t, 91 usb_hub_class_feature_t); 92 93 bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *); 94 95 errno_t usb_hub_reserve_default_address(usb_hub_dev_t *, async_exch_t *, 96 usb_port_t *); 97 errno_t usb_hub_release_default_address(usb_hub_dev_t *, async_exch_t *); 91 98 92 99 #endif -
uspace/drv/bus/usb/usbmid/dump.c
rf5e5f73 rdf6ded8 54 54 const int type = data[1]; 55 55 if (type == USB_DESCTYPE_INTERFACE) { 56 usb_standard_interface_descriptor_t *descriptor 57 =(usb_standard_interface_descriptor_t *) data;58 usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x). \n",56 usb_standard_interface_descriptor_t *descriptor = 57 (usb_standard_interface_descriptor_t *) data; 58 usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x).", 59 59 usb_str_class(descriptor->interface_class), 60 60 (int) descriptor->interface_class, -
uspace/drv/bus/usb/usbmid/explore.c
rf5e5f73 rdf6ded8 106 106 107 107 108 usb_log_info("Creating child for interface %d (%s). \n",108 usb_log_info("Creating child for interface %d (%s).", 109 109 interface->interface_number, 110 110 usb_str_class(interface->interface_class)); … … 144 144 dev_class, usb_str_class(dev_class), 145 145 USB_CLASS_USE_INTERFACE); 146 usb_log_error("Not a multi-interface device, refusing. \n");146 usb_log_error("Not a multi-interface device, refusing."); 147 147 return ENOTSUP; 148 148 } … … 160 160 config_descriptor->configuration_number); 161 161 if (rc != EOK) { 162 usb_log_error("Failed to set device configuration: %s. \n",162 usb_log_error("Failed to set device configuration: %s.", 163 163 str_error(rc)); 164 164 return rc; … … 168 168 usb_mid_t *usb_mid = usb_device_data_alloc(dev, sizeof(usb_mid_t)); 169 169 if (!usb_mid) { 170 usb_log_error("Failed to create USB MID structure. \n");170 usb_log_error("Failed to create USB MID structure."); 171 171 return ENOMEM; 172 172 } … … 175 175 usb_mid->ctl_fun = usb_device_ddf_fun_create(dev, fun_exposed, "ctl"); 176 176 if (usb_mid->ctl_fun == NULL) { 177 usb_log_error("Failed to create control function. \n");177 usb_log_error("Failed to create control function."); 178 178 return ENOMEM; 179 179 } … … 182 182 rc = ddf_fun_bind(usb_mid->ctl_fun); 183 183 if (rc != EOK) { 184 usb_log_error("Failed to bind control function: %s. \n",184 usb_log_error("Failed to bind control function: %s.", 185 185 str_error(rc)); 186 186 ddf_fun_destroy(usb_mid->ctl_fun); -
uspace/drv/bus/usb/usbmid/main.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Petr Manek, Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 51 52 static errno_t usbmid_device_add(usb_device_t *dev) 52 53 { 53 usb_log_info("Taking care of new MID `%s'. \n", usb_device_get_name(dev));54 usb_log_info("Taking care of new MID `%s'.", usb_device_get_name(dev)); 54 55 55 56 return usbmid_explore_device(dev); 57 } 58 59 static errno_t destroy_interfaces(usb_mid_t *usb_mid) 60 { 61 errno_t ret = EOK; 62 63 while (!list_empty(&usb_mid->interface_list)) { 64 link_t *item = list_first(&usb_mid->interface_list); 65 list_remove(item); 66 67 usbmid_interface_t *iface = usbmid_interface_from_link(item); 68 69 const errno_t pret = usbmid_interface_destroy(iface); 70 if (pret != EOK) { 71 usb_log_error("Failed to remove child `%s': %s", 72 ddf_fun_get_name(iface->fun), str_error(pret)); 73 ret = pret; 74 } 75 } 76 77 return ret; 56 78 } 57 79 … … 70 92 errno_t ret = ddf_fun_unbind(usb_mid->ctl_fun); 71 93 if (ret != EOK) { 72 usb_log_error("Failed to unbind USB MID ctl function: %s. \n",94 usb_log_error("Failed to unbind USB MID ctl function: %s.", 73 95 str_error(ret)); 74 96 return ret; … … 77 99 78 100 /* Remove all children */ 79 while (!list_empty(&usb_mid->interface_list)) { 80 link_t *item = list_first(&usb_mid->interface_list); 81 list_remove(item); 82 83 usbmid_interface_t *iface = usbmid_interface_from_link(item); 84 85 usb_log_info("Removing child `%s'.\n", 101 list_foreach(usb_mid->interface_list, link, usbmid_interface_t, iface) { 102 usb_log_info("Removing child `%s'.", 86 103 ddf_fun_get_name(iface->fun)); 87 104 88 /* Tell the child to go off -line. */105 /* Tell the child to go offline. */ 89 106 errno_t pret = ddf_fun_offline(iface->fun); 90 107 if (pret != EOK) { 91 usb_log_warning("Failed to turn off child `%s': %s \n",108 usb_log_warning("Failed to turn off child `%s': %s", 92 109 ddf_fun_get_name(iface->fun), str_error(pret)); 93 ret = pret;94 }95 96 /* Now remove the child. */97 pret = usbmid_interface_destroy(iface);98 if (pret != EOK) {99 usb_log_error("Failed to destroy child `%s': %s\n",100 ddf_fun_get_name(iface->fun), str_error(pret));101 ret = pret;102 110 } 103 111 } 104 return ret; 112 113 return destroy_interfaces(usb_mid); 105 114 } 106 115 … … 116 125 assert(usb_mid); 117 126 118 usb_log_info("USB MID gone: `%s'. \n", usb_device_get_name(dev));127 usb_log_info("USB MID gone: `%s'.", usb_device_get_name(dev)); 119 128 120 129 /* Remove ctl function */ 121 130 errno_t ret = ddf_fun_unbind(usb_mid->ctl_fun); 122 131 if (ret != EOK) { 123 usb_log_error("Failed to unbind USB MID ctl function: %s. \n",132 usb_log_error("Failed to unbind USB MID ctl function: %s.", 124 133 str_error(ret)); 125 134 return ret; … … 127 136 ddf_fun_destroy(usb_mid->ctl_fun); 128 137 129 /* Now remove all other functions */ 130 while (!list_empty(&usb_mid->interface_list)) { 131 link_t *item = list_first(&usb_mid->interface_list); 132 list_remove(item); 138 /* Destroy children and tell their drivers they are gone. */ 139 return destroy_interfaces(usb_mid); 140 } 133 141 134 usbmid_interface_t *iface = usbmid_interface_from_link(item); 142 static errno_t usbmid_function_online(ddf_fun_t *fun) 143 { 144 usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun)); 145 usb_mid_t *usb_mid = usb_device_data_get(usb_dev); 146 if (fun == usb_mid->ctl_fun) 147 return ENOTSUP; 135 148 136 usb_log_info("Child `%s' is gone.\n",137 ddf_fun_get_name(iface->fun)); 149 return ddf_fun_online(fun); 150 } 138 151 139 const errno_t pret = usbmid_interface_destroy(iface); 140 if (pret != EOK){141 usb_log_error("Failed to remove child `%s': %s\n",142 ddf_fun_get_name(iface->fun), str_error(pret));143 ret = pret;144 }145 } 146 return ret;152 static errno_t usbmid_function_offline(ddf_fun_t *fun) 153 { 154 usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun)); 155 usb_mid_t *usb_mid = usb_device_data_get(usb_dev); 156 if (fun == usb_mid->ctl_fun) 157 return ENOTSUP; 158 159 return ddf_fun_offline(fun); 147 160 } 148 161 … … 150 163 static const usb_driver_ops_t mid_driver_ops = { 151 164 .device_add = usbmid_device_add, 152 .device_rem = usbmid_device_remove,165 .device_remove = usbmid_device_remove, 153 166 .device_gone = usbmid_device_gone, 167 .function_online = usbmid_function_online, 168 .function_offline = usbmid_function_offline 154 169 }; 155 170 -
uspace/drv/bus/usb/usbmid/usbmid.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 45 46 #include "usbmid.h" 46 47 47 /** Get USB device handle by calling the parent usb_device_t. 48 /** 49 * Get USB device description by calling HC and altering the interface field. 48 50 * 49 51 * @param[in] fun Device function the operation is running on. 50 * @param[out] handle Device handle.52 * @param[out] desc Device descriptor. 51 53 * @return Error code. 52 54 */ 53 static errno_t usb_iface_device_handle(ddf_fun_t *fun, devman_handle_t *handle) 54 { 55 assert(fun); 56 assert(handle); 57 usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun)); 58 *handle = usb_device_get_devman_handle(usb_dev); 59 return EOK; 60 } 61 62 /** Callback for DDF USB get interface. */ 63 static errno_t usb_iface_iface_no(ddf_fun_t *fun, int *iface_no) 55 static errno_t usb_iface_description(ddf_fun_t *fun, usb_device_desc_t *desc) 64 56 { 65 57 usbmid_interface_t *iface = ddf_fun_data_get(fun); 66 58 assert(iface); 59 usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun)); 60 assert(usb_dev); 67 61 68 if (iface_no) 69 *iface_no = iface->interface_no; 62 async_exch_t *exch = usb_device_bus_exchange_begin(usb_dev); 63 if (!exch) 64 return EPARTY; 65 66 usb_device_desc_t tmp_desc; 67 const errno_t ret = usb_get_my_description(exch, &tmp_desc); 68 69 if (ret == EOK && desc) { 70 *desc = tmp_desc; 71 desc->iface = iface->interface_no; 72 } 73 74 usb_device_bus_exchange_end(exch); 70 75 71 76 return EOK; … … 74 79 /** DDF interface of the child - USB functions. */ 75 80 static usb_iface_t child_usb_iface = { 76 .get_my_device_handle = usb_iface_device_handle, 77 .get_my_interface = usb_iface_iface_no, 81 .get_my_description = usb_iface_description, 78 82 }; 79 83 … … 117 121 * class name something humanly understandable. 118 122 */ 119 int ret = asprintf(&child_name, "%s%hhu",123 errno_t ret = asprintf(&child_name, "%s%hhu", 120 124 usb_str_class(interface_descriptor->interface_class), 121 125 interface_descriptor->interface_number); -
uspace/drv/bus/usb/vhc/conndev.c
rf5e5f73 rdf6ded8 113 113 receive_device_name(callback); 114 114 115 usb_log_info("New virtual device `%s' (id: %" PRIxn "). \n",115 usb_log_info("New virtual device `%s' (id: %" PRIxn ").", 116 116 plugged_device_name, plugged_device_handle); 117 117 } else … … 130 130 131 131 if (plugged_device_handle != 0) { 132 usb_log_info("Virtual device `%s' disconnected (id: %" PRIxn "). \n",132 usb_log_info("Virtual device `%s' disconnected (id: %" PRIxn ").", 133 133 plugged_device_name, plugged_device_handle); 134 134 vhc_virtdev_unplug(vhc, plugged_device_handle); -
uspace/drv/bus/usb/vhc/hub/hub.c
rf5e5f73 rdf6ded8 68 68 69 69 /** Convert hub port state to a char. */ 70 char hub_port_state_to_char(hub_port_state_t state) { 70 char hub_port_state_to_char(hub_port_state_t state) 71 { 71 72 switch (state) { 72 case HUB_PORT_STATE_NOT_CONFIGURED:73 return '-';74 case HUB_PORT_STATE_POWERED_OFF:75 return 'O';76 case HUB_PORT_STATE_DISCONNECTED:77 return 'X';78 case HUB_PORT_STATE_DISABLED:79 return 'D';80 case HUB_PORT_STATE_RESETTING:81 return 'R';82 case HUB_PORT_STATE_ENABLED:83 return 'E';84 case HUB_PORT_STATE_SUSPENDED:85 return 'S';86 case HUB_PORT_STATE_RESUMING:87 return 'F';88 default:89 return '?';73 case HUB_PORT_STATE_NOT_CONFIGURED: 74 return '-'; 75 case HUB_PORT_STATE_POWERED_OFF: 76 return 'O'; 77 case HUB_PORT_STATE_DISCONNECTED: 78 return 'X'; 79 case HUB_PORT_STATE_DISABLED: 80 return 'D'; 81 case HUB_PORT_STATE_RESETTING: 82 return 'R'; 83 case HUB_PORT_STATE_ENABLED: 84 return 'E'; 85 case HUB_PORT_STATE_SUSPENDED: 86 return 'S'; 87 case HUB_PORT_STATE_RESUMING: 88 return 'F'; 89 default: 90 return '?'; 90 91 } 91 92 } … … 231 232 } 232 233 233 usb_log_debug("Setting port %zu to state %d. \n", port_index, state);234 usb_log_debug("Setting port %zu to state %d.", port_index, state); 234 235 235 236 switch (state) { 236 case HUB_PORT_STATE_POWERED_OFF:237 clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);238 clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);239 clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);240 break;241 case HUB_PORT_STATE_RESUMING:242 port->state = state;243 set_port_state_delayed(hub, port_index,244 10, state, HUB_PORT_STATE_ENABLED);245 break;246 case HUB_PORT_STATE_RESETTING:247 port->state = state;248 set_port_state_delayed(hub, port_index,249 10, state, HUB_PORT_STATE_ENABLED);250 break;251 case HUB_PORT_STATE_ENABLED:252 if (port->state == HUB_PORT_STATE_RESETTING) {253 set_port_status_change(port, HUB_STATUS_C_PORT_RESET);254 }255 break;256 default:257 break;237 case HUB_PORT_STATE_POWERED_OFF: 238 clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION); 239 clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE); 240 clear_port_status_change(port, HUB_STATUS_C_PORT_RESET); 241 break; 242 case HUB_PORT_STATE_RESUMING: 243 port->state = state; 244 set_port_state_delayed(hub, port_index, 245 10, state, HUB_PORT_STATE_ENABLED); 246 break; 247 case HUB_PORT_STATE_RESETTING: 248 port->state = state; 249 set_port_state_delayed(hub, port_index, 250 10, state, HUB_PORT_STATE_ENABLED); 251 break; 252 case HUB_PORT_STATE_ENABLED: 253 if (port->state == HUB_PORT_STATE_RESETTING) { 254 set_port_status_change(port, HUB_STATUS_C_PORT_RESET); 255 } 256 break; 257 default: 258 break; 258 259 } 259 260 … … 336 337 } 337 338 338 uint32_t status; 339 status = MAKE_BYTE( 339 uint32_t status = MAKE_BYTE( 340 340 /* Current connect status. */ 341 341 port->connected_device == NULL ? 0 : 1, … … 344 344 /* Suspend. */ 345 345 (port->state == HUB_PORT_STATE_SUSPENDED) 346 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,346 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0, 347 347 /* Over-current. */ 348 348 0, … … 350 350 port->state == HUB_PORT_STATE_RESETTING ? 1 : 0, 351 351 /* Reserved. */ 352 0, 0, 0) 353 354 | (MAKE_BYTE(352 0, 0, 0); 353 354 status |= MAKE_BYTE( 355 355 /* Port power. */ 356 356 port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1, … … 359 359 /* Reserved. */ 360 360 0, 0, 0, 0, 0, 0 361 ) )<< 8;361 ) << 8; 362 362 363 363 status |= (port->status_change << 16); … … 423 423 uint16_t old_value = port->status_change; 424 424 port->status_change |= change; 425 usb_log_debug("Changing status change on %zu: %04x => %04x \n",425 usb_log_debug("Changing status change on %zu: %04x => %04x", 426 426 port->index, 427 427 (unsigned int) old_value, (unsigned int) port->status_change); … … 463 463 static errno_t set_port_state_delayed_fibril(void *arg) 464 464 { 465 struct delay_port_state_change *change 466 =(struct delay_port_state_change *) arg;465 struct delay_port_state_change *change = 466 (struct delay_port_state_change *) arg; 467 467 468 468 async_usleep(change->delay); … … 500 500 hub_port_state_t old_state, hub_port_state_t new_state) 501 501 { 502 struct delay_port_state_change *change 503 =malloc(sizeof(struct delay_port_state_change));502 struct delay_port_state_change *change = 503 malloc(sizeof(struct delay_port_state_change)); 504 504 505 505 change->hub = hub; … … 510 510 fid_t fibril = fibril_create(set_port_state_delayed_fibril, change); 511 511 if (fibril == 0) { 512 printf("Failed to create fibril\n");512 usb_log_error("Failed to create fibril."); 513 513 free(change); 514 514 return; -
uspace/drv/bus/usb/vhc/hub/virthubops.c
rf5e5f73 rdf6ded8 137 137 138 138 switch (feature) { 139 case USB _HUB_FEATURE_PORT_ENABLE:139 case USB2_HUB_FEATURE_PORT_ENABLE: 140 140 if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED) 141 141 && (port_state != HUB_PORT_STATE_POWERED_OFF)) { … … 145 145 break; 146 146 147 case USB _HUB_FEATURE_PORT_SUSPEND:147 case USB2_HUB_FEATURE_PORT_SUSPEND: 148 148 if (port_state != HUB_PORT_STATE_SUSPENDED) { 149 149 rc = EOK; … … 166 166 break; 167 167 168 case USB _HUB_FEATURE_C_PORT_ENABLE:168 case USB2_HUB_FEATURE_C_PORT_ENABLE: 169 169 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE); 170 170 rc = EOK; 171 171 break; 172 172 173 case USB _HUB_FEATURE_C_PORT_SUSPEND:173 case USB2_HUB_FEATURE_C_PORT_SUSPEND: 174 174 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND); 175 175 rc = EOK; … … 317 317 break; 318 318 319 case USB _HUB_FEATURE_PORT_SUSPEND:319 case USB2_HUB_FEATURE_PORT_SUSPEND: 320 320 if (port_state == HUB_PORT_STATE_ENABLED) { 321 321 hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED); -
uspace/drv/bus/usb/vhc/main.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 40 41 41 42 #include <usb/host/ddf_helpers.h> 43 #include <usb/host/utility.h> 42 44 43 45 #include <usb/debug.h> … … 69 71 return ret; 70 72 } 71 vhc_init(vhc);72 73 return EOK; 73 74 } 74 75 75 hcd_ops_t vhc_hc_ops = {76 .schedule = vhc_schedule,77 };78 79 76 static errno_t vhc_dev_add(ddf_dev_t *dev) 80 77 { 78 /* Initialize generic structures */ 79 errno_t ret = hcd_ddf_setup_hc(dev, sizeof(vhc_data_t)); 80 if (ret != EOK) { 81 usb_log_error("Failed to init HCD structures: %s.", 82 str_error(ret)); 83 return ret; 84 } 85 vhc_data_t *vhc = ddf_dev_data_get(dev); 86 vhc_init(vhc); 87 88 hc_device_setup(&vhc->base, (bus_t *) &vhc->bus); 89 81 90 /* Initialize virtual structure */ 82 91 ddf_fun_t *ctl_fun = NULL; 83 errno_tret = vhc_control_node(dev, &ctl_fun);92 ret = vhc_control_node(dev, &ctl_fun); 84 93 if (ret != EOK) { 85 usb_log_error("Failed to setup control node.\n"); 86 return ret; 87 } 88 vhc_data_t *data = ddf_fun_data_get(ctl_fun); 89 90 /* Initialize generic structures */ 91 ret = hcd_ddf_setup_hc(dev, USB_SPEED_FULL, 92 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 93 if (ret != EOK) { 94 usb_log_error("Failed to init HCD structures: %s.\n", 95 str_error(ret)); 96 ddf_fun_destroy(ctl_fun); 94 usb_log_error("Failed to setup control node."); 97 95 return ret; 98 96 } 99 97 100 hcd_set_implementation(dev_to_hcd(dev), data, &vhc_hc_ops);101 102 98 /* Add virtual hub device */ 103 ret = vhc_virtdev_plug_hub( data, &data->hub, NULL, 0);99 ret = vhc_virtdev_plug_hub(vhc, &vhc->hub, NULL, 0); 104 100 if (ret != EOK) { 105 usb_log_error("Failed to plug root hub: %s. \n", str_error(ret));101 usb_log_error("Failed to plug root hub: %s.", str_error(ret)); 106 102 ddf_fun_destroy(ctl_fun); 107 103 return ret; … … 112 108 * needs to be ready at this time. 113 109 */ 114 ret = hc d_ddf_setup_root_hub(dev);110 ret = hc_setup_virtual_root_hub(&vhc->base, USB_SPEED_HIGH); 115 111 if (ret != EOK) { 116 usb_log_error("Failed to init VHC root hub: %s \n",112 usb_log_error("Failed to init VHC root hub: %s", 117 113 str_error(ret)); 118 114 // TODO do something here... -
uspace/drv/bus/usb/vhc/transfer.c
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 31 32 #include <usb/debug.h> 32 33 #include <usbvirt/device.h> 34 #include <usb/host/bandwidth.h> 35 #include <usb/host/endpoint.h> 36 #include <usb/host/usb_transfer_batch.h> 33 37 #include <usbvirt/ipc.h> 34 38 #include "vhcd.h" … … 37 41 static bool is_set_address_transfer(vhc_transfer_t *transfer) 38 42 { 39 if (transfer->batch ->ep->endpoint != 0) {40 return false; 41 } 42 if (transfer->batch ->ep->transfer_type != USB_TRANSFER_CONTROL) {43 return false; 44 } 45 if ( usb_transfer_batch_direction(transfer->batch)!= USB_DIRECTION_OUT) {43 if (transfer->batch.target.endpoint != 0) { 44 return false; 45 } 46 if (transfer->batch.ep->transfer_type != USB_TRANSFER_CONTROL) { 47 return false; 48 } 49 if (transfer->batch.dir != USB_DIRECTION_OUT) { 46 50 return false; 47 51 } 48 52 const usb_device_request_setup_packet_t *setup = 49 (void*)transfer->batch->setup_buffer;53 &transfer->batch.setup.packet; 50 54 if (setup->request_type != 0) { 51 55 return false; … … 62 66 { 63 67 errno_t rc; 64 65 const usb_direction_t dir = usb_transfer_batch_direction(batch);68 69 const usb_direction_t dir = batch->dir; 66 70 67 71 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 68 72 if (dir == USB_DIRECTION_IN) { 69 73 rc = usbvirt_control_read(dev, 70 batch->setup _buffer, batch->setup_size,71 batch-> buffer, batch->buffer_size,74 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 75 batch->dma_buffer.virt, batch->size, 72 76 actual_data_size); 73 77 } else { 74 78 assert(dir == USB_DIRECTION_OUT); 75 79 rc = usbvirt_control_write(dev, 76 batch->setup _buffer, batch->setup_size,77 batch-> buffer, batch->buffer_size);80 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 81 batch->dma_buffer.virt, batch->size); 78 82 } 79 83 } else { … … 81 85 rc = usbvirt_data_in(dev, batch->ep->transfer_type, 82 86 batch->ep->endpoint, 83 batch-> buffer, batch->buffer_size,87 batch->dma_buffer.virt, batch->size, 84 88 actual_data_size); 85 89 } else { … … 87 91 rc = usbvirt_data_out(dev, batch->ep->transfer_type, 88 92 batch->ep->endpoint, 89 batch-> buffer, batch->buffer_size);93 batch->dma_buffer.virt, batch->size); 90 94 } 91 95 } … … 99 103 errno_t rc; 100 104 101 const usb_direction_t dir = usb_transfer_batch_direction(batch);105 const usb_direction_t dir = batch->dir; 102 106 103 107 if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) { 104 108 if (dir == USB_DIRECTION_IN) { 105 109 rc = usbvirt_ipc_send_control_read(sess, 106 batch->setup _buffer, batch->setup_size,107 batch-> buffer, batch->buffer_size,110 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 111 batch->dma_buffer.virt, batch->size, 108 112 actual_data_size); 109 113 } else { 110 114 assert(dir == USB_DIRECTION_OUT); 111 115 rc = usbvirt_ipc_send_control_write(sess, 112 batch->setup _buffer, batch->setup_size,113 batch-> buffer, batch->buffer_size);116 batch->setup.buffer, USB_SETUP_PACKET_SIZE, 117 batch->dma_buffer.virt, batch->size); 114 118 } 115 119 } else { … … 117 121 rc = usbvirt_ipc_send_data_in(sess, batch->ep->endpoint, 118 122 batch->ep->transfer_type, 119 batch-> buffer, batch->buffer_size,123 batch->dma_buffer.virt, batch->size, 120 124 actual_data_size); 121 125 } else { … … 123 127 rc = usbvirt_ipc_send_data_out(sess, batch->ep->endpoint, 124 128 batch->ep->transfer_type, 125 batch-> buffer, batch->buffer_size);129 batch->dma_buffer.virt, batch->size); 126 130 } 127 131 } … … 135 139 assert(!list_empty(&dev->transfer_queue)); 136 140 137 vhc_transfer_t *transfer = list_get_instance( 138 list_first(&dev->transfer_queue), vhc_transfer_t, link); 141 vhc_transfer_t *transfer = 142 list_get_instance(list_first(&dev->transfer_queue), 143 vhc_transfer_t, link); 139 144 list_remove(&transfer->link); 140 145 … … 147 152 assert(outcome != ENAK); 148 153 assert(transfer); 149 assert(transfer->batch); 150 usb_transfer_batch_finish_error(transfer->batch, NULL, 151 data_transfer_size, outcome); 152 usb_transfer_batch_destroy(transfer->batch); 153 free(transfer); 154 } 154 transfer->batch.error = outcome; 155 transfer->batch.transferred_size = data_transfer_size; 156 usb_transfer_batch_finish(&transfer->batch); 157 } 158 159 static usb_transfer_batch_t *batch_create(endpoint_t *ep) 160 { 161 vhc_transfer_t *transfer = calloc(1, sizeof(vhc_transfer_t)); 162 usb_transfer_batch_init(&transfer->batch, ep); 163 link_initialize(&transfer->link); 164 return &transfer->batch; 165 } 166 167 static int device_enumerate(device_t *device) 168 { 169 vhc_data_t *vhc = bus_to_vhc(device->bus); 170 return usb2_bus_device_enumerate(&vhc->bus_helper, device); 171 } 172 173 static int endpoint_register(endpoint_t *endpoint) 174 { 175 vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus); 176 return usb2_bus_endpoint_register(&vhc->bus_helper, endpoint); 177 } 178 179 static void endpoint_unregister(endpoint_t *endpoint) 180 { 181 vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus); 182 usb2_bus_endpoint_unregister(&vhc->bus_helper, endpoint); 183 184 // TODO: abort transfer? 185 } 186 187 static const bus_ops_t vhc_bus_ops = { 188 .batch_create = batch_create, 189 .batch_schedule = vhc_schedule, 190 191 .device_enumerate = device_enumerate, 192 .endpoint_register = endpoint_register, 193 .endpoint_unregister = endpoint_unregister, 194 }; 155 195 156 196 errno_t vhc_init(vhc_data_t *instance) … … 159 199 list_initialize(&instance->devices); 160 200 fibril_mutex_initialize(&instance->guard); 161 instance->magic = 0xDEADBEEF; 201 bus_init(&instance->bus, sizeof(device_t)); 202 usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11); 203 instance->bus.ops = &vhc_bus_ops; 162 204 return virthub_init(&instance->hub, "root hub"); 163 205 } 164 206 165 errno_t vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 166 { 167 assert(hcd); 207 errno_t vhc_schedule(usb_transfer_batch_t *batch) 208 { 168 209 assert(batch); 169 vhc_data_t *vhc = hcd_get_driver_data(hcd); 210 vhc_transfer_t *transfer = (vhc_transfer_t *) batch; 211 vhc_data_t *vhc = bus_to_vhc(endpoint_get_bus(batch->ep)); 170 212 assert(vhc); 171 172 vhc_transfer_t *transfer = malloc(sizeof(vhc_transfer_t));173 if (!transfer)174 return ENOMEM;175 link_initialize(&transfer->link);176 transfer->batch = batch;177 213 178 214 fibril_mutex_lock(&vhc->guard); … … 182 218 list_foreach(vhc->devices, link, vhc_virtdev_t, dev) { 183 219 fibril_mutex_lock(&dev->guard); 184 if (dev->address == transfer->batch ->ep->address) {220 if (dev->address == transfer->batch.target.address) { 185 221 if (!targets) { 186 222 list_append(&transfer->link, &dev->transfer_queue); … … 194 230 195 231 if (targets > 1) 196 usb_log_warning("Transfer would be accepted by more devices! \n");232 usb_log_warning("Transfer would be accepted by more devices!"); 197 233 198 234 return targets ? EOK : ENOENT; … … 217 253 size_t data_transfer_size = 0; 218 254 if (dev->dev_sess) { 219 rc = process_transfer_remote( transfer->batch,255 rc = process_transfer_remote(&transfer->batch, 220 256 dev->dev_sess, &data_transfer_size); 221 257 } else if (dev->dev_local != NULL) { 222 rc = process_transfer_local( transfer->batch,258 rc = process_transfer_local(&transfer->batch, 223 259 dev->dev_local, &data_transfer_size); 224 260 } else { 225 usb_log_warning("Device has no remote phone nor local node.\n"); 261 usb_log_warning("Device has no remote phone " 262 "nor local node."); 226 263 rc = ESTALL; 227 264 } 228 265 229 usb_log_debug2("Transfer %p processed: %s. \n",266 usb_log_debug2("Transfer %p processed: %s.", 230 267 transfer, str_error(rc)); 231 268 … … 234 271 if (is_set_address_transfer(transfer)) { 235 272 usb_device_request_setup_packet_t *setup = 236 (void *) transfer->batch->setup_buffer;273 (void *) transfer->batch.setup.buffer; 237 274 dev->address = setup->value; 238 usb_log_debug2("Address changed to %d \n",275 usb_log_debug2("Address changed to %d", 239 276 dev->address); 240 277 } -
uspace/drv/bus/usb/vhc/vhcd.h
rf5e5f73 rdf6ded8 1 1 /* 2 2 * Copyright (c) 2010 Vojtech Horky 3 * Copyright (c) 2018 Ondrej Hlavaty 3 4 * All rights reserved. 4 5 * … … 38 39 39 40 #include <usbvirt/device.h> 40 #include <usbhc_iface.h>41 41 #include <async.h> 42 #include <macros.h> 42 43 43 44 #include <usb/host/hcd.h> 45 #include <usb/host/usb2_bus.h> 46 #include <usb/host/usb_transfer_batch.h> 44 47 45 48 #define NAME "vhc" … … 56 59 57 60 typedef struct { 58 uint32_t magic; 61 hc_device_t base; 62 63 bus_t bus; 64 usb2_bus_helper_t bus_helper; 65 66 ddf_fun_t *virtual_fun; 59 67 list_t devices; 60 68 fibril_mutex_t guard; … … 63 71 64 72 typedef struct { 73 usb_transfer_batch_t batch; 65 74 link_t link; 66 usb_transfer_batch_t *batch;67 75 } vhc_transfer_t; 76 77 static inline vhc_data_t *hcd_to_vhc(hc_device_t *hcd) 78 { 79 assert(hcd); 80 return (vhc_data_t *) hcd; 81 } 82 83 static inline vhc_data_t *bus_to_vhc(bus_t *bus) 84 { 85 assert(bus); 86 return member_to_inst(bus, vhc_data_t, bus); 87 } 68 88 69 89 void on_client_close(ddf_fun_t *fun); … … 73 93 errno_t vhc_virtdev_plug(vhc_data_t *, async_sess_t *, uintptr_t *); 74 94 errno_t vhc_virtdev_plug_local(vhc_data_t *, usbvirt_device_t *, uintptr_t *); 75 errno_t vhc_virtdev_plug_hub(vhc_data_t *, usbvirt_device_t *, uintptr_t *, usb_address_t address); 95 errno_t vhc_virtdev_plug_hub(vhc_data_t *, usbvirt_device_t *, uintptr_t *, 96 usb_address_t address); 76 97 void vhc_virtdev_unplug(vhc_data_t *, uintptr_t); 77 98 78 errno_t vhc_init(vhc_data_t * instance);79 errno_t vhc_schedule( hcd_t *hcd, usb_transfer_batch_t *batch);99 errno_t vhc_init(vhc_data_t *); 100 errno_t vhc_schedule(usb_transfer_batch_t *); 80 101 errno_t vhc_transfer_queue_processor(void *arg); 81 102
Note:
See TracChangeset
for help on using the changeset viewer.
