Changes in / [04efacc:03936831] in mainline
- Files:
-
- 37 added
- 6 deleted
- 57 edited
Legend:
- Unmodified
- Added
- Removed
-
.bzrignore
r04efacc r03936831 234 234 uspace/dist/drv/virt/ 235 235 uspace/dist/drv/xtkbd/ 236 uspace/dist/drv/xhci/ 236 237 uspace/dist/inc/_link.ld 237 238 uspace/dist/inc/c/ … … 288 289 uspace/drv/bus/usb/usbmid/usbmid 289 290 uspace/drv/bus/usb/vhc/vhc 291 uspace/drv/bus/usb/xhci/xhci 292 uspace/drv/bus/usb/xhci/test-xhci 290 293 uspace/drv/char/atkbd/atkbd 291 294 uspace/drv/char/i8042/i8042 -
boot/Makefile.common
r04efacc r03936831 237 237 $(USPACE_PATH)/lib/posix/test-libposix \ 238 238 $(USPACE_PATH)/lib/uri/test-liburi \ 239 $(USPACE_PATH)/drv/bus/usb/xhci/test-xhci \ 239 240 $(USPACE_PATH)/app/bdsh/test-bdsh \ 240 241 $(USPACE_PATH)/srv/net/tcp/test-tcp -
boot/arch/amd64/Makefile.inc
r04efacc r03936831 54 54 bus/usb/usbmast \ 55 55 bus/usb/usbmid \ 56 bus/usb/vhc 56 bus/usb/vhc \ 57 bus/usb/xhci 57 58 58 59 RD_DRV_CFG += \ -
tools/ew.py
r04efacc r03936831 160 160 return ' -usb' 161 161 162 def qemu_xhci_options(): 163 if is_override('noxhci'): 164 return '' 165 return ' -device nec-usb-xhci,id=xhci' 166 162 167 def qemu_audio_options(): 163 168 if is_override('nosnd'): … … 180 185 if (not 'usb' in cfg.keys()) or cfg['usb']: 181 186 cmdline += qemu_usb_options() 187 if (not 'xhci' in cfg.keys()) or cfg['xhci']: 188 cmdline += qemu_xhci_options() 182 189 if (not 'audio' in cfg.keys()) or cfg['audio']: 183 190 cmdline += qemu_audio_options() … … 286 293 def usage(): 287 294 print("%s - emulator wrapper for running HelenOS\n" % os.path.basename(sys.argv[0])) 288 print("%s [-d] [-h] [-net e1k|rtl8139|ne2k] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] \n" %295 print("%s [-d] [-h] [-net e1k|rtl8139|ne2k] [-nohdd] [-nokvm] [-nonet] [-nosnd] [-nousb] [-noxhci]\n" % 289 296 os.path.basename(sys.argv[0])) 290 297 print("-d\tDry run: do not run the emulation, just print the command line.") … … 295 302 print("-nosnd\tDisable sound, if applicable.") 296 303 print("-nousb\tDisable USB support, if applicable.") 304 print("-noxhci\tDisable XHCI support, if applicable.") 297 305 298 306 def fail(platform, machine): … … 336 344 elif sys.argv[i] == '-nousb': 337 345 overrides['nousb'] = True 346 elif sys.argv[i] == '-noxhci': 347 overrides['noxhci'] = True 338 348 else: 339 349 usage() -
uspace/Makefile
r04efacc r03936831 156 156 drv/bus/usb/usbmid \ 157 157 drv/bus/usb/vhc \ 158 drv/bus/usb/xhci \ 158 159 drv/char/i8042 \ 159 160 drv/char/ns8250 \ -
uspace/drv/bus/usb/ehci/Makefile
r04efacc r03936831 46 46 SOURCES = \ 47 47 ehci_batch.c \ 48 ehci_ endpoint.c \48 ehci_bus.c \ 49 49 ehci_rh.c \ 50 50 endpoint_list.c \ -
uspace/drv/bus/usb/ehci/ehci_batch.c
r04efacc r03936831 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 -
uspace/drv/bus/usb/ehci/ehci_rh.c
r04efacc r03936831 144 144 assert(instance); 145 145 assert(batch); 146 const usb_target_t target = {{ 147 .address = batch->ep->address, 148 .endpoint = batch->ep->endpoint, 149 }}; 146 const usb_target_t target = batch->ep->target; 150 147 batch->error = virthub_base_request(&instance->base, target, 151 148 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer, … … 183 180 instance, batch); 184 181 if (batch) { 185 const usb_target_t target = {{ 186 .address = batch->ep->address, 187 .endpoint = batch->ep->endpoint, 188 }}; 182 const usb_target_t target = batch->ep->target; 189 183 batch->error = virthub_base_request(&instance->base, target, 190 184 usb_transfer_batch_direction(batch), -
uspace/drv/bus/usb/ehci/endpoint_list.h
r04efacc r03936831 40 40 #include <usb/host/utils/malloc32.h> 41 41 42 #include "ehci_ endpoint.h"42 #include "ehci_bus.h" 43 43 #include "hw_struct/queue_head.h" 44 44 -
uspace/drv/bus/usb/ehci/hc.c
r04efacc r03936831 89 89 }; 90 90 91 static void hc_start(hc_t *instance);92 91 static int hc_init_memory(hc_t *instance); 93 92 … … 98 97 * @return Error code. 99 98 */ 100 int ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)99 int ehci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res) 101 100 { 102 101 assert(code); 103 102 assert(hw_res); 103 104 hc_t *instance = hcd_get_driver_data(hcd); 104 105 105 106 if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1) … … 128 129 129 130 memcpy(code->cmds, ehci_irq_commands, sizeof(ehci_irq_commands)); 130 ehci_caps_regs_t *caps = NULL;131 132 int ret = pio_enable_range(®s, (void**)&caps);133 if (ret != EOK) {134 free(code->ranges);135 free(code->cmds);136 return ret;137 }138 131 139 132 ehci_regs_t *registers = 140 (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(caps->caplength));133 (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(instance->caps->caplength)); 141 134 code->cmds[0].addr = (void *) ®isters->usbsts; 142 135 code->cmds[3].addr = (void *) ®isters->usbsts; … … 156 149 * @return Error code 157 150 */ 158 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res , bool interrupts)151 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res) 159 152 { 160 153 assert(instance); … … 172 165 return ret; 173 166 } 167 174 168 usb_log_info("HC(%p): Device registers at %"PRIx64" (%zuB) accessible.", 175 169 instance, hw_res->mem_ranges.ranges[0].address.absolute, … … 195 189 ehci_rh_init( 196 190 &instance->rh, instance->caps, instance->registers, "ehci rh"); 197 usb_log_debug("HC(%p): Starting HW.", instance); 198 hc_start(instance); 199 191 192 ehci_bus_init(&instance->bus, instance); 200 193 return EOK; 201 194 } … … 222 215 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 223 216 usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)\n", instance, 224 ep-> address, ep->endpoint,217 ep->target.address, ep->target.endpoint, 225 218 usb_str_transfer_type_short(ep->transfer_type), 226 219 usb_str_direction(ep->direction)); … … 246 239 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 247 240 usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)\n", instance, 248 ep-> address, ep->endpoint,241 ep->target.address, ep->target.endpoint, 249 242 usb_str_transfer_type_short(ep->transfer_type), 250 243 usb_str_direction(ep->direction)); … … 298 291 299 292 /* Check for root hub communication */ 300 if (batch->ep-> address == ehci_rh_get_address(&instance->rh)) {293 if (batch->ep->target.address == ehci_rh_get_address(&instance->rh)) { 301 294 usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)", 302 295 instance, batch, &instance->rh); … … 368 361 * @param[in] instance EHCI hc driver structure. 369 362 */ 370 void hc_start(hc_t *instance) 371 { 372 assert(instance); 363 int hc_start(hc_t *instance, bool interrupts) 364 { 365 assert(instance); 366 usb_log_debug("HC(%p): Starting HW.", instance); 367 373 368 /* Turn off the HC if it's running, Reseting a running device is 374 369 * undefined */ … … 435 430 EHCI_WR(instance->registers->usbsts, EHCI_RD(instance->registers->usbsts)); 436 431 EHCI_WR(instance->registers->usbintr, EHCI_USED_INTERRUPTS); 432 433 return EOK; 437 434 } 438 435 -
uspace/drv/bus/usb/ehci/hc.h
r04efacc r03936831 80 80 /** USB hub emulation structure */ 81 81 ehci_rh_t rh; 82 83 /** USB bookkeeping */ 84 ehci_bus_t bus; 82 85 } hc_t; 83 86 84 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts); 87 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res); 88 int hc_start(hc_t *instance, bool interrupts); 85 89 void hc_fini(hc_t *instance); 86 90 … … 88 92 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep); 89 93 90 int ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res);94 int ehci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res); 91 95 92 96 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status); -
uspace/drv/bus/usb/ehci/hw_struct/queue_head.c
r04efacc r03936831 37 37 #include <mem.h> 38 38 #include <macros.h> 39 #include <usb/host/bus.h> 39 40 40 41 #include "mem_access.h" … … 65 66 assert(ep->speed < ARRAY_SIZE(speed)); 66 67 EHCI_MEM32_WR(instance->ep_char, 67 QH_EP_CHAR_ADDR_SET(ep-> address) |68 QH_EP_CHAR_EP_SET(ep-> endpoint) |68 QH_EP_CHAR_ADDR_SET(ep->target.address) | 69 QH_EP_CHAR_EP_SET(ep->target.endpoint) | 69 70 speed[ep->speed] | 70 71 QH_EP_CHAR_MAX_LENGTH_SET(ep->max_packet_size) … … 81 82 if (ep->speed != USB_SPEED_HIGH) { 82 83 ep_cap |= 83 QH_EP_CAP_TT_PORT_SET(ep-> tt.port) |84 QH_EP_CAP_TT_ADDR_SET(ep-> tt.address);84 QH_EP_CAP_TT_PORT_SET(ep->device->tt.port) | 85 QH_EP_CAP_TT_ADDR_SET(ep->device->tt.address); 85 86 } 86 87 if (ep->transfer_type == USB_TRANSFER_INTERRUPT) { -
uspace/drv/bus/usb/ehci/main.c
r04efacc r03936831 48 48 #include "res.h" 49 49 #include "hc.h" 50 #include "ehci_endpoint.h"51 50 52 51 #define NAME "ehci" 53 52 54 static int ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 53 static int ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *); 54 static int ehci_driver_claim(hcd_t *, ddf_dev_t *); 55 static int ehci_driver_start(hcd_t *, bool); 55 56 static void ehci_driver_fini(hcd_t *); 56 57 57 58 static const ddf_hc_driver_t ehci_hc_driver = { 58 . claim = disable_legacy,59 . hc_speed = USB_SPEED_HIGH,59 .name = "EHCI-PCI", 60 .init = ehci_driver_init, 60 61 .irq_code_gen = ehci_hc_gen_irq_code, 61 .init = ehci_driver_init, 62 .claim = ehci_driver_claim, 63 .start = ehci_driver_start, 64 .setup_root_hub = hcd_setup_virtual_root_hub, 62 65 .fini = ehci_driver_fini, 63 .name = "EHCI-PCI",64 66 .ops = { 65 67 .schedule = ehci_hc_schedule, 66 .ep_add_hook = ehci_endpoint_init,67 .ep_remove_hook = ehci_endpoint_fini,68 68 .irq_hook = ehci_hc_interrupt, 69 69 .status_hook = ehci_hc_status, … … 72 72 73 73 74 static int ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, 75 bool irq) 74 static int ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, ddf_dev_t *device) 76 75 { 77 76 assert(hcd); … … 82 81 return ENOMEM; 83 82 84 const int ret = hc_init(instance, res , irq);83 const int ret = hc_init(instance, res); 85 84 if (ret == EOK) { 86 hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops );85 hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops, &instance->bus.base.base); 87 86 } else { 88 87 free(instance); 89 88 } 90 89 return ret; 90 } 91 92 static int ehci_driver_claim(hcd_t *hcd, ddf_dev_t *dev) 93 { 94 hc_t *instance = hcd_get_driver_data(hcd); 95 assert(instance); 96 97 return disable_legacy(instance, dev); 98 } 99 100 static int ehci_driver_start(hcd_t *hcd, bool irq) { 101 hc_t *instance = hcd_get_driver_data(hcd); 102 assert(instance); 103 104 return hc_start(instance, irq); 91 105 } 92 106 … … 99 113 100 114 free(hc); 101 hcd_set_implementation(hcd, NULL, NULL );115 hcd_set_implementation(hcd, NULL, NULL, NULL); 102 116 } 103 117 -
uspace/drv/bus/usb/ehci/res.c
r04efacc r03936831 172 172 } 173 173 174 int disable_legacy( ddf_dev_t *device)174 int disable_legacy(hc_t *hc, ddf_dev_t *device) 175 175 { 176 176 assert(device); … … 182 182 usb_log_debug("Disabling EHCI legacy support.\n"); 183 183 184 hw_res_list_parsed_t res; 185 hw_res_list_parsed_init(&res); 186 int 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); 184 185 const uint32_t hcc_params = EHCI_RD(hc->caps->hccparams); 214 186 usb_log_debug2("Value of hcc params register: %x.\n", hcc_params); 215 187 … … 220 192 usb_log_debug2("Value of EECP: %x.\n", eecp); 221 193 222 ret = disable_extended_caps(parent_sess, eecp);194 int ret = disable_extended_caps(parent_sess, eecp); 223 195 if (ret != EOK) { 224 196 usb_log_error("Failed to disable extended capabilities: %s.\n", … … 227 199 } 228 200 clean: 229 //TODO unmap registers 230 hw_res_list_parsed_clean(&res); 201 async_hangup(parent_sess); 231 202 return ret; 232 203 } -
uspace/drv/bus/usb/ehci/res.h
r04efacc r03936831 39 39 #include <device/hw_res_parsed.h> 40 40 41 extern int disable_legacy(ddf_dev_t *); 41 #include "hc.h" 42 43 extern int disable_legacy(hc_t *, ddf_dev_t *); 42 44 43 45 #endif -
uspace/drv/bus/usb/ohci/Makefile
r04efacc r03936831 49 49 main.c \ 50 50 ohci_batch.c \ 51 ohci_ endpoint.c \51 ohci_bus.c \ 52 52 ohci_rh.c \ 53 53 hw_struct/endpoint_descriptor.c \ -
uspace/drv/bus/usb/ohci/endpoint_list.h
r04efacc r03936831 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
r04efacc r03936831 47 47 #include <usb/usb.h> 48 48 49 #include "ohci_ endpoint.h"49 #include "ohci_bus.h" 50 50 #include "ohci_batch.h" 51 51 … … 89 89 }; 90 90 91 static void hc_gain_control(hc_t *instance);92 static void hc_start(hc_t *instance);93 91 static int hc_init_transfer_lists(hc_t *instance); 94 92 static int hc_init_memory(hc_t *instance); … … 103 101 * @return Error code. 104 102 */ 105 int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)103 int ohci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res) 106 104 { 107 105 assert(code); … … 151 149 * @return Error code 152 150 */ 153 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res , bool interrupts)151 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res) 154 152 { 155 153 assert(instance); … … 172 170 list_initialize(&instance->pending_batches); 173 171 fibril_mutex_initialize(&instance->guard); 174 instance->hw_interrupts = interrupts;175 172 176 173 ret = hc_init_memory(instance); … … 181 178 return ret; 182 179 } 183 184 hc_gain_control(instance);185 186 ohci_rh_init(&instance->rh, instance->registers, "ohci rh");187 hc_start(instance);188 180 189 181 return EOK; … … 295 287 296 288 /* Check for root hub communication */ 297 if (batch->ep-> address == ohci_rh_get_address(&instance->rh)) {289 if (batch->ep->target.address == ohci_rh_get_address(&instance->rh)) { 298 290 usb_log_debug("OHCI root hub request.\n"); 299 291 return ohci_rh_schedule(&instance->rh, batch); … … 443 435 void hc_start(hc_t *instance) 444 436 { 437 ohci_rh_init(&instance->rh, instance->registers, "ohci rh"); 438 445 439 /* OHCI guide page 42 */ 446 440 assert(instance); -
uspace/drv/bus/usb/ohci/hc.h
r04efacc r03936831 52 52 #include "ohci_regs.h" 53 53 #include "ohci_rh.h" 54 #include "ohci_bus.h" 54 55 #include "endpoint_list.h" 55 56 #include "hw_struct/hcca.h" … … 59 60 /** Memory mapped I/O registers area */ 60 61 ohci_regs_t *registers; 62 61 63 /** Host controller communication area structure */ 62 64 hcca_t *hcca; … … 64 66 /** Transfer schedules */ 65 67 endpoint_list_t lists[4]; 68 66 69 /** List of active transfers */ 67 70 list_t pending_batches; … … 78 81 /** USB hub emulation structure */ 79 82 ohci_rh_t rh; 83 84 /** USB bookkeeping */ 85 ohci_bus_t bus; 80 86 } hc_t; 81 87 82 extern int hc_init(hc_t *, const hw_res_list_parsed_t *, bool); 88 extern int hc_init(hc_t *, const hw_res_list_parsed_t *); 89 extern void hc_gain_control(hc_t *instance); 90 extern void hc_start(hc_t *instance); 83 91 extern void hc_fini(hc_t *); 84 92 … … 86 94 extern void hc_dequeue_endpoint(hc_t *, const endpoint_t *); 87 95 88 int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res);96 int ohci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res); 89 97 90 98 extern void ohci_hc_interrupt(hcd_t *, uint32_t); -
uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c
r04efacc r03936831 79 79 /* Status: address, endpoint nr, direction mask and max packet size. */ 80 80 OHCI_MEM32_WR(instance->status, 81 ((ep-> address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)82 | ((ep-> endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)81 ((ep->target.address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT) 82 | ((ep->target.endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT) 83 83 | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT) 84 84 | ((ep->max_packet_size & ED_STATUS_MPS_MASK) -
uspace/drv/bus/usb/ohci/main.c
r04efacc r03936831 45 45 46 46 #include "hc.h" 47 #include "ohci_bus.h" 47 48 48 49 #define NAME "ohci" 49 static int ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 50 static int ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *); 51 static int ohci_driver_start(hcd_t *, bool); 52 static int ohci_driver_claim(hcd_t *, ddf_dev_t *); 50 53 static void ohci_driver_fini(hcd_t *); 51 54 52 55 static const ddf_hc_driver_t ohci_hc_driver = { 53 .hc_speed = USB_SPEED_FULL,54 56 .irq_code_gen = ohci_hc_gen_irq_code, 55 57 .init = ohci_driver_init, 58 .claim = ohci_driver_claim, 59 .start = ohci_driver_start, 60 .setup_root_hub = hcd_setup_virtual_root_hub, 56 61 .fini = ohci_driver_fini, 57 62 .name = "OHCI", 58 63 .ops = { 59 64 .schedule = ohci_hc_schedule, 60 .ep_add_hook = ohci_endpoint_init,61 .ep_remove_hook = ohci_endpoint_fini,62 65 .irq_hook = ohci_hc_interrupt, 63 66 .status_hook = ohci_hc_status, … … 66 69 67 70 68 static int ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)71 static int ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, ddf_dev_t *device) 69 72 { 73 int err; 74 70 75 assert(hcd); 71 76 assert(hcd_get_driver_data(hcd) == NULL); … … 75 80 return ENOMEM; 76 81 77 const int 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; 82 if ((err = hc_init(instance, res)) != EOK) 83 goto err; 84 85 if ((err = ohci_bus_init(&instance->bus, instance))) 86 goto err; 87 88 hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops, &instance->bus.base.base); 89 90 return EOK; 91 92 err: 93 free(instance); 94 return err; 95 } 96 97 static int ohci_driver_claim(hcd_t *hcd, ddf_dev_t *dev) 98 { 99 hc_t *hc = hcd_get_driver_data(hcd); 100 assert(hc); 101 102 hc_gain_control(hc); 103 104 return EOK; 105 } 106 107 static int ohci_driver_start(hcd_t *hcd, bool interrupts) 108 { 109 hc_t *hc = hcd_get_driver_data(hcd); 110 assert(hc); 111 112 hc->hw_interrupts = interrupts; 113 hc_start(hc); 114 return EOK; 84 115 } 85 116 … … 91 122 hc_fini(hc); 92 123 93 hcd_set_implementation(hcd, NULL, NULL );124 hcd_set_implementation(hcd, NULL, NULL, NULL); 94 125 free(hc); 95 126 } -
uspace/drv/bus/usb/ohci/ohci_batch.c
r04efacc r03936831 45 45 46 46 #include "ohci_batch.h" 47 #include "ohci_ endpoint.h"47 #include "ohci_bus.h" 48 48 49 49 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t); -
uspace/drv/bus/usb/ohci/ohci_rh.c
r04efacc r03936831 178 178 assert(instance); 179 179 assert(batch); 180 const usb_target_t target = {{ 181 .address = batch->ep->address, 182 .endpoint = batch->ep->endpoint, 183 }}; 180 const usb_target_t target = batch->ep->target; 184 181 batch->error = virthub_base_request(&instance->base, target, 185 182 usb_transfer_batch_direction(batch), (void*)batch->setup_buffer, … … 211 208 instance->unfinished_interrupt_transfer = NULL; 212 209 if (batch) { 213 const usb_target_t target = {{ 214 .address = batch->ep->address, 215 .endpoint = batch->ep->endpoint, 216 }}; 210 const usb_target_t target = batch->ep->target; 217 211 batch->error = virthub_base_request(&instance->base, target, 218 212 usb_transfer_batch_direction(batch), -
uspace/drv/bus/usb/uhci/hc.c
r04efacc r03936831 50 50 #include <usb/usb.h> 51 51 #include <usb/host/utils/malloc32.h> 52 #include <usb/host/bandwidth.h> 52 53 53 54 #include "uhci_batch.h" … … 106 107 * @return Error code. 107 108 */ 108 int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)109 int uhci_hc_gen_irq_code(irq_code_t *code, hcd_t *hcd, const hw_res_list_parsed_t *hw_res) 109 110 { 110 111 assert(code); … … 214 215 * interrupt fibrils. 215 216 */ 216 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res , bool interrupts)217 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res) 217 218 { 218 219 assert(instance); … … 222 223 return EINVAL; 223 224 224 instance->hw_interrupts = interrupts;225 225 instance->hw_failures = 0; 226 226 … … 246 246 } 247 247 248 return EOK; 249 } 250 251 void hc_start(hc_t *instance) 252 { 248 253 hc_init_hw(instance); 249 254 (void)hc_debug_checker; 250 255 251 256 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 252 253 return EOK;254 257 } 255 258 … … 318 321 int hc_init_mem_structures(hc_t *instance) 319 322 { 320 assert(instance); 323 int err; 324 assert(instance); 325 326 if ((err = usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11))) 327 return err; 321 328 322 329 /* Init USB frame list page */ … … 440 447 assert(batch); 441 448 442 if (batch->ep-> address == uhci_rh_get_address(&instance->rh))449 if (batch->ep->target.address == uhci_rh_get_address(&instance->rh)) 443 450 return uhci_rh_schedule(&instance->rh, batch); 444 451 -
uspace/drv/bus/usb/uhci/hc.h
r04efacc r03936831 43 43 #include <ddi.h> 44 44 #include <usb/host/hcd.h> 45 #include <usb/host/usb2_bus.h> 45 46 #include <usb/host/usb_transfer_batch.h> 46 47 … … 100 101 typedef struct hc { 101 102 uhci_rh_t rh; 103 usb2_bus_t bus; 102 104 /** Addresses of I/O registers */ 103 105 uhci_regs_t *registers; … … 124 126 } hc_t; 125 127 126 extern int hc_init(hc_t *, const hw_res_list_parsed_t *, bool); 128 extern int hc_init(hc_t *, const hw_res_list_parsed_t *); 129 extern void hc_start(hc_t *); 127 130 extern void hc_fini(hc_t *); 128 131 129 extern int uhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *);132 extern int uhci_hc_gen_irq_code(irq_code_t *, hcd_t *,const hw_res_list_parsed_t *); 130 133 131 134 extern void uhci_hc_interrupt(hcd_t *, uint32_t); -
uspace/drv/bus/usb/uhci/main.c
r04efacc r03936831 49 49 #define NAME "uhci" 50 50 51 static int uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 51 static int uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *); 52 static int uhci_driver_start(hcd_t *, bool); 52 53 static void uhci_driver_fini(hcd_t *); 53 static int disable_legacy( ddf_dev_t *);54 static int disable_legacy(hcd_t *, ddf_dev_t *); 54 55 55 56 static const ddf_hc_driver_t uhci_hc_driver = { 56 57 .claim = disable_legacy, 57 .hc_speed = USB_SPEED_FULL,58 58 .irq_code_gen = uhci_hc_gen_irq_code, 59 59 .init = uhci_driver_init, 60 .start = uhci_driver_start, 61 .setup_root_hub = hcd_setup_virtual_root_hub, 60 62 .fini = uhci_driver_fini, 61 63 .name = "UHCI", … … 67 69 }; 68 70 69 static int uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)71 static int uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, ddf_dev_t *device) 70 72 { 73 int err; 74 71 75 assert(hcd); 72 76 assert(hcd_get_driver_data(hcd) == NULL); … … 76 80 return ENOMEM; 77 81 78 const int 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; 82 if ((err = hc_init(instance, res)) != EOK) 83 goto err; 84 85 hcd_set_implementation(hcd, instance, &uhci_hc_driver.ops, &instance->bus.base); 86 87 return EOK; 88 89 err: 90 free(instance); 91 return err; 92 } 93 94 static int uhci_driver_start(hcd_t *hcd, bool interrupts) 95 { 96 assert(hcd); 97 hc_t *hc = hcd_get_driver_data(hcd); 98 99 hc->hw_interrupts = interrupts; 100 hc_start(hc); 101 return EOK; 85 102 } 86 103 … … 92 109 hc_fini(hc); 93 110 94 hcd_set_implementation(hcd, NULL, NULL );111 hcd_set_implementation(hcd, NULL, NULL, NULL); 95 112 free(hc); 96 113 } … … 101 118 * @return Error code. 102 119 */ 103 static int disable_legacy( ddf_dev_t *device)120 static int disable_legacy(hcd_t *hcd, ddf_dev_t *device) 104 121 { 105 122 assert(device); -
uspace/drv/bus/usb/uhci/uhci_batch.c
r04efacc r03936831 228 228 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 229 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 }}; 230 const usb_target_t target = uhci_batch->usb_batch->ep->target; 233 231 234 232 int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep); … … 293 291 uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW; 294 292 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 }}; 293 const usb_target_t target = uhci_batch->usb_batch->ep->target; 298 294 299 295 /* setup stage */ -
uspace/drv/bus/usb/uhci/uhci_rh.c
r04efacc r03936831 103 103 assert(batch); 104 104 105 const usb_target_t target = {{ 106 .address = batch->ep->address, 107 .endpoint = batch->ep->endpoint 108 }}; 105 const usb_target_t target = batch->ep->target; 109 106 do { 110 107 batch->error = virthub_base_request(&instance->base, target, -
uspace/drv/bus/usb/usbhid/main.c
r04efacc r03936831 95 95 usb_hid_polling_callback, 96 96 /* How much data to request. */ 97 hid_dev->poll_pipe_mapping->pipe. max_packet_size,97 hid_dev->poll_pipe_mapping->pipe.desc.max_packet_size, 98 98 /* Delay */ 99 99 -1, -
uspace/drv/bus/usb/usbhub/status.h
r04efacc r03936831 110 110 if ((status & USB_HUB_PORT_STATUS_HIGH_SPEED) != 0) 111 111 return USB_SPEED_HIGH; 112 /* TODO: add super speed */ 112 113 return USB_SPEED_FULL; 113 114 } -
uspace/drv/bus/usb/usbmast/main.c
r04efacc r03936831 172 172 usb_device_get_name(dev)); 173 173 usb_log_debug("Bulk in endpoint: %d [%zuB].\n", 174 epm_in->pipe. endpoint_no, epm_in->pipe.max_packet_size);174 epm_in->pipe.desc.endpoint_no, epm_in->pipe.desc.max_packet_size); 175 175 usb_log_debug("Bulk out endpoint: %d [%zuB].\n", 176 epm_out->pipe. endpoint_no, epm_out->pipe.max_packet_size);176 epm_out->pipe.desc.endpoint_no, epm_out->pipe.desc.max_packet_size); 177 177 178 178 usb_log_debug("Get LUN count...\n"); -
uspace/drv/bus/usb/vhc/main.c
r04efacc r03936831 89 89 90 90 /* Initialize generic structures */ 91 ret = hcd_ddf_setup_hc(dev, USB_SPEED_FULL, 92 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 91 ret = hcd_ddf_setup_hc(dev); 93 92 if (ret != EOK) { 94 93 usb_log_error("Failed to init HCD structures: %s.\n", … … 98 97 } 99 98 100 hcd_set_implementation(dev_to_hcd(dev), data, &vhc_hc_ops );99 hcd_set_implementation(dev_to_hcd(dev), data, &vhc_hc_ops, &data->bus.base); 101 100 102 101 /* Add virtual hub device */ … … 112 111 * needs to be ready at this time. 113 112 */ 114 ret = hcd_ ddf_setup_root_hub(dev);113 ret = hcd_setup_virtual_root_hub(dev_to_hcd(dev), dev); 115 114 if (ret != EOK) { 116 115 usb_log_error("Failed to init VHC root hub: %s\n", -
uspace/drv/bus/usb/vhc/transfer.c
r04efacc r03936831 31 31 #include <usb/debug.h> 32 32 #include <usbvirt/device.h> 33 #include <usb/host/bandwidth.h> 33 34 #include <usbvirt/ipc.h> 34 35 #include "vhcd.h" … … 37 38 static bool is_set_address_transfer(vhc_transfer_t *transfer) 38 39 { 39 if (transfer->batch->ep-> endpoint != 0) {40 if (transfer->batch->ep->target.endpoint != 0) { 40 41 return false; 41 42 } … … 80 81 if (dir == USB_DIRECTION_IN) { 81 82 rc = usbvirt_data_in(dev, batch->ep->transfer_type, 82 batch->ep-> endpoint,83 batch->ep->target.endpoint, 83 84 batch->buffer, batch->buffer_size, 84 85 actual_data_size); … … 86 87 assert(dir == USB_DIRECTION_OUT); 87 88 rc = usbvirt_data_out(dev, batch->ep->transfer_type, 88 batch->ep-> endpoint,89 batch->ep->target.endpoint, 89 90 batch->buffer, batch->buffer_size); 90 91 } … … 115 116 } else { 116 117 if (dir == USB_DIRECTION_IN) { 117 rc = usbvirt_ipc_send_data_in(sess, batch->ep-> endpoint,118 rc = usbvirt_ipc_send_data_in(sess, batch->ep->target.endpoint, 118 119 batch->ep->transfer_type, 119 120 batch->buffer, batch->buffer_size, … … 121 122 } else { 122 123 assert(dir == USB_DIRECTION_OUT); 123 rc = usbvirt_ipc_send_data_out(sess, batch->ep-> endpoint,124 rc = usbvirt_ipc_send_data_out(sess, batch->ep->target.endpoint, 124 125 batch->ep->transfer_type, 125 126 batch->buffer, batch->buffer_size); … … 159 160 list_initialize(&instance->devices); 160 161 fibril_mutex_initialize(&instance->guard); 162 usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 161 163 instance->magic = 0xDEADBEEF; 162 164 return virthub_init(&instance->hub, "root hub"); … … 182 184 list_foreach(vhc->devices, link, vhc_virtdev_t, dev) { 183 185 fibril_mutex_lock(&dev->guard); 184 if (dev->address == transfer->batch->ep-> address) {186 if (dev->address == transfer->batch->ep->target.address) { 185 187 if (!targets) { 186 188 list_append(&transfer->link, &dev->transfer_queue); -
uspace/drv/bus/usb/vhc/vhcd.h
r04efacc r03936831 42 42 43 43 #include <usb/host/hcd.h> 44 #include <usb/host/usb2_bus.h> 44 45 45 46 #define NAME "vhc" … … 60 61 fibril_mutex_t guard; 61 62 usbvirt_device_t hub; 63 usb2_bus_t bus; 62 64 } vhc_data_t; 63 65 -
uspace/lib/c/include/bitops.h
r04efacc r03936831 54 54 #define BIT_RANGE_EXTRACT(type, hi, lo, value) \ 55 55 (((value) >> (lo)) & BIT_RRANGE(type, (hi) - (lo) + 1)) 56 57 /** Insert @a value between bits @a hi .. @a lo. */ 58 #define BIT_RANGE_INSERT(type, hi, lo, value) \ 59 (((value) & BIT_RRANGE(type, (hi) - (lo) + 1)) << (lo)) 56 60 57 61 /** Return position of first non-zero bit from left (i.e. [log_2(arg)]). -
uspace/lib/c/include/byteorder.h
r04efacc r03936831 85 85 #define ntohl(n) uint32_t_be2host((n)) 86 86 87 #define uint8_t_be2host(n) (n) 88 #define uint8_t_le2host(n) (n) 89 #define host2uint8_t_be(n) (n) 90 #define host2uint8_t_le(n) (n) 91 87 92 static inline uint64_t uint64_t_byteorder_swap(uint64_t n) 88 93 { -
uspace/lib/drv/generic/remote_usb.c
r04efacc r03936831 175 175 } pack8_t; 176 176 177 int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 178 usb_transfer_type_t type, usb_direction_t direction, 179 size_t mps, unsigned packets, unsigned interval) 180 { 181 if (!exch) 182 return EBADMEM; 183 pack8_t pack; 184 pack.arr[0] = type; 185 pack.arr[1] = direction; 186 pack.arr[2] = interval; 187 pack.arr[3] = packets; 188 189 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 190 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps); 191 192 } 193 194 int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 195 usb_direction_t direction) 196 { 197 if (!exch) 198 return EBADMEM; 199 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 200 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction); 177 int usb_register_endpoint(async_exch_t *exch, 178 usb_endpoint_desc_t *endpoint_desc) 179 { 180 if (!exch) 181 return EBADMEM; 182 183 aid_t opening_request = async_send_1(exch, 184 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL); 185 186 if (opening_request == 0) { 187 return ENOMEM; 188 } 189 190 const int ret = async_data_write_start(exch, (void *) endpoint_desc, 191 sizeof(usb_endpoint_desc_t)); 192 193 if (ret != EOK) { 194 async_forget(opening_request); 195 return ret; 196 } 197 198 /* Wait for the answer. */ 199 sysarg_t opening_request_rc; 200 async_wait_for(opening_request, &opening_request_rc); 201 202 return (int) opening_request_rc; 203 } 204 205 int usb_unregister_endpoint(async_exch_t *exch, 206 usb_endpoint_desc_t *endpoint_desc) 207 { 208 if (!exch) 209 return EBADMEM; 210 211 aid_t opening_request = async_send_1(exch, 212 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL); 213 214 if (opening_request == 0) { 215 return ENOMEM; 216 } 217 218 const int ret = async_data_write_start(exch, endpoint_desc, 219 sizeof(usb_endpoint_desc_t)); 220 if (ret != EOK) { 221 async_forget(opening_request); 222 return ret; 223 } 224 225 /* Wait for the answer. */ 226 sysarg_t opening_request_rc; 227 async_wait_for(opening_request, &opening_request_rc); 228 229 return (int) opening_request_rc; 201 230 } 202 231 … … 317 346 }; 318 347 348 typedef struct { 349 ipc_callid_t caller; 350 ipc_callid_t data_caller; 351 void *buffer; 352 } async_transaction_t; 353 319 354 void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface, 320 355 ipc_callid_t callid, ipc_call_t *call) … … 417 452 ipc_callid_t callid, ipc_call_t *call) 418 453 { 419 usb_iface_t *usb_iface = (usb_iface_t *) iface; 454 assert(fun); 455 assert(iface); 456 assert(call); 457 458 const usb_iface_t *usb_iface = iface; 420 459 421 460 if (!usb_iface->register_endpoint) { … … 424 463 } 425 464 426 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call); 427 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)}; 428 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call); 429 430 const usb_transfer_type_t transfer_type = pack.arr[0]; 431 const usb_direction_t direction = pack.arr[1]; 432 unsigned packets = pack.arr[2]; 433 unsigned interval = pack.arr[3]; 434 435 const int ret = usb_iface->register_endpoint(fun, endpoint, 436 transfer_type, direction, max_packet_size, packets, interval); 437 438 async_answer_0(callid, ret); 465 void *buffer = NULL; 466 size_t size = 0; 467 int rc = async_data_write_accept(&buffer, false, 468 sizeof(usb_endpoint_desc_t), sizeof(usb_endpoint_desc_t), 0, &size); 469 470 if (rc != EOK) { 471 free(buffer); 472 async_answer_0(callid, rc); 473 return; 474 } 475 476 usb_endpoint_desc_t *endpoint_desc = (usb_endpoint_desc_t *) buffer; 477 rc = usb_iface->register_endpoint(fun, endpoint_desc); 478 479 free(buffer); 480 async_answer_0(callid, rc); 439 481 } 440 482 … … 442 484 ipc_callid_t callid, ipc_call_t *call) 443 485 { 444 usb_iface_t *usb_iface = (usb_iface_t *) iface; 486 assert(fun); 487 assert(iface); 488 assert(call); 489 490 const usb_iface_t *usb_iface = iface; 445 491 446 492 if (!usb_iface->unregister_endpoint) { … … 449 495 } 450 496 451 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call); 452 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call); 453 454 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction); 455 456 async_answer_0(callid, rc); 457 } 458 459 typedef struct { 460 ipc_callid_t caller; 461 ipc_callid_t data_caller; 462 void *buffer; 463 } async_transaction_t; 497 void *buffer = NULL; 498 size_t size = 0; 499 int rc = async_data_write_accept(&buffer, false, 500 sizeof(usb_endpoint_desc_t), sizeof(usb_endpoint_desc_t), 0, &size); 501 502 if (rc != EOK) { 503 free(buffer); 504 async_answer_0(callid, rc); 505 return; 506 } 507 508 usb_endpoint_desc_t *endpoint_desc = (usb_endpoint_desc_t *) buffer; 509 usb_iface->unregister_endpoint(fun, endpoint_desc); 510 511 free(buffer); 512 if (rc != EOK) { 513 async_answer_0(callid, rc); 514 } 515 } 464 516 465 517 static void async_transaction_destroy(async_transaction_t *trans) -
uspace/lib/drv/include/usb_iface.h
r04efacc r03936831 57 57 extern int usb_device_remove(async_exch_t *, unsigned port); 58 58 59 extern int usb_register_endpoint(async_exch_t *, usb_endpoint_t, 60 usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned); 61 extern int usb_unregister_endpoint(async_exch_t *, usb_endpoint_t, 62 usb_direction_t); 59 extern int usb_register_endpoint(async_exch_t *, usb_endpoint_desc_t *); 60 extern int usb_unregister_endpoint(async_exch_t *, usb_endpoint_desc_t *); 63 61 extern int usb_read(async_exch_t *, usb_endpoint_t, uint64_t, void *, size_t, 64 62 size_t *); … … 83 81 int (*device_remove)(ddf_fun_t *, unsigned); 84 82 85 int (*register_endpoint)(ddf_fun_t *, usb_endpoint_t, 86 usb_transfer_type_t, usb_direction_t, size_t, unsigned, unsigned); 87 int (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_t, 88 usb_direction_t); 83 int (*register_endpoint)(ddf_fun_t *, usb_endpoint_desc_t *); 84 int (*unregister_endpoint)(ddf_fun_t *, usb_endpoint_desc_t *); 89 85 90 86 int (*read)(ddf_fun_t *, usb_endpoint_t, uint64_t, uint8_t *, size_t, -
uspace/lib/pcm/src/format.c
r04efacc r03936831 41 41 42 42 #include "format.h" 43 44 #define uint8_t_le2host(x) (x)45 #define host2uint8_t_le(x) (x)46 #define uint8_t_be2host(x) (x)47 #define host2uint8_t_be(x) (x)48 43 49 44 #define int8_t_le2host(x) (x) -
uspace/lib/usb/include/usb/descriptor.h
r04efacc r03936831 49 49 USB_DESCTYPE_OTHER_SPEED_CONFIGURATION = 7, 50 50 USB_DESCTYPE_INTERFACE_POWER = 8, 51 /* USB 3.0 types */ 52 USB_DESCTYPE_OTG = 9, 53 USB_DESCTYPE_DEBUG = 0xa, 54 USB_DESCTYPE_IFACE_ASSOC = 0xb, 55 USB_DESCTYPE_BOS = 0xf, 56 USB_DESCTYPE_DEVICE_CAP = 0x10, 51 57 /* Class specific */ 52 58 USB_DESCTYPE_HID = 0x21, … … 54 60 USB_DESCTYPE_HID_PHYSICAL = 0x23, 55 61 USB_DESCTYPE_HUB = 0x29, 62 USB_DESCTYPE_SSPEED_EP_COMPANION = 0x30 56 63 /* USB_DESCTYPE_ = */ 57 64 } usb_descriptor_type_t; … … 217 224 } __attribute__ ((packed)) usb_standard_endpoint_descriptor_t; 218 225 226 /** Superspeed USB endpoint companion descriptor. 227 * See USB 3 specification, section 9.6.7. 228 */ 229 typedef struct { 230 /** Size of this descriptor in bytes */ 231 uint8_t length; 232 /** Descriptor type (USB_DESCTYPE_SSPEED_EP_COMPANION). */ 233 uint8_t descriptor_type; 234 /** The maximum number of packets the endpoint can send 235 * or receive as part of a burst. Valid values are from 0 to 15. 236 * The endpoint can only burst max_burst + 1 packets at a time. 237 */ 238 uint8_t max_burst; 239 /** Valid only for bulk and isochronous endpoints. 240 * For bulk endpoints, this field contains the amount of streams 241 * supported by the endpoint. 242 * For isochronous endpoints, this field contains either maximum 243 * number of packets supported within a service interval, or 244 * whether an isochronous endpoint companion descriptor follows. 245 */ 246 uint8_t attributes; 247 /** The total number of bytes this endpoint will transfer 248 * every service interval (SI). 249 * This field is only valid for periodic endpoints. 250 */ 251 uint16_t bytes_per_interval; 252 } __attribute__ ((packed)) usb_superspeed_endpoint_companion_descriptor_t; 253 219 254 /** Part of standard USB HID descriptor specifying one class descriptor. 220 255 * -
uspace/lib/usb/include/usb/request.h
r04efacc r03936831 112 112 const usb_device_request_setup_packet_t *request); 113 113 114 #define GET_DEVICE_DESC(size) \ 115 { \ 116 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \ 117 | (USB_REQUEST_TYPE_STANDARD << 5) \ 118 | USB_REQUEST_RECIPIENT_DEVICE, \ 119 .request = USB_DEVREQ_GET_DESCRIPTOR, \ 120 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \ 121 .index = uint16_host2usb(0), \ 122 .length = uint16_host2usb(size), \ 123 }; 124 125 #define SET_ADDRESS(address) \ 126 { \ 127 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \ 128 | (USB_REQUEST_TYPE_STANDARD << 5) \ 129 | USB_REQUEST_RECIPIENT_DEVICE, \ 130 .request = USB_DEVREQ_SET_ADDRESS, \ 131 .value = uint16_host2usb(address), \ 132 .index = uint16_host2usb(0), \ 133 .length = uint16_host2usb(0), \ 134 }; 135 136 #define CTRL_PIPE_MIN_PACKET_SIZE 8 137 114 138 #endif 115 139 /** -
uspace/lib/usb/include/usb/usb.h
r04efacc r03936831 81 81 /** USB 2.0 high speed (480Mbits/s). */ 82 82 USB_SPEED_HIGH, 83 /** USB 3.0 super speed (5Gbits/s). */ 84 USB_SPEED_SUPER, 83 85 /** Psuedo-speed serving as a boundary. */ 84 86 USB_SPEED_MAX … … 113 115 typedef int16_t usb_address_t; 114 116 117 typedef struct { 118 usb_address_t address; 119 unsigned port; 120 } usb_tt_address_t; 121 115 122 /** Default USB address. */ 116 123 #define USB_ADDRESS_DEFAULT 0 … … 157 164 158 165 159 /** USB complete address type. 166 /** USB complete address type. 160 167 * Pair address + endpoint is identification of transaction recipient. 161 168 */ … … 167 174 uint32_t packed; 168 175 } usb_target_t; 176 177 /** Description of usb endpoint. 178 */ 179 typedef struct { 180 /** Endpoint number. */ 181 usb_endpoint_t endpoint_no; 182 183 /** Endpoint transfer type. */ 184 usb_transfer_type_t transfer_type; 185 186 /** Endpoint direction. */ 187 usb_direction_t direction; 188 189 /** Maximum packet size for the endpoint. */ 190 size_t max_packet_size; 191 192 /** Number of packets per frame/uframe. 193 * Only valid for HS INT and ISO transfers. All others should set to 1*/ 194 unsigned packets; 195 196 struct { 197 unsigned polling_interval; 198 } usb2; 199 } usb_endpoint_desc_t; 169 200 170 201 /** Check USB target for allowed values (address and endpoint). -
uspace/lib/usb/src/usb.c
r04efacc r03936831 44 44 [USB_SPEED_FULL] = "full", 45 45 [USB_SPEED_HIGH] = "high", 46 [USB_SPEED_SUPER] = "super", 46 47 }; 47 48 -
uspace/lib/usbdev/include/usb/dev/pipes.h
r04efacc r03936831 50 50 */ 51 51 typedef struct { 52 /** Endpoint number. */ 53 usb_endpoint_t endpoint_no; 54 55 /** Endpoint transfer type. */ 56 usb_transfer_type_t transfer_type; 57 58 /** Endpoint direction. */ 59 usb_direction_t direction; 60 61 /** Maximum packet size for the endpoint. */ 62 size_t max_packet_size; 63 64 /** Number of packets per frame/uframe. 65 * Only valid for HS INT and ISO transfers. All others should set to 1*/ 66 unsigned packets; 67 52 /** Endpoint description */ 53 usb_endpoint_desc_t desc; 68 54 /** Whether to automatically reset halt on the endpoint. 69 55 * Valid only for control endpoint zero. 70 56 */ 71 57 bool auto_reset_halt; 72 73 58 /** The connection used for sending the data. */ 74 59 usb_dev_session_t *bus_session; -
uspace/lib/usbdev/src/devdrv.c
r04efacc r03936831 56 56 /** Connection to device on USB bus */ 57 57 usb_dev_session_t *bus_session; 58 58 59 59 /** devman handle */ 60 60 devman_handle_t handle; 61 61 62 62 /** The default control pipe. */ 63 63 usb_pipe_t ctrl_pipe; 64 64 65 65 /** Other endpoint pipes. 66 66 * … … 69 69 */ 70 70 usb_endpoint_mapping_t *pipes; 71 71 72 72 /** Number of other endpoint pipes. */ 73 73 size_t pipes_count; 74 74 75 75 /** Current interface. 76 76 * … … 79 79 */ 80 80 int interface_no; 81 81 82 82 /** Alternative interfaces. */ 83 83 usb_alternate_interfaces_t alternate_interfaces; 84 84 85 85 /** Some useful descriptors for USB device. */ 86 86 usb_device_descriptors_t descriptors; 87 87 88 88 /** Generic DDF device backing this one. DO NOT TOUCH! */ 89 89 ddf_dev_t *ddf_dev; 90 90 91 91 /** Custom driver data. 92 92 * … … 146 146 return rc; 147 147 } 148 148 149 149 /* Change current alternative */ 150 150 usb_dev->alternate_interfaces.current = alternate_setting; … … 296 296 assert(usb_dev); 297 297 assert(usb_dev->pipes || usb_dev->pipes_count == 0); 298 298 299 299 /* Destroy the pipes. */ 300 300 for (size_t i = 0; i < usb_dev->pipes_count; ++i) { … … 304 304 usb_pipe_unregister(&usb_dev->pipes[i].pipe); 305 305 } 306 306 307 307 free(usb_dev->pipes); 308 308 usb_dev->pipes = NULL; … … 332 332 assert(usb_dev); 333 333 for (unsigned i = 0; i < usb_dev->pipes_count; ++i) { 334 if (usb_dev->pipes[i].pipe. endpoint_no == ep)334 if (usb_dev->pipes[i].pipe.desc.endpoint_no == ep) 335 335 return &usb_dev->pipes[i]; 336 336 } … … 462 462 assert(handle); 463 463 assert(iface_no); 464 464 465 465 async_exch_t *exch = async_exchange_begin(sess); 466 466 if (!exch) 467 467 return EPARTY; 468 468 469 469 int ret = usb_get_my_device_handle(exch, handle); 470 470 if (ret == EOK) { … … 475 475 } 476 476 } 477 477 478 478 async_exchange_end(exch); 479 479 return ret; … … 502 502 return ENOMEM; 503 503 } 504 504 505 505 return usb_device_init(usb_dev, ddf_dev, desc, err, h, iface_no); 506 506 } -
uspace/lib/usbdev/src/devpoll.c
r04efacc r03936831 96 96 (int) mapping->interface->interface_subclass, 97 97 (int) mapping->interface->interface_protocol, 98 data->request_size, pipe-> max_packet_size);98 data->request_size, pipe->desc.max_packet_size); 99 99 } 100 100 … … 128 128 usb_request_clear_endpoint_halt( 129 129 usb_device_get_default_pipe(data->dev), 130 pipe-> endpoint_no);130 pipe->desc.endpoint_no); 131 131 } 132 132 … … 156 156 157 157 /* Take a rest before next request. */ 158 158 159 159 // FIXME TODO: This is broken, the time is in ms not us. 160 160 // but first we need to fix drivers to actually stop using this, … … 216 216 if (request_size == 0) 217 217 return EINVAL; 218 219 if (!epm || (epm->pipe. transfer_type != USB_TRANSFER_INTERRUPT) ||220 (epm->pipe.d irection != USB_DIRECTION_IN))218 219 if (!epm || (epm->pipe.desc.transfer_type != USB_TRANSFER_INTERRUPT) || 220 (epm->pipe.desc.direction != USB_DIRECTION_IN)) 221 221 return EINVAL; 222 222 223 223 224 224 polling_data_t *polling_data = malloc(sizeof(polling_data_t)); -
uspace/lib/usbdev/src/pipes.c
r04efacc r03936831 51 51 assert(pipe != NULL); 52 52 53 if (!pipe->auto_reset_halt || (pipe-> endpoint_no != 0)) {53 if (!pipe->auto_reset_halt || (pipe->desc.endpoint_no != 0)) { 54 54 return; 55 55 } … … 88 88 } 89 89 90 if ((pipe->d irection != USB_DIRECTION_BOTH)91 || (pipe-> transfer_type != USB_TRANSFER_CONTROL)) {90 if ((pipe->desc.direction != USB_DIRECTION_BOTH) 91 || (pipe->desc.transfer_type != USB_TRANSFER_CONTROL)) { 92 92 return EBADF; 93 93 } … … 98 98 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 99 99 size_t act_size = 0; 100 const int rc = usb_read(exch, pipe-> endpoint_no, setup_packet, buffer,100 const int rc = usb_read(exch, pipe->desc.endpoint_no, setup_packet, buffer, 101 101 buffer_size, &act_size); 102 102 async_exchange_end(exch); … … 142 142 } 143 143 144 if ((pipe->d irection != USB_DIRECTION_BOTH)145 || (pipe-> transfer_type != USB_TRANSFER_CONTROL)) {144 if ((pipe->desc.direction != USB_DIRECTION_BOTH) 145 || (pipe->desc.transfer_type != USB_TRANSFER_CONTROL)) { 146 146 return EBADF; 147 147 } … … 152 152 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 153 153 const int rc = usb_write(exch, 154 pipe-> endpoint_no, setup_packet, buffer, buffer_size);154 pipe->desc.endpoint_no, setup_packet, buffer, buffer_size); 155 155 async_exchange_end(exch); 156 156 … … 183 183 } 184 184 185 if (pipe->d irection != USB_DIRECTION_IN) {186 return EBADF; 187 } 188 189 if (pipe-> transfer_type == USB_TRANSFER_CONTROL) {185 if (pipe->desc.direction != USB_DIRECTION_IN) { 186 return EBADF; 187 } 188 189 if (pipe->desc.transfer_type == USB_TRANSFER_CONTROL) { 190 190 return EBADF; 191 191 } 192 192 193 193 /* Isochronous transfer are not supported (yet) */ 194 if (pipe-> transfer_type != USB_TRANSFER_INTERRUPT &&195 pipe-> transfer_type != USB_TRANSFER_BULK)194 if (pipe->desc.transfer_type != USB_TRANSFER_INTERRUPT && 195 pipe->desc.transfer_type != USB_TRANSFER_BULK) 196 196 return ENOTSUP; 197 197 … … 199 199 size_t act_size = 0; 200 200 const int rc = 201 usb_read(exch, pipe-> endpoint_no, 0, buffer, size, &act_size);201 usb_read(exch, pipe->desc.endpoint_no, 0, buffer, size, &act_size); 202 202 async_exchange_end(exch); 203 203 … … 224 224 } 225 225 226 if (pipe->d irection != USB_DIRECTION_OUT) {227 return EBADF; 228 } 229 230 if (pipe-> transfer_type == USB_TRANSFER_CONTROL) {226 if (pipe->desc.direction != USB_DIRECTION_OUT) { 227 return EBADF; 228 } 229 230 if (pipe->desc.transfer_type == USB_TRANSFER_CONTROL) { 231 231 return EBADF; 232 232 } 233 233 234 234 /* Isochronous transfer are not supported (yet) */ 235 if (pipe-> transfer_type != USB_TRANSFER_INTERRUPT &&236 pipe-> transfer_type != USB_TRANSFER_BULK)235 if (pipe->desc.transfer_type != USB_TRANSFER_INTERRUPT && 236 pipe->desc.transfer_type != USB_TRANSFER_BULK) 237 237 return ENOTSUP; 238 238 239 239 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 240 const int rc = usb_write(exch, pipe-> endpoint_no, 0, buffer, size);240 const int rc = usb_write(exch, pipe->desc.endpoint_no, 0, buffer, size); 241 241 async_exchange_end(exch); 242 242 return rc; … … 258 258 assert(pipe); 259 259 260 pipe-> endpoint_no = endpoint_no;261 pipe-> transfer_type = transfer_type;262 pipe-> packets = packets;263 pipe-> max_packet_size = max_packet_size;264 pipe->d irection = direction;260 pipe->desc.endpoint_no = endpoint_no; 261 pipe->desc.transfer_type = transfer_type; 262 pipe->desc.packets = packets; 263 pipe->desc.max_packet_size = max_packet_size; 264 pipe->desc.direction = direction; 265 265 pipe->auto_reset_halt = false; 266 266 pipe->bus_session = bus_session; … … 297 297 assert(pipe); 298 298 assert(pipe->bus_session); 299 300 pipe->desc.usb2.polling_interval = interval; 299 301 async_exch_t *exch = async_exchange_begin(pipe->bus_session); 300 302 if (!exch) 301 303 return ENOMEM; 302 const int ret = usb_register_endpoint(exch, pipe->endpoint_no, 303 pipe->transfer_type, pipe->direction, pipe->max_packet_size,304 pipe->packets, interval); 304 305 const int ret = usb_register_endpoint(exch, &pipe->desc); 306 305 307 async_exchange_end(exch); 306 308 return ret; … … 319 321 if (!exch) 320 322 return ENOMEM; 321 const int ret = usb_unregister_endpoint(exch, pipe->endpoint_no, 322 pipe->direction); 323 324 const int ret = usb_unregister_endpoint(exch, &pipe->desc); 325 323 326 async_exchange_end(exch); 324 327 return ret; -
uspace/lib/usbdev/src/pipesinit.c
r04efacc r03936831 288 288 if (config_descriptor == NULL) 289 289 return EBADMEM; 290 290 291 291 if (config_descriptor_size < 292 292 sizeof(usb_standard_configuration_descriptor_t)) { … … 343 343 static_assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE); 344 344 345 if ((pipe->d irection != USB_DIRECTION_BOTH) ||346 (pipe-> transfer_type != USB_TRANSFER_CONTROL) ||347 (pipe-> endpoint_no != 0)) {345 if ((pipe->desc.direction != USB_DIRECTION_BOTH) || 346 (pipe->desc.transfer_type != USB_TRANSFER_CONTROL) || 347 (pipe->desc.endpoint_no != 0)) { 348 348 return EINVAL; 349 349 } … … 369 369 } 370 370 371 pipe-> max_packet_size371 pipe->desc.max_packet_size 372 372 = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET]; 373 373 -
uspace/lib/usbdev/src/request.c
r04efacc r03936831 844 844 } 845 845 return usb_request_clear_endpoint_halt(ctrl_pipe, 846 target_pipe-> endpoint_no);846 target_pipe->desc.endpoint_no); 847 847 } 848 848 … … 858 858 { 859 859 uint16_t status_tmp; 860 uint16_t pipe_index = (uint16_t) pipe-> endpoint_no;860 uint16_t pipe_index = (uint16_t) pipe->desc.endpoint_no; 861 861 int rc = usb_request_get_status(ctrl_pipe, 862 862 USB_REQUEST_RECIPIENT_ENDPOINT, uint16_host2usb(pipe_index), -
uspace/lib/usbhost/Makefile
r04efacc r03936831 39 39 src/endpoint.c \ 40 40 src/hcd.c \ 41 src/usb_bus.c \ 41 src/bus.c \ 42 src/usb2_bus.c \ 43 src/bandwidth.c \ 42 44 src/usb_transfer_batch.c 43 45 -
uspace/lib/usbhost/include/usb/host/ddf_helpers.h
r04efacc r03936831 38 38 39 39 #include <usb/host/hcd.h> 40 #include <usb/host/ usb_bus.h>40 #include <usb/host/bus.h> 41 41 #include <usb/usb.h> 42 42 … … 45 45 #include <device/hw_res_parsed.h> 46 46 47 typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, bool); 47 typedef int (*driver_init_t)(hcd_t *, const hw_res_list_parsed_t *, ddf_dev_t *); 48 typedef int (*irq_code_gen_t)(irq_code_t *, hcd_t *, const hw_res_list_parsed_t *); 49 typedef int (*claim_t)(hcd_t *, ddf_dev_t *); 50 typedef int (*driver_start_t)(hcd_t *, bool irq); 51 typedef int (*setup_root_hub_t)(hcd_t *, ddf_dev_t *); 52 53 typedef void (*driver_stop_t)(hcd_t *); 48 54 typedef void (*driver_fini_t)(hcd_t *); 49 typedef int (*claim_t)(ddf_dev_t *);50 typedef int (*irq_code_gen_t)(irq_code_t *, const hw_res_list_parsed_t *);51 55 56 /** 57 * All callbacks are optional. 58 */ 52 59 typedef struct { 53 60 hcd_ops_t ops; 54 claim_t claim;55 usb_speed_t hc_speed;56 driver_init_t init;57 driver_fini_t fini;58 interrupt_handler_t *irq_handler;59 irq_code_gen_t irq_code_gen;60 61 const char *name; 62 63 interrupt_handler_t *irq_handler; /**< Handler of IRQ. Do have generic implementation. */ 64 65 /* Initialization sequence: */ 66 driver_init_t init; /**< Initialize internal structures, memory */ 67 claim_t claim; /**< Claim device from BIOS */ 68 irq_code_gen_t irq_code_gen; /**< Generate IRQ handling code */ 69 driver_start_t start; /**< Start the HC */ 70 setup_root_hub_t setup_root_hub; /**< Setup the root hub */ 71 72 /* Destruction sequence: */ 73 driver_stop_t stop; /**< Stop the HC (counterpart of start) */ 74 driver_fini_t fini; /**< Destroy internal structures (counterpart of init) */ 61 75 } ddf_hc_driver_t; 62 76 63 77 int hcd_ddf_add_hc(ddf_dev_t *device, const ddf_hc_driver_t *driver); 64 78 65 int hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed, 66 size_t bw, bw_count_func_t bw_count); 79 int hcd_ddf_setup_hc(ddf_dev_t *device); 67 80 void hcd_ddf_clean_hc(ddf_dev_t *device); 68 int hcd_ddf_setup_root_hub(ddf_dev_t *device); 81 82 int hcd_setup_virtual_root_hub(hcd_t *, ddf_dev_t *); 83 84 device_t *hcd_ddf_device_create(ddf_dev_t *, size_t); 85 void hcd_ddf_device_destroy(device_t *); 86 int hcd_ddf_device_explore(hcd_t *, device_t *); 69 87 70 88 hcd_t *dev_to_hcd(ddf_dev_t *dev); … … 75 93 const hw_res_list_parsed_t *hw_res, 76 94 interrupt_handler_t handler, 77 i nt (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *));95 irq_code_gen_t gen_irq_code); 78 96 void ddf_hcd_gen_irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev); 79 97 -
uspace/lib/usbhost/include/usb/host/endpoint.h
r04efacc r03936831 32 32 /** @file 33 33 * 34 * Endpoint structure is tightly coupled to the bus. The bus controls the 35 * life-cycle of endpoint. In order to keep endpoints lightweight, operations 36 * on endpoints are part of the bus structure. 37 * 34 38 */ 35 39 #ifndef LIBUSBHOST_HOST_ENDPOINT_H … … 42 46 #include <atomic.h> 43 47 48 typedef struct bus bus_t; 49 typedef struct device device_t; 50 44 51 /** Host controller side endpoint structure. */ 45 52 typedef struct endpoint { 53 /** Managing bus */ 54 bus_t *bus; 46 55 /** Reference count. */ 47 atomic_t refcnt; 56 atomic_t refcnt; 48 57 /** Part of linked list. */ 49 58 link_t link; 59 /** USB device */ 60 device_t *device; 50 61 /** USB address. */ 51 usb_address_t address; 52 /** USB endpoint number. */ 53 usb_endpoint_t endpoint; 62 usb_target_t target; 54 63 /** Communication direction. */ 55 64 usb_direction_t direction; … … 62 71 /** Additional opportunities per uframe */ 63 72 unsigned packets; 64 /** Necessarybandwidth. */73 /** Reserved bandwidth. */ 65 74 size_t bandwidth; 66 75 /** Value of the toggle bit. */ 67 76 unsigned toggle:1; 68 77 /** True if there is a batch using this scheduled for this endpoint. */ 69 volatilebool active;78 bool active; 70 79 /** Protects resources and active status changes. */ 71 80 fibril_mutex_t guard; 72 81 /** Signals change of active status. */ 73 82 fibril_condvar_t avail; 74 /** High speed TT data */ 75 struct { 76 usb_address_t address; 77 unsigned port; 78 } tt; 79 /** Optional device specific data. */ 80 struct { 81 /** Device specific data. */ 82 void *data; 83 /** Callback to get the value of toggle bit. */ 84 int (*toggle_get)(void *); 85 /** Callback to set the value of toggle bit. */ 86 void (*toggle_set)(void *, int); 87 } hc_data; 83 84 /* This structure is meant to be extended by overriding. */ 88 85 } endpoint_t; 89 86 90 extern endpoint_t *endpoint_create(usb_address_t, usb_endpoint_t, 91 usb_direction_t, usb_transfer_type_t, usb_speed_t, size_t, unsigned int, 92 size_t, usb_address_t, unsigned int); 93 extern void endpoint_destroy(endpoint_t *); 87 extern void endpoint_init(endpoint_t *, bus_t *); 94 88 95 89 extern void endpoint_add_ref(endpoint_t *); 96 90 extern void endpoint_del_ref(endpoint_t *); 97 98 extern void endpoint_set_hc_data(endpoint_t *, void *, int (*)(void *),99 void (*)(void *, int));100 extern void endpoint_clear_hc_data(endpoint_t *);101 91 102 92 extern void endpoint_use(endpoint_t *); … … 104 94 105 95 extern int endpoint_toggle_get(endpoint_t *); 106 extern void endpoint_toggle_set(endpoint_t *, int);96 extern void endpoint_toggle_set(endpoint_t *, unsigned); 107 97 108 98 /** list_get_instance wrapper. -
uspace/lib/usbhost/include/usb/host/hcd.h
r04efacc r03936831 38 38 39 39 #include <usb/host/endpoint.h> 40 #include <usb/host/ usb_bus.h>40 #include <usb/host/bus.h> 41 41 #include <usb/host/usb_transfer_batch.h> 42 42 #include <usb/usb.h> … … 50 50 51 51 typedef int (*schedule_hook_t)(hcd_t *, usb_transfer_batch_t *); 52 typedef int (*ep_add_hook_t)(hcd_t *, endpoint_t *);53 typedef void (*ep_remove_hook_t)(hcd_t *, endpoint_t *);54 52 typedef void (*interrupt_hook_t)(hcd_t *, uint32_t); 55 53 typedef int (*status_hook_t)(hcd_t *, uint32_t *); 54 typedef int (*address_device_hook_t)(hcd_t *, usb_speed_t, usb_tt_address_t, usb_address_t *); 56 55 57 56 typedef struct { 58 57 /** Transfer scheduling, implement in device driver. */ 59 58 schedule_hook_t schedule; 60 /** Hook called upon registering new endpoint. */61 ep_add_hook_t ep_add_hook;62 /** Hook called upon removing of an endpoint. */63 ep_remove_hook_t ep_remove_hook;64 59 /** Hook to be called on device interrupt, passes ARG1 */ 65 60 interrupt_hook_t irq_hook; 66 61 /** Periodic polling hook */ 67 62 status_hook_t status_hook; 63 /** Hook to setup device address */ 64 address_device_hook_t address_device; 68 65 } hcd_ops_t; 69 66 … … 71 68 struct hcd { 72 69 /** Endpoint manager. */ 73 usb_bus_tbus;70 bus_t *bus; 74 71 75 72 /** Interrupt replacement fibril */ … … 78 75 /** Driver implementation */ 79 76 hcd_ops_t ops; 77 80 78 /** Device specific driver data. */ 81 79 void * driver_data; 82 80 }; 83 81 84 extern void hcd_init(hcd_t * , usb_speed_t, size_t, bw_count_func_t);82 extern void hcd_init(hcd_t *); 85 83 86 84 static inline void hcd_set_implementation(hcd_t *hcd, void *data, 87 const hcd_ops_t *ops )85 const hcd_ops_t *ops, bus_t *bus) 88 86 { 89 87 assert(hcd); … … 91 89 hcd->driver_data = data; 92 90 hcd->ops = *ops; 91 hcd->bus = bus; 93 92 } else { 94 93 memset(&hcd->ops, 0, sizeof(hcd->ops)); … … 104 103 extern usb_address_t hcd_request_address(hcd_t *, usb_speed_t); 105 104 106 extern int hcd_release_address(hcd_t *, usb_address_t);107 108 extern int hcd_reserve_default_address(hcd_t *, usb_speed_t);109 110 static inline int hcd_release_default_address(hcd_t *hcd)111 {112 return hcd_release_address(hcd, USB_ADDRESS_DEFAULT);113 }114 115 105 extern int hcd_add_ep(hcd_t *, usb_target_t, usb_direction_t, 116 usb_transfer_type_t, size_t, unsigned int, size_t, usb_address_t, 117 unsigned int); 106 usb_transfer_type_t, size_t, unsigned int, size_t, usb_tt_address_t); 118 107 119 108 extern int hcd_remove_ep(hcd_t *, usb_target_t, usb_direction_t); -
uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h
r04efacc r03936831 89 89 */ 90 90 #define USB_TRANSFER_BATCH_ARGS(batch) \ 91 (batch).ep-> address, (batch).ep->endpoint, \91 (batch).ep->target.address, (batch).ep->target.endpoint, \ 92 92 usb_str_speed((batch).ep->speed), \ 93 93 usb_str_transfer_type_short((batch).ep->transfer_type), \ -
uspace/lib/usbhost/src/ddf_helpers.c
r04efacc r03936831 35 35 36 36 #include <usb/classes/classes.h> 37 #include <usb/host/bus.h> 37 38 #include <usb/debug.h> 38 39 #include <usb/descriptor.h> … … 49 50 #include <fibril_synch.h> 50 51 #include <macros.h> 51 #include <stdio.h>52 52 #include <stdlib.h> 53 53 #include <str_error.h> … … 56 56 #include "ddf_helpers.h" 57 57 58 #define CTRL_PIPE_MIN_PACKET_SIZE 859 60 typedef struct usb_dev {61 link_t link;62 list_t devices;63 fibril_mutex_t guard;64 ddf_fun_t *fun;65 usb_address_t address;66 usb_speed_t speed;67 usb_address_t tt_address;68 unsigned port;69 } usb_dev_t;70 71 58 typedef struct hc_dev { 72 59 ddf_fun_t *ctl_fun; 73 60 hcd_t hcd; 74 usb_dev_t *root_hub;75 61 } hc_dev_t; 76 62 … … 91 77 92 78 93 static int hcd_ddf_new_device( ddf_dev_t *device, usb_dev_t *hub, unsigned port);94 static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);79 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub_dev, unsigned port); 80 static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, unsigned port); 95 81 96 82 … … 99 85 /** Register endpoint interface function. 100 86 * @param fun DDF function. 101 * @param address USB address of the device. 102 * @param endpoint USB endpoint number to be registered. 103 * @param transfer_type Endpoint's transfer type. 104 * @param direction USB communication direction the endpoint is capable of. 105 * @param max_packet_size Maximu size of packets the endpoint accepts. 106 * @param interval Preferred timeout between communication. 87 * @param endpoint_desc Endpoint description. 107 88 * @return Error code. 108 89 */ 109 90 static int register_endpoint( 110 ddf_fun_t *fun, usb_endpoint_t endpoint, 111 usb_transfer_type_t transfer_type, usb_direction_t direction, 112 size_t max_packet_size, unsigned packets, unsigned interval) 91 ddf_fun_t *fun, usb_endpoint_desc_t *endpoint_desc) 113 92 { 114 93 assert(fun); 115 94 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 116 usb_dev_t *dev = ddf_fun_data_get(fun);95 device_t *dev = ddf_fun_data_get(fun); 117 96 assert(hcd); 97 assert(hcd->bus); 118 98 assert(dev); 119 const size_t size = max_packet_size; 120 const usb_target_t target = 121 {{.address = dev->address, .endpoint = endpoint}}; 99 100 const size_t size = endpoint_desc->max_packet_size; 122 101 123 102 usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n", 124 dev->address, endpoint, usb_str_transfer_type(transfer_type), 125 usb_str_direction(direction), max_packet_size, interval); 126 127 return hcd_add_ep(hcd, target, direction, transfer_type, 128 max_packet_size, packets, size, dev->tt_address, dev->port); 129 } 130 131 /** Unregister endpoint interface function. 132 * @param fun DDF function. 133 * @param address USB address of the endpoint. 134 * @param endpoint USB endpoint number. 135 * @param direction Communication direction of the enpdoint to unregister. 136 * @return Error code. 137 */ 103 dev->address, endpoint_desc->endpoint_no, 104 usb_str_transfer_type(endpoint_desc->transfer_type), 105 usb_str_direction(endpoint_desc->direction), 106 endpoint_desc->max_packet_size, endpoint_desc->usb2.polling_interval); 107 108 return bus_add_ep(hcd->bus, dev, endpoint_desc->endpoint_no, 109 endpoint_desc->direction, endpoint_desc->transfer_type, 110 endpoint_desc->max_packet_size, endpoint_desc->packets, 111 size); 112 } 113 114 /** Unregister endpoint interface function. 115 * @param fun DDF function. 116 * @param endpoint_desc Endpoint description. 117 * @return Error code. 118 */ 138 119 static int unregister_endpoint( 139 ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction)120 ddf_fun_t *fun, usb_endpoint_desc_t *endpoint_desc) 140 121 { 141 122 assert(fun); 142 123 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 143 usb_dev_t *dev = ddf_fun_data_get(fun);124 device_t *dev = ddf_fun_data_get(fun); 144 125 assert(hcd); 126 assert(hcd->bus); 145 127 assert(dev); 146 const usb_target_t target = 147 {{.address = dev->address, .endpoint = endpoint}}; 128 129 const usb_target_t target = {{ 130 .address = dev->address, 131 .endpoint = endpoint_desc->endpoint_no 132 }}; 133 148 134 usb_log_debug("Unregister endpoint %d:%d %s.\n", 149 dev->address, endpoint, usb_str_direction(direction)); 150 return hcd_remove_ep(hcd, target, direction); 135 dev->address, endpoint_desc->endpoint_no, 136 usb_str_direction(endpoint_desc->direction)); 137 return bus_remove_ep(hcd->bus, target, endpoint_desc->direction); 151 138 } 152 139 … … 155 142 assert(fun); 156 143 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 157 usb_dev_t *dev = ddf_fun_data_get(fun);144 device_t *dev = ddf_fun_data_get(fun); 158 145 assert(hcd); 146 assert(hcd->bus); 159 147 assert(dev); 160 148 161 149 usb_log_debug("Device %d requested default address at %s speed\n", 162 150 dev->address, usb_str_speed(speed)); 163 return hcd_reserve_default_address(hcd, speed);151 return bus_reserve_default_address(hcd->bus, speed); 164 152 } 165 153 … … 168 156 assert(fun); 169 157 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun)); 170 usb_dev_t *dev = ddf_fun_data_get(fun);158 device_t *dev = ddf_fun_data_get(fun); 171 159 assert(hcd); 160 assert(hcd->bus); 172 161 assert(dev); 173 162 174 163 usb_log_debug("Device %d released default address\n", dev->address); 175 return hcd_release_default_address(hcd);164 return bus_release_default_address(hcd->bus); 176 165 } 177 166 178 167 static int device_enumerate(ddf_fun_t *fun, unsigned port) 168 { 169 assert(fun); 170 ddf_dev_t *hc = ddf_fun_get_dev(fun); 171 assert(hc); 172 hcd_t *hcd = dev_to_hcd(hc); 173 assert(hcd); 174 device_t *hub = ddf_fun_data_get(fun); 175 assert(hub); 176 177 usb_log_debug("Hub %d reported a new USB device on port: %u\n", 178 hub->address, port); 179 return hcd_ddf_new_device(hcd, hc, hub, port); 180 } 181 182 static int device_remove(ddf_fun_t *fun, unsigned port) 179 183 { 180 184 assert(fun); 181 185 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 182 usb_dev_t *dev = ddf_fun_data_get(fun); 183 assert(ddf_dev); 184 assert(dev); 185 usb_log_debug("Hub %d reported a new USB device on port: %u\n", 186 dev->address, port); 187 return hcd_ddf_new_device(ddf_dev, dev, port); 188 } 189 190 static int device_remove(ddf_fun_t *fun, unsigned port) 191 { 192 assert(fun); 193 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun); 194 usb_dev_t *dev = ddf_fun_data_get(fun); 186 device_t *dev = ddf_fun_data_get(fun); 195 187 assert(ddf_dev); 196 188 assert(dev); … … 229 221 { 230 222 assert(fun); 231 usb_dev_t *usb_dev = ddf_fun_data_get(fun);232 assert( usb_dev);223 device_t *dev = ddf_fun_data_get(fun); 224 assert(dev); 233 225 const usb_target_t target = {{ 234 .address = usb_dev->address,226 .address = dev->address, 235 227 .endpoint = endpoint, 236 228 }}; … … 255 247 { 256 248 assert(fun); 257 usb_dev_t *usb_dev = ddf_fun_data_get(fun);258 assert( usb_dev);249 device_t *dev = ddf_fun_data_get(fun); 250 assert(dev); 259 251 const usb_target_t target = {{ 260 .address = usb_dev->address,252 .address = dev->address, 261 253 .endpoint = endpoint, 262 254 }}; … … 290 282 291 283 /* DDF HELPERS */ 292 293 #define GET_DEVICE_DESC(size) \294 { \295 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \296 | (USB_REQUEST_TYPE_STANDARD << 5) \297 | USB_REQUEST_RECIPIENT_DEVICE, \298 .request = USB_DEVREQ_GET_DESCRIPTOR, \299 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \300 .index = uint16_host2usb(0), \301 .length = uint16_host2usb(size), \302 };303 304 #define SET_ADDRESS(address) \305 { \306 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \307 | (USB_REQUEST_TYPE_STANDARD << 5) \308 | USB_REQUEST_RECIPIENT_DEVICE, \309 .request = USB_DEVREQ_SET_ADDRESS, \310 .value = uint16_host2usb(address), \311 .index = uint16_host2usb(0), \312 .length = uint16_host2usb(0), \313 };314 315 static int hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,316 unsigned port, usb_address_t address, usb_speed_t speed, const char *name,317 const match_id_list_t *mids)318 {319 assert(parent);320 321 char default_name[10] = { 0 }; /* usbxyz-ss */322 if (!name) {323 snprintf(default_name, sizeof(default_name) - 1,324 "usb%u-%cs", address, usb_str_speed(speed)[0]);325 name = default_name;326 }327 328 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);329 if (!fun)330 return ENOMEM;331 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));332 if (!info) {333 ddf_fun_destroy(fun);334 return ENOMEM;335 }336 info->address = address;337 info->speed = speed;338 info->fun = fun;339 info->port = port;340 info->tt_address = hub_dev ? hub_dev->tt_address : -1;341 link_initialize(&info->link);342 list_initialize(&info->devices);343 fibril_mutex_initialize(&info->guard);344 345 if (hub_dev && hub_dev->speed == USB_SPEED_HIGH && usb_speed_is_11(speed))346 info->tt_address = hub_dev->address;347 348 ddf_fun_set_ops(fun, &usb_ops);349 list_foreach(mids->ids, link, const match_id_t, mid) {350 ddf_fun_add_match_id(fun, mid->id, mid->score);351 }352 353 int ret = ddf_fun_bind(fun);354 if (ret != EOK) {355 ddf_fun_destroy(fun);356 return ret;357 }358 359 if (hub_dev) {360 fibril_mutex_lock(&hub_dev->guard);361 list_append(&info->link, &hub_dev->devices);362 fibril_mutex_unlock(&hub_dev->guard);363 } else {364 hc_dev_t *hc_dev = dev_to_hc_dev(parent);365 assert(hc_dev->root_hub == NULL);366 hc_dev->root_hub = info;367 }368 return EOK;369 }370 284 371 285 #define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \ … … 394 308 assert(l); 395 309 assert(d); 396 310 397 311 if (d->vendor_id != 0) { 398 312 /* First, with release number. */ … … 401 315 d->vendor_id, d->product_id, (d->device_version >> 8), 402 316 (d->device_version & 0xff)); 403 317 404 318 /* Next, without release number. */ 405 319 ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x", … … 415 329 416 330 return EOK; 417 418 } 419 420 static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, 331 } 332 333 static int hcd_ddf_remove_device(ddf_dev_t *device, device_t *hub, 421 334 unsigned port) 422 335 { … … 425 338 hcd_t *hcd = dev_to_hcd(device); 426 339 assert(hcd); 340 assert(hcd->bus); 427 341 428 342 hc_dev_t *hc_dev = dev_to_hc_dev(device); … … 431 345 fibril_mutex_lock(&hub->guard); 432 346 433 usb_dev_t *victim = NULL;434 435 list_foreach(hub->devices, link, usb_dev_t, it) {347 device_t *victim = NULL; 348 349 list_foreach(hub->devices, link, device_t, it) { 436 350 if (it->port == port) { 437 351 victim = it; … … 440 354 } 441 355 if (victim) { 356 assert(victim->fun); 442 357 assert(victim->port == port); 358 assert(victim->hub == hub); 443 359 list_remove(&victim->link); 444 360 fibril_mutex_unlock(&hub->guard); … … 446 362 if (ret == EOK) { 447 363 usb_address_t address = victim->address; 364 bus_remove_device(hcd->bus, hcd, victim); 448 365 ddf_fun_destroy(victim->fun); 449 hcd_release_address(hcd, address);366 bus_release_address(hcd->bus, address); 450 367 } else { 451 368 usb_log_warning("Failed to unbind device `%s': %s\n", … … 458 375 } 459 376 460 static int hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port) 461 { 462 assert(device); 463 464 hcd_t *hcd = dev_to_hcd(device); 465 assert(hcd); 466 467 usb_speed_t speed = USB_SPEED_MAX; 468 469 /* This checks whether the default address is reserved and gets speed */ 470 int ret = usb_bus_get_speed(&hcd->bus, USB_ADDRESS_DEFAULT, &speed); 471 if (ret != EOK) { 472 usb_log_error("Failed to verify speed: %s.", str_error(ret)); 473 return ret; 474 } 475 476 usb_log_debug("Found new %s speed USB device.", usb_str_speed(speed)); 477 478 static const usb_target_t default_target = {{ 479 .address = USB_ADDRESS_DEFAULT, 480 .endpoint = 0, 377 device_t *hcd_ddf_device_create(ddf_dev_t *hc, size_t device_size) 378 { 379 /* Create DDF function for the new device */ 380 ddf_fun_t *fun = ddf_fun_create(hc, fun_inner, NULL); 381 if (!fun) 382 return NULL; 383 384 ddf_fun_set_ops(fun, &usb_ops); 385 386 /* Create USB device node for the new device */ 387 device_t *dev = ddf_fun_data_alloc(fun, device_size); 388 if (!dev) { 389 ddf_fun_destroy(fun); 390 return NULL; 391 } 392 393 device_init(dev); 394 dev->fun = fun; 395 return dev; 396 } 397 398 void hcd_ddf_device_destroy(device_t *dev) 399 { 400 assert(dev); 401 assert(dev->fun); 402 ddf_fun_destroy(dev->fun); 403 } 404 405 int hcd_ddf_device_explore(hcd_t *hcd, device_t *device) 406 { 407 int err; 408 match_id_list_t mids; 409 usb_standard_device_descriptor_t desc = { 0 }; 410 411 init_match_ids(&mids); 412 413 usb_target_t control_ep = {{ 414 .address = device->address, 415 .endpoint = 0 481 416 }}; 482 483 const usb_address_t address = hcd_request_address(hcd, speed);484 if (address < 0) {485 usb_log_error("Failed to reserve new address: %s.",486 str_error(address));487 return address;488 }489 490 usb_log_debug("Reserved new address: %d\n", address);491 492 const usb_target_t target = {{493 .address = address,494 .endpoint = 0,495 }};496 497 const usb_address_t tt_address = hub ? hub->tt_address : -1;498 499 /* Add default pipe on default address */500 usb_log_debug("Device(%d): Adding default target(0:0)\n", address);501 ret = hcd_add_ep(hcd,502 default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,503 CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE, 1,504 tt_address, port);505 if (ret != EOK) {506 usb_log_error("Device(%d): Failed to add default target: %s.",507 address, str_error(ret));508 hcd_release_address(hcd, address);509 return ret;510 }511 512 /* Get max packet size for default pipe */513 usb_standard_device_descriptor_t desc = { 0 };514 const usb_device_request_setup_packet_t get_device_desc_8 =515 GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);516 517 // TODO CALLBACKS518 usb_log_debug("Device(%d): Requesting first 8B of device descriptor.",519 address);520 ssize_t got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,521 &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,522 "read first 8 bytes of dev descriptor");523 524 if (got != CTRL_PIPE_MIN_PACKET_SIZE) {525 ret = got < 0 ? got : EOVERFLOW;526 usb_log_error("Device(%d): Failed to get 8B of dev descr: %s.",527 address, str_error(ret));528 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);529 hcd_release_address(hcd, address);530 return ret;531 }532 533 /* Register EP on the new address */534 usb_log_debug("Device(%d): Registering control EP.", address);535 ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,536 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),537 ED_MPS_TRANS_OPPORTUNITIES_GET(uint16_usb2host(desc.max_packet_size)),538 ED_MPS_PACKET_SIZE_GET(uint16_usb2host(desc.max_packet_size)),539 tt_address, port);540 if (ret != EOK) {541 usb_log_error("Device(%d): Failed to register EP0: %s",542 address, str_error(ret));543 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);544 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);545 hcd_release_address(hcd, address);546 return ret;547 }548 549 /* Set new address */550 const usb_device_request_setup_packet_t set_address =551 SET_ADDRESS(target.address);552 553 usb_log_debug("Device(%d): Setting USB address.", address);554 got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,555 NULL, 0, *(uint64_t *)&set_address, "set address");556 557 usb_log_debug("Device(%d): Removing default (0:0) EP.", address);558 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);559 560 if (got != 0) {561 usb_log_error("Device(%d): Failed to set new address: %s.",562 address, str_error(got));563 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);564 hcd_release_address(hcd, address);565 return got;566 }567 417 568 418 /* Get std device descriptor */ … … 571 421 572 422 usb_log_debug("Device(%d): Requesting full device descriptor.", 573 address);574 got = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN,423 device->address); 424 ssize_t got = hcd_send_batch_sync(hcd, control_ep, USB_DIRECTION_IN, 575 425 &desc, sizeof(desc), *(uint64_t *)&get_device_desc, 576 426 "read device descriptor"); 577 if (ret != EOK) { 427 if (got < 0) { 428 err = got < 0 ? got : EOVERFLOW; 578 429 usb_log_error("Device(%d): Failed to set get dev descriptor: %s", 579 address, str_error(ret)); 580 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 581 hcd_release_address(hcd, target.address); 582 return ret; 430 device->address, str_error(err)); 431 goto out; 583 432 } 584 433 585 434 /* Create match ids from the device descriptor */ 586 match_id_list_t mids; 587 init_match_ids(&mids); 588 589 usb_log_debug("Device(%d): Creating match IDs.", address); 590 ret = create_match_ids(&mids, &desc); 591 if (ret != EOK) { 592 usb_log_error("Device(%d): Failed to create match ids: %s", 593 address, str_error(ret)); 594 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 595 hcd_release_address(hcd, target.address); 596 return ret; 597 } 598 599 /* Register device */ 600 usb_log_debug("Device(%d): Registering DDF device.", address); 601 ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids); 435 usb_log_debug("Device(%d): Creating match IDs.", device->address); 436 if ((err = create_match_ids(&mids, &desc))) { 437 usb_log_error("Device(%d): Failed to create match ids: %s", device->address, str_error(err)); 438 goto out; 439 } 440 441 list_foreach(mids.ids, link, const match_id_t, mid) { 442 ddf_fun_add_match_id(device->fun, mid->id, mid->score); 443 } 444 445 out: 602 446 clean_match_ids(&mids); 603 if (ret != EOK) { 604 usb_log_error("Device(%d): Failed to register: %s.", 605 address, str_error(ret)); 606 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH); 607 hcd_release_address(hcd, target.address); 608 } 609 610 return ret; 447 return err; 448 } 449 450 static int hcd_ddf_new_device(hcd_t *hcd, ddf_dev_t *hc, device_t *hub, unsigned port) 451 { 452 int err; 453 assert(hcd); 454 assert(hcd->bus); 455 assert(hub); 456 assert(hc); 457 458 device_t *dev = hcd_ddf_device_create(hc, hcd->bus->device_size); 459 if (!dev) { 460 usb_log_error("Failed to create USB device function."); 461 return ENOMEM; 462 } 463 464 dev->hub = hub; 465 dev->port = port; 466 467 if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) { 468 usb_log_error("Failed to initialize USB dev memory structures."); 469 return err; 470 } 471 472 /* If the driver didn't name the dev when enumerating, 473 * do it in some generic way. 474 */ 475 if (!ddf_fun_get_name(dev->fun)) { 476 device_set_default_name(dev); 477 } 478 479 if ((err = ddf_fun_bind(dev->fun))) { 480 usb_log_error("Device(%d): Failed to register: %s.", dev->address, str_error(err)); 481 goto err_usb_dev; 482 } 483 484 fibril_mutex_lock(&hub->guard); 485 list_append(&dev->link, &hub->devices); 486 fibril_mutex_unlock(&hub->guard); 487 488 return EOK; 489 490 err_usb_dev: 491 hcd_ddf_device_destroy(dev); 492 return err; 611 493 } 612 494 … … 616 498 * @return Error code 617 499 */ 618 int hcd_ddf_setup_root_hub(ddf_dev_t *device) 619 { 620 assert(device); 621 hcd_t *hcd = dev_to_hcd(device); 500 int hcd_setup_virtual_root_hub(hcd_t *hcd, ddf_dev_t *hc) 501 { 502 int err; 503 504 assert(hc); 622 505 assert(hcd); 623 624 hcd_reserve_default_address(hcd, hcd->bus.max_speed); 625 const int ret = hcd_ddf_new_device(device, NULL, 0); 626 hcd_release_default_address(hcd); 627 return ret; 506 assert(hcd->bus); 507 508 if ((err = bus_reserve_default_address(hcd->bus, USB_SPEED_MAX))) { 509 usb_log_error("Failed to reserve default address for roothub setup: %s", str_error(err)); 510 return err; 511 } 512 513 device_t *dev = hcd_ddf_device_create(hc, USB_SPEED_MAX); 514 if (!dev) { 515 usb_log_error("Failed to create function for the root hub."); 516 goto err_default_address; 517 } 518 519 ddf_fun_set_name(dev->fun, "roothub"); 520 521 dev->tt = (usb_tt_address_t) { 522 .address = -1, 523 .port = 0, 524 }; 525 526 /* Assign an address to the device */ 527 if ((err = bus_enumerate_device(hcd->bus, hcd, dev))) { 528 usb_log_error("Failed to enumerate roothub device: %s", str_error(err)); 529 goto err_usb_dev; 530 } 531 532 if ((err = ddf_fun_bind(dev->fun))) { 533 usb_log_error("Failed to register roothub: %s.", str_error(err)); 534 goto err_usb_dev; 535 } 536 537 bus_release_default_address(hcd->bus); 538 return EOK; 539 540 err_usb_dev: 541 hcd_ddf_device_destroy(dev); 542 err_default_address: 543 bus_release_default_address(hcd->bus); 544 return err; 628 545 } 629 546 … … 638 555 * This function does all the ddf work for hc driver. 639 556 */ 640 int hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed, 641 size_t bw, bw_count_func_t bw_count) 557 int hcd_ddf_setup_hc(ddf_dev_t *device) 642 558 { 643 559 assert(device); … … 648 564 return ENOMEM; 649 565 } 650 instance->root_hub = NULL; 651 hcd_init(&instance->hcd, max_speed, bw, bw_count); 566 hcd_init(&instance->hcd); 652 567 653 568 int ret = ENOMEM; … … 748 663 const hw_res_list_parsed_t *hw_res, 749 664 interrupt_handler_t handler, 750 int (*gen_irq_code)(irq_code_t *, const hw_res_list_parsed_t *hw_res)) 751 { 752 665 irq_code_gen_t gen_irq_code) 666 { 753 667 assert(device); 668 669 hcd_t *hcd = dev_to_hcd(device); 670 754 671 if (!handler || !gen_irq_code) 755 672 return ENOTSUP; … … 757 674 irq_code_t irq_code = {0}; 758 675 759 const int irq = gen_irq_code(&irq_code, h w_res);676 const int irq = gen_irq_code(&irq_code, hcd, hw_res); 760 677 if (irq < 0) { 761 678 usb_log_error("Failed to generate IRQ code: %s.\n", … … 777 694 int ret = hcd_ddf_enable_interrupt(device, irq); 778 695 if (ret != EOK) { 779 usb_log_error("Failed to register interrupt handler: %s.\n",696 usb_log_error("Failed to enable interrupts: %s.\n", 780 697 str_error(ret)); 781 698 unregister_interrupt_handler(device, irq_cap); … … 844 761 { 845 762 assert(driver); 846 static const struct { size_t bw; bw_count_func_t bw_count; }bw[] = {847 [USB_SPEED_FULL] = { .bw = BANDWIDTH_AVAILABLE_USB11,848 .bw_count = bandwidth_count_usb11 },849 [USB_SPEED_HIGH] = { .bw = BANDWIDTH_AVAILABLE_USB11,850 .bw_count = bandwidth_count_usb11 },851 };852 763 853 764 int ret = EOK; 854 const usb_speed_t speed = driver->hc_speed;855 if (speed >= ARRAY_SIZE(bw) || bw[speed].bw == 0) {856 usb_log_error("Driver `%s' reported unsupported speed: %s",857 driver->name, usb_str_speed(speed));858 return ENOTSUP;859 }860 765 861 766 hw_res_list_parsed_t hw_res; … … 868 773 } 869 774 870 ret = hcd_ddf_setup_hc(device , speed, bw[speed].bw, bw[speed].bw_count);775 ret = hcd_ddf_setup_hc(device); 871 776 if (ret != EOK) { 872 777 usb_log_error("Failed to setup generic HCD.\n"); 873 hw_res_list_parsed_clean(&hw_res); 874 return ret; 875 } 876 778 goto err_hw_res; 779 } 780 781 hcd_t *hcd = dev_to_hcd(device); 782 783 if (driver->init) 784 ret = driver->init(hcd, &hw_res, device); 785 if (ret != EOK) { 786 usb_log_error("Failed to init HCD.\n"); 787 goto err_hcd; 788 } 789 790 /* Setup interrupts */ 877 791 interrupt_handler_t *irq_handler = 878 792 driver->irq_handler ? driver->irq_handler : ddf_hcd_gen_irq_handler; … … 884 798 } 885 799 800 /* Claim the device from BIOS */ 886 801 if (driver->claim) 887 ret = driver->claim( device);802 ret = driver->claim(hcd, device); 888 803 if (ret != EOK) { 889 usb_log_error("Failed to claim `%s' for driver `%s'", 890 ddf_dev_get_name(device), driver->name); 891 return ret; 892 } 893 894 895 /* Init hw driver */ 896 hcd_t *hcd = dev_to_hcd(device); 897 ret = driver->init(hcd, &hw_res, irqs_enabled); 898 hw_res_list_parsed_clean(&hw_res); 804 usb_log_error("Failed to claim `%s' for driver `%s': %s", 805 ddf_dev_get_name(device), driver->name, str_error(ret)); 806 goto err_irq; 807 } 808 809 /* Start hw driver */ 810 if (driver->start) 811 ret = driver->start(hcd, irqs_enabled); 899 812 if (ret != EOK) { 900 usb_log_error("Failed to init HCD: %s.\n", str_error(ret));901 goto irq_unregister;813 usb_log_error("Failed to start HCD: %s.\n", str_error(ret)); 814 goto err_irq; 902 815 } 903 816 … … 908 821 usb_log_error("Failed to create polling fibril\n"); 909 822 ret = ENOMEM; 910 goto irq_unregister;823 goto err_started; 911 824 } 912 825 fibril_add_ready(hcd->polling_fibril); … … 919 832 * needs to be ready at this time. 920 833 */ 921 ret = hcd_ddf_setup_root_hub(device); 834 if (driver->setup_root_hub) 835 ret = driver->setup_root_hub(hcd, device); 922 836 if (ret != EOK) { 923 837 usb_log_error("Failed to setup HC root hub: %s.\n", 924 838 str_error(ret)); 925 driver->fini(dev_to_hcd(device)); 926 irq_unregister: 927 /* Unregistering non-existent should be ok */ 928 unregister_interrupt_handler(device, irq_cap); 929 hcd_ddf_clean_hc(device); 930 return ret; 839 goto err_polling; 931 840 } 932 841 … … 934 843 driver->name, ddf_dev_get_name(device)); 935 844 return EOK; 936 } 845 846 err_polling: 847 // TODO: Stop the polling fibril (refactor the interrupt_polling func) 848 // 849 err_started: 850 if (driver->stop) 851 driver->stop(hcd); 852 err_irq: 853 unregister_interrupt_handler(device, irq_cap); 854 if (driver->fini) 855 driver->fini(hcd); 856 err_hcd: 857 hcd_ddf_clean_hc(device); 858 err_hw_res: 859 hw_res_list_parsed_clean(&hw_res); 860 return ret; 861 } 862 937 863 /** 938 864 * @} -
uspace/lib/usbhost/src/endpoint.c
r04efacc r03936831 1 1 /* 2 2 * Copyright (c) 2011 Jan Vesely 3 * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz> 3 4 * All rights reserved. 4 5 * … … 35 36 36 37 #include <usb/host/endpoint.h> 38 #include <usb/host/bus.h> 37 39 38 40 #include <assert.h> 41 #include <atomic.h> 42 #include <mem.h> 39 43 #include <stdlib.h> 40 #include <atomic.h>41 44 42 /** Allocate ad initialize endpoint_t structure. 43 * @param address USB address. 44 * @param endpoint USB endpoint number. 45 * @param direction Communication direction. 46 * @param type USB transfer type. 47 * @param speed Communication speed. 48 * @param max_packet_size Maximum size of data packets. 49 * @param bw Required bandwidth. 50 * @return Pointer to initialized endpoint_t structure, NULL on failure. 45 /** Initialize provided endpoint structure. 51 46 */ 52 endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint, 53 usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed, 54 size_t max_packet_size, unsigned packets, size_t bw, 55 usb_address_t tt_address, unsigned tt_p) 47 void endpoint_init(endpoint_t *ep, bus_t *bus) 56 48 { 57 endpoint_t *instance = malloc(sizeof(endpoint_t)); 58 if (instance) { 59 atomic_set(&instance->refcnt, 0); 60 instance->address = address; 61 instance->endpoint = endpoint; 62 instance->direction = direction; 63 instance->transfer_type = type; 64 instance->speed = speed; 65 instance->max_packet_size = max_packet_size; 66 instance->packets = packets; 67 instance->bandwidth = bw; 68 instance->toggle = 0; 69 instance->active = false; 70 instance->tt.address = tt_address; 71 instance->tt.port = tt_p; 72 instance->hc_data.data = NULL; 73 instance->hc_data.toggle_get = NULL; 74 instance->hc_data.toggle_set = NULL; 75 link_initialize(&instance->link); 76 fibril_mutex_initialize(&instance->guard); 77 fibril_condvar_initialize(&instance->avail); 78 } 79 return instance; 49 memset(ep, 0, sizeof(endpoint_t)); 50 51 ep->bus = bus; 52 atomic_set(&ep->refcnt, 0); 53 link_initialize(&ep->link); 54 fibril_mutex_initialize(&ep->guard); 55 fibril_condvar_initialize(&ep->avail); 80 56 } 81 57 82 /** Properly dispose of endpoint_t structure. 83 * @param instance endpoint_t structure. 84 */ 85 void endpoint_destroy(endpoint_t *instance) 58 void endpoint_add_ref(endpoint_t *ep) 86 59 { 87 assert(instance); 88 assert(!instance->active); 89 assert(instance->hc_data.data == NULL); 90 free(instance); 60 atomic_inc(&ep->refcnt); 91 61 } 92 62 93 void endpoint_ add_ref(endpoint_t *instance)63 void endpoint_del_ref(endpoint_t *ep) 94 64 { 95 atomic_inc(&instance->refcnt); 96 } 65 if (atomic_predec(&ep->refcnt) == 0) { 66 if (ep->bus->ops.destroy_endpoint) { 67 ep->bus->ops.destroy_endpoint(ep); 68 } 69 else { 70 assert(!ep->active); 97 71 98 void endpoint_del_ref(endpoint_t *instance) 99 { 100 if (atomic_predec(&instance->refcnt) == 0) 101 endpoint_destroy(instance); 102 } 103 104 /** Set device specific data and hooks. 105 * @param instance endpoint_t structure. 106 * @param data device specific data. 107 * @param toggle_get Hook to call when retrieving value of toggle bit. 108 * @param toggle_set Hook to call when setting the value of toggle bit. 109 */ 110 void endpoint_set_hc_data(endpoint_t *instance, 111 void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int)) 112 { 113 assert(instance); 114 fibril_mutex_lock(&instance->guard); 115 instance->hc_data.data = data; 116 instance->hc_data.toggle_get = toggle_get; 117 instance->hc_data.toggle_set = toggle_set; 118 fibril_mutex_unlock(&instance->guard); 119 } 120 121 /** Clear device specific data and hooks. 122 * @param instance endpoint_t structure. 123 * @note This function does not free memory pointed to by data pointer. 124 */ 125 void endpoint_clear_hc_data(endpoint_t *instance) 126 { 127 assert(instance); 128 endpoint_set_hc_data(instance, NULL, NULL, NULL); 72 /* Assume mostly the eps will be allocated by malloc. */ 73 free(ep); 74 } 75 } 129 76 } 130 77 131 78 /** Mark the endpoint as active and block access for further fibrils. 132 * @param instanceendpoint_t structure.79 * @param ep endpoint_t structure. 133 80 */ 134 void endpoint_use(endpoint_t * instance)81 void endpoint_use(endpoint_t *ep) 135 82 { 136 assert( instance);83 assert(ep); 137 84 /* Add reference for active endpoint. */ 138 endpoint_add_ref( instance);139 fibril_mutex_lock(& instance->guard);140 while ( instance->active)141 fibril_condvar_wait(& instance->avail, &instance->guard);142 instance->active = true;143 fibril_mutex_unlock(& instance->guard);85 endpoint_add_ref(ep); 86 fibril_mutex_lock(&ep->guard); 87 while (ep->active) 88 fibril_condvar_wait(&ep->avail, &ep->guard); 89 ep->active = true; 90 fibril_mutex_unlock(&ep->guard); 144 91 } 145 92 146 93 /** Mark the endpoint as inactive and allow access for further fibrils. 147 * @param instanceendpoint_t structure.94 * @param ep endpoint_t structure. 148 95 */ 149 void endpoint_release(endpoint_t * instance)96 void endpoint_release(endpoint_t *ep) 150 97 { 151 assert( instance);152 fibril_mutex_lock(& instance->guard);153 instance->active = false;154 fibril_mutex_unlock(& instance->guard);155 fibril_condvar_signal(& instance->avail);98 assert(ep); 99 fibril_mutex_lock(&ep->guard); 100 ep->active = false; 101 fibril_mutex_unlock(&ep->guard); 102 fibril_condvar_signal(&ep->avail); 156 103 /* Drop reference for active endpoint. */ 157 endpoint_del_ref( instance);104 endpoint_del_ref(ep); 158 105 } 159 106 160 /** Get the value of toggle bit. 161 * @param instance endpoint_t structure.162 * @ note Will use provided hook.107 /** Get the value of toggle bit. Either uses the toggle_get op, or just returns 108 * the value of the toggle. 109 * @param ep endpoint_t structure. 163 110 */ 164 int endpoint_toggle_get(endpoint_t * instance)111 int endpoint_toggle_get(endpoint_t *ep) 165 112 { 166 assert(instance); 167 fibril_mutex_lock(&instance->guard); 168 if (instance->hc_data.toggle_get) 169 instance->toggle = 170 instance->hc_data.toggle_get(instance->hc_data.data); 171 const int ret = instance->toggle; 172 fibril_mutex_unlock(&instance->guard); 113 assert(ep); 114 fibril_mutex_lock(&ep->guard); 115 const int ret = ep->bus->ops.endpoint_get_toggle 116 ? ep->bus->ops.endpoint_get_toggle(ep) 117 : ep->toggle; 118 fibril_mutex_unlock(&ep->guard); 173 119 return ret; 174 120 } 175 121 176 /** Set the value of toggle bit. 177 * @param instance endpoint_t structure.178 * @ note Will use provided hook.122 /** Set the value of toggle bit. Either uses the toggle_set op, or just sets 123 * the toggle inside. 124 * @param ep endpoint_t structure. 179 125 */ 180 void endpoint_toggle_set(endpoint_t * instance, inttoggle)126 void endpoint_toggle_set(endpoint_t *ep, unsigned toggle) 181 127 { 182 assert( instance);128 assert(ep); 183 129 assert(toggle == 0 || toggle == 1); 184 fibril_mutex_lock(&instance->guard); 185 instance->toggle = toggle; 186 if (instance->hc_data.toggle_set) 187 instance->hc_data.toggle_set(instance->hc_data.data, toggle); 188 fibril_mutex_unlock(&instance->guard); 130 fibril_mutex_lock(&ep->guard); 131 if (ep->bus->ops.endpoint_set_toggle) { 132 ep->bus->ops.endpoint_set_toggle(ep, toggle); 133 } 134 else { 135 ep->toggle = toggle; 136 } 137 fibril_mutex_unlock(&ep->guard); 189 138 } 139 190 140 191 141 /** -
uspace/lib/usbhost/src/hcd.c
r04efacc r03936831 44 44 #include "hcd.h" 45 45 46 /** Calls ep_add_hook upon endpoint registration.47 * @param ep Endpoint to be registered.48 * @param arg hcd_t in disguise.49 * @return Error code.50 */51 static int register_helper(endpoint_t *ep, void *arg)52 {53 hcd_t *hcd = arg;54 assert(ep);55 assert(hcd);56 if (hcd->ops.ep_add_hook)57 return hcd->ops.ep_add_hook(hcd, ep);58 return EOK;59 }60 61 /** Calls ep_remove_hook upon endpoint removal.62 * @param ep Endpoint to be unregistered.63 * @param arg hcd_t in disguise.64 */65 static void unregister_helper(endpoint_t *ep, void *arg)66 {67 hcd_t *hcd = arg;68 assert(ep);69 assert(hcd);70 if (hcd->ops.ep_remove_hook)71 hcd->ops.ep_remove_hook(hcd, ep);72 }73 74 /** Calls ep_remove_hook upon endpoint removal. Prints warning.75 * * @param ep Endpoint to be unregistered.76 * * @param arg hcd_t in disguise.77 * */78 static void unregister_helper_warn(endpoint_t *ep, void *arg)79 {80 assert(ep);81 usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",82 ep->address, ep->endpoint, usb_str_direction(ep->direction));83 unregister_helper(ep, arg);84 }85 86 46 87 47 /** Initialize hcd_t structure. … … 93 53 * @param bw_count Bandwidth compute function, passed to endpoint manager. 94 54 */ 95 void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth, 96 bw_count_func_t bw_count) 97 { 98 assert(hcd); 99 usb_bus_init(&hcd->bus, bandwidth, bw_count, max_speed); 100 101 hcd_set_implementation(hcd, NULL, NULL); 55 void hcd_init(hcd_t *hcd) { 56 assert(hcd); 57 58 hcd_set_implementation(hcd, NULL, NULL, NULL); 102 59 } 103 60 … … 106 63 assert(hcd); 107 64 usb_address_t address = 0; 108 const int ret = usb_bus_request_address( 109 &hcd->bus, &address, false, speed); 65 const int ret = bus_request_address(hcd->bus, &address, false, speed); 110 66 if (ret != EOK) 111 67 return ret; 112 68 return address; 113 69 } 114 115 int hcd_release_address(hcd_t *hcd, usb_address_t address)116 {117 assert(hcd);118 return usb_bus_remove_address(&hcd->bus, address,119 unregister_helper_warn, hcd);120 }121 122 int hcd_reserve_default_address(hcd_t *hcd, usb_speed_t speed)123 {124 assert(hcd);125 usb_address_t address = 0;126 return usb_bus_request_address(&hcd->bus, &address, true, speed);127 }128 129 int hcd_add_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir,130 usb_transfer_type_t type, size_t max_packet_size, unsigned packets,131 size_t size, usb_address_t tt_address, unsigned tt_port)132 {133 assert(hcd);134 return usb_bus_add_ep(&hcd->bus, target.address,135 target.endpoint, dir, type, max_packet_size, packets, size,136 register_helper, hcd, tt_address, tt_port);137 }138 139 int hcd_remove_ep(hcd_t *hcd, usb_target_t target, usb_direction_t dir)140 {141 assert(hcd);142 return usb_bus_remove_ep(&hcd->bus, target.address,143 target.endpoint, dir, unregister_helper, hcd);144 }145 146 70 147 71 typedef struct { … … 159 83 usb_log_debug2("Reseting toggle on %d:%d.\n", 160 84 toggle->target.address, toggle->target.endpoint); 161 usb_bus_reset_toggle(&toggle->hcd->bus,85 bus_reset_toggle(toggle->hcd->bus, 162 86 toggle->target, toggle->target.endpoint == 0); 163 87 } … … 185 109 assert(hcd); 186 110 187 endpoint_t *ep = usb_bus_find_ep(&hcd->bus, 188 target.address, target.endpoint, direction); 111 endpoint_t *ep = bus_find_endpoint(hcd->bus, target, direction); 189 112 if (ep == NULL) { 190 113 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", … … 196 119 name, target.address, target.endpoint, size, ep->max_packet_size); 197 120 198 const size_t bw = bandwidth_count_usb11( 199 ep->speed, ep->transfer_type, size, ep->max_packet_size); 121 const size_t bw = bus_count_bw(ep, size); 200 122 /* Check if we have enough bandwidth reserved */ 201 123 if (ep->bandwidth < bw) { 202 124 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 203 125 "but only %zu is reserved.\n", 204 ep-> address, ep->endpoint, name, bw, ep->bandwidth);126 ep->target.address, ep->target.endpoint, name, bw, ep->bandwidth); 205 127 return ENOSPC; 206 128 } … … 248 170 249 171 typedef struct { 250 volatile unsigned done; 172 fibril_mutex_t done_mtx; 173 fibril_condvar_t done_cv; 174 unsigned done; 251 175 int ret; 252 176 size_t size; … … 258 182 assert(d); 259 183 d->ret = ret; 184 d->size = size; 185 fibril_mutex_lock(&d->done_mtx); 260 186 d->done = 1; 261 d->size = size; 187 fibril_condvar_broadcast(&d->done_cv); 188 fibril_mutex_unlock(&d->done_mtx); 262 189 } 263 190 … … 267 194 assert(data); 268 195 d->ret = ret; 196 fibril_mutex_lock(&d->done_mtx); 269 197 d->done = 1; 198 fibril_condvar_broadcast(&d->done_cv); 199 fibril_mutex_unlock(&d->done_mtx); 270 200 } 271 201 … … 277 207 assert(hcd); 278 208 sync_data_t sd = { .done = 0, .ret = EBUSY, .size = size }; 209 fibril_mutex_initialize(&sd.done_mtx); 210 fibril_condvar_initialize(&sd.done_cv); 279 211 280 212 const int ret = hcd_send_batch(hcd, target, dir, data, size, setup_data, … … 284 216 return ret; 285 217 286 while (!sd.done) { 287 async_usleep(1000); 288 } 218 fibril_mutex_lock(&sd.done_mtx); 219 while (!sd.done) 220 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx); 221 fibril_mutex_unlock(&sd.done_mtx); 289 222 290 223 if (sd.ret == EOK)
Note:
See TracChangeset
for help on using the changeset viewer.