Changeset 72af8da in mainline
- Timestamp:
- 2011-03-16T18:50:17Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 42a3a57
- Parents:
- 3e7b7cd (diff), fcf07e6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 10 added
- 3 deleted
- 78 edited
- 4 moved
Legend:
- Unmodified
- Added
- Removed
-
.bzrignore
r3e7b7cd r72af8da 84 84 ./uspace/drv/test1/test1 85 85 ./uspace/drv/test2/test2 86 ./uspace/drv/ehci-hcd/ehci-hcd 86 87 ./uspace/drv/uhci-hcd/uhci-hcd 87 88 ./uspace/drv/uhci-rhd/uhci-rhd -
boot/arch/amd64/Makefile.inc
r3e7b7cd r72af8da 43 43 isa \ 44 44 ns8250 \ 45 ehci-hcd \ 45 46 uhci-hcd \ 46 47 uhci-rhd \ -
boot/arch/mips32/src/asm.S
r3e7b7cd r72af8da 41 41 42 42 start: 43 /* Setup CPU map (on msim this code 44 is executed in parallel on all CPUs, 45 but it not an issue) */ 43 /* 44 * Setup the CP0 configuration 45 * - Disable 64-bit kernel addressing mode 46 * - DIsable 64-bit supervisor adressing mode 47 * - Disable 64-bit user addressing mode 48 */ 49 mfc0 $a0, $status 50 la $a1, 0xffffff1f 51 and $a0, $a1, $a0 52 mtc0 $a0, $status 53 54 /* 55 * Setup CPU map (on msim this code 56 * is executed in parallel on all CPUs, 57 * but it not an issue). 58 */ 46 59 la $a0, PA2KA(CPUMAP_OFFSET) 47 60 … … 94 107 lw $k1, ($k0) 95 108 96 /* If we are not running on BSP 97 then end in an infinite loop */ 109 /* 110 * If we are not running on BSP 111 * then end in an infinite loop. 112 */ 98 113 beq $k1, $zero, bsp 99 114 nop … … 127 142 128 143 jump_to_kernel: 129 # 130 # TODO: 131 # Make sure that the I-cache, D-cache and memory are mutually coherent 132 # before passing control to the copied code. 133 # 144 /* 145 * TODO: 146 * 147 * Make sure that the I-cache, D-cache and memory are mutually 148 * coherent before passing control to the copied code. 149 */ 134 150 j $a0 135 151 nop -
dist/Makefile
r3e7b7cd r72af8da 43 43 44 44 SUFFIX = $(suffix $(IMGFILE)) 45 DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX) 45 46 ifdef PROFILE 47 DISTFILE = Helenos-$(shell echo $(PROFILE) | tr '/' '-')$(SUFFIX) 48 else 49 DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX) 50 endif 46 51 47 52 .PHONY: all clean dist distfile … … 53 58 cp $< $@ 54 59 60 $(IMGFILE): 61 $(MAKE) -C .. 62 55 63 dist: 56 64 for profile in $(PROFILES); do \ -
uspace/Makefile
r3e7b7cd r72af8da 117 117 srv/hw/irc/apic \ 118 118 srv/hw/irc/i8259 \ 119 drv/ehci-hcd \ 119 120 drv/uhci-hcd \ 120 121 drv/uhci-rhd \ … … 134 135 srv/hw/irc/apic \ 135 136 srv/hw/irc/i8259 \ 137 drv/ehci-hcd \ 136 138 drv/uhci-hcd \ 137 139 drv/uhci-rhd \ -
uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
r3e7b7cd r72af8da 125 125 126 126 for (c = 0, optind = 0, opt_ind = 0; c != -1;) { 127 c = getopt_long(argc, argv, " pvhVfm:", long_options, &opt_ind);127 c = getopt_long(argc, argv, "s:h", long_options, &opt_ind); 128 128 switch (c) { 129 129 case 'h': -
uspace/app/usbinfo/info.c
r3e7b7cd r72af8da 65 65 goto leave; 66 66 } 67 rc = usb_endpoint_pipe_probe_default_control(&ctrl_pipe); 68 if (rc != EOK) { 69 fprintf(stderr, 70 NAME ": probing default control pipe failed: %s.\n", 71 str_error(rc)); 72 goto leave; 73 } 67 74 rc = usb_endpoint_pipe_start_session(&ctrl_pipe); 68 75 if (rc != EOK) { -
uspace/app/usbinfo/main.c
r3e7b7cd r72af8da 82 82 83 83 if (str_cmp(path, "uhci") == 0) { 84 path = "/hw/pci0/00:01.2/uhci ";84 path = "/hw/pci0/00:01.2/uhci-hc"; 85 85 } 86 86 -
uspace/doc/doxygroups.h
r3e7b7cd r72af8da 253 253 * @defgroup drvusbuhci UHCI driver 254 254 * @ingroup usb 255 * @brief Driver for USB host controller UHCI. 256 */ 257 255 * @brief Drivers for USB UHCI host controller and root hub. 256 */ 257 258 /** 259 * @defgroup drvusbuhcirh UHCI root hub driver 260 * @ingroup drvusbuhci 261 * @brief Driver for UHCI complaint root hub. 262 */ 263 264 /** 265 * @defgroup drvusbuhcihc UHCI host controller driver 266 * @ingroup drvusbuhci 267 * @brief Driver for UHCI complaint USB host controller. 268 */ 269 270 /** 271 * @defgroup drvusbehci EHCI driver 272 * @ingroup usb 273 * @brief Driver for EHCI host controller. 274 */ 275 276 -
uspace/drv/ehci-hcd/pci.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 2011 Jan Vesely2 * Copyright (c) 2011 Vojtech Horky 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb 28 29 /** @addtogroup drvusbehci 29 30 * @{ 30 31 */ 31 32 /** @file 32 * @brief UHCI driver33 * PCI related functions needed by EHCI driver. 33 34 */ 34 #i nclude <assert.h>35 # include <stdio.h>35 #ifndef DRV_EHCI_PCI_H 36 #define DRV_EHCI_PCI_H 36 37 37 #include < usb/debug.h>38 #include <ddf/driver.h> 38 39 39 #include "port_status.h" 40 int pci_get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *); 41 int pci_enable_interrupts(ddf_dev_t *); 42 int pci_disable_legacy(ddf_dev_t *); 40 43 41 struct flag_name 42 { 43 uint16_t flag; 44 const char *name; 45 }; 46 47 static const struct flag_name flags[] = 48 { 49 { STATUS_SUSPEND, "suspended" }, 50 { STATUS_IN_RESET, "in reset" }, 51 { STATUS_LOW_SPEED, "low speed device" }, 52 { STATUS_ALWAYS_ONE, "always 1 bit" }, 53 { STATUS_RESUME, "resume" }, 54 { STATUS_LINE_D_MINUS, "line D- value" }, 55 { STATUS_LINE_D_PLUS, "line D+ value" }, 56 { STATUS_ENABLED_CHANGED, "enabled changed" }, 57 { STATUS_ENABLED, "enabled" }, 58 { STATUS_CONNECTED_CHANGED, "connected changed" }, 59 { STATUS_CONNECTED, "connected" } 60 }; 61 62 void print_port_status(port_status_t value) 63 { 64 unsigned i = 0; 65 for (;i < sizeof(flags)/sizeof(struct flag_name); ++i) { 66 usb_log_debug2("\t%s status: %s.\n", flags[i].name, 67 ((value & flags[i].flag) != 0) ? "YES" : "NO"); 68 } 69 } 44 #endif 70 45 /** 71 46 * @} 72 47 */ 48 -
uspace/drv/pciintel/pci.c
r3e7b7cd r72af8da 92 92 pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data; 93 93 94 95 94 sysarg_t apic; 95 sysarg_t i8259; 96 96 97 97 int irc_phone = -1; 98 int irc_service = 0;99 100 101 98 int irc_service = -1; 99 100 if ((sysinfo_get_value("apic", &apic) == EOK) && (apic)) { 101 irc_service = SERVICE_APIC; 102 102 } else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)) { 103 104 } 105 106 if (irc_service == 0) 103 irc_service = SERVICE_I8259; 104 } 105 106 if (irc_service == -1) { 107 107 return false; 108 } 108 109 109 110 irc_phone = service_connect_blocking(irc_service, 0, 0); 110 if (irc_phone < 0) 111 if (irc_phone < 0) { 111 112 return false; 113 } 112 114 113 115 size_t i; 114 116 for (i = 0; i < dev_data->hw_resources.count; i++) { 115 117 if (dev_data->hw_resources.resources[i].type == INTERRUPT) { 116 118 int irq = dev_data->hw_resources.resources[i].res.interrupt.irq; … … 127 129 } 128 130 129 static int pci_config_space_write_16(ddf_fun_t *fun, uint32_t address, uint16_t data) 131 static int pci_config_space_write_32( 132 ddf_fun_t *fun, uint32_t address, uint32_t data) 133 { 134 if (address > 252) 135 return EINVAL; 136 pci_conf_write_32(PCI_FUN(fun), address, data); 137 return EOK; 138 } 139 140 static int pci_config_space_write_16( 141 ddf_fun_t *fun, uint32_t address, uint16_t data) 130 142 { 131 143 if (address > 254) … … 135 147 } 136 148 149 static int pci_config_space_write_8( 150 ddf_fun_t *fun, uint32_t address, uint8_t data) 151 { 152 if (address > 255) 153 return EINVAL; 154 pci_conf_write_8(PCI_FUN(fun), address, data); 155 return EOK; 156 } 157 158 static int pci_config_space_read_32( 159 ddf_fun_t *fun, uint32_t address, uint32_t *data) 160 { 161 if (address > 252) 162 return EINVAL; 163 *data = pci_conf_read_32(PCI_FUN(fun), address); 164 return EOK; 165 } 166 167 static int pci_config_space_read_16( 168 ddf_fun_t *fun, uint32_t address, uint16_t *data) 169 { 170 if (address > 254) 171 return EINVAL; 172 *data = pci_conf_read_16(PCI_FUN(fun), address); 173 return EOK; 174 } 175 176 static int pci_config_space_read_8( 177 ddf_fun_t *fun, uint32_t address, uint8_t *data) 178 { 179 if (address > 255) 180 return EINVAL; 181 *data = pci_conf_read_8(PCI_FUN(fun), address); 182 return EOK; 183 } 137 184 138 185 static hw_res_ops_t pciintel_hw_res_ops = { … … 142 189 143 190 static pci_dev_iface_t pci_dev_ops = { 144 .config_space_read_8 = NULL,145 .config_space_read_16 = NULL,146 .config_space_read_32 = NULL,147 .config_space_write_8 = NULL,191 .config_space_read_8 = &pci_config_space_read_8, 192 .config_space_read_16 = &pci_config_space_read_16, 193 .config_space_read_32 = &pci_config_space_read_32, 194 .config_space_write_8 = &pci_config_space_write_8, 148 195 .config_space_write_16 = &pci_config_space_write_16, 149 .config_space_write_32 = NULL196 .config_space_write_32 = &pci_config_space_write_32 150 197 }; 151 198 -
uspace/drv/uhci-hcd/Makefile
r3e7b7cd r72af8da 35 35 iface.c \ 36 36 main.c \ 37 root_hub.c \38 37 transfer_list.c \ 39 38 uhci.c \ 39 uhci_hc.c \ 40 uhci_rh.c \ 40 41 uhci_struct/transfer_descriptor.c \ 41 42 utils/device_keeper.c \ -
uspace/drv/uhci-hcd/batch.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver USB transaction structure 33 33 */ 34 34 #include <errno.h> … … 40 40 #include "batch.h" 41 41 #include "transfer_list.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/malloc32.h" 44 44 45 45 #define DEFAULT_ERROR_COUNT 3 46 46 47 static int batch_schedule(batch_t *instance); 48 49 static void batch_control( 50 batch_t *instance, int data_stage, int status_stage); 47 static void batch_control(batch_t *instance, 48 usb_packet_id data_stage, usb_packet_id status_stage); 49 static void batch_data(batch_t *instance, usb_packet_id pid); 51 50 static void batch_call_in(batch_t *instance); 52 51 static void batch_call_out(batch_t *instance); … … 55 54 56 55 56 /** Allocate memory and initialize internal data structure. 57 * 58 * @param[in] fun DDF function to pass to callback. 59 * @param[in] target Device and endpoint target of the transaction. 60 * @param[in] transfer_type Interrupt, Control or Bulk. 61 * @param[in] max_packet_size maximum allowed size of data packets. 62 * @param[in] speed Speed of the transaction. 63 * @param[in] buffer Data source/destination. 64 * @param[in] size Size of the buffer. 65 * @param[in] setup_buffer Setup data source (if not NULL) 66 * @param[in] setup_size Size of setup_buffer (should be always 8) 67 * @param[in] func_in function to call on inbound transaction completion 68 * @param[in] func_out function to call on outbound transaction completion 69 * @param[in] arg additional parameter to func_in or func_out 70 * @param[in] manager Pointer to toggle management structure. 71 * @return Valid pointer if all substructures were successfully created, 72 * NULL otherwise. 73 * 74 * Determines the number of needed packets (TDs). Prepares a transport buffer 75 * (that is accessible by the hardware). Initializes parameters needed for the 76 * transaction and callback. 77 */ 57 78 batch_t * batch_get(ddf_fun_t *fun, usb_target_t target, 58 79 usb_transfer_type_t transfer_type, size_t max_packet_size, … … 60 81 char* setup_buffer, size_t setup_size, 61 82 usbhc_iface_transfer_in_callback_t func_in, 62 usbhc_iface_transfer_out_callback_t func_out, void *arg) 83 usbhc_iface_transfer_out_callback_t func_out, void *arg, 84 device_keeper_t *manager 85 ) 63 86 { 64 87 assert(func_in == NULL || func_out == NULL); 65 88 assert(func_in != NULL || func_out != NULL); 66 89 90 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ 91 if (ptr == NULL) { \ 92 usb_log_error(message); \ 93 if (instance) { \ 94 batch_dispose(instance); \ 95 } \ 96 return NULL; \ 97 } else (void)0 98 67 99 batch_t *instance = malloc(sizeof(batch_t)); 68 if (instance == NULL) { 69 usb_log_error("Failed to allocate batch instance.\n"); 70 return NULL; 71 } 72 73 instance->qh = queue_head_get(); 74 if (instance->qh == NULL) { 75 usb_log_error("Failed to allocate queue head.\n"); 76 free(instance); 77 return NULL; 78 } 100 CHECK_NULL_DISPOSE_RETURN(instance, 101 "Failed to allocate batch instance.\n"); 102 bzero(instance, sizeof(batch_t)); 103 104 instance->qh = malloc32(sizeof(qh_t)); 105 CHECK_NULL_DISPOSE_RETURN(instance->qh, 106 "Failed to allocate batch queue head.\n"); 107 qh_init(instance->qh); 79 108 80 109 instance->packets = (size + max_packet_size - 1) / max_packet_size; … … 83 112 } 84 113 85 instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets); 86 if (instance->tds == NULL) { 87 usb_log_error("Failed to allocate transfer descriptors.\n"); 88 queue_head_dispose(instance->qh); 89 free(instance); 90 return NULL; 91 } 92 bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets); 93 94 const size_t transport_size = max_packet_size * instance->packets; 95 96 instance->transport_buffer = 97 (size > 0) ? malloc32(transport_size) : NULL; 98 99 if ((size > 0) && (instance->transport_buffer == NULL)) { 100 usb_log_error("Failed to allocate device accessible buffer.\n"); 101 queue_head_dispose(instance->qh); 102 free32(instance->tds); 103 free(instance); 104 return NULL; 105 } 106 107 instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL; 108 if ((setup_size > 0) && (instance->setup_buffer == NULL)) { 109 usb_log_error("Failed to allocate device accessible setup buffer.\n"); 110 queue_head_dispose(instance->qh); 111 free32(instance->tds); 112 free32(instance->transport_buffer); 113 free(instance); 114 return NULL; 115 } 116 if (instance->setup_buffer) { 114 instance->tds = malloc32(sizeof(td_t) * instance->packets); 115 CHECK_NULL_DISPOSE_RETURN( 116 instance->tds, "Failed to allocate transfer descriptors.\n"); 117 bzero(instance->tds, sizeof(td_t) * instance->packets); 118 119 if (size > 0) { 120 instance->transport_buffer = malloc32(size); 121 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 122 "Failed to allocate device accessible buffer.\n"); 123 } 124 125 if (setup_size > 0) { 126 instance->setup_buffer = malloc32(setup_size); 127 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 128 "Failed to allocate device accessible setup buffer.\n"); 117 129 memcpy(instance->setup_buffer, setup_buffer, setup_size); 118 130 } 119 131 132 133 link_initialize(&instance->link); 134 120 135 instance->max_packet_size = max_packet_size; 121 122 link_initialize(&instance->link);123 124 136 instance->target = target; 125 137 instance->transfer_type = transfer_type; 126 127 if (func_out)128 instance->callback_out = func_out;129 if (func_in)130 instance->callback_in = func_in;131 132 138 instance->buffer = buffer; 133 139 instance->buffer_size = size; … … 136 142 instance->arg = arg; 137 143 instance->speed = speed; 138 139 queue_head_element_td(instance->qh, addr_to_phys(instance->tds)); 144 instance->manager = manager; 145 instance->callback_out = func_out; 146 instance->callback_in = func_in; 147 148 qh_set_element_td(instance->qh, addr_to_phys(instance->tds)); 149 140 150 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 141 151 instance, target.address, target.endpoint); … … 143 153 } 144 154 /*----------------------------------------------------------------------------*/ 155 /** Check batch TDs for activity. 156 * 157 * @param[in] instance Batch structure to use. 158 * @return False, if there is an active TD, true otherwise. 159 * 160 * Walk all TDs. Stop with false if there is an active one (it is to be 161 * processed). Stop with true if an error is found. Return true if the last TS 162 * is reached. 163 */ 145 164 bool batch_is_complete(batch_t *instance) 146 165 { … … 151 170 size_t i = 0; 152 171 for (;i < instance->packets; ++i) { 153 if (t ransfer_descriptor_is_active(&instance->tds[i])) {172 if (td_is_active(&instance->tds[i])) { 154 173 return false; 155 174 } 156 instance->error = transfer_descriptor_status(&instance->tds[i]); 175 176 instance->error = td_status(&instance->tds[i]); 157 177 if (instance->error != EOK) { 178 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 179 instance, i, instance->tds[i].status); 180 td_print_status(&instance->tds[i]); 181 182 device_keeper_set_toggle(instance->manager, 183 instance->target, td_toggle(&instance->tds[i])); 158 184 if (i > 0) 159 instance->transfered_size -= instance->setup_size; 160 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 161 instance, i, instance->tds[i].status); 185 goto substract_ret; 162 186 return true; 163 187 } 164 instance->transfered_size += 165 transfer_descriptor_actual_size(&instance->tds[i]); 166 } 188 189 instance->transfered_size += td_act_size(&instance->tds[i]); 190 if (td_is_short(&instance->tds[i])) 191 goto substract_ret; 192 } 193 substract_ret: 167 194 instance->transfered_size -= instance->setup_size; 168 195 return true; 169 196 } 170 197 /*----------------------------------------------------------------------------*/ 198 /** Prepares control write transaction. 199 * 200 * @param[in] instance Batch structure to use. 201 * 202 * Uses genercir control function with pids OUT and IN. 203 */ 171 204 void batch_control_write(batch_t *instance) 172 205 { 173 206 assert(instance); 174 /* we are data out, we are supposed to provide data */ 175 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 207 /* We are data out, we are supposed to provide data */ 208 memcpy(instance->transport_buffer, instance->buffer, 209 instance->buffer_size); 176 210 batch_control(instance, USB_PID_OUT, USB_PID_IN); 177 211 instance->next_step = batch_call_out_and_dispose; 178 212 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 179 batch_schedule(instance); 180 } 181 /*----------------------------------------------------------------------------*/ 213 } 214 /*----------------------------------------------------------------------------*/ 215 /** Prepares control read transaction. 216 * 217 * @param[in] instance Batch structure to use. 218 * 219 * Uses generic control with pids IN and OUT. 220 */ 182 221 void batch_control_read(batch_t *instance) 183 222 { … … 186 225 instance->next_step = batch_call_in_and_dispose; 187 226 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 188 batch_schedule(instance); 189 } 190 /*----------------------------------------------------------------------------*/ 227 } 228 /*----------------------------------------------------------------------------*/ 229 /** Prepare interrupt in transaction. 230 * 231 * @param[in] instance Batch structure to use. 232 * 233 * Data transaction with PID_IN. 234 */ 191 235 void batch_interrupt_in(batch_t *instance) 192 236 { 193 237 assert(instance); 194 195 const bool low_speed = instance->speed == USB_SPEED_LOW; 196 int toggle = 1; 197 size_t i = 0; 198 for (;i < instance->packets; ++i) { 199 char *data = 200 instance->transport_buffer + (i * instance->max_packet_size); 201 transfer_descriptor_t *next = (i + 1) < instance->packets ? 202 &instance->tds[i + 1] : NULL; 203 toggle = 1 - toggle; 204 205 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 206 instance->max_packet_size, toggle, false, low_speed, 207 instance->target, USB_PID_IN, data, next); 208 } 209 210 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 211 238 batch_data(instance, USB_PID_IN); 212 239 instance->next_step = batch_call_in_and_dispose; 213 240 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 214 batch_schedule(instance); 215 } 216 /*----------------------------------------------------------------------------*/ 241 } 242 /*----------------------------------------------------------------------------*/ 243 /** Prepare interrupt out transaction. 244 * 245 * @param[in] instance Batch structure to use. 246 * 247 * Data transaction with PID_OUT. 248 */ 217 249 void batch_interrupt_out(batch_t *instance) 218 250 { 219 251 assert(instance); 252 /* We are data out, we are supposed to provide data */ 220 253 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 221 222 const bool low_speed = instance->speed == USB_SPEED_LOW; 223 int toggle = 1; 224 size_t i = 0; 225 for (;i < instance->packets; ++i) { 226 char *data = 227 instance->transport_buffer + (i * instance->max_packet_size); 228 transfer_descriptor_t *next = (i + 1) < instance->packets ? 229 &instance->tds[i + 1] : NULL; 230 toggle = 1 - toggle; 231 232 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT, 233 instance->max_packet_size, toggle++, false, low_speed, 234 instance->target, USB_PID_OUT, data, next); 235 } 236 237 instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 238 254 batch_data(instance, USB_PID_OUT); 239 255 instance->next_step = batch_call_out_and_dispose; 240 256 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 241 batch_schedule(instance); 242 } 243 /*----------------------------------------------------------------------------*/ 244 static void batch_control( 245 batch_t *instance, int data_stage, int status_stage) 257 } 258 /*----------------------------------------------------------------------------*/ 259 /** Prepare bulk in transaction. 260 * 261 * @param[in] instance Batch structure to use. 262 * 263 * Data transaction with PID_IN. 264 */ 265 void batch_bulk_in(batch_t *instance) 266 { 267 assert(instance); 268 batch_data(instance, USB_PID_IN); 269 instance->next_step = batch_call_in_and_dispose; 270 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 271 } 272 /*----------------------------------------------------------------------------*/ 273 /** Prepare bulk out transaction. 274 * 275 * @param[in] instance Batch structure to use. 276 * 277 * Data transaction with PID_OUT. 278 */ 279 void batch_bulk_out(batch_t *instance) 280 { 281 assert(instance); 282 /* We are data out, we are supposed to provide data */ 283 memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size); 284 batch_data(instance, USB_PID_OUT); 285 instance->next_step = batch_call_out_and_dispose; 286 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 287 } 288 /*----------------------------------------------------------------------------*/ 289 /** Prepare generic data transaction 290 * 291 * @param[in] instance Batch structure to use. 292 * @param[in] pid to use for data packets. 293 * 294 * Packets with alternating toggle bit and supplied pid value. 295 * The last packet is marked with IOC flag. 296 */ 297 void batch_data(batch_t *instance, usb_packet_id pid) 298 { 299 assert(instance); 300 const bool low_speed = instance->speed == USB_SPEED_LOW; 301 int toggle = 302 device_keeper_get_toggle(instance->manager, instance->target); 303 assert(toggle == 0 || toggle == 1); 304 305 size_t packet = 0; 306 size_t remain_size = instance->buffer_size; 307 while (remain_size > 0) { 308 char *data = 309 instance->transport_buffer + instance->buffer_size 310 - remain_size; 311 312 const size_t packet_size = 313 (instance->max_packet_size > remain_size) ? 314 remain_size : instance->max_packet_size; 315 316 td_t *next_packet = (packet + 1 < instance->packets) 317 ? &instance->tds[packet + 1] : NULL; 318 319 assert(packet < instance->packets); 320 assert(packet_size <= remain_size); 321 322 td_init( 323 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 324 toggle, false, low_speed, instance->target, pid, data, 325 next_packet); 326 327 328 toggle = 1 - toggle; 329 remain_size -= packet_size; 330 ++packet; 331 } 332 td_set_ioc(&instance->tds[packet - 1]); 333 device_keeper_set_toggle(instance->manager, instance->target, toggle); 334 } 335 /*----------------------------------------------------------------------------*/ 336 /** Prepare generic control transaction 337 * 338 * @param[in] instance Batch structure to use. 339 * @param[in] data_stage to use for data packets. 340 * @param[in] status_stage to use for data packets. 341 * 342 * Setup stage with toggle 0 and USB_PID_SETUP. 343 * Data stage with alternating toggle and pid supplied by parameter. 344 * Status stage with toggle 1 and pid supplied by parameter. 345 * The last packet is marked with IOC. 346 */ 347 void batch_control(batch_t *instance, 348 usb_packet_id data_stage, usb_packet_id status_stage) 246 349 { 247 350 assert(instance); … … 250 353 int toggle = 0; 251 354 /* setup stage */ 252 t ransfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,355 td_init(instance->tds, DEFAULT_ERROR_COUNT, 253 356 instance->setup_size, toggle, false, low_speed, instance->target, 254 357 USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]); … … 268 371 remain_size : instance->max_packet_size; 269 372 270 t ransfer_descriptor_init(&instance->tds[packet],271 DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,272 instance->target, data_stage, data,273 &instance->tds[packet + 1]);373 td_init( 374 &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size, 375 toggle, false, low_speed, instance->target, data_stage, 376 data, &instance->tds[packet + 1]); 274 377 275 378 ++packet; … … 281 384 /* status stage */ 282 385 assert(packet == instance->packets - 1); 283 t ransfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,386 td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT, 284 387 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 285 388 286 287 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 389 td_set_ioc(&instance->tds[packet]); 288 390 usb_log_debug2("Control last TD status: %x.\n", 289 391 instance->tds[packet].status); 290 392 } 291 393 /*----------------------------------------------------------------------------*/ 394 /** Prepare data, get error status and call callback in. 395 * 396 * @param[in] instance Batch structure to use. 397 * Copies data from transport buffer, and calls callback with appropriate 398 * parameters. 399 */ 292 400 void batch_call_in(batch_t *instance) 293 401 { … … 295 403 assert(instance->callback_in); 296 404 297 memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size); 405 /* We are data in, we need data */ 406 memcpy(instance->buffer, instance->transport_buffer, 407 instance->buffer_size); 298 408 299 409 int err = instance->error; … … 302 412 instance->transfered_size); 303 413 304 instance->callback_in(instance->fun, 305 err, instance->transfered_size, 306 instance->arg); 307 } 308 /*----------------------------------------------------------------------------*/ 414 instance->callback_in( 415 instance->fun, err, instance->transfered_size, instance->arg); 416 } 417 /*----------------------------------------------------------------------------*/ 418 /** Get error status and call callback out. 419 * 420 * @param[in] instance Batch structure to use. 421 */ 309 422 void batch_call_out(batch_t *instance) 310 423 { … … 319 432 } 320 433 /*----------------------------------------------------------------------------*/ 434 /** Helper function calls callback and correctly disposes of batch structure. 435 * 436 * @param[in] instance Batch structure to use. 437 */ 321 438 void batch_call_in_and_dispose(batch_t *instance) 322 439 { 323 440 assert(instance); 324 441 batch_call_in(instance); 442 batch_dispose(instance); 443 } 444 /*----------------------------------------------------------------------------*/ 445 /** Helper function calls callback and correctly disposes of batch structure. 446 * 447 * @param[in] instance Batch structure to use. 448 */ 449 void batch_call_out_and_dispose(batch_t *instance) 450 { 451 assert(instance); 452 batch_call_out(instance); 453 batch_dispose(instance); 454 } 455 /*----------------------------------------------------------------------------*/ 456 /** Correctly dispose all used data structures. 457 * 458 * @param[in] instance Batch structure to use. 459 */ 460 void batch_dispose(batch_t *instance) 461 { 462 assert(instance); 325 463 usb_log_debug("Batch(%p) disposing.\n", instance); 464 /* free32 is NULL safe */ 326 465 free32(instance->tds); 327 466 free32(instance->qh); … … 330 469 free(instance); 331 470 } 332 /*----------------------------------------------------------------------------*/333 void batch_call_out_and_dispose(batch_t *instance)334 {335 assert(instance);336 batch_call_out(instance);337 usb_log_debug("Batch(%p) disposing.\n", instance);338 free32(instance->tds);339 free32(instance->qh);340 free32(instance->setup_buffer);341 free32(instance->transport_buffer);342 free(instance);343 }344 /*----------------------------------------------------------------------------*/345 int batch_schedule(batch_t *instance)346 {347 assert(instance);348 uhci_t *hc = fun_to_uhci(instance->fun);349 assert(hc);350 return uhci_schedule(hc, instance);351 }352 471 /** 353 472 * @} -
uspace/drv/uhci-hcd/batch.h
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver USB transaction structure 33 33 */ 34 34 #ifndef DRV_UHCI_BATCH_H … … 42 42 #include "uhci_struct/transfer_descriptor.h" 43 43 #include "uhci_struct/queue_head.h" 44 #include "utils/device_keeper.h" 44 45 45 46 typedef struct batch … … 49 50 usb_target_t target; 50 51 usb_transfer_type_t transfer_type; 51 union { 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 54 }; 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 55 54 void *arg; 56 55 char *transport_buffer; … … 64 63 int error; 65 64 ddf_fun_t *fun; 66 q ueue_head_t *qh;67 t ransfer_descriptor_t *tds;65 qh_t *qh; 66 td_t *tds; 68 67 void (*next_step)(struct batch*); 68 device_keeper_t *manager; 69 69 } batch_t; 70 70 … … 74 74 char *setup_buffer, size_t setup_size, 75 75 usbhc_iface_transfer_in_callback_t func_in, 76 usbhc_iface_transfer_out_callback_t func_out, void *arg); 76 usbhc_iface_transfer_out_callback_t func_out, void *arg, 77 device_keeper_t *manager 78 ); 79 80 void batch_dispose(batch_t *instance); 77 81 78 82 bool batch_is_complete(batch_t *instance); … … 86 90 void batch_interrupt_out(batch_t *instance); 87 91 88 /* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */ 89 void batch_control_setup_old(batch_t *instance); 92 void batch_bulk_in(batch_t *instance); 90 93 91 void batch_control_write_data_old(batch_t *instance); 92 93 void batch_control_read_data_old(batch_t *instance); 94 95 void batch_control_write_status_old(batch_t *instance); 96 97 void batch_control_read_status_old(batch_t *instance); 94 void batch_bulk_out(batch_t *instance); 98 95 #endif 99 96 /** -
uspace/drv/uhci-hcd/iface.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver hc interface implementation 33 33 */ 34 34 #include <ddf/driver.h> … … 40 40 41 41 #include "iface.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/device_keeper.h" 44 44 45 /** Reserve default address interface function 46 * 47 * @param[in] fun DDF function that was called. 48 * @param[in] speed Speed to associate with the new default address. 49 * @return Error code. 50 */ 45 51 /*----------------------------------------------------------------------------*/ 46 52 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 47 53 { 48 54 assert(fun); 49 uhci_ t *hc = fun_to_uhci(fun);55 uhci_hc_t *hc = fun_to_uhci_hc(fun); 50 56 assert(hc); 51 57 usb_log_debug("Default address request with speed %d.\n", speed); … … 54 60 } 55 61 /*----------------------------------------------------------------------------*/ 62 /** Release default address interface function 63 * 64 * @param[in] fun DDF function that was called. 65 * @return Error code. 66 */ 56 67 static int release_default_address(ddf_fun_t *fun) 57 68 { 58 69 assert(fun); 59 uhci_ t *hc = fun_to_uhci(fun);70 uhci_hc_t *hc = fun_to_uhci_hc(fun); 60 71 assert(hc); 61 72 usb_log_debug("Default address release.\n"); … … 64 75 } 65 76 /*----------------------------------------------------------------------------*/ 77 /** Request address interface function 78 * 79 * @param[in] fun DDF function that was called. 80 * @param[in] speed Speed to associate with the new default address. 81 * @param[out] address Place to write a new address. 82 * @return Error code. 83 */ 66 84 static int request_address(ddf_fun_t *fun, usb_speed_t speed, 67 85 usb_address_t *address) 68 86 { 69 87 assert(fun); 70 uhci_ t *hc = fun_to_uhci(fun);88 uhci_hc_t *hc = fun_to_uhci_hc(fun); 71 89 assert(hc); 72 90 assert(address); … … 80 98 } 81 99 /*----------------------------------------------------------------------------*/ 100 /** Bind address interface function 101 * 102 * @param[in] fun DDF function that was called. 103 * @param[in] address Address of the device 104 * @param[in] handle Devman handle of the device driver. 105 * @return Error code. 106 */ 82 107 static int bind_address( 83 108 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle) 84 109 { 85 110 assert(fun); 86 uhci_ t *hc = fun_to_uhci(fun);111 uhci_hc_t *hc = fun_to_uhci_hc(fun); 87 112 assert(hc); 88 113 usb_log_debug("Address bind %d-%d.\n", address, handle); … … 91 116 } 92 117 /*----------------------------------------------------------------------------*/ 118 /** Release address interface function 119 * 120 * @param[in] fun DDF function that was called. 121 * @param[in] address USB address to be released. 122 * @return Error code. 123 */ 93 124 static int release_address(ddf_fun_t *fun, usb_address_t address) 94 125 { 95 126 assert(fun); 96 uhci_ t *hc = fun_to_uhci(fun);127 uhci_hc_t *hc = fun_to_uhci_hc(fun); 97 128 assert(hc); 98 129 usb_log_debug("Address release %d.\n", address); … … 101 132 } 102 133 /*----------------------------------------------------------------------------*/ 134 /** Interrupt out transaction interface function 135 * 136 * @param[in] fun DDF function that was called. 137 * @param[in] target USB device to write to. 138 * @param[in] max_packet_size maximum size of data packet the device accepts 139 * @param[in] data Source of data. 140 * @param[in] size Size of data source. 141 * @param[in] callback Function to call on transaction completion 142 * @param[in] arg Additional for callback function. 143 * @return Error code. 144 */ 103 145 static int interrupt_out(ddf_fun_t *fun, usb_target_t target, 104 146 size_t max_packet_size, void *data, size_t size, … … 106 148 { 107 149 assert(fun); 108 uhci_ t *hc = fun_to_uhci(fun);150 uhci_hc_t *hc = fun_to_uhci_hc(fun); 109 151 assert(hc); 110 152 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 114 156 115 157 batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT, 116 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg); 158 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg, 159 &hc->device_manager); 117 160 if (!batch) 118 161 return ENOMEM; 119 162 batch_interrupt_out(batch); 120 return EOK; 121 } 122 /*----------------------------------------------------------------------------*/ 163 const int ret = uhci_hc_schedule(hc, batch); 164 if (ret != EOK) { 165 batch_dispose(batch); 166 return ret; 167 } 168 return EOK; 169 } 170 /*----------------------------------------------------------------------------*/ 171 /** Interrupt in transaction interface function 172 * 173 * @param[in] fun DDF function that was called. 174 * @param[in] target USB device to write to. 175 * @param[in] max_packet_size maximum size of data packet the device accepts 176 * @param[out] data Data destination. 177 * @param[in] size Size of data source. 178 * @param[in] callback Function to call on transaction completion 179 * @param[in] arg Additional for callback function. 180 * @return Error code. 181 */ 123 182 static int interrupt_in(ddf_fun_t *fun, usb_target_t target, 124 183 size_t max_packet_size, void *data, size_t size, … … 126 185 { 127 186 assert(fun); 128 uhci_ t *hc = fun_to_uhci(fun);187 uhci_hc_t *hc = fun_to_uhci_hc(fun); 129 188 assert(hc); 130 189 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 133 192 134 193 batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT, 135 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg); 194 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg, 195 &hc->device_manager); 136 196 if (!batch) 137 197 return ENOMEM; 138 198 batch_interrupt_in(batch); 139 return EOK; 140 } 141 /*----------------------------------------------------------------------------*/ 199 const int ret = uhci_hc_schedule(hc, batch); 200 if (ret != EOK) { 201 batch_dispose(batch); 202 return ret; 203 } 204 return EOK; 205 } 206 /*----------------------------------------------------------------------------*/ 207 /** Bulk out transaction interface function 208 * 209 * @param[in] fun DDF function that was called. 210 * @param[in] target USB device to write to. 211 * @param[in] max_packet_size maximum size of data packet the device accepts 212 * @param[in] data Source of data. 213 * @param[in] size Size of data source. 214 * @param[in] callback Function to call on transaction completion 215 * @param[in] arg Additional for callback function. 216 * @return Error code. 217 */ 218 static int bulk_out(ddf_fun_t *fun, usb_target_t target, 219 size_t max_packet_size, void *data, size_t size, 220 usbhc_iface_transfer_out_callback_t callback, void *arg) 221 { 222 assert(fun); 223 uhci_hc_t *hc = fun_to_uhci_hc(fun); 224 assert(hc); 225 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 226 227 usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n", 228 target.address, target.endpoint, size, max_packet_size); 229 230 batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK, 231 max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg, 232 &hc->device_manager); 233 if (!batch) 234 return ENOMEM; 235 batch_bulk_out(batch); 236 const int ret = uhci_hc_schedule(hc, batch); 237 if (ret != EOK) { 238 batch_dispose(batch); 239 return ret; 240 } 241 return EOK; 242 } 243 /*----------------------------------------------------------------------------*/ 244 /** Bulk in transaction interface function 245 * 246 * @param[in] fun DDF function that was called. 247 * @param[in] target USB device to write to. 248 * @param[in] max_packet_size maximum size of data packet the device accepts 249 * @param[out] data Data destination. 250 * @param[in] size Size of data source. 251 * @param[in] callback Function to call on transaction completion 252 * @param[in] arg Additional for callback function. 253 * @return Error code. 254 */ 255 static int bulk_in(ddf_fun_t *fun, usb_target_t target, 256 size_t max_packet_size, void *data, size_t size, 257 usbhc_iface_transfer_in_callback_t callback, void *arg) 258 { 259 assert(fun); 260 uhci_hc_t *hc = fun_to_uhci_hc(fun); 261 assert(hc); 262 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 263 usb_log_debug("Bulk IN %d:%d %zu(%zu).\n", 264 target.address, target.endpoint, size, max_packet_size); 265 266 batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK, 267 max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg, 268 &hc->device_manager); 269 if (!batch) 270 return ENOMEM; 271 batch_bulk_in(batch); 272 const int ret = uhci_hc_schedule(hc, batch); 273 if (ret != EOK) { 274 batch_dispose(batch); 275 return ret; 276 } 277 return EOK; 278 } 279 /*----------------------------------------------------------------------------*/ 280 /** Control write transaction interface function 281 * 282 * @param[in] fun DDF function that was called. 283 * @param[in] target USB device to write to. 284 * @param[in] max_packet_size maximum size of data packet the device accepts. 285 * @param[in] setup_data Data to send with SETUP packet. 286 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B). 287 * @param[in] data Source of data. 288 * @param[in] size Size of data source. 289 * @param[in] callback Function to call on transaction completion. 290 * @param[in] arg Additional for callback function. 291 * @return Error code. 292 */ 142 293 static int control_write(ddf_fun_t *fun, usb_target_t target, 143 294 size_t max_packet_size, … … 146 297 { 147 298 assert(fun); 148 uhci_t *hc = fun_to_uhci(fun); 149 assert(hc); 150 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 151 usb_log_debug("Control WRITE %d:%d %zu(%zu).\n", 152 target.address, target.endpoint, size, max_packet_size); 299 uhci_hc_t *hc = fun_to_uhci_hc(fun); 300 assert(hc); 301 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 302 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n", 303 speed, target.address, target.endpoint, size, max_packet_size); 304 305 if (setup_size != 8) 306 return EINVAL; 153 307 154 308 batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL, 155 309 max_packet_size, speed, data, size, setup_data, setup_size, 156 NULL, callback, arg); 157 if (!batch) 158 return ENOMEM; 310 NULL, callback, arg, &hc->device_manager); 311 if (!batch) 312 return ENOMEM; 313 device_keeper_reset_if_need(&hc->device_manager, target, setup_data); 159 314 batch_control_write(batch); 160 return EOK; 161 } 162 /*----------------------------------------------------------------------------*/ 315 const int ret = uhci_hc_schedule(hc, batch); 316 if (ret != EOK) { 317 batch_dispose(batch); 318 return ret; 319 } 320 return EOK; 321 } 322 /*----------------------------------------------------------------------------*/ 323 /** Control read transaction interface function 324 * 325 * @param[in] fun DDF function that was called. 326 * @param[in] target USB device to write to. 327 * @param[in] max_packet_size maximum size of data packet the device accepts. 328 * @param[in] setup_data Data to send with SETUP packet. 329 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B). 330 * @param[out] data Source of data. 331 * @param[in] size Size of data source. 332 * @param[in] callback Function to call on transaction completion. 333 * @param[in] arg Additional for callback function. 334 * @return Error code. 335 */ 163 336 static int control_read(ddf_fun_t *fun, usb_target_t target, 164 337 size_t max_packet_size, … … 167 340 { 168 341 assert(fun); 169 uhci_ t *hc = fun_to_uhci(fun);170 assert(hc); 171 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 172 173 usb_log_debug("Control READ %d:%d %zu(%zu).\n",174 target.address, target.endpoint, size, max_packet_size);342 uhci_hc_t *hc = fun_to_uhci_hc(fun); 343 assert(hc); 344 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 345 346 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n", 347 speed, target.address, target.endpoint, size, max_packet_size); 175 348 batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL, 176 349 max_packet_size, speed, data, size, setup_data, setup_size, callback, 177 NULL, arg );350 NULL, arg, &hc->device_manager); 178 351 if (!batch) 179 352 return ENOMEM; 180 353 batch_control_read(batch); 181 return EOK; 182 } 183 184 185 /*----------------------------------------------------------------------------*/ 186 usbhc_iface_t uhci_iface = { 354 const int ret = uhci_hc_schedule(hc, batch); 355 if (ret != EOK) { 356 batch_dispose(batch); 357 return ret; 358 } 359 return EOK; 360 } 361 /*----------------------------------------------------------------------------*/ 362 usbhc_iface_t uhci_hc_iface = { 187 363 .reserve_default_address = reserve_default_address, 188 364 .release_default_address = release_default_address, … … 194 370 .interrupt_in = interrupt_in, 195 371 372 .bulk_in = bulk_in, 373 .bulk_out = bulk_out, 374 196 375 .control_read = control_read, 197 376 .control_write = control_write, -
uspace/drv/uhci-hcd/iface.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup usb29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver iface 34 34 */ 35 35 #ifndef DRV_UHCI_IFACE_H … … 38 38 #include <usbhc_iface.h> 39 39 40 extern usbhc_iface_t uhci_ iface;40 extern usbhc_iface_t uhci_hc_iface; 41 41 42 42 #endif -
uspace/drv/uhci-hcd/main.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver initialization 33 33 */ 34 34 #include <ddf/driver.h> 35 #include <ddf/interrupt.h>36 #include <device/hw_res.h>37 35 #include <errno.h> 38 36 #include <str_error.h> 39 37 40 #include <usb_iface.h>41 38 #include <usb/ddfiface.h> 42 39 #include <usb/debug.h> 43 40 44 41 #include "iface.h" 45 #include "pci.h"46 #include "root_hub.h"47 42 #include "uhci.h" 48 43 … … 60 55 }; 61 56 /*----------------------------------------------------------------------------*/ 62 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 57 /** Initialize a new ddf driver instance for uhci hc and hub. 58 * 59 * @param[in] device DDF instance of the device to initialize. 60 * @return Error code. 61 */ 62 int uhci_add_device(ddf_dev_t *device) 63 63 { 64 assert(dev); 65 uhci_t *hc = dev_to_uhci(dev); 66 uint16_t status = IPC_GET_ARG1(*call); 67 assert(hc); 68 uhci_interrupt(hc, status); 64 usb_log_info("uhci_add_device() called\n"); 65 assert(device); 66 uhci_t *uhci = malloc(sizeof(uhci_t)); 67 if (uhci == NULL) { 68 usb_log_error("Failed to allocate UHCI driver.\n"); 69 return ENOMEM; 70 } 71 72 int ret = uhci_init(uhci, device); 73 if (ret != EOK) { 74 usb_log_error("Failed to initialzie UHCI driver.\n"); 75 return ret; 76 } 77 device->driver_data = uhci; 78 return EOK; 69 79 } 70 80 /*----------------------------------------------------------------------------*/ 71 static int uhci_add_device(ddf_dev_t *device) 72 { 73 assert(device); 74 uhci_t *hcd = NULL; 75 #define CHECK_RET_FREE_HC_RETURN(ret, message...) \ 76 if (ret != EOK) { \ 77 usb_log_error(message); \ 78 if (hcd != NULL) \ 79 free(hcd); \ 80 return ret; \ 81 } 82 83 usb_log_info("uhci_add_device() called\n"); 84 85 uintptr_t io_reg_base = 0; 86 size_t io_reg_size = 0; 87 int irq = 0; 88 89 int ret = 90 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 91 CHECK_RET_FREE_HC_RETURN(ret, 92 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 93 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 94 io_reg_base, io_reg_size, irq); 95 96 ret = pci_disable_legacy(device); 97 CHECK_RET_FREE_HC_RETURN(ret, 98 "Failed(%d) disable legacy USB: %s.\n", ret, str_error(ret)); 99 100 #if 0 101 ret = pci_enable_interrupts(device); 102 if (ret != EOK) { 103 usb_log_warning( 104 "Failed(%d) to enable interrupts, fall back to polling.\n", 105 ret); 106 } 107 #endif 108 109 hcd = malloc(sizeof(uhci_t)); 110 ret = (hcd != NULL) ? EOK : ENOMEM; 111 CHECK_RET_FREE_HC_RETURN(ret, 112 "Failed(%d) to allocate memory for uhci hcd.\n", ret); 113 114 ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size); 115 CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", 116 ret); 117 #undef CHECK_RET_FREE_HC_RETURN 118 119 /* 120 * We might free hcd, but that does not matter since no one 121 * else would access driver_data anyway. 122 */ 123 device->driver_data = hcd; 124 125 ddf_fun_t *rh = NULL; 126 #define CHECK_RET_FINI_FREE_RETURN(ret, message...) \ 127 if (ret != EOK) { \ 128 usb_log_error(message); \ 129 if (hcd != NULL) {\ 130 uhci_fini(hcd); \ 131 free(hcd); \ 132 } \ 133 if (rh != NULL) \ 134 free(rh); \ 135 return ret; \ 136 } 137 138 /* It does no harm if we register this on polling */ 139 ret = register_interrupt_handler(device, irq, irq_handler, 140 &hcd->interrupt_code); 141 CHECK_RET_FINI_FREE_RETURN(ret, 142 "Failed(%d) to register interrupt handler.\n", ret); 143 144 ret = setup_root_hub(&rh, device); 145 CHECK_RET_FINI_FREE_RETURN(ret, 146 "Failed(%d) to setup UHCI root hub.\n", ret); 147 rh->driver_data = hcd->ddf_instance; 148 149 ret = ddf_fun_bind(rh); 150 CHECK_RET_FINI_FREE_RETURN(ret, 151 "Failed(%d) to register UHCI root hub.\n", ret); 152 153 return EOK; 154 #undef CHECK_RET_FINI_FREE_RETURN 155 } 156 /*----------------------------------------------------------------------------*/ 81 /** Initialize global driver structures (NONE). 82 * 83 * @param[in] argc Nmber of arguments in argv vector (ignored). 84 * @param[in] argv Cmdline argument vector (ignored). 85 * @return Error code. 86 * 87 * Driver debug level is set here. 88 */ 157 89 int main(int argc, char *argv[]) 158 90 { 159 sleep(3); 91 sleep(3); /* TODO: remove in final version */ 160 92 usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME); 161 93 -
uspace/drv/uhci-hcd/pci.c
r3e7b7cd r72af8da 27 27 */ 28 28 /** 29 * @addtogroup drvusbuhci 29 * @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 65 65 66 66 int rc; 67 68 67 hw_resource_list_t hw_resources; 69 68 rc = hw_res_get_resource_list(parent_phone, &hw_resources); … … 82 81 for (i = 0; i < hw_resources.count; i++) { 83 82 hw_resource_t *res = &hw_resources.resources[i]; 84 switch (res->type) { 85 case INTERRUPT: 86 irq = res->res.interrupt.irq; 87 irq_found = true; 88 usb_log_debug2("Found interrupt: %d.\n", irq); 89 break; 90 case IO_RANGE: 91 io_address = res->res.io_range.address; 92 io_size = res->res.io_range.size; 93 usb_log_debug2("Found io: %llx %zu.\n", 94 res->res.io_range.address, res->res.io_range.size); 95 io_found = true; 96 break; 97 default: 98 break; 83 switch (res->type) 84 { 85 case INTERRUPT: 86 irq = res->res.interrupt.irq; 87 irq_found = true; 88 usb_log_debug2("Found interrupt: %d.\n", irq); 89 break; 90 91 case IO_RANGE: 92 io_address = res->res.io_range.address; 93 io_size = res->res.io_range.size; 94 usb_log_debug2("Found io: %llx %zu.\n", 95 res->res.io_range.address, res->res.io_range.size); 96 io_found = true; 97 98 default: 99 break; 99 100 } 100 101 } 101 102 102 if (!io_found) { 103 rc = ENOENT; 104 goto leave; 105 } 106 107 if (!irq_found) { 103 if (!io_found || !irq_found) { 108 104 rc = ENOENT; 109 105 goto leave; … … 121 117 } 122 118 /*----------------------------------------------------------------------------*/ 119 /** Call the PCI driver with a request to enable interrupts 120 * 121 * @param[in] device Device asking for interrupts 122 * @return Error code. 123 */ 123 124 int pci_enable_interrupts(ddf_dev_t *device) 124 125 { … … 130 131 } 131 132 /*----------------------------------------------------------------------------*/ 133 /** Call the PCI driver with a request to clear legacy support register 134 * 135 * @param[in] device Device asking to disable interrupts 136 * @return Error code. 137 */ 132 138 int pci_disable_legacy(ddf_dev_t *device) 133 139 { 134 140 assert(device); 135 int parent_phone = devman_parent_device_connect(device->handle,136 141 int parent_phone = 142 devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING); 137 143 if (parent_phone < 0) { 138 144 return parent_phone; … … 144 150 sysarg_t value = 0x8f00; 145 151 146 152 int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 147 153 IPC_M_CONFIG_SPACE_WRITE_16, address, value); 148 154 async_hangup(parent_phone); 149 155 150 156 return rc; 151 157 } 152 158 /*----------------------------------------------------------------------------*/ -
uspace/drv/uhci-hcd/pci.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver PCI helper functions 34 34 */ 35 35 #ifndef DRV_UHCI_PCI_H -
uspace/drv/uhci-hcd/transfer_list.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver transfer list implementation 33 33 */ 34 34 #include <errno.h> 35 36 35 #include <usb/debug.h> 37 36 38 37 #include "transfer_list.h" 39 38 39 static void transfer_list_remove_batch( 40 transfer_list_t *instance, batch_t *batch); 41 /*----------------------------------------------------------------------------*/ 42 /** Initialize transfer list structures. 43 * 44 * @param[in] instance Memory place to use. 45 * @param[in] name Name of the new list. 46 * @return Error code 47 * 48 * Allocates memory for internal qh_t structure. 49 */ 40 50 int transfer_list_init(transfer_list_t *instance, const char *name) 41 51 { 42 52 assert(instance); 43 instance->next = NULL;44 53 instance->name = name; 45 instance->queue_head = queue_head_get();54 instance->queue_head = malloc32(sizeof(qh_t)); 46 55 if (!instance->queue_head) { 47 56 usb_log_error("Failed to allocate queue head.\n"); 48 57 return ENOMEM; 49 58 } 50 instance->queue_head_pa = (uintptr_t)addr_to_phys(instance->queue_head);51 52 q ueue_head_init(instance->queue_head);59 instance->queue_head_pa = addr_to_phys(instance->queue_head); 60 61 qh_init(instance->queue_head); 53 62 list_initialize(&instance->batch_list); 54 63 fibril_mutex_initialize(&instance->guard); … … 56 65 } 57 66 /*----------------------------------------------------------------------------*/ 67 /** Set the next list in transfer list chain. 68 * 69 * @param[in] instance List to lead. 70 * @param[in] next List to append. 71 * @return Error code 72 * 73 * Does not check whether this replaces an existing list . 74 */ 58 75 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next) 59 76 { … … 62 79 if (!instance->queue_head) 63 80 return; 64 queue_head_append_qh(instance->queue_head, next->queue_head_pa); 65 instance->queue_head->element = instance->queue_head->next_queue; 66 } 67 /*----------------------------------------------------------------------------*/ 81 /* Set both next and element to point to the same QH */ 82 qh_set_next_qh(instance->queue_head, next->queue_head_pa); 83 qh_set_element_qh(instance->queue_head, next->queue_head_pa); 84 } 85 /*----------------------------------------------------------------------------*/ 86 /** Submit transfer batch to the list and queue. 87 * 88 * @param[in] instance List to use. 89 * @param[in] batch Transfer batch to submit. 90 * @return Error code 91 * 92 * The batch is added to the end of the list and queue. 93 */ 68 94 void transfer_list_add_batch(transfer_list_t *instance, batch_t *batch) 69 95 { 70 96 assert(instance); 71 97 assert(batch); 72 usb_log_debug2(" Adding batch(%p) to queue %s.\n", batch, instance->name);73 74 uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);98 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch); 99 100 const uint32_t pa = addr_to_phys(batch->qh); 75 101 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 76 pa |= LINK_POINTER_QUEUE_HEAD_FLAG; 77 78 batch->qh->next_queue = instance->queue_head->next_queue; 102 103 /* New batch will be added to the end of the current list 104 * so set the link accordingly */ 105 qh_set_next_qh(batch->qh, instance->queue_head->next); 79 106 80 107 fibril_mutex_lock(&instance->guard); 81 108 82 if (instance->queue_head->element == instance->queue_head->next_queue) { 83 /* there is nothing scheduled */ 84 list_append(&batch->link, &instance->batch_list); 85 instance->queue_head->element = pa; 86 usb_log_debug("Batch(%p) added to queue %s first.\n", 87 batch, instance->name); 88 fibril_mutex_unlock(&instance->guard); 89 return; 90 } 91 /* now we can be sure that there is someting scheduled */ 92 assert(!list_empty(&instance->batch_list)); 109 /* Add to the hardware queue. */ 110 if (list_empty(&instance->batch_list)) { 111 /* There is nothing scheduled */ 112 qh_t *qh = instance->queue_head; 113 assert(qh->element == qh->next); 114 qh_set_element_qh(qh, pa); 115 } else { 116 /* There is something scheduled */ 117 batch_t *last = list_get_instance( 118 instance->batch_list.prev, batch_t, link); 119 qh_set_next_qh(last->qh, pa); 120 } 121 /* Add to the driver list */ 122 list_append(&batch->link, &instance->batch_list); 123 93 124 batch_t *first = list_get_instance( 94 instance->batch_list.next, batch_t, link); 95 batch_t *last = list_get_instance( 96 instance->batch_list.prev, batch_t, link); 97 queue_head_append_qh(last->qh, pa); 98 list_append(&batch->link, &instance->batch_list); 99 usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n", 100 batch, instance->name, first ); 125 instance->batch_list.next, batch_t, link); 126 usb_log_debug("Batch(%p) added to queue %s, first is %p.\n", 127 batch, instance->name, first); 101 128 fibril_mutex_unlock(&instance->guard); 102 129 } 103 130 /*----------------------------------------------------------------------------*/ 104 static void transfer_list_remove_batch( 105 transfer_list_t *instance, batch_t *batch) 131 /** Remove a transfer batch from the list and queue. 132 * 133 * @param[in] instance List to use. 134 * @param[in] batch Transfer batch to remove. 135 * @return Error code 136 * 137 * Does not lock the transfer list, caller is responsible for that. 138 */ 139 void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch) 106 140 { 107 141 assert(instance); … … 109 143 assert(instance->queue_head); 110 144 assert(batch->qh); 111 usb_log_debug2("Removing batch(%p) from queue %s.\n", batch, instance->name); 112 113 /* I'm the first one here */ 145 usb_log_debug2( 146 "Queue %s: removing batch(%p).\n", instance->name, batch); 147 148 const char * pos = NULL; 149 /* Remove from the hardware queue */ 114 150 if (batch->link.prev == &instance->batch_list) { 115 usb_log_debug("Batch(%p) removed (FIRST) from queue %s, next element %x.\n",116 batch, instance->name, batch->qh->next_queue);117 instance->queue_head->element = batch->qh->next_queue;151 /* I'm the first one here */ 152 qh_set_element_qh(instance->queue_head, batch->qh->next); 153 pos = "FIRST"; 118 154 } else { 119 usb_log_debug("Batch(%p) removed (NOT FIRST) from queue, next element %x.\n", 120 batch, instance->name, batch->qh->next_queue); 121 batch_t *prev = list_get_instance(batch->link.prev, batch_t, link); 122 prev->qh->next_queue = batch->qh->next_queue; 123 } 155 batch_t *prev = 156 list_get_instance(batch->link.prev, batch_t, link); 157 qh_set_next_qh(prev->qh, batch->qh->next); 158 pos = "NOT FIRST"; 159 } 160 /* Remove from the driver list */ 124 161 list_remove(&batch->link); 125 } 126 /*----------------------------------------------------------------------------*/ 162 usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n", 163 batch, pos, instance->name, batch->qh->next); 164 } 165 /*----------------------------------------------------------------------------*/ 166 /** Check list for finished batches. 167 * 168 * @param[in] instance List to use. 169 * @return Error code 170 * 171 * Creates a local list of finished batches and calls next_step on each and 172 * every one. This is safer because next_step may theoretically access 173 * this transfer list leading to the deadlock if its done inline. 174 */ 127 175 void transfer_list_remove_finished(transfer_list_t *instance) 128 176 { … … 138 186 139 187 if (batch_is_complete(batch)) { 188 /* Save for post-processing */ 140 189 transfer_list_remove_batch(instance, batch); 141 190 list_append(current, &done); -
uspace/drv/uhci-hcd/transfer_list.h
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 32 * @brief UHCI driver transfer list structure 33 33 */ 34 34 #ifndef DRV_UHCI_TRANSFER_LIST_H … … 44 44 { 45 45 fibril_mutex_t guard; 46 q ueue_head_t *queue_head;46 qh_t *queue_head; 47 47 uint32_t queue_head_pa; 48 struct transfer_list *next;49 48 const char *name; 50 49 link_t batch_list; 51 50 } transfer_list_t; 51 52 /** Dispose transfer list structures. 53 * 54 * @param[in] instance Memory place to use. 55 * 56 * Frees memory for internal qh_t structure. 57 */ 58 static inline void transfer_list_fini(transfer_list_t *instance) 59 { 60 assert(instance); 61 free32(instance->queue_head); 62 } 52 63 53 64 int transfer_list_init(transfer_list_t *instance, const char *name); … … 55 66 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next); 56 67 57 static inline void transfer_list_fini(transfer_list_t *instance)58 {59 assert(instance);60 queue_head_dispose(instance->queue_head);61 }62 68 void transfer_list_remove_finished(transfer_list_t *instance); 63 69 -
uspace/drv/uhci-hcd/uhci.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb 28 29 /** @addtogroup drvusbuhci 29 30 * @{ 30 31 */ … … 34 35 #include <errno.h> 35 36 #include <str_error.h> 36 #include < adt/list.h>37 #include < libarch/ddi.h>38 37 #include <ddf/interrupt.h> 38 #include <usb_iface.h> 39 #include <usb/ddfiface.h> 39 40 #include <usb/debug.h> 40 #include <usb/usb.h>41 #include <usb/ddfiface.h>42 #include <usb_iface.h>43 41 44 42 #include "uhci.h" 45 43 #include "iface.h" 46 47 static irq_cmd_t uhci_cmds[] = { 48 { 49 .cmd = CMD_PIO_READ_16, 50 .addr = NULL, /* patched for every instance */ 51 .dstarg = 1 52 }, 53 { 54 .cmd = CMD_PIO_WRITE_16, 55 .addr = NULL, /* pathed for every instance */ 56 .value = 0x1f 57 }, 58 { 59 .cmd = CMD_ACCEPT 60 } 61 }; 62 63 static int usb_iface_get_address(ddf_fun_t *fun, devman_handle_t handle, 64 usb_address_t *address) 44 #include "pci.h" 45 46 47 /** IRQ handling callback, identifies device 48 * 49 * @param[in] dev DDF instance of the device to use. 50 * @param[in] iid (Unused). 51 * @param[in] call Pointer to the call that represents interrupt. 52 */ 53 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 54 { 55 assert(dev); 56 uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc; 57 uint16_t status = IPC_GET_ARG1(*call); 58 assert(hc); 59 uhci_hc_interrupt(hc, status); 60 } 61 /*----------------------------------------------------------------------------*/ 62 /** Get address of the device identified by handle. 63 * 64 * @param[in] dev DDF instance of the device to use. 65 * @param[in] iid (Unused). 66 * @param[in] call Pointer to the call that represents interrupt. 67 */ 68 static int usb_iface_get_address( 69 ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address) 65 70 { 66 71 assert(fun); 67 uhci_t *hc = fun_to_uhci(fun); 68 assert(hc); 69 70 usb_address_t addr = device_keeper_find(&hc->device_manager, 71 handle); 72 device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager; 73 74 usb_address_t addr = device_keeper_find(manager, handle); 72 75 if (addr < 0) { 73 76 return addr; … … 81 84 } 82 85 /*----------------------------------------------------------------------------*/ 83 static usb_iface_t hc_usb_iface = { 84 .get_hc_handle = usb_iface_get_hc_handle_hc_impl, 86 /** Gets handle of the respective hc (this or parent device). 87 * 88 * @param[in] root_hub_fun Root hub function seeking hc handle. 89 * @param[out] handle Place to write the handle. 90 * @return Error code. 91 */ 92 static int usb_iface_get_hc_handle( 93 ddf_fun_t *fun, devman_handle_t *handle) 94 { 95 assert(handle); 96 ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun; 97 assert(hc_fun != NULL); 98 99 *handle = hc_fun->handle; 100 return EOK; 101 } 102 /*----------------------------------------------------------------------------*/ 103 /** This iface is generic for both RH and HC. */ 104 static usb_iface_t usb_iface = { 105 .get_hc_handle = usb_iface_get_hc_handle, 85 106 .get_address = usb_iface_get_address 86 107 }; 87 108 /*----------------------------------------------------------------------------*/ 88 static ddf_dev_ops_t uhci_ops = { 89 .interfaces[USB_DEV_IFACE] = &hc_usb_iface, 90 .interfaces[USBHC_DEV_IFACE] = &uhci_iface, 91 }; 92 /*----------------------------------------------------------------------------*/ 93 static int uhci_init_transfer_lists(uhci_t *instance); 94 static int uhci_init_mem_structures(uhci_t *instance); 95 static void uhci_init_hw(uhci_t *instance); 96 97 static int uhci_interrupt_emulator(void *arg); 98 static int uhci_debug_checker(void *arg); 99 100 static bool allowed_usb_packet( 101 bool low_speed, usb_transfer_type_t, size_t size); 102 103 104 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size) 105 { 106 assert(reg_size >= sizeof(regs_t)); 107 int ret; 108 109 static ddf_dev_ops_t uhci_hc_ops = { 110 .interfaces[USB_DEV_IFACE] = &usb_iface, 111 .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */ 112 }; 113 /*----------------------------------------------------------------------------*/ 114 /** Get root hub hw resources (I/O registers). 115 * 116 * @param[in] fun Root hub function. 117 * @return Pointer to the resource list used by the root hub. 118 */ 119 static hw_resource_list_t *get_resource_list(ddf_fun_t *fun) 120 { 121 assert(fun); 122 return &((uhci_rh_t*)fun->driver_data)->resource_list; 123 } 124 /*----------------------------------------------------------------------------*/ 125 static hw_res_ops_t hw_res_iface = { 126 .get_resource_list = get_resource_list, 127 .enable_interrupt = NULL 128 }; 129 /*----------------------------------------------------------------------------*/ 130 static ddf_dev_ops_t uhci_rh_ops = { 131 .interfaces[USB_DEV_IFACE] = &usb_iface, 132 .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface 133 }; 134 /*----------------------------------------------------------------------------*/ 135 /** Initialize hc and rh ddf structures and their respective drivers. 136 * 137 * @param[in] instance UHCI structure to use. 138 * @param[in] device DDF instance of the device to use. 139 * 140 * This function does all the preparatory work for hc and rh drivers: 141 * - gets device hw resources 142 * - disables UHCI legacy support 143 * - asks for interrupt 144 * - registers interrupt handler 145 */ 146 int uhci_init(uhci_t *instance, ddf_dev_t *device) 147 { 148 assert(instance); 149 instance->hc_fun = NULL; 150 instance->rh_fun = NULL; 109 151 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \ 110 if (ret != EOK) { \ 111 usb_log_error(message); \ 112 if (instance->ddf_instance) \ 113 ddf_fun_destroy(instance->ddf_instance); \ 114 return ret; \ 115 } else (void) 0 116 117 /* Create UHCI function. */ 118 instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci"); 119 ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK; 120 CHECK_RET_DEST_FUN_RETURN(ret, 121 "Failed to create UHCI device function.\n"); 122 123 instance->ddf_instance->ops = &uhci_ops; 124 instance->ddf_instance->driver_data = instance; 125 126 ret = ddf_fun_bind(instance->ddf_instance); 152 if (ret != EOK) { \ 153 usb_log_error(message); \ 154 if (instance->hc_fun) \ 155 ddf_fun_destroy(instance->hc_fun); \ 156 if (instance->rh_fun) \ 157 ddf_fun_destroy(instance->rh_fun); \ 158 return ret; \ 159 } 160 161 uintptr_t io_reg_base = 0; 162 size_t io_reg_size = 0; 163 int irq = 0; 164 165 int ret = 166 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 167 CHECK_RET_DEST_FUN_RETURN(ret, 168 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 169 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 170 io_reg_base, io_reg_size, irq); 171 172 ret = pci_disable_legacy(device); 173 CHECK_RET_DEST_FUN_RETURN(ret, 174 "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret)); 175 176 bool interrupts = false; 177 ret = pci_enable_interrupts(device); 178 if (ret != EOK) { 179 usb_log_warning( 180 "Failed(%d) to enable interrupts, fall back to polling.\n", 181 ret); 182 } else { 183 usb_log_debug("Hw interrupts enabled.\n"); 184 interrupts = true; 185 } 186 187 instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc"); 188 ret = (instance->hc_fun == NULL) ? ENOMEM : EOK; 189 CHECK_RET_DEST_FUN_RETURN(ret, 190 "Failed(%d) to create HC function.\n", ret); 191 192 ret = uhci_hc_init(&instance->hc, instance->hc_fun, 193 (void*)io_reg_base, io_reg_size, interrupts); 194 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 195 instance->hc_fun->ops = &uhci_hc_ops; 196 instance->hc_fun->driver_data = &instance->hc; 197 ret = ddf_fun_bind(instance->hc_fun); 127 198 CHECK_RET_DEST_FUN_RETURN(ret, 128 199 "Failed(%d) to bind UHCI device function: %s.\n", 129 200 ret, str_error(ret)); 130 131 /* allow access to hc control registers */ 132 regs_t *io; 133 ret = pio_enable(regs, reg_size, (void**)&io); 134 CHECK_RET_DEST_FUN_RETURN(ret, 135 "Failed(%d) to gain access to registers at %p: %s.\n", 136 ret, str_error(ret), io); 137 instance->registers = io; 138 usb_log_debug("Device registers at %p(%u) accessible.\n", 139 io, reg_size); 140 141 ret = uhci_init_mem_structures(instance); 142 CHECK_RET_DEST_FUN_RETURN(ret, 143 "Failed to initialize UHCI memory structures.\n"); 144 145 uhci_init_hw(instance); 146 instance->cleaner = 147 fibril_create(uhci_interrupt_emulator, instance); 148 fibril_add_ready(instance->cleaner); 149 150 instance->debug_checker = fibril_create(uhci_debug_checker, instance); 151 fibril_add_ready(instance->debug_checker); 152 153 usb_log_info("Started UHCI driver.\n"); 201 #undef CHECK_RET_HC_RETURN 202 203 #define CHECK_RET_FINI_RETURN(ret, message...) \ 204 if (ret != EOK) { \ 205 usb_log_error(message); \ 206 if (instance->hc_fun) \ 207 ddf_fun_destroy(instance->hc_fun); \ 208 if (instance->rh_fun) \ 209 ddf_fun_destroy(instance->rh_fun); \ 210 uhci_hc_fini(&instance->hc); \ 211 return ret; \ 212 } 213 214 /* It does no harm if we register this on polling */ 215 ret = register_interrupt_handler(device, irq, irq_handler, 216 &instance->hc.interrupt_code); 217 CHECK_RET_FINI_RETURN(ret, 218 "Failed(%d) to register interrupt handler.\n", ret); 219 220 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh"); 221 ret = (instance->rh_fun == NULL) ? ENOMEM : EOK; 222 CHECK_RET_FINI_RETURN(ret, 223 "Failed(%d) to create root hub function.\n", ret); 224 225 ret = uhci_rh_init(&instance->rh, instance->rh_fun, 226 (uintptr_t)instance->hc.registers + 0x10, 4); 227 CHECK_RET_FINI_RETURN(ret, 228 "Failed(%d) to setup UHCI root hub.\n", ret); 229 230 instance->rh_fun->ops = &uhci_rh_ops; 231 instance->rh_fun->driver_data = &instance->rh; 232 ret = ddf_fun_bind(instance->rh_fun); 233 CHECK_RET_FINI_RETURN(ret, 234 "Failed(%d) to register UHCI root hub.\n", ret); 235 154 236 return EOK; 155 #undef CHECK_RET_DEST_FUN_RETURN 156 } 157 /*----------------------------------------------------------------------------*/ 158 void uhci_init_hw(uhci_t *instance) 159 { 160 assert(instance); 161 162 /* reset everything, who knows what touched it before us */ 163 pio_write_16(&instance->registers->usbcmd, UHCI_CMD_GLOBAL_RESET); 164 async_usleep(10000); /* 10ms according to USB spec */ 165 pio_write_16(&instance->registers->usbcmd, 0); 166 167 /* reset hc, all states and counters */ 168 pio_write_16(&instance->registers->usbcmd, UHCI_CMD_HCRESET); 169 while ((pio_read_16(&instance->registers->usbcmd) & UHCI_CMD_HCRESET) != 0) 170 { async_usleep(10); } 171 172 /* set framelist pointer */ 173 const uint32_t pa = addr_to_phys(instance->frame_list); 174 pio_write_32(&instance->registers->flbaseadd, pa); 175 176 /* enable all interrupts, but resume interrupt */ 177 pio_write_16(&instance->registers->usbintr, 178 UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET); 179 180 /* Start the hc with large(64B) packet FSBR */ 181 pio_write_16(&instance->registers->usbcmd, 182 UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE); 183 } 184 /*----------------------------------------------------------------------------*/ 185 int uhci_init_mem_structures(uhci_t *instance) 186 { 187 assert(instance); 188 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \ 189 if (ret != EOK) { \ 190 usb_log_error(message); \ 191 if (instance->interrupt_code.cmds != NULL) \ 192 free(instance->interrupt_code.cmds); \ 193 return ret; \ 194 } else (void) 0 195 196 /* init interrupt code */ 197 instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds)); 198 int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK; 199 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to allocate interrupt cmds space.\n"); 200 201 { 202 irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds; 203 memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds)); 204 interrupt_commands[0].addr = (void*)&instance->registers->usbsts; 205 interrupt_commands[1].addr = (void*)&instance->registers->usbsts; 206 instance->interrupt_code.cmdcount = 207 sizeof(uhci_cmds) / sizeof(irq_cmd_t); 208 } 209 210 /* init transfer lists */ 211 ret = uhci_init_transfer_lists(instance); 212 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to initialize transfer lists.\n"); 213 usb_log_debug("Initialized transfer lists.\n"); 214 215 /* frame list initialization */ 216 instance->frame_list = get_page(); 217 ret = instance ? EOK : ENOMEM; 218 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n"); 219 usb_log_debug("Initialized frame list.\n"); 220 221 /* initialize all frames to point to the first queue head */ 222 const uint32_t queue = 223 instance->transfers_interrupt.queue_head_pa 224 | LINK_POINTER_QUEUE_HEAD_FLAG; 225 226 unsigned i = 0; 227 for(; i < UHCI_FRAME_LIST_COUNT; ++i) { 228 instance->frame_list[i] = queue; 229 } 230 231 /* init address keeper(libusb) */ 232 device_keeper_init(&instance->device_manager); 233 usb_log_debug("Initialized device manager.\n"); 234 235 return EOK; 236 #undef CHECK_RET_DEST_CMDS_RETURN 237 } 238 /*----------------------------------------------------------------------------*/ 239 int uhci_init_transfer_lists(uhci_t *instance) 240 { 241 assert(instance); 242 #define CHECK_RET_CLEAR_RETURN(ret, message...) \ 243 if (ret != EOK) { \ 244 usb_log_error(message); \ 245 transfer_list_fini(&instance->transfers_bulk_full); \ 246 transfer_list_fini(&instance->transfers_control_full); \ 247 transfer_list_fini(&instance->transfers_control_slow); \ 248 transfer_list_fini(&instance->transfers_interrupt); \ 249 return ret; \ 250 } else (void) 0 251 252 /* initialize TODO: check errors */ 253 int ret; 254 ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL"); 255 CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list."); 256 257 ret = transfer_list_init(&instance->transfers_control_full, "CONTROL_FULL"); 258 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list."); 259 260 ret = transfer_list_init(&instance->transfers_control_slow, "CONTROL_SLOW"); 261 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list."); 262 263 ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT"); 264 CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list."); 265 266 transfer_list_set_next(&instance->transfers_control_full, 267 &instance->transfers_bulk_full); 268 transfer_list_set_next(&instance->transfers_control_slow, 269 &instance->transfers_control_full); 270 transfer_list_set_next(&instance->transfers_interrupt, 271 &instance->transfers_control_slow); 272 273 /*FSBR*/ 274 #ifdef FSBR 275 transfer_list_set_next(&instance->transfers_bulk_full, 276 &instance->transfers_control_full); 277 #endif 278 279 instance->transfers[0][USB_TRANSFER_INTERRUPT] = 280 &instance->transfers_interrupt; 281 instance->transfers[1][USB_TRANSFER_INTERRUPT] = 282 &instance->transfers_interrupt; 283 instance->transfers[0][USB_TRANSFER_CONTROL] = 284 &instance->transfers_control_full; 285 instance->transfers[1][USB_TRANSFER_CONTROL] = 286 &instance->transfers_control_slow; 287 instance->transfers[0][USB_TRANSFER_BULK] = 288 &instance->transfers_bulk_full; 289 290 return EOK; 291 #undef CHECK_RET_CLEAR_RETURN 292 } 293 /*----------------------------------------------------------------------------*/ 294 int uhci_schedule(uhci_t *instance, batch_t *batch) 295 { 296 assert(instance); 297 assert(batch); 298 const int low_speed = (batch->speed == USB_SPEED_LOW); 299 if (!allowed_usb_packet( 300 low_speed, batch->transfer_type, batch->max_packet_size)) { 301 usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n", 302 low_speed ? "LOW" : "FULL" , batch->transfer_type, 303 batch->max_packet_size); 304 return ENOTSUP; 305 } 306 /* TODO: check available bandwith here */ 307 308 transfer_list_t *list = 309 instance->transfers[low_speed][batch->transfer_type]; 310 assert(list); 311 transfer_list_add_batch(list, batch); 312 313 return EOK; 314 } 315 /*----------------------------------------------------------------------------*/ 316 void uhci_interrupt(uhci_t *instance, uint16_t status) 317 { 318 assert(instance); 319 transfer_list_remove_finished(&instance->transfers_interrupt); 320 transfer_list_remove_finished(&instance->transfers_control_slow); 321 transfer_list_remove_finished(&instance->transfers_control_full); 322 transfer_list_remove_finished(&instance->transfers_bulk_full); 323 } 324 /*----------------------------------------------------------------------------*/ 325 int uhci_interrupt_emulator(void* arg) 326 { 327 usb_log_debug("Started interrupt emulator.\n"); 328 uhci_t *instance = (uhci_t*)arg; 329 assert(instance); 330 331 while (1) { 332 uint16_t status = pio_read_16(&instance->registers->usbsts); 333 if (status != 0) 334 usb_log_debug2("UHCI status: %x.\n", status); 335 status |= 1; 336 uhci_interrupt(instance, status); 337 pio_write_16(&instance->registers->usbsts, 0x1f); 338 async_usleep(UHCI_CLEANER_TIMEOUT * 5); 339 } 340 return EOK; 341 } 342 /*---------------------------------------------------------------------------*/ 343 int uhci_debug_checker(void *arg) 344 { 345 uhci_t *instance = (uhci_t*)arg; 346 assert(instance); 347 348 #define QH(queue) \ 349 instance->transfers_##queue.queue_head 350 351 while (1) { 352 const uint16_t cmd = pio_read_16(&instance->registers->usbcmd); 353 const uint16_t sts = pio_read_16(&instance->registers->usbsts); 354 const uint16_t intr = 355 pio_read_16(&instance->registers->usbintr); 356 357 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 358 usb_log_debug2("Command: %X Status: %X Intr: %x\n", 359 cmd, sts, intr); 360 } 361 362 uintptr_t frame_list = 363 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 364 if (frame_list != addr_to_phys(instance->frame_list)) { 365 usb_log_debug("Framelist address: %p vs. %p.\n", 366 frame_list, addr_to_phys(instance->frame_list)); 367 } 368 369 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff; 370 usb_log_debug2("Framelist item: %d \n", frnum ); 371 372 uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf); 373 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 374 if (expected_pa != real_pa) { 375 usb_log_debug("Interrupt QH: %p vs. %p.\n", 376 expected_pa, real_pa); 377 } 378 379 expected_pa = QH(interrupt)->next_queue & (~0xf); 380 real_pa = addr_to_phys(QH(control_slow)); 381 if (expected_pa != real_pa) { 382 usb_log_debug("Control Slow QH: %p vs. %p.\n", 383 expected_pa, real_pa); 384 } 385 386 expected_pa = QH(control_slow)->next_queue & (~0xf); 387 real_pa = addr_to_phys(QH(control_full)); 388 if (expected_pa != real_pa) { 389 usb_log_debug("Control Full QH: %p vs. %p.\n", 390 expected_pa, real_pa); 391 } 392 393 expected_pa = QH(control_full)->next_queue & (~0xf); 394 real_pa = addr_to_phys(QH(bulk_full)); 395 if (expected_pa != real_pa ) { 396 usb_log_debug("Bulk QH: %p vs. %p.\n", 397 expected_pa, real_pa); 398 } 399 async_usleep(UHCI_DEBUGER_TIMEOUT); 400 } 401 return 0; 402 #undef QH 403 } 404 /*----------------------------------------------------------------------------*/ 405 bool allowed_usb_packet( 406 bool low_speed, usb_transfer_type_t transfer, size_t size) 407 { 408 /* see USB specification chapter 5.5-5.8 for magic numbers used here */ 409 switch(transfer) 410 { 411 case USB_TRANSFER_ISOCHRONOUS: 412 return (!low_speed && size < 1024); 413 case USB_TRANSFER_INTERRUPT: 414 return size <= (low_speed ? 8 : 64); 415 case USB_TRANSFER_CONTROL: /* device specifies its own max size */ 416 return (size <= (low_speed ? 8 : 64)); 417 case USB_TRANSFER_BULK: /* device specifies its own max size */ 418 return (!low_speed && size <= 64); 419 } 420 return false; 237 #undef CHECK_RET_FINI_RETURN 421 238 } 422 239 /** -
uspace/drv/uhci-hcd/uhci.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 /** @file 33 * @brief UHCI driver 33 * @brief UHCI driver main structure for both host controller and root-hub. 34 34 */ 35 35 #ifndef DRV_UHCI_UHCI_H 36 36 #define DRV_UHCI_UHCI_H 37 #include <ddi.h> 38 #include <ddf/driver.h> 37 39 38 #include <fibril.h> 39 #include <fibril_synch.h> 40 #include <adt/list.h> 41 #include <ddi.h> 42 43 #include <usbhc_iface.h> 44 45 #include "batch.h" 46 #include "transfer_list.h" 47 #include "utils/device_keeper.h" 48 49 typedef struct uhci_regs { 50 uint16_t usbcmd; 51 #define UHCI_CMD_MAX_PACKET (1 << 7) 52 #define UHCI_CMD_CONFIGURE (1 << 6) 53 #define UHCI_CMD_DEBUG (1 << 5) 54 #define UHCI_CMD_FORCE_GLOBAL_RESUME (1 << 4) 55 #define UHCI_CMD_FORCE_GLOBAL_SUSPEND (1 << 3) 56 #define UHCI_CMD_GLOBAL_RESET (1 << 2) 57 #define UHCI_CMD_HCRESET (1 << 1) 58 #define UHCI_CMD_RUN_STOP (1 << 0) 59 60 uint16_t usbsts; 61 #define UHCI_STATUS_HALTED (1 << 5) 62 #define UHCI_STATUS_PROCESS_ERROR (1 << 4) 63 #define UHCI_STATUS_SYSTEM_ERROR (1 << 3) 64 #define UHCI_STATUS_RESUME (1 << 2) 65 #define UHCI_STATUS_ERROR_INTERRUPT (1 << 1) 66 #define UHCI_STATUS_INTERRUPT (1 << 0) 67 68 uint16_t usbintr; 69 #define UHCI_INTR_SHORT_PACKET (1 << 3) 70 #define UHCI_INTR_COMPLETE (1 << 2) 71 #define UHCI_INTR_RESUME (1 << 1) 72 #define UHCI_INTR_CRC (1 << 0) 73 74 uint16_t frnum; 75 uint32_t flbaseadd; 76 uint8_t sofmod; 77 } regs_t; 78 79 #define UHCI_FRAME_LIST_COUNT 1024 80 #define UHCI_CLEANER_TIMEOUT 10000 81 #define UHCI_DEBUGER_TIMEOUT 5000000 40 #include "uhci_hc.h" 41 #include "uhci_rh.h" 82 42 83 43 typedef struct uhci { 84 device_keeper_t device_manager; 44 ddf_fun_t *hc_fun; 45 ddf_fun_t *rh_fun; 85 46 86 volatile regs_t *registers; 87 88 link_pointer_t *frame_list; 89 90 transfer_list_t transfers_bulk_full; 91 transfer_list_t transfers_control_full; 92 transfer_list_t transfers_control_slow; 93 transfer_list_t transfers_interrupt; 94 95 transfer_list_t *transfers[2][4]; 96 97 irq_code_t interrupt_code; 98 99 fid_t cleaner; 100 fid_t debug_checker; 101 102 ddf_fun_t *ddf_instance; 47 uhci_hc_t hc; 48 uhci_rh_t rh; 103 49 } uhci_t; 104 50 105 /* init uhci specifics in device.driver_data */ 106 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size); 107 108 static inline void uhci_fini(uhci_t *instance) {}; 109 110 int uhci_schedule(uhci_t *instance, batch_t *batch); 111 112 void uhci_interrupt(uhci_t *instance, uint16_t status); 113 114 static inline uhci_t * dev_to_uhci(ddf_dev_t *dev) 115 { return (uhci_t*)dev->driver_data; } 116 117 static inline uhci_t * fun_to_uhci(ddf_fun_t *fun) 118 { return (uhci_t*)fun->driver_data; } 119 51 int uhci_init(uhci_t *instance, ddf_dev_t *device); 120 52 121 53 #endif -
uspace/drv/uhci-hcd/uhci_rh.c
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0 Vojtech Horky2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup libusb 28 /** @addtogroup drvusbuhci 30 29 * @{ 31 30 */ 32 31 /** @file 33 * @brief Common definitions for both HC driver and hub driver.32 * @brief UHCI driver 34 33 */ 35 #ifndef LIBUSB_HCDHUBD_PRIVATE_H_ 36 #define LIBUSB_HCDHUBD_PRIVATE_H_ 34 #include <assert.h> 35 #include <errno.h> 36 #include <str_error.h> 37 #include <stdio.h> 37 38 38 #define USB_HUB_DEVICE_NAME "usbhub" 39 #define USB_KBD_DEVICE_NAME "hid" 39 #include <usb/debug.h> 40 40 41 extern link_t hc_list; 42 extern usb_hc_driver_t *hc_driver; 41 #include "uhci_rh.h" 42 #include "uhci_hc.h" 43 43 44 extern usbhc_iface_t usbhc_interface; 44 /** Root hub initialization 45 * @param[in] instance RH structure to initialize 46 * @param[in] fun DDF function representing UHCI root hub 47 * @param[in] reg_addr Address of root hub status and control registers. 48 * @param[in] reg_size Size of accessible address space. 49 * @return Error code. 50 */ 51 int uhci_rh_init( 52 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size) 53 { 54 assert(fun); 45 55 46 usb_address_t usb_get_address_by_handle(devman_handle_t); 47 int usb_add_hc_device(device_t *); 56 char *match_str = NULL; 57 int ret = asprintf(&match_str, "usb&uhci&root-hub"); 58 if (ret < 0) { 59 usb_log_error("Failed to create root hub match string.\n"); 60 return ENOMEM; 61 } 48 62 49 /** lowest allowed usb address */ 50 extern int usb_lowest_address; 63 ret = ddf_fun_add_match_id(fun, match_str, 100); 64 if (ret != EOK) { 65 usb_log_error("Failed(%d) to add root hub match id: %s\n", 66 ret, str_error(ret)); 67 return ret; 68 } 51 69 52 /** highest allowed usb address */ 53 extern int usb_highest_address; 70 hw_resource_list_t *resource_list = &instance->resource_list; 71 resource_list->count = 1; 72 resource_list->resources = &instance->io_regs; 73 assert(resource_list->resources); 74 instance->io_regs.type = IO_RANGE; 75 instance->io_regs.res.io_range.address = reg_addr; 76 instance->io_regs.res.io_range.size = reg_size; 77 instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN; 54 78 55 /** 56 * @brief initialize address list of given hcd 57 * 58 * This function should be used only for hcd initialization. 59 * It creates interval list of free addresses, thus it is initialized as 60 * list with one interval with whole address space. Using an address shrinks 61 * the interval, freeing an address extends an interval or creates a 62 * new one. 63 * 64 * @param hcd 65 * @return 66 */ 67 void usb_create_address_list(usb_hc_device_t * hcd); 68 69 70 71 72 73 74 #endif 79 return EOK; 80 } 75 81 /** 76 82 * @} -
uspace/drv/uhci-hcd/uhci_rh.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 33 33 * @brief UHCI driver 34 34 */ 35 #ifndef DRV_UHCI_ ROOT_HUB_H36 #define DRV_UHCI_ ROOT_HUB_H35 #ifndef DRV_UHCI_UHCI_RH_H 36 #define DRV_UHCI_UHCI_RH_H 37 37 38 38 #include <ddf/driver.h> 39 #include <ops/hw_res.h> 39 40 40 int setup_root_hub(ddf_fun_t **device, ddf_dev_t *hc); 41 typedef struct uhci_rh { 42 hw_resource_list_t resource_list; 43 hw_resource_t io_regs; 44 } uhci_rh_t; 45 46 int uhci_rh_init( 47 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size); 41 48 42 49 #endif -
uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ … … 46 46 #define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */ 47 47 48 #define LINK_POINTER_QH(address) \ 49 ((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG) 50 48 51 #endif 49 52 /** -
uspace/drv/uhci-hcd/uhci_struct/queue_head.h
r3e7b7cd r72af8da 1 2 1 /* 3 2 * Copyright (c) 2010 Jan Vesely … … 27 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 27 */ 29 /** @addtogroup usb28 /** @addtogroup drv usbuhcihc 30 29 * @{ 31 30 */ … … 43 42 44 43 typedef struct queue_head { 45 volatile link_pointer_t next _queue;44 volatile link_pointer_t next; 46 45 volatile link_pointer_t element; 47 } __attribute__((packed)) queue_head_t; 48 49 static inline void queue_head_init(queue_head_t *instance) 46 } __attribute__((packed)) qh_t; 47 /*----------------------------------------------------------------------------*/ 48 /** Initialize queue head structure 49 * 50 * @param[in] instance qh_t structure to initialize. 51 * 52 * Sets both pointer to terminal NULL. 53 */ 54 static inline void qh_init(qh_t *instance) 50 55 { 51 56 assert(instance); 52 57 53 58 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 54 instance->next _queue= 0 | LINK_POINTER_TERMINATE_FLAG;59 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 55 60 } 56 57 static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa) 61 /*----------------------------------------------------------------------------*/ 62 /** Set queue head next pointer 63 * 64 * @param[in] instance qh_t structure to use. 65 * @param[in] pa Physical address of the next queue head. 66 * 67 * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal 68 * NULL. 69 */ 70 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa) 58 71 { 59 if (pa) { 60 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 72 /* Address is valid and not terminal */ 73 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 74 instance->next = (pa & LINK_POINTER_ADDRESS_MASK) 61 75 | LINK_POINTER_QUEUE_HEAD_FLAG; 76 } else { 77 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 62 78 } 63 79 } 64 65 static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa) 80 /*----------------------------------------------------------------------------*/ 81 /** Set queue head element pointer 82 * 83 * @param[in] instance qh_t structure to initialize. 84 * @param[in] pa Physical address of the next queue head. 85 * 86 * Adds proper flag. If the pointer is NULL or terminal, sets element 87 * to terminal NULL. 88 */ 89 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa) 66 90 { 67 if (pa) { 68 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 91 /* Address is valid and not terminal */ 92 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 93 instance->element = (pa & LINK_POINTER_ADDRESS_MASK) 69 94 | LINK_POINTER_QUEUE_HEAD_FLAG; 95 } else { 96 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 70 97 } 71 98 } 72 73 static inline void queue_head_element_td(queue_head_t *instance, uint32_t pa) 99 /*----------------------------------------------------------------------------*/ 100 /** Set queue head element pointer 101 * 102 * @param[in] instance qh_t structure to initialize. 103 * @param[in] pa Physical address of the TD structure. 104 * 105 * Adds proper flag. If the pointer is NULL or terminal, sets element 106 * to terminal NULL. 107 */ 108 static inline void qh_set_element_td(qh_t *instance, uint32_t pa) 74 109 { 75 if (pa ) {110 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 76 111 instance->element = (pa & LINK_POINTER_ADDRESS_MASK); 112 } else { 113 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 77 114 } 78 115 } 79 80 static inline queue_head_t * queue_head_get() {81 queue_head_t *ret = malloc32(sizeof(queue_head_t));82 if (ret)83 queue_head_init(ret);84 return ret;85 }86 87 static inline void queue_head_dispose(queue_head_t *head)88 { free32(head); }89 90 116 91 117 #endif -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ … … 38 38 #include "utils/malloc32.h" 39 39 40 void transfer_descriptor_init(transfer_descriptor_t *instance, 41 int error_count, size_t size, bool toggle, bool isochronous, bool low_speed, 42 usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next) 40 /** Initialize Transfer Descriptor 41 * 42 * @param[in] instance Memory place to initialize. 43 * @param[in] err_count Number of retries hc should attempt. 44 * @param[in] size Size of data source. 45 * @param[in] toggle Value of toggle bit. 46 * @param[in] iso True if TD represents Isochronous transfer. 47 * @param[in] low_speed Target device's speed. 48 * @param[in] target Address and endpoint receiving the transfer. 49 * @param[in] pid Packet identification (SETUP, IN or OUT). 50 * @param[in] buffer Source of data. 51 * @param[in] next Net TD in transaction. 52 * @return Error code. 53 * 54 * Uses a mix of supplied and default values. 55 * Implicit values: 56 * - all TDs have vertical flag set (makes transfers to endpoints atomic) 57 * - in the error field only active it is set 58 * - if the packet uses PID_IN and is not isochronous SPD is set 59 * 60 * Dumps 8 bytes of buffer if PID_SETUP is used. 61 */ 62 void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso, 63 bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer, 64 td_t *next) 43 65 { 44 66 assert(instance); 67 assert(size < 1024); 68 assert((pid == USB_PID_SETUP) || (pid == USB_PID_IN) 69 || (pid == USB_PID_OUT)); 45 70 46 71 instance->next = 0 … … 49 74 50 75 instance->status = 0 51 | ((error_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 52 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 53 | TD_STATUS_ERROR_ACTIVE; 76 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 77 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 78 | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0) 79 | TD_STATUS_ERROR_ACTIVE; 54 80 55 assert(size < 1024); 81 if (pid == USB_PID_IN && !iso) { 82 instance->status |= TD_STATUS_SPD_FLAG; 83 } 84 56 85 instance->device = 0 57 58 59 60 61 86 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS) 87 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0) 88 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS) 89 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS) 90 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS); 62 91 63 92 instance->buffer_ptr = 0; … … 67 96 } 68 97 69 usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n", 70 instance->next, instance->status, instance->device, 71 instance->buffer_ptr, buffer); 98 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n", 99 instance, instance->next, instance->status, instance->device, 100 instance->buffer_ptr, buffer); 101 td_print_status(instance); 102 if (pid == USB_PID_SETUP) { 103 usb_log_debug("SETUP BUFFER: %s\n", 104 usb_debug_str_buffer(buffer, 8, 8)); 105 } 72 106 } 73 107 /*----------------------------------------------------------------------------*/ 74 int transfer_descriptor_status(transfer_descriptor_t *instance) 108 /** Convert TD status into standard error code 109 * 110 * @param[in] instance TD structure to use. 111 * @return Error code. 112 */ 113 int td_status(td_t *instance) 75 114 { 76 115 assert(instance); … … 96 135 return EOK; 97 136 } 137 /*----------------------------------------------------------------------------*/ 138 /** Print values in status field (dw1) in a human readable way. 139 * 140 * @param[in] instance TD structure to use. 141 */ 142 void td_print_status(td_t *instance) 143 { 144 assert(instance); 145 const uint32_t s = instance->status; 146 usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n", 147 instance, instance->status, 148 (s & TD_STATUS_SPD_FLAG) ? " SPD," : "", 149 (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK, 150 (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "", 151 (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "", 152 (s & TD_STATUS_IOC_FLAG) ? " IOC," : "", 153 (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "", 154 (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "", 155 (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "", 156 (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "", 157 (s & TD_STATUS_ERROR_NAK) ? " NAK," : "", 158 (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "", 159 (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "", 160 (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "", 161 (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK 162 ); 163 } 98 164 /** 99 165 * @} -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ … … 45 45 46 46 volatile uint32_t status; 47 48 47 #define TD_STATUS_RESERVED_MASK 0xc000f800 49 48 #define TD_STATUS_SPD_FLAG ( 1 << 29 ) 50 49 #define TD_STATUS_ERROR_COUNT_POS ( 27 ) 51 50 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 ) 52 #define TD_STATUS_ERROR_COUNT_DEFAULT 353 51 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 ) 54 52 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 ) 55 #define TD_STATUS_ COMPLETE_INTERRUPT_FLAG ( 1 << 24 )53 #define TD_STATUS_IOC_FLAG ( 1 << 24 ) 56 54 57 55 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23 ) … … 70 68 71 69 volatile uint32_t device; 72 73 70 #define TD_DEVICE_MAXLEN_POS 21 74 71 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff ) … … 85 82 86 83 /* there is 16 bytes of data available here, according to UHCI 87 * Design guide, according to linux kernel the hardware does not care 88 * we don't use it anyway84 * Design guide, according to linux kernel the hardware does not care, 85 * it just needs to be aligned, we don't use it anyway 89 86 */ 90 } __attribute__((packed)) t ransfer_descriptor_t;87 } __attribute__((packed)) td_t; 91 88 92 89 93 void t ransfer_descriptor_init(transfer_descriptor_t *instance,94 int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,95 usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next);90 void td_init(td_t *instance, int error_count, size_t size, bool toggle, 91 bool iso, bool low_speed, usb_target_t target, usb_packet_id pid, 92 void *buffer, td_t *next); 96 93 97 int t ransfer_descriptor_status(transfer_descriptor_t *instance);94 int td_status(td_t *instance); 98 95 99 static inline size_t transfer_descriptor_actual_size( 100 transfer_descriptor_t *instance) 96 void td_print_status(td_t *instance); 97 /*----------------------------------------------------------------------------*/ 98 /** Helper function for parsing actual size out of TD. 99 * 100 * @param[in] instance TD structure to use. 101 * @return Parsed actual size. 102 */ 103 static inline size_t td_act_size(td_t *instance) 101 104 { 102 105 assert(instance); 106 const uint32_t s = instance->status; 107 return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK; 108 } 109 /*----------------------------------------------------------------------------*/ 110 /** Check whether less than max data were recieved and packet is marked as SPD. 111 * 112 * @param[in] instance TD structure to use. 113 * @return True if packet is short (less than max bytes and SPD set), false 114 * otherwise. 115 */ 116 static inline bool td_is_short(td_t *instance) 117 { 118 const size_t act_size = td_act_size(instance); 119 const size_t max_size = 120 ((instance->device >> TD_DEVICE_MAXLEN_POS) + 1) 121 & TD_DEVICE_MAXLEN_MASK; 103 122 return 104 ( (instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;123 (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size; 105 124 } 106 107 static inline bool transfer_descriptor_is_active( 108 transfer_descriptor_t *instance) 125 /*----------------------------------------------------------------------------*/ 126 /** Helper function for parsing value of toggle bit. 127 * 128 * @param[in] instance TD structure to use. 129 * @return Toggle bit value. 130 */ 131 static inline int td_toggle(td_t *instance) 132 { 133 assert(instance); 134 return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0; 135 } 136 /*----------------------------------------------------------------------------*/ 137 /** Helper function for parsing value of active bit 138 * 139 * @param[in] instance TD structure to use. 140 * @return Active bit value. 141 */ 142 static inline bool td_is_active(td_t *instance) 109 143 { 110 144 assert(instance); 111 145 return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0; 112 146 } 147 /*----------------------------------------------------------------------------*/ 148 /** Helper function for setting IOC bit. 149 * 150 * @param[in] instance TD structure to use. 151 */ 152 static inline void td_set_ioc(td_t *instance) 153 { 154 assert(instance); 155 instance->status |= TD_STATUS_IOC_FLAG; 156 } 157 /*----------------------------------------------------------------------------*/ 113 158 #endif 114 159 /** -
uspace/drv/uhci-hcd/utils/device_keeper.c
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 35 35 #include <assert.h> 36 36 #include <errno.h> 37 #include <usb/debug.h> 37 38 38 39 #include "device_keeper.h" 39 40 40 41 /*----------------------------------------------------------------------------*/ 42 /** Initialize device keeper structure. 43 * 44 * @param[in] instance Memory place to initialize. 45 * 46 * Set all values to false/0. 47 */ 41 48 void device_keeper_init(device_keeper_t *instance) 42 49 { … … 49 56 instance->devices[i].occupied = false; 50 57 instance->devices[i].handle = 0; 51 } 52 } 53 /*----------------------------------------------------------------------------*/ 54 void device_keeper_reserve_default( 55 device_keeper_t *instance, usb_speed_t speed) 58 instance->devices[i].toggle_status = 0; 59 } 60 } 61 /*----------------------------------------------------------------------------*/ 62 /** Attempt to obtain address 0, blocks. 63 * 64 * @param[in] instance Device keeper structure to use. 65 * @param[in] speed Speed of the device requesting default address. 66 */ 67 void device_keeper_reserve_default(device_keeper_t *instance, usb_speed_t speed) 56 68 { 57 69 assert(instance); … … 66 78 } 67 79 /*----------------------------------------------------------------------------*/ 80 /** Attempt to obtain address 0, blocks. 81 * 82 * @param[in] instance Device keeper structure to use. 83 * @param[in] speed Speed of the device requesting default address. 84 */ 68 85 void device_keeper_release_default(device_keeper_t *instance) 69 86 { … … 75 92 } 76 93 /*----------------------------------------------------------------------------*/ 94 /** Check setup packet data for signs of toggle reset. 95 * 96 * @param[in] instance Device keeper structure to use. 97 * @param[in] target Device to receive setup packet. 98 * @param[in] data Setup packet data. 99 * 100 * Really ugly one. 101 */ 102 void device_keeper_reset_if_need( 103 device_keeper_t *instance, usb_target_t target, const unsigned char *data) 104 { 105 assert(instance); 106 fibril_mutex_lock(&instance->guard); 107 if (target.endpoint > 15 || target.endpoint < 0 108 || target.address >= USB_ADDRESS_COUNT || target.address < 0 109 || !instance->devices[target.address].occupied) { 110 fibril_mutex_unlock(&instance->guard); 111 usb_log_error("Invalid data when checking for toggle reset.\n"); 112 return; 113 } 114 115 switch (data[1]) 116 { 117 case 0x01: /*clear feature*/ 118 /* recipient is endpoint, value is zero (ENDPOINT_STALL) */ 119 if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) { 120 /* endpoint number is < 16, thus first byte is enough */ 121 instance->devices[target.address].toggle_status &= 122 ~(1 << data[4]); 123 } 124 break; 125 126 case 0x9: /* set configuration */ 127 case 0x11: /* set interface */ 128 /* target must be device */ 129 if ((data[0] & 0xf) == 0) { 130 instance->devices[target.address].toggle_status = 0; 131 } 132 break; 133 } 134 fibril_mutex_unlock(&instance->guard); 135 } 136 /*----------------------------------------------------------------------------*/ 137 /** Get current value of endpoint toggle. 138 * 139 * @param[in] instance Device keeper structure to use. 140 * @param[in] target Device and endpoint used. 141 * @return Error code 142 */ 143 int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target) 144 { 145 assert(instance); 146 int ret; 147 fibril_mutex_lock(&instance->guard); 148 if (target.endpoint > 15 || target.endpoint < 0 149 || target.address >= USB_ADDRESS_COUNT || target.address < 0 150 || !instance->devices[target.address].occupied) { 151 usb_log_error("Invalid data when asking for toggle value.\n"); 152 ret = EINVAL; 153 } else { 154 ret = (instance->devices[target.address].toggle_status 155 >> target.endpoint) & 1; 156 } 157 fibril_mutex_unlock(&instance->guard); 158 return ret; 159 } 160 /*----------------------------------------------------------------------------*/ 161 /** Set current value of endpoint toggle. 162 * 163 * @param[in] instance Device keeper structure to use. 164 * @param[in] target Device and endpoint used. 165 * @param[in] toggle Toggle value. 166 * @return Error code. 167 */ 168 int device_keeper_set_toggle( 169 device_keeper_t *instance, usb_target_t target, bool toggle) 170 { 171 assert(instance); 172 int ret; 173 fibril_mutex_lock(&instance->guard); 174 if (target.endpoint > 15 || target.endpoint < 0 175 || target.address >= USB_ADDRESS_COUNT || target.address < 0 176 || !instance->devices[target.address].occupied) { 177 usb_log_error("Invalid data when setting toggle value.\n"); 178 ret = EINVAL; 179 } else { 180 if (toggle) { 181 instance->devices[target.address].toggle_status |= (1 << target.endpoint); 182 } else { 183 instance->devices[target.address].toggle_status &= ~(1 << target.endpoint); 184 } 185 ret = EOK; 186 } 187 fibril_mutex_unlock(&instance->guard); 188 return ret; 189 } 190 /*----------------------------------------------------------------------------*/ 191 /** Get a free USB address 192 * 193 * @param[in] instance Device keeper structure to use. 194 * @param[in] speed Speed of the device requiring address. 195 * @return Free address, or error code. 196 */ 77 197 usb_address_t device_keeper_request( 78 198 device_keeper_t *instance, usb_speed_t speed) … … 96 216 instance->devices[new_address].occupied = true; 97 217 instance->devices[new_address].speed = speed; 218 instance->devices[new_address].toggle_status = 0; 98 219 instance->last_address = new_address; 99 220 fibril_mutex_unlock(&instance->guard); … … 101 222 } 102 223 /*----------------------------------------------------------------------------*/ 224 /** Bind USB address to devman handle. 225 * 226 * @param[in] instance Device keeper structure to use. 227 * @param[in] address Device address 228 * @param[in] handle Devman handle of the device. 229 */ 103 230 void device_keeper_bind( 104 231 device_keeper_t *instance, usb_address_t address, devman_handle_t handle) … … 113 240 } 114 241 /*----------------------------------------------------------------------------*/ 242 /** Release used USB address. 243 * 244 * @param[in] instance Device keeper structure to use. 245 * @param[in] address Device address 246 */ 115 247 void device_keeper_release(device_keeper_t *instance, usb_address_t address) 116 248 { … … 125 257 } 126 258 /*----------------------------------------------------------------------------*/ 259 /** Find USB address associated with the device 260 * 261 * @param[in] instance Device keeper structure to use. 262 * @param[in] handle Devman handle of the device seeking its address. 263 * @return USB Address, or error code. 264 */ 127 265 usb_address_t device_keeper_find( 128 266 device_keeper_t *instance, devman_handle_t handle) … … 142 280 } 143 281 /*----------------------------------------------------------------------------*/ 282 /** Get speed associated with the address 283 * 284 * @param[in] instance Device keeper structure to use. 285 * @param[in] address Address of the device. 286 * @return USB speed. 287 */ 144 288 usb_speed_t device_keeper_speed( 145 289 device_keeper_t *instance, usb_address_t address) -
uspace/drv/uhci-hcd/utils/device_keeper.h
r3e7b7cd r72af8da 27 27 */ 28 28 29 /** @addtogroup drvusbuhci 29 /** @addtogroup drvusbuhcihc 30 30 * @{ 31 31 */ … … 44 44 usb_speed_t speed; 45 45 bool occupied; 46 uint16_t toggle_status; 46 47 devman_handle_t handle; 47 48 }; … … 55 56 56 57 void device_keeper_init(device_keeper_t *instance); 58 57 59 void device_keeper_reserve_default( 58 60 device_keeper_t *instance, usb_speed_t speed); 61 59 62 void device_keeper_release_default(device_keeper_t *instance); 63 64 void device_keeper_reset_if_need( 65 device_keeper_t *instance, usb_target_t target, const unsigned char *setup_data); 66 67 int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target); 68 69 int device_keeper_set_toggle( 70 device_keeper_t *instance, usb_target_t target, bool toggle); 60 71 61 72 usb_address_t device_keeper_request( 62 73 device_keeper_t *instance, usb_speed_t speed); 74 63 75 void device_keeper_bind( 64 76 device_keeper_t *instance, usb_address_t address, devman_handle_t handle); 77 65 78 void device_keeper_release(device_keeper_t *instance, usb_address_t address); 79 66 80 usb_address_t device_keeper_find( 67 81 device_keeper_t *instance, devman_handle_t handle); -
uspace/drv/uhci-hcd/utils/malloc32.h
r3e7b7cd r72af8da 35 35 #define DRV_UHCI_TRANSLATOR_H 36 36 37 #include <usb/usbmem.h>38 39 37 #include <assert.h> 40 38 #include <malloc.h> … … 45 43 #define UHCI_REQUIRED_PAGE_SIZE 4096 46 44 45 /** Get physical address translation 46 * 47 * @param[in] addr Virtual address to translate 48 * @return Physical address if exists, NULL otherwise. 49 */ 47 50 static inline uintptr_t addr_to_phys(void *addr) 48 51 { … … 50 53 int ret = as_get_physical_mapping(addr, &result); 51 54 52 assert(ret == 0); 55 if (ret != EOK) 56 return 0; 53 57 return (result | ((uintptr_t)addr & 0xfff)); 54 58 } 55 59 /*----------------------------------------------------------------------------*/ 60 /** Physical mallocator simulator 61 * 62 * @param[in] size Size of the required memory space 63 * @return Address of the alligned and big enough memory place, NULL on failure. 64 */ 56 65 static inline void * malloc32(size_t size) 57 66 { return memalign(UHCI_STRCUTURES_ALIGNMENT, size); } 58 59 static inline void * get_page() 67 /*----------------------------------------------------------------------------*/ 68 /** Physical mallocator simulator 69 * 70 * @param[in] addr Address of the place allocated by malloc32 71 */ 72 static inline void free32(void *addr) 73 { if (addr) free(addr); } 74 /*----------------------------------------------------------------------------*/ 75 /** Create 4KB page mapping 76 * 77 * @return Address of the mapped page, NULL on failure. 78 */ 79 static inline void * get_page(void) 60 80 { 61 81 void * free_address = as_get_mappable_page(UHCI_REQUIRED_PAGE_SIZE); 62 82 assert(free_address); 63 83 if (free_address == 0) 64 return 0;84 return NULL; 65 85 void* ret = 66 86 as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE, 67 87 AS_AREA_READ | AS_AREA_WRITE); 68 88 if (ret != free_address) 69 return 0;89 return NULL; 70 90 return ret; 71 91 } 72 73 static inline void free32(void *addr)74 { if (addr) free(addr); }75 92 76 93 #endif -
uspace/drv/uhci-rhd/Makefile
r3e7b7cd r72af8da 35 35 main.c \ 36 36 port.c \ 37 port_status.c \38 37 root_hub.c 39 38 -
uspace/drv/uhci-rhd/main.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver32 * @brief UHCI root hub initialization routines 33 33 */ 34 34 #include <ddf/driver.h> 35 35 #include <devman.h> 36 36 #include <device/hw_res.h> 37 #include <errno.h> 37 38 #include <usb_iface.h> 38 39 #include <usb/ddfiface.h> 39 40 #include <errno.h>41 42 40 #include <usb/debug.h> 43 41 … … 47 45 static int hc_get_my_registers(ddf_dev_t *dev, 48 46 uintptr_t *io_reg_address, size_t *io_reg_size); 49 47 #if 0 48 /*----------------------------------------------------------------------------*/ 50 49 static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle) 51 50 { … … 58 57 return EOK; 59 58 } 60 59 /*----------------------------------------------------------------------------*/ 61 60 static usb_iface_t uhci_rh_usb_iface = { 62 61 .get_hc_handle = usb_iface_get_hc_handle, 63 62 .get_address = usb_iface_get_address_hub_impl 64 63 }; 65 64 /*----------------------------------------------------------------------------*/ 66 65 static ddf_dev_ops_t uhci_rh_ops = { 67 66 .interfaces[USB_DEV_IFACE] = &uhci_rh_usb_iface, 68 67 }; 69 68 #endif 69 /*----------------------------------------------------------------------------*/ 70 /** Initialize a new ddf driver instance of UHCI root hub. 71 * 72 * @param[in] device DDF instance of the device to initialize. 73 * @return Error code. 74 */ 70 75 static int uhci_rh_add_device(ddf_dev_t *device) 71 76 { … … 76 81 77 82 //device->ops = &uhci_rh_ops; 78 (void) uhci_rh_ops;79 80 uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t));81 if (!rh) {82 usb_log_error("Failed to allocate memory for driver instance.\n");83 return ENOMEM;84 }85 86 83 uintptr_t io_regs = 0; 87 84 size_t io_size = 0; 88 85 89 86 int ret = hc_get_my_registers(device, &io_regs, &io_size); 90 assert(ret == EOK); 87 if (ret != EOK) { 88 usb_log_error("Failed(%d) to get registers from parent hc.", 89 ret); 90 } 91 usb_log_info("I/O regs at %#X (size %zu).\n", io_regs, io_size); 91 92 92 /* TODO: verify values from hc */ 93 usb_log_info("I/O regs at 0x%X (size %zu).\n", io_regs, io_size); 93 uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t)); 94 if (!rh) { 95 usb_log_error("Failed to allocate driver instance.\n"); 96 return ENOMEM; 97 } 98 94 99 ret = uhci_root_hub_init(rh, (void*)io_regs, io_size, device); 95 100 if (ret != EOK) { … … 104 109 return EOK; 105 110 } 106 111 /*----------------------------------------------------------------------------*/ 107 112 static driver_ops_t uhci_rh_driver_ops = { 108 113 .add_device = uhci_rh_add_device, 109 114 }; 110 115 /*----------------------------------------------------------------------------*/ 111 116 static driver_t uhci_rh_driver = { 112 117 .name = NAME, … … 114 119 }; 115 120 /*----------------------------------------------------------------------------*/ 121 /** Initialize global driver structures (NONE). 122 * 123 * @param[in] argc Nmber of arguments in argv vector (ignored). 124 * @param[in] argv Cmdline argument vector (ignored). 125 * @return Error code. 126 * 127 * Driver debug level is set here. 128 */ 116 129 int main(int argc, char *argv[]) 117 130 { … … 120 133 } 121 134 /*----------------------------------------------------------------------------*/ 122 int hc_get_my_registers(ddf_dev_t *dev, 123 uintptr_t *io_reg_address, size_t *io_reg_size) 135 /** Get address of I/O registers. 136 * 137 * @param[in] dev Device asking for the addresses. 138 * @param[out] io_reg_address Base address of the memory range. 139 * @param[out] io_reg_size Size of the memory range. 140 * @return Error code. 141 */ 142 int hc_get_my_registers( 143 ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size) 124 144 { 125 145 assert(dev != NULL); … … 146 166 for (i = 0; i < hw_resources.count; i++) { 147 167 hw_resource_t *res = &hw_resources.resources[i]; 148 switch (res->type) {149 case IO_RANGE:150 io_address = (uintptr_t)151 152 153 154 break; 155 156 168 switch (res->type) 169 { 170 case IO_RANGE: 171 io_address = (uintptr_t) res->res.io_range.address; 172 io_size = res->res.io_range.size; 173 io_found = true; 174 175 default: 176 break; 157 177 } 158 178 } … … 170 190 } 171 191 rc = EOK; 192 172 193 leave: 173 194 async_hangup(parent_phone); 174 175 195 return rc; 176 196 } -
uspace/drv/uhci-rhd/port.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 33 */ 32 * @brief UHCI root hub port routines 33 */ 34 #include <libarch/ddi.h> /* pio_read and pio_write */ 34 35 #include <errno.h> 35 36 #include <str_error.h> … … 37 38 38 39 #include <usb/usb.h> /* usb_address_t */ 39 #include <usb/usbdevice.h>40 40 #include <usb/hub.h> 41 #include <usb/request.h>42 41 #include <usb/debug.h> 43 #include <usb/recognise.h>44 42 45 43 #include "port.h" 46 #include "port_status.h" 47 48 static int uhci_port_new_device(uhci_port_t *port, uint16_t status); 44 45 static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed); 49 46 static int uhci_port_remove_device(uhci_port_t *port); 50 47 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled); 51 48 static int uhci_port_check(void *port); 52 static int new_device_enable_port(int portno, void *arg); 53 54 int uhci_port_init( 55 uhci_port_t *port, port_status_t *address, unsigned number, 56 unsigned usec, ddf_dev_t *rh) 57 { 58 assert(port); 49 static int uhci_port_reset_enable(int portno, void *arg); 50 static void uhci_port_print_status( 51 uhci_port_t *port, const port_status_t value); 52 53 /** Register reading helper function. 54 * 55 * @param[in] port Structure to use. 56 * @return Error code. (Always EOK) 57 */ 58 static inline port_status_t uhci_port_read_status(uhci_port_t *port) 59 { 60 assert(port); 61 return pio_read_16(port->address); 62 } 63 /*----------------------------------------------------------------------------*/ 64 /** Register writing helper function. 65 * 66 * @param[in] port Structure to use. 67 * @param[in] value New register value. 68 * @return Error code. (Always EOK) 69 */ 70 static inline void uhci_port_write_status( 71 uhci_port_t *port, port_status_t value) 72 { 73 assert(port); 74 pio_write_16(port->address, value); 75 } 76 77 /*----------------------------------------------------------------------------*/ 78 /** Initialize UHCI root hub port instance. 79 * 80 * @param[in] port Memory structure to use. 81 * @param[in] addr Address of I/O register. 82 * @param[in] number Port number. 83 * @param[in] usec Polling interval. 84 * @param[in] rh Pointer to ddf instance fo the root hub driver. 85 * @return Error code. 86 * 87 * Creates and starts the polling fibril. 88 */ 89 int uhci_port_init(uhci_port_t *port, 90 port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh) 91 { 92 assert(port); 93 asprintf(&port->id_string, "Port (%p - %d)", port, number); 94 if (port->id_string == NULL) { 95 return ENOMEM; 96 } 97 59 98 port->address = address; 60 99 port->number = number; … … 62 101 port->attached_device = 0; 63 102 port->rh = rh; 103 64 104 int rc = usb_hc_connection_initialize_from_device( 65 105 &port->hc_connection, rh); … … 71 111 port->checker = fibril_create(uhci_port_check, port); 72 112 if (port->checker == 0) { 73 usb_log_error(" Port(%p - %d): failed to launch root hubfibril.",74 port-> address, port->number);113 usb_log_error("%s: failed to create polling fibril.", 114 port->id_string); 75 115 return ENOMEM; 76 116 } 117 77 118 fibril_add_ready(port->checker); 78 usb_log_debug("Port(%p - %d): Added fibril. %x\n", 79 port->address, port->number, port->checker); 80 return EOK; 81 } 82 /*----------------------------------------------------------------------------*/ 119 usb_log_debug("%s: Started polling fibril(%x).\n", 120 port->id_string, port->checker); 121 return EOK; 122 } 123 /*----------------------------------------------------------------------------*/ 124 /** Cleanup UHCI root hub port instance. 125 * 126 * @param[in] port Memory structure to use. 127 * 128 * Stops the polling fibril. 129 */ 83 130 void uhci_port_fini(uhci_port_t *port) 84 131 { 85 // TODO: destroy fibril 86 // TODO: hangup phone 87 // fibril_teardown(port->checker); 132 assert(port); 133 free(port->id_string); 134 /* TODO: Kill fibril here */ 88 135 return; 89 136 } 90 137 /*----------------------------------------------------------------------------*/ 138 /** Periodically checks port status and reports new devices. 139 * 140 * @param[in] port Port structure to use. 141 * @return Error code. 142 */ 91 143 int uhci_port_check(void *port) 92 144 { 93 uhci_port_t *port_instance = port; 94 assert(port_instance); 95 // port_status_write(port_instance->address, 0); 96 97 unsigned count = 0; 145 uhci_port_t *instance = port; 146 assert(instance); 98 147 99 148 while (1) { 100 async_usleep(port_instance->wait_period_usec); 101 102 /* read register value */ 103 port_status_t port_status = 104 port_status_read(port_instance->address); 105 106 /* debug print */ 107 static fibril_mutex_t dbg_mtx = FIBRIL_MUTEX_INITIALIZER(dbg_mtx); 108 fibril_mutex_lock(&dbg_mtx); 109 usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n", 110 port_instance->address, port_instance->number, port_status, count++); 111 // print_port_status(port_status); 112 fibril_mutex_unlock(&dbg_mtx); 113 114 if ((port_status & STATUS_CONNECTED_CHANGED) != 0) { 115 usb_log_debug("Port(%p - %d): Connected change detected: %x.\n", 116 port_instance->address, port_instance->number, port_status); 117 118 119 int rc = usb_hc_connection_open( 120 &port_instance->hc_connection); 121 if (rc != EOK) { 122 usb_log_error("Port(%p - %d): Failed to connect to HC.", 123 port_instance->address, port_instance->number); 124 continue; 125 } 126 127 /* remove any old device */ 128 if (port_instance->attached_device) { 129 usb_log_debug("Port(%p - %d): Removing device.\n", 130 port_instance->address, port_instance->number); 131 uhci_port_remove_device(port_instance); 132 } 133 134 if ((port_status & STATUS_CONNECTED) != 0) { 135 /* new device */ 136 uhci_port_new_device(port_instance, port_status); 137 } else { 138 /* ack changes by writing one to WC bits */ 139 port_status_write(port_instance->address, port_status); 140 usb_log_debug("Port(%p - %d): Change status ACK.\n", 141 port_instance->address, port_instance->number); 142 } 143 144 rc = usb_hc_connection_close( 145 &port_instance->hc_connection); 146 if (rc != EOK) { 147 usb_log_error("Port(%p - %d): Failed to disconnect from HC.", 148 port_instance->address, port_instance->number); 149 } 149 async_usleep(instance->wait_period_usec); 150 151 /* Read register value */ 152 port_status_t port_status = uhci_port_read_status(instance); 153 154 /* Print the value if it's interesting */ 155 if (port_status & ~STATUS_ALWAYS_ONE) 156 uhci_port_print_status(instance, port_status); 157 158 if ((port_status & STATUS_CONNECTED_CHANGED) == 0) 159 continue; 160 161 usb_log_debug("%s: Connected change detected: %x.\n", 162 instance->id_string, port_status); 163 164 int rc = 165 usb_hc_connection_open(&instance->hc_connection); 166 if (rc != EOK) { 167 usb_log_error("%s: Failed to connect to HC.", 168 instance->id_string); 169 continue; 150 170 } 151 } 152 return EOK; 153 } 154 171 172 /* Remove any old device */ 173 if (instance->attached_device) { 174 usb_log_debug2("%s: Removing device.\n", 175 instance->id_string); 176 uhci_port_remove_device(instance); 177 } 178 179 if ((port_status & STATUS_CONNECTED) != 0) { 180 /* New device */ 181 const usb_speed_t speed = 182 ((port_status & STATUS_LOW_SPEED) != 0) ? 183 USB_SPEED_LOW : USB_SPEED_FULL; 184 uhci_port_new_device(instance, speed); 185 } else { 186 /* Write one to WC bits, to ack changes */ 187 uhci_port_write_status(instance, port_status); 188 usb_log_debug("%s: status change ACK.\n", 189 instance->id_string); 190 } 191 192 rc = usb_hc_connection_close(&instance->hc_connection); 193 if (rc != EOK) { 194 usb_log_error("%s: Failed to disconnect.", 195 instance->id_string); 196 } 197 } 198 return EOK; 199 } 200 /*----------------------------------------------------------------------------*/ 155 201 /** Callback for enabling port during adding a new device. 156 202 * … … 158 204 * @param arg Pointer to uhci_port_t of port with the new device. 159 205 * @return Error code. 160 */ 161 static int new_device_enable_port(int portno, void *arg) 206 * 207 * Resets and enables the ub port. 208 */ 209 int uhci_port_reset_enable(int portno, void *arg) 162 210 { 163 211 uhci_port_t *port = (uhci_port_t *) arg; 164 212 165 usb_log_debug2("Port(%p - %d): new_device_enable_port.\n", 166 port->address, port->number); 213 usb_log_debug2("%s: new_device_enable_port.\n", port->id_string); 167 214 168 215 /* … … 172 219 async_usleep(100000); 173 220 174 175 /* The hub maintains the reset signal to that port for 10 ms 176 * (See Section 11.5.1.5) 221 /* 222 * Resets from root ports should be nominally 50ms 177 223 */ 178 224 { 179 usb_log_debug("Port(%p - %d): Reset Signal start.\n", 180 port->address, port->number); 181 port_status_t port_status = 182 port_status_read(port->address); 225 usb_log_debug("%s: Reset Signal start.\n", port->id_string); 226 port_status_t port_status = uhci_port_read_status(port); 183 227 port_status |= STATUS_IN_RESET; 184 port_status_write(port->address, port_status); 185 async_usleep(10000); 186 port_status = 187 port_status_read(port->address); 228 uhci_port_write_status(port, port_status); 229 async_usleep(50000); 230 port_status = uhci_port_read_status(port); 188 231 port_status &= ~STATUS_IN_RESET; 189 port_status_write(port->address, port_status); 190 usb_log_debug("Port(%p - %d): Reset Signal stop.\n", 191 port->address, port->number); 192 } 232 uhci_port_write_status(port, port_status); 233 usb_log_debug("%s: Reset Signal stop.\n", port->id_string); 234 } 235 236 /* the reset recovery time 10ms */ 237 async_usleep(10000); 193 238 194 239 /* Enable the port. */ … … 197 242 return EOK; 198 243 } 199 200 /*----------------------------------------------------------------------------*/ 201 static int uhci_port_new_device(uhci_port_t *port, uint16_t status) 244 /*----------------------------------------------------------------------------*/ 245 /** Initialize and report connected device. 246 * 247 * @param[in] port Port structure to use. 248 * @param[in] speed Detected speed. 249 * @return Error code. 250 * 251 * Uses libUSB function to do the actual work. 252 */ 253 int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed) 202 254 { 203 255 assert(port); 204 256 assert(usb_hc_connection_is_opened(&port->hc_connection)); 205 257 206 usb_log_info("Port(%p-%d): Detected new device.\n", 207 port->address, port->number); 258 usb_log_info("%s: Detected new device.\n", port->id_string); 208 259 209 260 usb_address_t dev_addr; 210 261 int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection, 211 ((status & STATUS_LOW_SPEED) != 0) ? USB_SPEED_LOW : USB_SPEED_FULL, 212 new_device_enable_port, port->number, port, 262 speed, uhci_port_reset_enable, port->number, port, 213 263 &dev_addr, &port->attached_device, NULL, NULL, NULL); 214 264 215 265 if (rc != EOK) { 216 usb_log_error(" Port(%p-%d): Failed(%d) adding newdevice: %s.\n",217 port-> address, port->number, rc, str_error(rc));266 usb_log_error("%s: Failed(%d) to add device: %s.\n", 267 port->id_string, rc, str_error(rc)); 218 268 uhci_port_set_enabled(port, false); 219 269 return rc; 220 270 } 221 271 222 usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n", 223 port->address, port->number, dev_addr, port->attached_device); 224 225 return EOK; 226 } 227 228 /*----------------------------------------------------------------------------*/ 229 static int uhci_port_remove_device(uhci_port_t *port) 230 { 231 usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n", 232 port->address, port->number, (unsigned int)port->attached_device); 233 // uhci_port_set_enabled(port, false); 234 return EOK; 235 } 236 /*----------------------------------------------------------------------------*/ 237 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled) 238 { 239 assert(port); 240 241 /* read register value */ 242 port_status_t port_status 243 = port_status_read(port->address); 244 245 /* enable port: register write */ 272 usb_log_info("%s: New device has address %d (handle %zu).\n", 273 port->id_string, dev_addr, port->attached_device); 274 275 return EOK; 276 } 277 /*----------------------------------------------------------------------------*/ 278 /** Remove device. 279 * 280 * @param[in] port Memory structure to use. 281 * @return Error code. 282 * 283 * Does not work, DDF does not support device removal. 284 * Does not even free used USB address (it would be dangerous if tis driver 285 * is still running). 286 */ 287 int uhci_port_remove_device(uhci_port_t *port) 288 { 289 usb_log_error("%s: Don't know how to remove device %d.\n", 290 port->id_string, (unsigned int)port->attached_device); 291 return EOK; 292 } 293 /*----------------------------------------------------------------------------*/ 294 /** Enable or disable root hub port. 295 * 296 * @param[in] port Port structure to use. 297 * @param[in] enabled Port status to set. 298 * @return Error code. (Always EOK) 299 */ 300 int uhci_port_set_enabled(uhci_port_t *port, bool enabled) 301 { 302 assert(port); 303 304 /* Read register value */ 305 port_status_t port_status = uhci_port_read_status(port); 306 307 /* Set enabled bit */ 246 308 if (enabled) { 247 309 port_status |= STATUS_ENABLED; … … 249 311 port_status &= ~STATUS_ENABLED; 250 312 } 251 port_status_write(port->address, port_status); 252 253 usb_log_info("Port(%p-%d): %sabled port.\n", 254 port->address, port->number, enabled ? "En" : "Dis"); 255 return EOK; 256 } 257 /*----------------------------------------------------------------------------*/ 313 314 /* Write new value. */ 315 uhci_port_write_status(port, port_status); 316 317 usb_log_info("%s: %sabled port.\n", 318 port->id_string, enabled ? "En" : "Dis"); 319 return EOK; 320 } 321 /*----------------------------------------------------------------------------*/ 322 /** Print the port status value in a human friendly way 323 * 324 * @param[in] port Port structure to use. 325 * @param[in] value Port register value to print. 326 * @return Error code. (Always EOK) 327 */ 328 void uhci_port_print_status(uhci_port_t *port, const port_status_t value) 329 { 330 assert(port); 331 usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n", 332 port->id_string, value, 333 (value & STATUS_SUSPEND) ? " SUSPENDED," : "", 334 (value & STATUS_RESUME) ? " IN RESUME," : "", 335 (value & STATUS_IN_RESET) ? " IN RESET," : "", 336 (value & STATUS_LINE_D_MINUS) ? " VD-," : "", 337 (value & STATUS_LINE_D_PLUS) ? " VD+," : "", 338 (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "", 339 (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "", 340 (value & STATUS_ENABLED) ? " ENABLED," : "", 341 (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "", 342 (value & STATUS_CONNECTED) ? " CONNECTED," : "", 343 (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE" 344 ); 345 } 258 346 /** 259 347 * @} -
uspace/drv/uhci-rhd/port.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI port driver32 * @brief UHCI root hub port routines 33 33 */ 34 34 #ifndef DRV_UHCI_PORT_H 35 35 #define DRV_UHCI_PORT_H 36 36 37 #include <assert.h> 37 #include <stdint.h> 38 #include <fibril.h> 38 39 #include <ddf/driver.h> 39 #include <stdint.h> 40 #include <usb/usbdevice.h> 40 #include <usb/usbdevice.h> /* usb_hc_connection_t */ 41 41 42 #include "port_status.h" 42 typedef uint16_t port_status_t; 43 #define STATUS_CONNECTED (1 << 0) 44 #define STATUS_CONNECTED_CHANGED (1 << 1) 45 #define STATUS_ENABLED (1 << 2) 46 #define STATUS_ENABLED_CHANGED (1 << 3) 47 #define STATUS_LINE_D_PLUS (1 << 4) 48 #define STATUS_LINE_D_MINUS (1 << 5) 49 #define STATUS_RESUME (1 << 6) 50 #define STATUS_ALWAYS_ONE (1 << 7) 51 52 #define STATUS_LOW_SPEED (1 << 8) 53 #define STATUS_IN_RESET (1 << 9) 54 #define STATUS_SUSPEND (1 << 12) 43 55 44 56 typedef struct uhci_port 45 57 { 58 char *id_string; 46 59 port_status_t *address; 47 60 unsigned number; … … 58 71 59 72 void uhci_port_fini(uhci_port_t *port); 73 60 74 #endif 61 75 /** -
uspace/drv/uhci-rhd/root_hub.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver32 * @brief UHCI root hub driver 33 33 */ 34 34 #include <errno.h> 35 #include <stdint.h>36 35 #include <ddi.h> 37 #include <devman.h>38 36 #include <usb/debug.h> 39 37 40 38 #include "root_hub.h" 41 39 40 /** Initialize UHCI root hub instance. 41 * 42 * @param[in] instance Driver memory structure to use. 43 * @param[in] addr Address of I/O registers. 44 * @param[in] size Size of available I/O space. 45 * @param[in] rh Pointer to ddf instance of the root hub driver. 46 * @return Error code. 47 */ 42 48 int uhci_root_hub_init( 43 49 uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh) … … 47 53 int ret; 48 54 49 /* allow access to root hubregisters */50 assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT == size);55 /* Allow access to root hub port registers */ 56 assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT <= size); 51 57 port_status_t *regs; 52 58 ret = pio_enable(addr, size, (void**)®s); 53 54 59 if (ret < 0) { 55 usb_log_error("Failed to gain access to port registers at %p\n", regs); 60 usb_log_error( 61 "Failed(%d) to gain access to port registers at %p\n", 62 ret, regs); 56 63 return ret; 57 64 } 58 65 59 /* add fibrils for periodic port checks */66 /* Initialize root hub ports */ 60 67 unsigned i = 0; 61 68 for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) { 62 /* mind pointer arithmetics*/69 /* NOTE: mind pointer arithmetics here */ 63 70 ret = uhci_port_init( 64 &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);71 &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh); 65 72 if (ret != EOK) { 66 73 unsigned j = 0; … … 74 81 } 75 82 /*----------------------------------------------------------------------------*/ 76 int uhci_root_hub_fini( uhci_root_hub_t* instance ) 83 /** Cleanup UHCI root hub instance. 84 * 85 * @param[in] instance Root hub structure to use. 86 * @return Error code. 87 */ 88 int uhci_root_hub_fini(uhci_root_hub_t* instance) 77 89 { 78 assert( instance ); 79 // TODO: 80 //destroy fibril here 81 //disable access to registers 90 assert(instance); 91 unsigned i = 0; 92 for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) { 93 uhci_port_fini(&instance->ports[i]); 94 } 82 95 return EOK; 83 96 } -
uspace/drv/uhci-rhd/root_hub.h
r3e7b7cd r72af8da 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ … … 35 35 #define DRV_UHCI_ROOT_HUB_H 36 36 37 #include <fibril.h>38 37 #include <ddf/driver.h> 39 38 -
uspace/drv/usbhid/Makefile
r3e7b7cd r72af8da 42 42 hidreq.c \ 43 43 kbddev.c \ 44 kbdrepeat.c \ 44 45 hiddev.c \ 45 46 $(STOLEN_LAYOUT_SOURCES) -
uspace/drv/usbhid/conv.c
r3e7b7cd r72af8da 40 40 #include "conv.h" 41 41 42 /** 43 * Mapping between USB HID key codes (from HID Usage Tables) and corresponding 44 * HelenOS key codes. 45 */ 42 46 static int scanmap_simple[255] = { 43 47 … … 163 167 }; 164 168 169 /** 170 * Translate USB HID key codes (from HID Usage Tables) to generic key codes 171 * recognized by HelenOS. 172 * 173 * @param scancode USB HID key code (from HID Usage Tables). 174 * 175 * @retval HelenOS key code corresponding to the given USB HID key code. 176 */ 165 177 unsigned int usbhid_parse_scancode(int scancode) 166 178 { -
uspace/drv/usbhid/descdump.c
r3e7b7cd r72af8da 44 44 #define BYTES_PER_LINE 12 45 45 46 /** 47 * Dumps the given buffer in hexadecimal format to standard output. 48 * 49 * @param msg Message to print before the buffer. 50 * @param buffer Buffer to print. 51 * @param length Size of the buffer in bytes. 52 */ 46 53 static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length) 47 54 { … … 62 69 #define INDENT " " 63 70 71 /** 72 * Print standard configuration descriptor to standard output. 73 * 74 * @param index Index of the descriptor. 75 * @param d Standard configuration descriptor to print. 76 */ 64 77 void dump_standard_configuration_descriptor( 65 78 int index, const usb_standard_configuration_descriptor_t *d) … … 84 97 } 85 98 99 /** 100 * Print standard interface descriptor to standard output. 101 * 102 * @param d Standard interface descriptor to print. 103 */ 86 104 void dump_standard_interface_descriptor( 87 105 const usb_standard_interface_descriptor_t *d) … … 99 117 } 100 118 119 /** 120 * Print standard endpoint descriptor to standard output. 121 * 122 * @param d Standard endpoint descriptor to print. 123 */ 101 124 void dump_standard_endpoint_descriptor( 102 125 const usb_standard_endpoint_descriptor_t *d) … … 126 149 } 127 150 151 /** 152 * Print standard HID descriptor to standard output. 153 * 154 * @param d Standard HID descriptor to print. 155 */ 128 156 void dump_standard_hid_descriptor_header( 129 157 const usb_standard_hid_descriptor_t *d) … … 139 167 } 140 168 169 /** 170 * Print HID class-specific descriptor header (type and length) to standard 171 * output. 172 * 173 * @param d HID class-specific descriptor header to print. 174 */ 141 175 void dump_standard_hid_class_descriptor_info( 142 176 const usb_standard_hid_class_descriptor_info_t *d) … … 146 180 } 147 181 182 /** 183 * Print HID class-specific descriptor (without the header) to standard output. 184 * 185 * @param index Index of the descriptor. 186 * @param type Type of the HID class-specific descriptor (Report or Physical). 187 * @param d HID class descriptor to print. 188 * @param size Size of the descriptor in bytes. 189 */ 148 190 void dump_hid_class_descriptor(int index, uint8_t type, 149 191 const uint8_t *d, size_t size ) -
uspace/drv/usbhid/hiddev.c
r3e7b7cd r72af8da 53 53 /* Non-API functions */ 54 54 /*----------------------------------------------------------------------------*/ 55 55 /** 56 * Retreives HID Report descriptor from the device. 57 * 58 * This function first parses the HID descriptor from the Interface descriptor 59 * to get the size of the Report descriptor and then requests the Report 60 * descriptor from the device. 61 * 62 * @param hid_dev HID device structure. 63 * @param config_desc Full configuration descriptor (including all nested 64 * descriptors). 65 * @param config_desc_size Size of the full configuration descriptor (in bytes). 66 * @param iface_desc Pointer to the interface descriptor inside the full 67 * configuration descriptor (@a config_desc) for the interface 68 * assigned with this device (@a hid_dev). 69 * 70 * @retval EOK if successful. 71 * @retval ENOENT if no HID descriptor could be found. 72 * @retval EINVAL if the HID descriptor or HID report descriptor have different 73 * size than expected. 74 * @retval ENOMEM if some allocation failed. 75 * @return Other value inherited from function usb_request_get_descriptor(). 76 * 77 * @sa usb_request_get_descriptor() 78 */ 56 79 static int usbhid_dev_get_report_descriptor(usbhid_dev_t *hid_dev, 57 80 uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc) … … 141 164 142 165 /*----------------------------------------------------------------------------*/ 143 166 /** 167 * Retreives descriptors from the device, initializes pipes and stores 168 * important information from descriptors. 169 * 170 * Initializes the polling pipe described by the given endpoint description 171 * (@a poll_ep_desc). 172 * 173 * Information retreived from descriptors and stored in the HID device structure: 174 * - Assigned interface number (the interface controlled by this instance of 175 * the driver) 176 * - Polling interval (from the interface descriptor) 177 * - Report descriptor 178 * 179 * @param hid_dev HID device structure to be initialized. 180 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint 181 * that has to be present in the device in order to 182 * successfuly initialize the structure. 183 * 184 * @sa usb_endpoint_pipe_initialize_from_configuration(), 185 * usbhid_dev_get_report_descriptor() 186 */ 144 187 static int usbhid_dev_process_descriptors(usbhid_dev_t *hid_dev, 145 188 usb_endpoint_description_t *poll_ep_desc) … … 230 273 /* API functions */ 231 274 /*----------------------------------------------------------------------------*/ 232 275 /** 276 * Creates new uninitialized HID device structure. 277 * 278 * @return Pointer to the new HID device structure, or NULL if an error occured. 279 */ 233 280 usbhid_dev_t *usbhid_dev_new(void) 234 281 { … … 249 296 250 297 /*----------------------------------------------------------------------------*/ 251 298 /** 299 * Properly destroys the HID device structure. 300 * 301 * @note Currently does not clean-up the used pipes, as there are no functions 302 * offering such functionality. 303 * 304 * @param hid_dev Pointer to the structure to be destroyed. 305 */ 252 306 void usbhid_dev_free(usbhid_dev_t **hid_dev) 253 307 { … … 272 326 273 327 /*----------------------------------------------------------------------------*/ 274 328 /** 329 * Initializes HID device structure. 330 * 331 * @param hid_dev HID device structure to be initialized. 332 * @param dev DDF device representing the HID device. 333 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint 334 * that has to be present in the device in order to 335 * successfuly initialize the structure. 336 * 337 * @retval EOK if successful. 338 * @retval EINVAL if some argument is missing. 339 * @return Other value inherited from one of functions 340 * usb_device_connection_initialize_from_device(), 341 * usb_endpoint_pipe_initialize_default_control(), 342 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 343 * usbhid_dev_process_descriptors(). 344 * 345 * @sa usbhid_dev_process_descriptors() 346 */ 275 347 int usbhid_dev_init(usbhid_dev_t *hid_dev, ddf_dev_t *dev, 276 348 usb_endpoint_description_t *poll_ep_desc) … … 319 391 return rc; 320 392 } 393 rc = usb_endpoint_pipe_probe_default_control(&hid_dev->ctrl_pipe); 394 if (rc != EOK) { 395 usb_log_error("Probing default control pipe failed: %s.\n", 396 str_error(rc)); 397 return rc; 398 } 321 399 322 400 /* 323 401 * Get descriptors, parse descriptors and save endpoints. 324 402 */ 325 usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 403 rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 404 if (rc != EOK) { 405 usb_log_error("Failed to start session on the control pipe: %s" 406 ".\n", str_error(rc)); 407 return rc; 408 } 326 409 327 410 rc = usbhid_dev_process_descriptors(hid_dev, poll_ep_desc); 328 329 usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 330 if (rc != EOK) { 411 if (rc != EOK) { 412 /* TODO: end session?? */ 331 413 usb_log_error("Failed to process descriptors: %s.\n", 332 414 str_error(rc)); … … 334 416 } 335 417 418 rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 419 if (rc != EOK) { 420 usb_log_warning("Failed to start session on the control pipe: " 421 "%s.\n", str_error(rc)); 422 return rc; 423 } 424 336 425 hid_dev->initialized = 1; 337 426 usb_log_info("HID device structure initialized.\n"); -
uspace/drv/usbhid/hiddev.h
r3e7b7cd r72af8da 48 48 49 49 /** 50 * @brief USB/HID device type. 50 * USB/HID device type. 51 * 52 * Holds a reference to DDF device structure, and HID-specific data, such 53 * as information about used pipes (one Control pipe and one Interrupt In pipe), 54 * polling interval, assigned interface number, Report descriptor and a 55 * reference to the Report parser used to parse incoming reports and composing 56 * outgoing reports. 51 57 */ 52 58 typedef struct { 59 /** DDF device representing the controlled HID device. */ 53 60 ddf_dev_t *device; 54 61 62 /** Physical connection to the device. */ 55 63 usb_device_connection_t wire; 64 /** USB pipe corresponding to the default Control endpoint. */ 56 65 usb_endpoint_pipe_t ctrl_pipe; 66 /** USB pipe corresponding to the Interrupt In (polling) pipe. */ 57 67 usb_endpoint_pipe_t poll_pipe; 58 68 69 /** Polling interval retreived from the Interface descriptor. */ 59 70 short poll_interval; 60 71 72 /** Interface number assigned to this device. */ 61 73 uint16_t iface; 62 74 75 /** Report descriptor. */ 63 76 uint8_t *report_desc; 77 /** HID Report parser. */ 64 78 usb_hid_report_parser_t *parser; 65 79 80 /** State of the structure (for checking before use). */ 66 81 int initialized; 67 82 } usbhid_dev_t; -
uspace/drv/usbhid/hidreq.c
r3e7b7cd r72af8da 46 46 47 47 /*----------------------------------------------------------------------------*/ 48 48 /** 49 * Send Set Report request to the HID device. 50 * 51 * @param hid_dev HID device to send the request to. 52 * @param type Type of the report. 53 * @param buffer Report data. 54 * @param buf_size Report data size (in bytes). 55 * 56 * @retval EOK if successful. 57 * @retval EINVAL if no HID device is given. 58 * @return Other value inherited from one of functions 59 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 60 * usb_control_request_set(). 61 */ 49 62 int usbhid_req_set_report(usbhid_dev_t *hid_dev, 50 63 usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size) … … 69 82 return sess_rc; 70 83 } 84 85 uint16_t value = 0; 86 value |= (type << 8); 71 87 72 88 usb_log_debug("Sending Set_Report request to the device.\n"); … … 74 90 rc = usb_control_request_set(&hid_dev->ctrl_pipe, 75 91 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 76 USB_HIDREQ_SET_REPORT, type, hid_dev->iface, buffer, buf_size); 77 78 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 79 80 if (rc != EOK) { 81 usb_log_warning("Error sending output report to the keyboard: " 82 "%s.\n", str_error(rc)); 83 return rc; 84 } 85 86 if (sess_rc != EOK) { 87 usb_log_warning("Error closing session: %s.\n", 88 str_error(sess_rc)); 89 return sess_rc; 90 } 91 92 return EOK; 93 } 94 95 /*----------------------------------------------------------------------------*/ 96 92 USB_HIDREQ_SET_REPORT, value, hid_dev->iface, buffer, buf_size); 93 94 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 95 96 if (rc != EOK) { 97 usb_log_warning("Error sending output report to the keyboard: " 98 "%s.\n", str_error(rc)); 99 return rc; 100 } 101 102 if (sess_rc != EOK) { 103 usb_log_warning("Error closing session: %s.\n", 104 str_error(sess_rc)); 105 return sess_rc; 106 } 107 108 return EOK; 109 } 110 111 /*----------------------------------------------------------------------------*/ 112 /** 113 * Send Set Protocol request to the HID device. 114 * 115 * @param hid_dev HID device to send the request to. 116 * @param protocol Protocol to set. 117 * 118 * @retval EOK if successful. 119 * @retval EINVAL if no HID device is given. 120 * @return Other value inherited from one of functions 121 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 122 * usb_control_request_set(). 123 */ 97 124 int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol) 98 125 { … … 142 169 143 170 /*----------------------------------------------------------------------------*/ 171 /** 172 * Send Set Idle request to the HID device. 173 * 174 * @param hid_dev HID device to send the request to. 175 * @param duration Duration value (is multiplicated by 4 by the device to 176 * get real duration in miliseconds). 177 * 178 * @retval EOK if successful. 179 * @retval EINVAL if no HID device is given. 180 * @return Other value inherited from one of functions 181 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 182 * usb_control_request_set(). 183 */ 184 int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration) 185 { 186 if (hid_dev == NULL) { 187 usb_log_error("usbhid_req_set_idle(): no HID device " 188 "structure given.\n"); 189 return EINVAL; 190 } 191 192 /* 193 * No need for checking other parameters, as they are checked in 194 * the called function (usb_control_request_set()). 195 */ 196 197 int rc, sess_rc; 198 199 sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 200 if (sess_rc != EOK) { 201 usb_log_warning("Failed to start a session: %s.\n", 202 str_error(sess_rc)); 203 return sess_rc; 204 } 205 206 usb_log_debug("Sending Set_Idle request to the device (" 207 "duration: %u, iface: %d).\n", duration, hid_dev->iface); 208 209 uint16_t value = duration << 8; 210 211 rc = usb_control_request_set(&hid_dev->ctrl_pipe, 212 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 213 USB_HIDREQ_SET_IDLE, value, hid_dev->iface, NULL, 0); 214 215 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 216 217 if (rc != EOK) { 218 usb_log_warning("Error sending output report to the keyboard: " 219 "%s.\n", str_error(rc)); 220 return rc; 221 } 222 223 if (sess_rc != EOK) { 224 usb_log_warning("Error closing session: %s.\n", 225 str_error(sess_rc)); 226 return sess_rc; 227 } 228 229 return EOK; 230 } 231 232 /*----------------------------------------------------------------------------*/ 233 /** 234 * Send Get Report request to the HID device. 235 * 236 * @param[in] hid_dev HID device to send the request to. 237 * @param[in] type Type of the report. 238 * @param[in][out] buffer Buffer for the report data. 239 * @param[in] buf_size Size of the buffer (in bytes). 240 * @param[out] actual_size Actual size of report received from the device 241 * (in bytes). 242 * 243 * @retval EOK if successful. 244 * @retval EINVAL if no HID device is given. 245 * @return Other value inherited from one of functions 246 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 247 * usb_control_request_set(). 248 */ 249 int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type, 250 uint8_t *buffer, size_t buf_size, size_t *actual_size) 251 { 252 if (hid_dev == NULL) { 253 usb_log_error("usbhid_req_set_report(): no HID device structure" 254 " given.\n"); 255 return EINVAL; 256 } 257 258 /* 259 * No need for checking other parameters, as they are checked in 260 * the called function (usb_control_request_set()). 261 */ 262 263 int rc, sess_rc; 264 265 sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 266 if (sess_rc != EOK) { 267 usb_log_warning("Failed to start a session: %s.\n", 268 str_error(sess_rc)); 269 return sess_rc; 270 } 271 272 uint16_t value = 0; 273 value |= (type << 8); 274 275 usb_log_debug("Sending Get_Report request to the device.\n"); 276 277 rc = usb_control_request_get(&hid_dev->ctrl_pipe, 278 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 279 USB_HIDREQ_GET_REPORT, value, hid_dev->iface, buffer, buf_size, 280 actual_size); 281 282 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 283 284 if (rc != EOK) { 285 usb_log_warning("Error sending output report to the keyboard: " 286 "%s.\n", str_error(rc)); 287 return rc; 288 } 289 290 if (sess_rc != EOK) { 291 usb_log_warning("Error closing session: %s.\n", 292 str_error(sess_rc)); 293 return sess_rc; 294 } 295 296 return EOK; 297 } 298 299 /*----------------------------------------------------------------------------*/ 300 /** 301 * Send Get Protocol request to the HID device. 302 * 303 * @param[in] hid_dev HID device to send the request to. 304 * @param[out] protocol Current protocol of the device. 305 * 306 * @retval EOK if successful. 307 * @retval EINVAL if no HID device is given. 308 * @return Other value inherited from one of functions 309 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 310 * usb_control_request_set(). 311 */ 312 int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol) 313 { 314 if (hid_dev == NULL) { 315 usb_log_error("usbhid_req_set_protocol(): no HID device " 316 "structure given.\n"); 317 return EINVAL; 318 } 319 320 /* 321 * No need for checking other parameters, as they are checked in 322 * the called function (usb_control_request_set()). 323 */ 324 325 int rc, sess_rc; 326 327 sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 328 if (sess_rc != EOK) { 329 usb_log_warning("Failed to start a session: %s.\n", 330 str_error(sess_rc)); 331 return sess_rc; 332 } 333 334 usb_log_debug("Sending Get_Protocol request to the device (" 335 "iface: %d).\n", hid_dev->iface); 336 337 uint8_t buffer[1]; 338 size_t actual_size = 0; 339 340 rc = usb_control_request_get(&hid_dev->ctrl_pipe, 341 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 342 USB_HIDREQ_GET_PROTOCOL, 0, hid_dev->iface, buffer, 1, &actual_size); 343 344 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 345 346 if (rc != EOK) { 347 usb_log_warning("Error sending output report to the keyboard: " 348 "%s.\n", str_error(rc)); 349 return rc; 350 } 351 352 if (sess_rc != EOK) { 353 usb_log_warning("Error closing session: %s.\n", 354 str_error(sess_rc)); 355 return sess_rc; 356 } 357 358 if (actual_size != 1) { 359 usb_log_warning("Wrong data size: %zu, expected: 1.\n", 360 actual_size); 361 return ELIMIT; 362 } 363 364 *protocol = buffer[0]; 365 366 return EOK; 367 } 368 369 /*----------------------------------------------------------------------------*/ 370 /** 371 * Send Get Idle request to the HID device. 372 * 373 * @param[in] hid_dev HID device to send the request to. 374 * @param[out] duration Duration value (multiplicate by 4 to get real duration 375 * in miliseconds). 376 * 377 * @retval EOK if successful. 378 * @retval EINVAL if no HID device is given. 379 * @return Other value inherited from one of functions 380 * usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(), 381 * usb_control_request_set(). 382 */ 383 int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration) 384 { 385 if (hid_dev == NULL) { 386 usb_log_error("usbhid_req_set_idle(): no HID device " 387 "structure given.\n"); 388 return EINVAL; 389 } 390 391 /* 392 * No need for checking other parameters, as they are checked in 393 * the called function (usb_control_request_set()). 394 */ 395 396 int rc, sess_rc; 397 398 sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe); 399 if (sess_rc != EOK) { 400 usb_log_warning("Failed to start a session: %s.\n", 401 str_error(sess_rc)); 402 return sess_rc; 403 } 404 405 usb_log_debug("Sending Get_Idle request to the device (" 406 "iface: %d).\n", hid_dev->iface); 407 408 uint16_t value = 0; 409 uint8_t buffer[1]; 410 size_t actual_size = 0; 411 412 rc = usb_control_request_get(&hid_dev->ctrl_pipe, 413 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 414 USB_HIDREQ_GET_IDLE, value, hid_dev->iface, buffer, 1, 415 &actual_size); 416 417 sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe); 418 419 if (rc != EOK) { 420 usb_log_warning("Error sending output report to the keyboard: " 421 "%s.\n", str_error(rc)); 422 return rc; 423 } 424 425 if (sess_rc != EOK) { 426 usb_log_warning("Error closing session: %s.\n", 427 str_error(sess_rc)); 428 return sess_rc; 429 } 430 431 if (actual_size != 1) { 432 usb_log_warning("Wrong data size: %zu, expected: 1.\n", 433 actual_size); 434 return ELIMIT; 435 } 436 437 *duration = buffer[0]; 438 439 return EOK; 440 } 441 442 /*----------------------------------------------------------------------------*/ 144 443 145 444 /** -
uspace/drv/usbhid/hidreq.h
r3e7b7cd r72af8da 50 50 int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol); 51 51 52 int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration); 53 54 int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type, 55 uint8_t *buffer, size_t buf_size, size_t *actual_size); 56 57 int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol); 58 59 int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration); 60 52 61 /*----------------------------------------------------------------------------*/ 53 62 -
uspace/drv/usbhid/kbddev.c
r3e7b7cd r72af8da 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include < fibril.h>39 #include <stdio.h> 40 40 41 41 #include <io/keycode.h> 42 42 #include <ipc/kbd.h> 43 43 #include <async.h> 44 #include <fibril.h> 45 #include <fibril_synch.h> 44 46 45 47 #include <usb/usb.h> … … 55 57 #include "layout.h" 56 58 #include "conv.h" 57 58 /*----------------------------------------------------------------------------*/ 59 59 #include "kbdrepeat.h" 60 61 /*----------------------------------------------------------------------------*/ 62 /** Default modifiers when the keyboard is initialized. */ 60 63 static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK; 64 65 /** Boot protocol report size (key part). */ 61 66 static const size_t BOOTP_REPORT_SIZE = 6; 67 68 /** Boot protocol total report size. */ 62 69 static const size_t BOOTP_BUFFER_SIZE = 8; 70 71 /** Boot protocol output report size. */ 63 72 static const size_t BOOTP_BUFFER_OUT_SIZE = 1; 73 74 /** Boot protocol error key code. */ 75 static const uint8_t BOOTP_ERROR_ROLLOVER = 1; 76 77 /** Default idle rate for keyboards. */ 78 static const uint8_t IDLE_RATE = 0; 79 80 /** Delay before a pressed key starts auto-repeating. */ 81 static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000; 82 83 /** Delay between two repeats of a pressed key when auto-repeating. */ 84 static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000; 64 85 65 86 /** Keyboard polling endpoint description for boot protocol class. */ … … 79 100 #define NUM_LAYOUTS 3 80 101 102 /** Keyboard layout map. */ 81 103 static layout_op_t *layout[NUM_LAYOUTS] = { 82 104 &us_qwerty_op, … … 90 112 /* Modifier constants */ 91 113 /*----------------------------------------------------------------------------*/ 92 114 /** Mapping of USB modifier key codes to generic modifier key codes. */ 93 115 static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = { 94 116 KC_LCTRL, /* USB_HID_MOD_LCTRL */ … … 111 133 }; 112 134 113 /** Default handler for IPC methods not handled by DDF. 114 * 115 * @param dev Device handling the call. 135 /** 136 * Default handler for IPC methods not handled by DDF. 137 * 138 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it 139 * assumes the caller is the console and thus it stores IPC phone to it for 140 * later use by the driver to notify about key events. 141 * 142 * @param fun Device function handling the call. 116 143 * @param icallid Call id. 117 144 * @param icall Call data. … … 144 171 /* Key processing functions */ 145 172 /*----------------------------------------------------------------------------*/ 146 173 /** 174 * Handles turning of LED lights on and off. 175 * 176 * In case of USB keyboards, the LEDs are handled in the driver, not in the 177 * device. When there should be a change (lock key was pressed), the driver 178 * uses a Set_Report request sent to the device to set the state of the LEDs. 179 * 180 * This functions sets the LED lights according to current settings of modifiers 181 * kept in the keyboard device structure. 182 * 183 * @param kbd_dev Keyboard device structure. 184 */ 147 185 static void usbhid_kbd_set_led(usbhid_kbd_t *kbd_dev) 148 186 { 149 187 uint8_t buffer[BOOTP_BUFFER_OUT_SIZE]; 150 188 int rc= 0; 151 unsigned i;152 189 153 190 memset(buffer, 0, BOOTP_BUFFER_OUT_SIZE); … … 177 214 } 178 215 179 // TODO: REFACTOR!!! 180 181 usb_log_debug("Output report buffer: "); 182 for (i = 0; i < BOOTP_BUFFER_OUT_SIZE; ++i) { 183 usb_log_debug("0x%x ", buffer[i]); 184 } 185 usb_log_debug("\n"); 186 187 uint16_t value = 0; 188 value |= (USB_HID_REPORT_TYPE_OUTPUT << 8); 189 216 usb_log_debug("Output report buffer: %s\n", 217 usb_debug_str_buffer(buffer, BOOTP_BUFFER_OUT_SIZE, 0)); 218 190 219 assert(kbd_dev->hid_dev != NULL); 191 220 assert(kbd_dev->hid_dev->initialized); 192 usbhid_req_set_report(kbd_dev->hid_dev, value, buffer, 193 BOOTP_BUFFER_OUT_SIZE); 194 } 195 196 /*----------------------------------------------------------------------------*/ 197 198 static void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, 199 unsigned int key) 221 usbhid_req_set_report(kbd_dev->hid_dev, USB_HID_REPORT_TYPE_OUTPUT, 222 buffer, BOOTP_BUFFER_OUT_SIZE); 223 } 224 225 /*----------------------------------------------------------------------------*/ 226 /** 227 * Processes key events. 228 * 229 * @note This function was copied from AT keyboard driver and modified to suit 230 * USB keyboard. 231 * 232 * @note Lock keys are not sent to the console, as they are completely handled 233 * in the driver. It may, however, be required later that the driver 234 * sends also these keys to application (otherwise it cannot use those 235 * keys at all). 236 * 237 * @param kbd_dev Keyboard device structure. 238 * @param type Type of the event (press / release). Recognized values: 239 * KEY_PRESS, KEY_RELEASE 240 * @param key Key code of the key according to HID Usage Tables. 241 */ 242 void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, unsigned int key) 200 243 { 201 244 console_event_t ev; 202 245 unsigned mod_mask; 203 246 204 // TODO: replace by our own parsing?? or are the key codes identical?? 247 /* 248 * These parts are copy-pasted from the AT keyboard driver. 249 * 250 * They definitely require some refactoring, but will keep it for later 251 * when the console and keyboard system is changed in HelenOS. 252 */ 205 253 switch (key) { 206 254 case KC_LCTRL: mod_mask = KM_LCTRL; break; … … 228 276 229 277 if (mod_mask != 0) { 230 usb_log_debug2("\n\nChanging mods and lock keys\n");231 usb_log_debug2("\nmods before: 0x%x\n", kbd_dev->mods);232 usb_log_debug2("\nLock keys before:0x%x\n\n",233 kbd_dev->lock_keys);234 235 278 if (type == KEY_PRESS) { 236 usb_log_debug2("\nKey pressed.\n");237 279 /* 238 280 * Only change lock state on transition from released … … 240 282 * up the lock state. 241 283 */ 284 unsigned int locks_old = kbd_dev->lock_keys; 285 242 286 kbd_dev->mods = 243 287 kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys); … … 245 289 246 290 /* Update keyboard lock indicator lights. */ 247 usbhid_kbd_set_led(kbd_dev); 291 if (kbd_dev->lock_keys != locks_old) { 292 usbhid_kbd_set_led(kbd_dev); 293 } 248 294 } else { 249 usb_log_debug2("\nKey released.\n");250 295 kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask; 251 296 } 252 297 } 253 298 254 usb_log_debug2("\n\nmods after: 0x%x\n", kbd_dev->mods);255 usb_log_debug2("\nLock keys after: 0x%x\n\n", kbd_dev->lock_keys);256 257 299 if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) { 258 300 // do not send anything to the console, this is our business … … 281 323 ev.key = key; 282 324 ev.mods = kbd_dev->mods; 283 284 if (ev.mods & KM_NUM_LOCK) {285 usb_log_debug("\n\nNum Lock turned on.\n\n");286 }287 325 288 326 ev.c = layout[active_layout]->parse_ev(&ev); … … 300 338 301 339 /*----------------------------------------------------------------------------*/ 302 340 /** 341 * Checks if modifiers were pressed or released and generates key events. 342 * 343 * @param kbd_dev Keyboard device structure. 344 * @param modifiers Bitmap of modifiers. 345 * 346 * @sa usbhid_kbd_push_ev() 347 */ 303 348 static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev, 304 349 uint8_t modifiers) … … 336 381 337 382 /*----------------------------------------------------------------------------*/ 338 383 /** 384 * Checks if some keys were pressed or released and generates key events. 385 * 386 * An event is created only when key is pressed or released. Besides handling 387 * the events (usbhid_kbd_push_ev()), the auto-repeat fibril is notified about 388 * key presses and releases (see usbhid_kbd_repeat_start() and 389 * usbhid_kbd_repeat_stop()). 390 * 391 * @param kbd_dev Keyboard device structure. 392 * @param key_codes Parsed keyboard report - codes of currently pressed keys 393 * according to HID Usage Tables. 394 * @param count Number of key codes in report (size of the report). 395 * 396 * @sa usbhid_kbd_push_ev(), usbhid_kbd_repeat_start(), usbhid_kbd_repeat_stop() 397 */ 339 398 static void usbhid_kbd_check_key_changes(usbhid_kbd_t *kbd_dev, 340 const uint8_t *key_codes) 341 { 342 // TODO: phantom state!! 343 399 const uint8_t *key_codes, size_t count) 400 { 344 401 unsigned int key; 345 402 unsigned int i, j; 346 403 347 // TODO: quite dummy right now, think of better implementation 404 /* 405 * First of all, check if the kbd have reported phantom state. 406 */ 407 i = 0; 408 // all fields should report Error Rollover 409 while (i < count && 410 key_codes[i] == BOOTP_ERROR_ROLLOVER) { 411 ++i; 412 } 413 if (i == count) { 414 usb_log_debug("Phantom state occured.\n"); 415 // phantom state, do nothing 416 return; 417 } 418 419 /* TODO: quite dummy right now, think of better implementation */ 420 assert(count == kbd_dev->key_count); 348 421 349 422 /* 350 423 * 1) Key releases 351 424 */ 352 for (j = 0; j < kbd_dev->keycode_count; ++j) {425 for (j = 0; j < count; ++j) { 353 426 // try to find the old key in the new key list 354 427 i = 0; 355 while (i < kbd_dev->key code_count356 && key_codes[i] != kbd_dev->key codes[j]) {428 while (i < kbd_dev->key_count 429 && key_codes[i] != kbd_dev->keys[j]) { 357 430 ++i; 358 431 } 359 432 360 if (i == kbd_dev->keycode_count) {433 if (i == count) { 361 434 // not found, i.e. the key was released 362 key = usbhid_parse_scancode(kbd_dev->keycodes[j]); 435 key = usbhid_parse_scancode(kbd_dev->keys[j]); 436 usbhid_kbd_repeat_stop(kbd_dev, key); 363 437 usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key); 364 usb_log_debug2(" \nKey released: %d\n", key);438 usb_log_debug2("Key released: %d\n", key); 365 439 } else { 366 440 // found, nothing happens … … 371 445 * 1) Key presses 372 446 */ 373 for (i = 0; i < kbd_dev->key code_count; ++i) {447 for (i = 0; i < kbd_dev->key_count; ++i) { 374 448 // try to find the new key in the old key list 375 449 j = 0; 376 while (j < kbd_dev->keycode_count 377 && kbd_dev->keycodes[j] != key_codes[i]) { 450 while (j < count && kbd_dev->keys[j] != key_codes[i]) { 378 451 ++j; 379 452 } 380 453 381 if (j == kbd_dev->keycode_count) {454 if (j == count) { 382 455 // not found, i.e. new key pressed 383 456 key = usbhid_parse_scancode(key_codes[i]); 384 usb_log_debug2(" \nKey pressed: %d (keycode: %d)\n", key,457 usb_log_debug2("Key pressed: %d (keycode: %d)\n", key, 385 458 key_codes[i]); 386 459 usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key); 460 usbhid_kbd_repeat_start(kbd_dev, key); 387 461 } else { 388 462 // found, nothing happens … … 390 464 } 391 465 392 memcpy(kbd_dev->keycodes, key_codes, kbd_dev->keycode_count); 393 394 usb_log_debug2("\nNew stored keycodes: "); 395 for (i = 0; i < kbd_dev->keycode_count; ++i) { 396 usb_log_debug2("%d ", kbd_dev->keycodes[i]); 397 } 466 memcpy(kbd_dev->keys, key_codes, count); 467 468 usb_log_debug("New stored keycodes: %s\n", 469 usb_debug_str_buffer(kbd_dev->keys, kbd_dev->key_count, 0)); 398 470 } 399 471 … … 401 473 /* Callbacks for parser */ 402 474 /*----------------------------------------------------------------------------*/ 403 475 /** 476 * Callback function for the HID report parser. 477 * 478 * This function is called by the HID report parser with the parsed report. 479 * The parsed report is used to check if any events occured (key was pressed or 480 * released, modifier was pressed or released). 481 * 482 * @param key_codes Parsed keyboard report - codes of currently pressed keys 483 * according to HID Usage Tables. 484 * @param count Number of key codes in report (size of the report). 485 * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI). 486 * @param arg User-specified argument. Expects pointer to the keyboard device 487 * structure representing the keyboard. 488 * 489 * @sa usbhid_kbd_check_key_changes(), usbhid_kbd_check_modifier_changes() 490 */ 404 491 static void usbhid_kbd_process_keycodes(const uint8_t *key_codes, size_t count, 405 492 uint8_t modifiers, void *arg) … … 410 497 return; 411 498 } 412 413 usb_log_debug2("Got keys from parser: ");414 unsigned i;415 for (i = 0; i < count; ++i) {416 usb_log_debug2("%d ", key_codes[i]);417 }418 usb_log_debug2("\n");419 499 420 500 usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg; 421 501 assert(kbd_dev != NULL); 422 423 if (count != kbd_dev->keycode_count) { 502 503 usb_log_debug("Got keys from parser: %s\n", 504 usb_debug_str_buffer(key_codes, kbd_dev->key_count, 0)); 505 506 if (count != kbd_dev->key_count) { 424 507 usb_log_warning("Number of received keycodes (%d) differs from" 425 " expected number (%d).\n", count, kbd_dev->key code_count);508 " expected number (%d).\n", count, kbd_dev->key_count); 426 509 return; 427 510 } 428 511 429 512 usbhid_kbd_check_modifier_changes(kbd_dev, modifiers); 430 usbhid_kbd_check_key_changes(kbd_dev, key_codes );513 usbhid_kbd_check_key_changes(kbd_dev, key_codes, count); 431 514 } 432 515 … … 434 517 /* General kbd functions */ 435 518 /*----------------------------------------------------------------------------*/ 436 519 /** 520 * Processes data received from the device in form of report. 521 * 522 * This function uses the HID report parser to translate the data received from 523 * the device into generic USB HID key codes and into generic modifiers bitmap. 524 * The parser then calls the given callback (usbhid_kbd_process_keycodes()). 525 * 526 * @note Currently, only the boot protocol is supported. 527 * 528 * @param kbd_dev Keyboard device structure (must be initialized). 529 * @param buffer Data from the keyboard (i.e. the report). 530 * @param actual_size Size of the data from keyboard (report size) in bytes. 531 * 532 * @sa usbhid_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(). 533 */ 437 534 static void usbhid_kbd_process_data(usbhid_kbd_t *kbd_dev, 438 535 uint8_t *buffer, size_t actual_size) … … 444 541 callbacks->keyboard = usbhid_kbd_process_keycodes; 445 542 446 //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 447 // NULL); 448 /*usb_log_debug2("Calling usb_hid_boot_keyboard_input_report() with size" 449 " %zu\n", actual_size);*/ 450 //dump_buffer("bufffer: ", buffer, actual_size); 543 usb_log_debug("Calling usb_hid_boot_keyboard_input_report() with " 544 "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0)); 451 545 452 546 int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size, … … 462 556 /* HID/KBD structure manipulation */ 463 557 /*----------------------------------------------------------------------------*/ 464 558 /** 559 * Creates a new USB/HID keyboard structure. 560 * 561 * The structure returned by this function is not initialized. Use 562 * usbhid_kbd_init() to initialize it prior to polling. 563 * 564 * @return New uninitialized structure for representing a USB/HID keyboard or 565 * NULL if not successful (memory error). 566 */ 465 567 static usbhid_kbd_t *usbhid_kbd_new(void) 466 568 { … … 488 590 489 591 /*----------------------------------------------------------------------------*/ 490 592 /** 593 * Properly destroys the USB/HID keyboard structure. 594 * 595 * @param kbd_dev Pointer to the structure to be destroyed. 596 */ 491 597 static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev) 492 598 { … … 503 609 } 504 610 611 if ((*kbd_dev)->repeat_mtx != NULL) { 612 /* TODO: replace by some check and wait */ 613 assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)); 614 free((*kbd_dev)->repeat_mtx); 615 } 616 505 617 free(*kbd_dev); 506 618 *kbd_dev = NULL; … … 508 620 509 621 /*----------------------------------------------------------------------------*/ 510 622 /** 623 * Initialization of the USB/HID keyboard structure. 624 * 625 * This functions initializes required structures from the device's descriptors. 626 * 627 * During initialization, the keyboard is switched into boot protocol, the idle 628 * rate is set to 0 (infinity), resulting in the keyboard only reporting event 629 * when a key is pressed or released. Finally, the LED lights are turned on 630 * according to the default setup of lock keys. 631 * 632 * @note By default, the keyboards is initialized with Num Lock turned on and 633 * other locks turned off. 634 * 635 * @param kbd_dev Keyboard device structure to be initialized. 636 * @param dev DDF device structure of the keyboard. 637 * 638 * @retval EOK if successful. 639 * @retval EINVAL if some parameter is not given. 640 * @return Other value inherited from function usbhid_dev_init(). 641 */ 511 642 static int usbhid_kbd_init(usbhid_kbd_t *kbd_dev, ddf_dev_t *dev) 512 643 { … … 543 674 544 675 // save the size of the report (boot protocol report by default) 545 kbd_dev->key code_count = BOOTP_REPORT_SIZE;546 kbd_dev->key codes = (uint8_t *)calloc(547 kbd_dev->key code_count, sizeof(uint8_t));548 549 if (kbd_dev->key codes == NULL) {676 kbd_dev->key_count = BOOTP_REPORT_SIZE; 677 kbd_dev->keys = (uint8_t *)calloc( 678 kbd_dev->key_count, sizeof(uint8_t)); 679 680 if (kbd_dev->keys == NULL) { 550 681 usb_log_fatal("No memory!\n"); 551 return rc;682 return ENOMEM; 552 683 } 553 684 … … 556 687 kbd_dev->lock_keys = 0; 557 688 689 kbd_dev->repeat.key_new = 0; 690 kbd_dev->repeat.key_repeated = 0; 691 kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT; 692 kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY; 693 694 kbd_dev->repeat_mtx = (fibril_mutex_t *)( 695 malloc(sizeof(fibril_mutex_t))); 696 if (kbd_dev->repeat_mtx == NULL) { 697 usb_log_fatal("No memory!\n"); 698 free(kbd_dev->keys); 699 return ENOMEM; 700 } 701 702 fibril_mutex_initialize(kbd_dev->repeat_mtx); 703 558 704 /* 559 705 * Set boot protocol. 560 706 * Set LEDs according to initial setup. 707 * Set Idle rate 561 708 */ 562 709 assert(kbd_dev->hid_dev != NULL); … … 566 713 usbhid_kbd_set_led(kbd_dev); 567 714 715 usbhid_req_set_idle(kbd_dev->hid_dev, IDLE_RATE); 716 568 717 kbd_dev->initialized = 1; 569 718 usb_log_info("HID/KBD device structure initialized.\n"); … … 575 724 /* HID/KBD polling */ 576 725 /*----------------------------------------------------------------------------*/ 577 726 /** 727 * Main keyboard polling function. 728 * 729 * This function uses the Interrupt In pipe of the keyboard to poll for events. 730 * The keyboard is initialized in a way that it reports only when a key is 731 * pressed or released, so there is no actual need for any sleeping between 732 * polls (see usbhid_kbd_try_add_device() or usbhid_kbd_init()). 733 * 734 * @param kbd_dev Initialized keyboard structure representing the device to 735 * poll. 736 * 737 * @sa usbhid_kbd_process_data() 738 */ 578 739 static void usbhid_kbd_poll(usbhid_kbd_t *kbd_dev) 579 740 { … … 598 759 usb_log_warning("Failed to start a session: %s.\n", 599 760 str_error(sess_rc)); 600 continue;761 break; 601 762 } 602 763 … … 610 771 usb_log_warning("Error polling the keyboard: %s.\n", 611 772 str_error(rc)); 612 continue;773 break; 613 774 } 614 775 … … 616 777 usb_log_warning("Error closing session: %s.\n", 617 778 str_error(sess_rc)); 618 continue;779 break; 619 780 } 620 781 … … 634 795 usbhid_kbd_process_data(kbd_dev, buffer, actual_size); 635 796 636 async_usleep(kbd_dev->hid_dev->poll_interval); 637 } 638 639 // not reached 640 assert(0); 641 } 642 643 /*----------------------------------------------------------------------------*/ 644 797 // disabled for now, no reason to sleep 798 //async_usleep(kbd_dev->hid_dev->poll_interval); 799 } 800 } 801 802 /*----------------------------------------------------------------------------*/ 803 /** 804 * Function executed by the main driver fibril. 805 * 806 * Just starts polling the keyboard for events. 807 * 808 * @param arg Initialized keyboard device structure (of type usbhid_kbd_t) 809 * representing the device. 810 * 811 * @retval EOK if the fibril finished polling the device. 812 * @retval EINVAL if no device was given in the argument. 813 * 814 * @sa usbhid_kbd_poll() 815 * 816 * @todo Change return value - only case when the fibril finishes is in case 817 * of some error, so the error should probably be propagated from function 818 * usbhid_kbd_poll() to here and up. 819 */ 645 820 static int usbhid_kbd_fibril(void *arg) 646 821 { … … 664 839 /* API functions */ 665 840 /*----------------------------------------------------------------------------*/ 666 841 /** 842 * Function for adding a new device of type USB/HID/keyboard. 843 * 844 * This functions initializes required structures from the device's descriptors 845 * and starts new fibril for polling the keyboard for events and another one for 846 * handling auto-repeat of keys. 847 * 848 * During initialization, the keyboard is switched into boot protocol, the idle 849 * rate is set to 0 (infinity), resulting in the keyboard only reporting event 850 * when a key is pressed or released. Finally, the LED lights are turned on 851 * according to the default setup of lock keys. 852 * 853 * @note By default, the keyboards is initialized with Num Lock turned on and 854 * other locks turned off. 855 * @note Currently supports only boot-protocol keyboards. 856 * 857 * @param dev Device to add. 858 * 859 * @retval EOK if successful. 860 * @retval ENOMEM if there 861 * @return Other error code inherited from one of functions usbhid_kbd_init(), 862 * ddf_fun_bind() and ddf_fun_add_to_class(). 863 * 864 * @sa usbhid_kbd_fibril(), usbhid_kbd_repeat_fibril() 865 */ 667 866 int usbhid_kbd_try_add_device(ddf_dev_t *dev) 668 867 { … … 686 885 "structure.\n"); 687 886 ddf_fun_destroy(kbd_fun); 688 return E INVAL; // TODO: some other code??887 return ENOMEM; // TODO: some other code?? 689 888 } 690 889 … … 735 934 } 736 935 fibril_add_ready(fid); 936 937 /* 938 * Create new fibril for auto-repeat 939 */ 940 fid = fibril_create(usbhid_kbd_repeat_fibril, kbd_dev); 941 if (fid == 0) { 942 usb_log_error("Failed to start fibril for KBD auto-repeat"); 943 return ENOMEM; 944 } 945 fibril_add_ready(fid); 737 946 738 947 (void)keyboard_ops; -
uspace/drv/usbhid/kbddev.h
r3e7b7cd r72af8da 39 39 #include <stdint.h> 40 40 41 #include <fibril_synch.h> 42 41 43 #include <usb/classes/hid.h> 42 44 #include <ddf/driver.h> … … 46 48 47 49 /*----------------------------------------------------------------------------*/ 50 /** 51 * Structure for keeping information needed for auto-repeat of keys. 52 */ 53 typedef struct { 54 /** Last pressed key. */ 55 unsigned int key_new; 56 /** Key to be repeated. */ 57 unsigned int key_repeated; 58 /** Delay before first repeat in microseconds. */ 59 unsigned int delay_before; 60 /** Delay between repeats in microseconds. */ 61 unsigned int delay_between; 62 } usbhid_kbd_repeat_t; 48 63 49 64 /** 50 * @brief USB/HID keyboard device type. 65 * USB/HID keyboard device type. 66 * 67 * Holds a reference to generic USB/HID device structure and keyboard-specific 68 * data, such as currently pressed keys, modifiers and lock keys. 69 * 70 * Also holds a IPC phone to the console (since there is now no other way to 71 * communicate with it). 72 * 73 * @note Storing active lock keys in this structure results in their setting 74 * being device-specific. 51 75 */ 52 76 typedef struct { 77 /** Structure holding generic USB/HID device information. */ 53 78 usbhid_dev_t *hid_dev; 54 79 55 uint8_t *keycodes; 56 size_t keycode_count; 80 /** Currently pressed keys (not translated to key codes). */ 81 uint8_t *keys; 82 /** Count of stored keys (i.e. number of keys in the report). */ 83 size_t key_count; 84 /** Currently pressed modifiers (bitmap). */ 57 85 uint8_t modifiers; 58 86 87 /** Currently active modifiers including locks. Sent to the console. */ 59 88 unsigned mods; 89 90 /** Currently active lock keys. */ 60 91 unsigned lock_keys; 61 92 93 /** IPC phone to the console device (for sending key events). */ 62 94 int console_phone; 63 95