Changeset e50cd7f in mainline for uspace/drv
- Timestamp:
- 2011-04-17T19:17:55Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 63517c2, cfbbe1d3
- Parents:
- ef354b6 (diff), 8595577b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace/drv
- Files:
-
- 34 added
- 51 edited
- 2 moved
-
ehci-hcd/hc_iface.c (modified) (14 diffs)
-
isa/isa.c (modified) (1 diff)
-
ohci/Makefile (modified) (1 diff)
-
ohci/batch.c (modified) (9 diffs)
-
ohci/batch.h (modified) (2 diffs)
-
ohci/endpoint_list.c (added)
-
ohci/endpoint_list.h (added)
-
ohci/hc.c (modified) (13 diffs)
-
ohci/hc.h (modified) (3 diffs)
-
ohci/hcd_endpoint.c (added)
-
ohci/hcd_endpoint.h (moved) (moved from kernel/generic/include/proc/tasklet.h ) (2 diffs)
-
ohci/hw_struct/completion_codes.h (modified) (2 diffs)
-
ohci/hw_struct/endpoint_descriptor.c (added)
-
ohci/hw_struct/endpoint_descriptor.h (modified) (4 diffs)
-
ohci/hw_struct/hcca.h (modified) (1 diff)
-
ohci/hw_struct/transfer_descriptor.c (added)
-
ohci/hw_struct/transfer_descriptor.h (modified) (4 diffs)
-
ohci/iface.c (modified) (20 diffs)
-
ohci/ohci.ma (modified) (1 diff)
-
ohci/ohci_regs.h (modified) (1 diff)
-
ohci/root_hub.c (modified) (31 diffs)
-
ohci/root_hub.h (modified) (1 diff)
-
ohci/utils/malloc32.h (modified) (2 diffs)
-
uhci-hcd/batch.c (modified) (13 diffs)
-
uhci-hcd/batch.h (modified) (2 diffs)
-
uhci-hcd/hc.c (modified) (13 diffs)
-
uhci-hcd/hc.h (modified) (4 diffs)
-
uhci-hcd/hw_struct/queue_head.h (modified) (4 diffs)
-
uhci-hcd/hw_struct/transfer_descriptor.c (modified) (4 diffs)
-
uhci-hcd/hw_struct/transfer_descriptor.h (modified) (1 diff)
-
uhci-hcd/iface.c (modified) (16 diffs)
-
uhci-hcd/main.c (modified) (5 diffs)
-
uhci-hcd/pci.c (modified) (5 diffs)
-
uhci-hcd/root_hub.c (modified) (2 diffs)
-
uhci-hcd/root_hub.h (modified) (1 diff)
-
uhci-hcd/transfer_list.c (modified) (11 diffs)
-
uhci-hcd/transfer_list.h (modified) (1 diff)
-
uhci-hcd/uhci.c (modified) (13 diffs)
-
uhci-hcd/uhci.h (modified) (1 diff)
-
uhci-rhd/port.c (modified) (5 diffs)
-
uhci-rhd/port.h (modified) (1 diff)
-
uhci-rhd/root_hub.c (modified) (4 diffs)
-
uhci-rhd/root_hub.h (modified) (1 diff)
-
usbhid/Makefile (added)
-
usbhid/generic/hiddev.c (added)
-
usbhid/generic/hiddev.h (moved) (moved from kernel/generic/src/proc/tasklet.c ) (2 diffs)
-
usbhid/kbd.h (added)
-
usbhid/kbd/conv.c (added)
-
usbhid/kbd/conv.h (added)
-
usbhid/kbd/kbddev.c (added)
-
usbhid/kbd/kbddev.h (added)
-
usbhid/kbd/kbdrepeat.c (added)
-
usbhid/kbd/kbdrepeat.h (added)
-
usbhid/kbd/layout.h (added)
-
usbhid/kbd/main.c (added)
-
usbhid/layout.h (added)
-
usbhid/lgtch-ultrax/lgtch-ultrax.c (added)
-
usbhid/lgtch-ultrax/lgtch-ultrax.h (added)
-
usbhid/main.c (added)
-
usbhid/mouse/mousedev.c (added)
-
usbhid/mouse/mousedev.h (added)
-
usbhid/subdrivers.c (added)
-
usbhid/subdrivers.h (added)
-
usbhid/usbhid.c (added)
-
usbhid/usbhid.h (added)
-
usbhid/usbhid.ma (added)
-
usbhub/Makefile (modified) (1 diff)
-
usbhub/port_status.h (modified) (15 diffs)
-
usbhub/ports.c (modified) (8 diffs)
-
usbhub/ports.h (modified) (3 diffs)
-
usbhub/usbhub.c (modified) (11 diffs)
-
usbhub/usbhub.h (modified) (3 diffs)
-
usbhub/usbhub_private.h (modified) (2 diffs)
-
usbhub/utils.c (modified) (1 diff)
-
usbkbd/kbddev.c (modified) (6 diffs)
-
usbkbd/main.c (modified) (7 diffs)
-
usbkbd/usbkbd.ma (modified) (1 diff)
-
usbmast/Makefile (added)
-
usbmast/cmds.h (added)
-
usbmast/main.c (added)
-
usbmast/mast.c (added)
-
usbmast/mast.h (added)
-
usbmast/scsi.h (added)
-
usbmast/usbmast.ma (added)
-
usbmid/main.c (modified) (2 diffs)
-
usbmouse/main.c (modified) (1 diff)
-
vhc/connhost.c (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ehci-hcd/hc_iface.c
ref354b6 re50cd7f 123 123 * @param[in] fun Device function the action was invoked on. 124 124 * @param[in] address USB address of the device. 125 * @param[in] speed Endpoint speed (invalid means to use device one). 125 126 * @param[in] endpoint Endpoint number. 126 127 * @param[in] transfer_type USB transfer type. … … 131 132 */ 132 133 static int register_endpoint(ddf_fun_t *fun, 133 usb_address_t address, usb_ endpoint_t endpoint,134 usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint, 134 135 usb_transfer_type_t transfer_type, usb_direction_t direction, 135 136 size_t max_packet_size, unsigned int interval) … … 165 166 * @param[in] fun Device function the action was invoked on. 166 167 * @param[in] target Target pipe (address and endpoint number) specification. 167 * @param[in] max_packet_size Max packet size for the transfer.168 168 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated 169 169 * by the caller). … … 174 174 */ 175 175 static int interrupt_out(ddf_fun_t *fun, usb_target_t target, 176 size_t max_packet_size,void *data, size_t size,176 void *data, size_t size, 177 177 usbhc_iface_transfer_out_callback_t callback, void *arg) 178 178 { … … 191 191 * @param[in] fun Device function the action was invoked on. 192 192 * @param[in] target Target pipe (address and endpoint number) specification. 193 * @param[in] max_packet_size Max packet size for the transfer.194 193 * @param[in] data Buffer where to store the data (in USB endianess, 195 194 * allocated and deallocated by the caller). … … 200 199 */ 201 200 static int interrupt_in(ddf_fun_t *fun, usb_target_t target, 202 size_t max_packet_size,void *data, size_t size,201 void *data, size_t size, 203 202 usbhc_iface_transfer_in_callback_t callback, void *arg) 204 203 { … … 217 216 * @param[in] fun Device function the action was invoked on. 218 217 * @param[in] target Target pipe (address and endpoint number) specification. 219 * @param[in] max_packet_size Max packet size for the transfer.220 218 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated 221 219 * by the caller). … … 226 224 */ 227 225 static int bulk_out(ddf_fun_t *fun, usb_target_t target, 228 size_t max_packet_size,void *data, size_t size,226 void *data, size_t size, 229 227 usbhc_iface_transfer_out_callback_t callback, void *arg) 230 228 { … … 243 241 * @param[in] fun Device function the action was invoked on. 244 242 * @param[in] target Target pipe (address and endpoint number) specification. 245 * @param[in] max_packet_size Max packet size for the transfer.246 243 * @param[in] data Buffer where to store the data (in USB endianess, 247 244 * allocated and deallocated by the caller). … … 252 249 */ 253 250 static int bulk_in(ddf_fun_t *fun, usb_target_t target, 254 size_t max_packet_size,void *data, size_t size,251 void *data, size_t size, 255 252 usbhc_iface_transfer_in_callback_t callback, void *arg) 256 253 { … … 269 266 * @param[in] fun Device function the action was invoked on. 270 267 * @param[in] target Target pipe (address and endpoint number) specification. 271 * @param[in] max_packet_size Max packet size for the transfer.272 268 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 273 269 * and deallocated by the caller). … … 281 277 */ 282 278 static int control_write(ddf_fun_t *fun, usb_target_t target, 283 size_t max_packet_size,284 279 void *setup_packet, size_t setup_packet_size, 285 280 void *data_buffer, size_t data_buffer_size, … … 300 295 * @param[in] fun Device function the action was invoked on. 301 296 * @param[in] target Target pipe (address and endpoint number) specification. 302 * @param[in] max_packet_size Max packet size for the transfer.303 297 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 304 298 * and deallocated by the caller). … … 312 306 */ 313 307 static int control_read(ddf_fun_t *fun, usb_target_t target, 314 size_t max_packet_size,315 308 void *setup_packet, size_t setup_packet_size, 316 309 void *data_buffer, size_t data_buffer_size, -
uspace/drv/isa/isa.c
ref354b6 re50cd7f 83 83 static bool isa_enable_fun_interrupt(ddf_fun_t *fnode) 84 84 { 85 / / TODO85 /* TODO */ 86 86 87 87 return false; -
uspace/drv/ohci/Makefile
ref354b6 re50cd7f 33 33 34 34 SOURCES = \ 35 batch.c \ 36 endpoint_list.c \ 37 hc.c \ 38 hcd_endpoint.c \ 35 39 iface.c \ 36 batch.c \37 40 main.c \ 38 hc.c \39 41 ohci.c \ 42 pci.c \ 40 43 root_hub.c \ 41 pci.c 44 hw_struct/endpoint_descriptor.c \ 45 hw_struct/transfer_descriptor.c 46 42 47 43 48 include $(USPACE_PREFIX)/Makefile.common -
uspace/drv/ohci/batch.c
ref354b6 re50cd7f 39 39 40 40 #include "batch.h" 41 #include "hcd_endpoint.h" 41 42 #include "utils/malloc32.h" 42 43 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance); 44 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance); 45 46 #define DEFAULT_ERROR_COUNT 3 47 usb_transfer_batch_t * batch_get( 48 ddf_fun_t *fun, 49 usb_target_t target, 50 usb_transfer_type_t transfer_type, 51 size_t max_packet_size, 52 usb_speed_t speed, 53 char *buffer, 54 size_t buffer_size, 55 char *setup_buffer, 56 size_t setup_size, 43 #include "hw_struct/endpoint_descriptor.h" 44 #include "hw_struct/transfer_descriptor.h" 45 46 typedef struct ohci_transfer_batch { 47 ed_t *ed; 48 td_t **tds; 49 size_t td_count; 50 size_t leave_td; 51 char *device_buffer; 52 } ohci_transfer_batch_t; 53 54 static void ohci_transfer_batch_dispose(void *ohci_batch) 55 { 56 ohci_transfer_batch_t *instance = ohci_batch; 57 if (!instance) 58 return; 59 free32(instance->device_buffer); 60 unsigned i = 0; 61 if (instance->tds) { 62 for (; i< instance->td_count; ++i) { 63 if (i != instance->leave_td) 64 free32(instance->tds[i]); 65 } 66 free(instance->tds); 67 } 68 free(instance); 69 } 70 /*----------------------------------------------------------------------------*/ 71 static void batch_control(usb_transfer_batch_t *instance, 72 usb_direction_t data_dir, usb_direction_t status_dir); 73 static void batch_data(usb_transfer_batch_t *instance); 74 /*----------------------------------------------------------------------------*/ 75 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, 76 char *buffer, size_t buffer_size, char* setup_buffer, size_t setup_size, 57 77 usbhc_iface_transfer_in_callback_t func_in, 58 usbhc_iface_transfer_out_callback_t func_out, 59 void *arg, 60 usb_device_keeper_t *manager 61 ) 78 usbhc_iface_transfer_out_callback_t func_out, void *arg) 62 79 { 63 80 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \ … … 65 82 usb_log_error(message); \ 66 83 if (instance) { \ 67 batch_dispose(instance); \84 usb_transfer_batch_dispose(instance); \ 68 85 } \ 69 86 return NULL; \ … … 73 90 CHECK_NULL_DISPOSE_RETURN(instance, 74 91 "Failed to allocate batch instance.\n"); 75 usb_transfer_batch_init(instance, target, transfer_type, speed, 76 max_packet_size, buffer, NULL, buffer_size, NULL, setup_size, 77 func_in, func_out, arg, fun, NULL, NULL); 78 79 if (buffer_size > 0) { 80 instance->transport_buffer = malloc32(buffer_size); 81 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 92 usb_transfer_batch_init(instance, ep, buffer, NULL, buffer_size, 93 NULL, setup_size, func_in, func_out, arg, fun, NULL, 94 ohci_transfer_batch_dispose); 95 96 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep); 97 assert(hcd_ep); 98 99 ohci_transfer_batch_t *data = calloc(sizeof(ohci_transfer_batch_t), 1); 100 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n"); 101 instance->private_data = data; 102 103 data->td_count = 104 ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER); 105 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 106 data->td_count += 2; 107 } 108 109 /* we need one extra place for td that is currently assigned to hcd_ep*/ 110 data->tds = calloc(sizeof(td_t*), data->td_count + 1); 111 CHECK_NULL_DISPOSE_RETURN(data->tds, 112 "Failed to allocate transfer descriptors.\n"); 113 114 data->tds[0] = hcd_ep->td; 115 data->leave_td = 0; 116 unsigned i = 1; 117 for (; i <= data->td_count; ++i) { 118 data->tds[i] = malloc32(sizeof(td_t)); 119 CHECK_NULL_DISPOSE_RETURN(data->tds[i], 120 "Failed to allocate TD %d.\n", i ); 121 } 122 123 data->ed = hcd_ep->ed; 124 125 if (setup_size + buffer_size > 0) { 126 data->device_buffer = malloc32(setup_size + buffer_size); 127 CHECK_NULL_DISPOSE_RETURN(data->device_buffer, 82 128 "Failed to allocate device accessible buffer.\n"); 83 } 84 85 if (setup_size > 0) { 86 instance->setup_buffer = malloc32(setup_size); 87 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 88 "Failed to allocate device accessible setup buffer.\n"); 129 instance->setup_buffer = data->device_buffer; 130 instance->data_buffer = data->device_buffer + setup_size; 89 131 memcpy(instance->setup_buffer, setup_buffer, setup_size); 90 132 } 91 133 92 93 134 return instance; 94 135 } 95 136 /*----------------------------------------------------------------------------*/ 96 void batch_dispose(usb_transfer_batch_t *instance) 97 { 98 assert(instance); 99 free32(instance->transport_buffer); 100 free32(instance->setup_buffer); 101 free(instance); 137 bool batch_is_complete(usb_transfer_batch_t *instance) 138 { 139 assert(instance); 140 ohci_transfer_batch_t *data = instance->private_data; 141 assert(data); 142 size_t tds = data->td_count; 143 usb_log_debug("Batch(%p) checking %d td(s) for completion.\n", 144 instance, tds); 145 usb_log_debug("ED: %x:%x:%x:%x.\n", 146 data->ed->status, data->ed->td_head, data->ed->td_tail, 147 data->ed->next); 148 size_t i = 0; 149 instance->transfered_size = instance->buffer_size; 150 for (; i < tds; ++i) { 151 assert(data->tds[i] != NULL); 152 usb_log_debug("TD %d: %x:%x:%x:%x.\n", i, 153 data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next, 154 data->tds[i]->be); 155 if (!td_is_finished(data->tds[i])) { 156 return false; 157 } 158 instance->error = td_error(data->tds[i]); 159 if (instance->error != EOK) { 160 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 161 instance, i, data->tds[i]->status); 162 /* Make sure TD queue is empty (one TD), 163 * ED should be marked as halted */ 164 data->ed->td_tail = 165 (data->ed->td_head & ED_TDTAIL_PTR_MASK); 166 ++i; 167 break; 168 } 169 } 170 data->leave_td = i; 171 assert(data->leave_td <= data->td_count); 172 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep); 173 assert(hcd_ep); 174 hcd_ep->td = data->tds[i]; 175 if (i > 0) 176 instance->transfered_size -= td_remain_size(data->tds[i - 1]); 177 178 /* Clear possible ED HALT */ 179 data->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG; 180 uint32_t pa = addr_to_phys(hcd_ep->td); 181 assert(pa == (data->ed->td_head & ED_TDHEAD_PTR_MASK)); 182 assert(pa == (data->ed->td_tail & ED_TDTAIL_PTR_MASK)); 183 184 return true; 185 } 186 /*----------------------------------------------------------------------------*/ 187 void batch_commit(usb_transfer_batch_t *instance) 188 { 189 assert(instance); 190 ohci_transfer_batch_t *data = instance->private_data; 191 assert(data); 192 ed_set_end_td(data->ed, data->tds[data->td_count]); 102 193 } 103 194 /*----------------------------------------------------------------------------*/ … … 106 197 assert(instance); 107 198 /* We are data out, we are supposed to provide data */ 108 memcpy(instance->transport_buffer, instance->buffer, 109 instance->buffer_size); 110 instance->next_step = batch_call_out_and_dispose; 111 /* TODO: implement */ 199 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 200 instance->next_step = usb_transfer_batch_call_out_and_dispose; 201 batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN); 112 202 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 113 203 } … … 116 206 { 117 207 assert(instance); 118 instance->next_step = batch_call_in_and_dispose;119 /* TODO: implement */208 instance->next_step = usb_transfer_batch_call_in_and_dispose; 209 batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT); 120 210 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 121 211 } … … 124 214 { 125 215 assert(instance); 126 instance->direction = USB_DIRECTION_IN; 127 instance->next_step = batch_call_in_and_dispose; 128 /* TODO: implement */ 216 instance->next_step = usb_transfer_batch_call_in_and_dispose; 217 batch_data(instance); 129 218 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 130 219 } … … 133 222 { 134 223 assert(instance); 135 instance->direction = USB_DIRECTION_OUT;136 224 /* We are data out, we are supposed to provide data */ 137 memcpy(instance->transport_buffer, instance->buffer, 138 instance->buffer_size); 139 instance->next_step = batch_call_out_and_dispose; 140 /* TODO: implement */ 225 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 226 instance->next_step = usb_transfer_batch_call_out_and_dispose; 227 batch_data(instance); 141 228 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 142 229 } … … 145 232 { 146 233 assert(instance); 147 instance->direction = USB_DIRECTION_IN; 148 instance->next_step = batch_call_in_and_dispose; 149 /* TODO: implement */ 234 instance->next_step = usb_transfer_batch_call_in_and_dispose; 235 batch_data(instance); 150 236 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 151 237 } … … 154 240 { 155 241 assert(instance); 156 instance->direction = USB_DIRECTION_IN; 157 instance->next_step = batch_call_in_and_dispose; 158 /* TODO: implement */ 159 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 160 } 161 /*----------------------------------------------------------------------------*/ 162 /** Helper function calls callback and correctly disposes of batch structure. 163 * 164 * @param[in] instance Batch structure to use. 165 */ 166 void batch_call_in_and_dispose(usb_transfer_batch_t *instance) 167 { 168 assert(instance); 169 usb_transfer_batch_call_in(instance); 170 batch_dispose(instance); 171 } 172 /*----------------------------------------------------------------------------*/ 173 /** Helper function calls callback and correctly disposes of batch structure. 174 * 175 * @param[in] instance Batch structure to use. 176 */ 177 void batch_call_out_and_dispose(usb_transfer_batch_t *instance) 178 { 179 assert(instance); 180 usb_transfer_batch_call_out(instance); 181 batch_dispose(instance); 242 /* We are data out, we are supposed to provide data */ 243 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 244 instance->next_step = usb_transfer_batch_call_out_and_dispose; 245 batch_data(instance); 246 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 247 } 248 /*----------------------------------------------------------------------------*/ 249 ed_t * batch_ed(usb_transfer_batch_t *instance) 250 { 251 assert(instance); 252 ohci_transfer_batch_t *data = instance->private_data; 253 assert(data); 254 return data->ed; 255 } 256 /*----------------------------------------------------------------------------*/ 257 void batch_control(usb_transfer_batch_t *instance, 258 usb_direction_t data_dir, usb_direction_t status_dir) 259 { 260 assert(instance); 261 ohci_transfer_batch_t *data = instance->private_data; 262 assert(data); 263 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed, 264 data->ed->status, data->ed->td_tail, data->ed->td_head, 265 data->ed->next); 266 int toggle = 0; 267 /* setup stage */ 268 td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer, 269 instance->setup_size, toggle); 270 td_set_next(data->tds[0], data->tds[1]); 271 usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0]->status, 272 data->tds[0]->cbp, data->tds[0]->next, data->tds[0]->be); 273 274 /* data stage */ 275 size_t td_current = 1; 276 size_t remain_size = instance->buffer_size; 277 char *buffer = instance->data_buffer; 278 while (remain_size > 0) { 279 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ? 280 OHCI_TD_MAX_TRANSFER : remain_size; 281 toggle = 1 - toggle; 282 283 td_init(data->tds[td_current], data_dir, buffer, 284 transfer_size, toggle); 285 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 286 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n", 287 data->tds[td_current]->status, data->tds[td_current]->cbp, 288 data->tds[td_current]->next, data->tds[td_current]->be); 289 290 buffer += transfer_size; 291 remain_size -= transfer_size; 292 assert(td_current < data->td_count - 1); 293 ++td_current; 294 } 295 296 /* status stage */ 297 assert(td_current == data->td_count - 1); 298 td_init(data->tds[td_current], status_dir, NULL, 0, 1); 299 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 300 usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n", 301 data->tds[td_current]->status, data->tds[td_current]->cbp, 302 data->tds[td_current]->next, data->tds[td_current]->be); 303 } 304 /*----------------------------------------------------------------------------*/ 305 void batch_data(usb_transfer_batch_t *instance) 306 { 307 assert(instance); 308 ohci_transfer_batch_t *data = instance->private_data; 309 assert(data); 310 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed, 311 data->ed->status, data->ed->td_tail, data->ed->td_head, 312 data->ed->next); 313 314 size_t td_current = 0; 315 size_t remain_size = instance->buffer_size; 316 char *buffer = instance->data_buffer; 317 while (remain_size > 0) { 318 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ? 319 OHCI_TD_MAX_TRANSFER : remain_size; 320 321 td_init(data->tds[td_current], instance->ep->direction, 322 buffer, transfer_size, -1); 323 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 324 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n", 325 data->tds[td_current]->status, data->tds[td_current]->cbp, 326 data->tds[td_current]->next, data->tds[td_current]->be); 327 328 buffer += transfer_size; 329 remain_size -= transfer_size; 330 assert(td_current < data->td_count); 331 ++td_current; 332 } 182 333 } 183 334 /** -
uspace/drv/ohci/batch.h
ref354b6 re50cd7f 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup drvusb ohci28 /** @addtogroup drvusbuhcihc 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief OHCI driver USB transaction structure32 * @brief UHCI driver USB transaction structure 33 33 */ 34 #ifndef DRV_OHCI_BATCH_H 35 #define DRV_OHCI_BATCH_H 36 34 #ifndef DRV_UHCI_BATCH_H 35 #define DRV_UHCI_BATCH_H 37 36 38 37 #include <usbhc_iface.h> 39 38 #include <usb/usb.h> 40 39 #include <usb/host/device_keeper.h> 40 #include <usb/host/endpoint.h> 41 41 #include <usb/host/batch.h> 42 42 43 #include "hw_struct/endpoint_descriptor.h" 44 43 45 usb_transfer_batch_t * batch_get( 44 ddf_fun_t *fun, 45 usb_target_t target, 46 usb_transfer_type_t transfer_type, 47 size_t max_packet_size, 48 usb_speed_t speed, 49 char *buffer, 50 size_t size, 51 char *setup_buffer, 52 size_t setup_size, 46 ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size, 47 char *setup_buffer, size_t setup_size, 53 48 usbhc_iface_transfer_in_callback_t func_in, 54 49 usbhc_iface_transfer_out_callback_t func_out, 55 void *arg, 56 usb_device_keeper_t *manager 57 ); 50 void *arg); 58 51 59 void batch_dispose(usb_transfer_batch_t *instance); 52 bool batch_is_complete(usb_transfer_batch_t *instance); 53 54 void batch_commit(usb_transfer_batch_t *instance); 60 55 61 56 void batch_control_write(usb_transfer_batch_t *instance); … … 70 65 71 66 void batch_bulk_out(usb_transfer_batch_t *instance); 67 68 ed_t * batch_ed(usb_transfer_batch_t *instance); 72 69 #endif 73 70 /** -
uspace/drv/ohci/hc.c
ref354b6 re50cd7f 43 43 44 44 #include "hc.h" 45 #include "hcd_endpoint.h" 45 46 46 47 static int interrupt_emulator(hc_t *instance); 47 48 static void hc_gain_control(hc_t *instance); 48 49 static void hc_init_hw(hc_t *instance); 50 static int hc_init_transfer_lists(hc_t *instance); 51 static int hc_init_memory(hc_t *instance); 49 52 /*----------------------------------------------------------------------------*/ 50 53 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun) … … 52 55 assert(instance); 53 56 assert(hub_fun); 57 58 int ret; 54 59 55 60 usb_address_t hub_address = 56 61 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL); 62 if (hub_address <= 0) { 63 usb_log_error("Failed to get OHCI root hub address.\n"); 64 return hub_address; 65 } 57 66 instance->rh.address = hub_address; 58 67 usb_device_keeper_bind( 59 68 &instance->manager, hub_address, hub_fun->handle); 60 69 70 ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL, 71 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0); 72 if (ret != EOK) { 73 usb_log_error("Failed to add OHCI rh endpoint 0.\n"); 74 usb_device_keeper_release(&instance->manager, hub_address); 75 return ret; 76 } 77 61 78 char *match_str = NULL; 62 int ret = asprintf(&match_str, "usb&class=hub");63 ret = (match_str == NULL) ? ret : EOK;79 /* DDF needs heap allocated string */ 80 ret = asprintf(&match_str, "usb&class=hub"); 64 81 if (ret < 0) { 65 usb_log_error("Failed to create root hub match-id string.\n"); 82 usb_log_error( 83 "Failed(%d) to create root hub match-id string.\n", ret); 84 usb_device_keeper_release(&instance->manager, hub_address); 66 85 return ret; 67 86 } … … 69 88 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 70 89 if (ret != EOK) { 71 usb_log_error("Failed add createroot hub match-id.\n");90 usb_log_error("Failed add root hub match-id.\n"); 72 91 } 73 92 return ret; … … 90 109 ret, str_error(ret)); 91 110 92 instance->ddf_instance = fun;93 111 usb_device_keeper_init(&instance->manager); 94 112 ret = usb_endpoint_manager_init(&instance->ep_manager, … … 97 115 ret, str_error(ret)); 98 116 117 hc_gain_control(instance); 118 ret = hc_init_memory(instance); 119 CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n", 120 ret, str_error(ret)); 121 hc_init_hw(instance); 122 fibril_mutex_initialize(&instance->guard); 123 124 rh_init(&instance->rh, instance->registers); 125 99 126 if (!interrupts) { 100 127 instance->interrupt_emulator = … … 103 130 } 104 131 105 hc_gain_control(instance); 106 107 rh_init(&instance->rh, dev, instance->registers); 108 109 hc_init_hw(instance); 110 111 /* TODO: implement */ 112 return EOK; 132 list_initialize(&instance->pending_batches); 133 #undef CHECK_RET_RETURN 134 return EOK; 135 } 136 /*----------------------------------------------------------------------------*/ 137 int hc_add_endpoint( 138 hc_t *instance, usb_address_t address, usb_endpoint_t endpoint, 139 usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction, 140 size_t mps, size_t size, unsigned interval) 141 { 142 endpoint_t *ep = malloc(sizeof(endpoint_t)); 143 if (ep == NULL) 144 return ENOMEM; 145 int ret = 146 endpoint_init(ep, address, endpoint, direction, type, speed, mps); 147 if (ret != EOK) { 148 free(ep); 149 return ret; 150 } 151 152 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); 153 if (hcd_ep == NULL) { 154 endpoint_destroy(ep); 155 return ENOMEM; 156 } 157 158 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 159 if (ret != EOK) { 160 hcd_endpoint_clear(ep); 161 endpoint_destroy(ep); 162 return ret; 163 } 164 165 /* Enqueue hcd_ep */ 166 switch (ep->transfer_type) { 167 case USB_TRANSFER_CONTROL: 168 instance->registers->control &= ~C_CLE; 169 endpoint_list_add_ep( 170 &instance->lists[ep->transfer_type], hcd_ep); 171 instance->registers->control_current = 0; 172 instance->registers->control |= C_CLE; 173 break; 174 case USB_TRANSFER_BULK: 175 instance->registers->control &= ~C_BLE; 176 endpoint_list_add_ep( 177 &instance->lists[ep->transfer_type], hcd_ep); 178 instance->registers->control |= C_BLE; 179 break; 180 case USB_TRANSFER_ISOCHRONOUS: 181 case USB_TRANSFER_INTERRUPT: 182 instance->registers->control &= (~C_PLE & ~C_IE); 183 endpoint_list_add_ep( 184 &instance->lists[ep->transfer_type], hcd_ep); 185 instance->registers->control |= C_PLE | C_IE; 186 break; 187 default: 188 break; 189 } 190 191 return EOK; 192 } 193 /*----------------------------------------------------------------------------*/ 194 int hc_remove_endpoint(hc_t *instance, usb_address_t address, 195 usb_endpoint_t endpoint, usb_direction_t direction) 196 { 197 assert(instance); 198 fibril_mutex_lock(&instance->guard); 199 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager, 200 address, endpoint, direction, NULL); 201 if (ep == NULL) { 202 usb_log_error("Endpoint unregister failed: No such EP.\n"); 203 fibril_mutex_unlock(&instance->guard); 204 return ENOENT; 205 } 206 207 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep); 208 if (hcd_ep) { 209 /* Dequeue hcd_ep */ 210 switch (ep->transfer_type) { 211 case USB_TRANSFER_CONTROL: 212 instance->registers->control &= ~C_CLE; 213 endpoint_list_remove_ep( 214 &instance->lists[ep->transfer_type], hcd_ep); 215 instance->registers->control_current = 0; 216 instance->registers->control |= C_CLE; 217 break; 218 case USB_TRANSFER_BULK: 219 instance->registers->control &= ~C_BLE; 220 endpoint_list_remove_ep( 221 &instance->lists[ep->transfer_type], hcd_ep); 222 instance->registers->control |= C_BLE; 223 break; 224 case USB_TRANSFER_ISOCHRONOUS: 225 case USB_TRANSFER_INTERRUPT: 226 instance->registers->control &= (~C_PLE & ~C_IE); 227 endpoint_list_remove_ep( 228 &instance->lists[ep->transfer_type], hcd_ep); 229 instance->registers->control |= C_PLE | C_IE; 230 break; 231 default: 232 break; 233 } 234 hcd_endpoint_clear(ep); 235 } else { 236 usb_log_warning("Endpoint without hcd equivalent structure.\n"); 237 } 238 int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager, 239 address, endpoint, direction); 240 fibril_mutex_unlock(&instance->guard); 241 return ret; 242 } 243 /*----------------------------------------------------------------------------*/ 244 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address, 245 usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw) 246 { 247 assert(instance); 248 fibril_mutex_lock(&instance->guard); 249 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager, 250 address, endpoint, direction, bw); 251 fibril_mutex_unlock(&instance->guard); 252 return ep; 113 253 } 114 254 /*----------------------------------------------------------------------------*/ … … 117 257 assert(instance); 118 258 assert(batch); 119 if (batch->target.address == instance->rh.address) { 259 assert(batch->ep); 260 261 /* check for root hub communication */ 262 if (batch->ep->address == instance->rh.address) { 120 263 return rh_request(&instance->rh, batch); 121 264 } 122 /* TODO: implement */ 123 return ENOTSUP; 265 266 fibril_mutex_lock(&instance->guard); 267 list_append(&batch->link, &instance->pending_batches); 268 batch_commit(batch); 269 switch (batch->ep->transfer_type) { 270 case USB_TRANSFER_CONTROL: 271 instance->registers->command_status |= CS_CLF; 272 break; 273 case USB_TRANSFER_BULK: 274 instance->registers->command_status |= CS_BLF; 275 break; 276 default: 277 break; 278 } 279 280 fibril_mutex_unlock(&instance->guard); 281 return EOK; 124 282 } 125 283 /*----------------------------------------------------------------------------*/ … … 127 285 { 128 286 assert(instance); 129 if ( status == 0)287 if ((status & ~IS_SF) == 0) /* ignore sof status */ 130 288 return; 131 289 if (status & IS_RHSC) 132 290 rh_interrupt(&instance->rh); 133 291 134 usb_log_info("OHCI interrupt: %x.\n", status); 135 136 /* TODO: Check for further interrupt causes */ 137 /* TODO: implement */ 292 usb_log_debug("OHCI interrupt: %x.\n", status); 293 294 if (status & IS_WDH) { 295 fibril_mutex_lock(&instance->guard); 296 usb_log_debug2("HCCA: %p-%p(%p).\n", instance->hcca, 297 instance->registers->hcca, addr_to_phys(instance->hcca)); 298 usb_log_debug2("Periodic current: %p.\n", 299 instance->registers->periodic_current); 300 301 link_t *current = instance->pending_batches.next; 302 while (current != &instance->pending_batches) { 303 link_t *next = current->next; 304 usb_transfer_batch_t *batch = 305 usb_transfer_batch_from_link(current); 306 307 if (batch_is_complete(batch)) { 308 list_remove(current); 309 usb_transfer_batch_finish(batch); 310 } 311 current = next; 312 } 313 fibril_mutex_unlock(&instance->guard); 314 } 138 315 } 139 316 /*----------------------------------------------------------------------------*/ … … 146 323 instance->registers->interrupt_status = status; 147 324 hc_interrupt(instance, status); 148 async_usleep( 1000);325 async_usleep(50000); 149 326 } 150 327 return EOK; … … 154 331 { 155 332 assert(instance); 333 /* Turn off legacy emulation */ 334 volatile uint32_t *ohci_emulation_reg = 335 (uint32_t*)((char*)instance->registers + 0x100); 336 usb_log_debug("OHCI legacy register %p: %x.\n", 337 ohci_emulation_reg, *ohci_emulation_reg); 338 *ohci_emulation_reg = 0; 339 156 340 /* Interrupt routing enabled => smm driver is active */ 157 341 if (instance->registers->control & C_IR) { 158 usb_log_ info("Found SMM driver requestingownership change.\n");342 usb_log_debug("SMM driver: request ownership change.\n"); 159 343 instance->registers->command_status |= CS_OCR; 160 344 while (instance->registers->control & C_IR) { 161 345 async_usleep(1000); 162 346 } 163 usb_log_info(" Ownership taken from SMM driver.\n");347 usb_log_info("SMM driver: Ownership taken.\n"); 164 348 return; 165 349 } … … 169 353 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 170 354 if (hc_status != C_HCFS_RESET) { 171 usb_log_ info("Found BIOS driver.\n");355 usb_log_debug("BIOS driver found.\n"); 172 356 if (hc_status == C_HCFS_OPERATIONAL) { 173 usb_log_info(" HC operational(BIOS).\n");357 usb_log_info("BIOS driver: HC operational.\n"); 174 358 return; 175 359 } … … 177 361 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT); 178 362 async_usleep(20000); 363 usb_log_info("BIOS driver: HC resumed.\n"); 179 364 return; 180 365 } … … 182 367 /* HC is in reset (hw startup) => no other driver 183 368 * maintain reset for at least the time specified in USB spec (50 ms)*/ 369 usb_log_info("HC found in reset.\n"); 184 370 async_usleep(50000); 185 186 /* turn off legacy emulation */187 volatile uint32_t *ohci_emulation_reg =188 (uint32_t*)((char*)instance->registers + 0x100);189 usb_log_info("OHCI legacy register status %p: %x.\n",190 ohci_emulation_reg, *ohci_emulation_reg);191 *ohci_emulation_reg = 0;192 193 371 } 194 372 /*----------------------------------------------------------------------------*/ 195 373 void hc_init_hw(hc_t *instance) 196 374 { 197 assert(instance); 375 /* OHCI guide page 42 */ 376 assert(instance); 377 usb_log_debug2("Started hc initialization routine.\n"); 378 379 /* Save contents of fm_interval register */ 198 380 const uint32_t fm_interval = instance->registers->fm_interval; 381 usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval); 382 383 /* Reset hc */ 384 usb_log_debug2("HC reset.\n"); 385 size_t time = 0; 199 386 instance->registers->command_status = CS_HCR; 200 async_usleep(10); 387 while (instance->registers->command_status & CS_HCR) { 388 async_usleep(10); 389 time += 10; 390 } 391 usb_log_debug2("HC reset complete in %zu us.\n", time); 392 393 /* Restore fm_interval */ 201 394 instance->registers->fm_interval = fm_interval; 202 395 assert((instance->registers->command_status & CS_HCR) == 0); 396 203 397 /* hc is now in suspend state */ 204 /* TODO: init HCCA block */ 205 /* TODO: init queues */ 206 /* TODO: enable queues */ 207 /* TODO: enable interrupts */ 208 /* TODO: set periodic start to 90% */ 398 usb_log_debug2("HC should be in suspend state(%x).\n", 399 instance->registers->control); 400 401 /* Use HCCA */ 402 instance->registers->hcca = addr_to_phys(instance->hcca); 403 404 /* Use queues */ 405 instance->registers->bulk_head = 406 instance->lists[USB_TRANSFER_BULK].list_head_pa; 407 usb_log_debug2("Bulk HEAD set to: %p(%p).\n", 408 instance->lists[USB_TRANSFER_BULK].list_head, 409 instance->lists[USB_TRANSFER_BULK].list_head_pa); 410 411 instance->registers->control_head = 412 instance->lists[USB_TRANSFER_CONTROL].list_head_pa; 413 usb_log_debug2("Control HEAD set to: %p(%p).\n", 414 instance->lists[USB_TRANSFER_CONTROL].list_head, 415 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); 416 417 /* Enable queues */ 418 instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE); 419 usb_log_debug2("All queues enabled(%x).\n", 420 instance->registers->control); 421 422 /* Disable interrupts */ 423 instance->registers->interrupt_disable = I_SF | I_OC; 424 usb_log_debug2("Disabling interrupts: %x.\n", 425 instance->registers->interrupt_disable); 426 instance->registers->interrupt_disable = I_MI; 427 usb_log_debug2("Enabled interrupts: %x.\n", 428 instance->registers->interrupt_enable); 429 430 /* Set periodic start to 90% */ 431 uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK); 432 instance->registers->periodic_start = (frame_length / 10) * 9; 433 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n", 434 instance->registers->periodic_start, 435 instance->registers->periodic_start, frame_length); 209 436 210 437 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT); 211 usb_log_info("OHCI HC up and running.\n"); 438 usb_log_info("OHCI HC up and running(%x).\n", 439 instance->registers->control); 440 } 441 /*----------------------------------------------------------------------------*/ 442 int hc_init_transfer_lists(hc_t *instance) 443 { 444 assert(instance); 445 446 #define SETUP_ENDPOINT_LIST(type) \ 447 do { \ 448 const char *name = usb_str_transfer_type(type); \ 449 int ret = endpoint_list_init(&instance->lists[type], name); \ 450 if (ret != EOK) { \ 451 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \ 452 ret, name); \ 453 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]); \ 454 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ 455 endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \ 456 endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \ 457 } \ 458 } while (0) 459 460 SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS); 461 SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT); 462 SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL); 463 SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK); 464 #undef SETUP_ENDPOINT_LIST 465 endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT], 466 &instance->lists[USB_TRANSFER_ISOCHRONOUS]); 467 468 return EOK; 469 } 470 /*----------------------------------------------------------------------------*/ 471 int hc_init_memory(hc_t *instance) 472 { 473 assert(instance); 474 /* Init queues */ 475 hc_init_transfer_lists(instance); 476 477 /*Init HCCA */ 478 instance->hcca = malloc32(sizeof(hcca_t)); 479 if (instance->hcca == NULL) 480 return ENOMEM; 481 bzero(instance->hcca, sizeof(hcca_t)); 482 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 483 484 unsigned i = 0; 485 for (; i < 32; ++i) { 486 instance->hcca->int_ep[i] = 487 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa; 488 } 489 usb_log_debug2("Interrupt HEADs set to: %p(%p).\n", 490 instance->lists[USB_TRANSFER_INTERRUPT].list_head, 491 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 492 493 return EOK; 212 494 } 213 495 /** -
uspace/drv/ohci/hc.h
ref354b6 re50cd7f 48 48 #include "ohci_regs.h" 49 49 #include "root_hub.h" 50 #include "endpoint_list.h" 50 51 #include "hw_struct/hcca.h" 51 52 52 53 typedef struct hc { 53 54 ohci_regs_t *registers; 55 hcca_t *hcca; 56 54 57 usb_address_t rh_address; 55 58 rh_t rh; 56 ddf_fun_t *ddf_instance; 59 60 endpoint_list_t lists[4]; 61 link_t pending_batches; 62 57 63 usb_device_keeper_t manager; 58 64 usb_endpoint_manager_t ep_manager; 59 65 fid_t interrupt_emulator; 66 fibril_mutex_t guard; 60 67 } hc_t; 61 68 … … 65 72 uintptr_t regs, size_t reg_size, bool interrupts); 66 73 67 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);68 69 void hc_interrupt(hc_t *instance, uint32_t status);70 71 74 /** Safely dispose host controller internal structures 72 75 * … … 74 77 */ 75 78 static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ }; 79 80 int hc_add_endpoint(hc_t *instance, usb_address_t address, usb_endpoint_t ep, 81 usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction, 82 size_t max_packet_size, size_t size, unsigned interval); 83 84 int hc_remove_endpoint(hc_t *instance, usb_address_t address, 85 usb_endpoint_t endpoint, usb_direction_t direction); 86 87 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address, 88 usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw); 89 90 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch); 91 92 void hc_interrupt(hc_t *instance, uint32_t status); 76 93 77 94 /** Get and cast pointer to the driver data -
uspace/drv/ohci/hcd_endpoint.h
ref354b6 re50cd7f 1 1 /* 2 * Copyright (c) 2007 Jan Hudecek 3 * Copyright (c) 2008 Martin Decky 2 * Copyright (c) 2011 Jan Vesely 4 3 * All rights reserved. 5 4 * … … 27 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 27 */ 29 30 /** @addtogroup genericproc 28 /** @addtogroup drvusbohci 31 29 * @{ 32 30 */ 33 /** @file tasklet.h34 * @brief Tasklets declarations31 /** @file 32 * @brief OHCI driver 35 33 */ 34 #ifndef DRV_OHCI_HCD_ENDPOINT_H 35 #define DRV_OHCI_HCD_ENDPOINT_H 36 36 37 #ifndef KERN_TASKLET_H_ 38 #define KERN_TASKLET_H_ 39 37 #include <assert.h> 40 38 #include <adt/list.h> 41 39 42 /** Tasklet callback type */ 43 typedef void (* tasklet_callback_t)(void *arg); 40 #include <usb/host/endpoint.h> 44 41 45 /** Tasklet state */ 46 typedef enum { 47 NotActive, 48 Scheduled, 49 InProgress, 50 Disabled 51 } tasklet_state_t; 42 #include "hw_struct/endpoint_descriptor.h" 43 #include "hw_struct/transfer_descriptor.h" 52 44 53 /** Structure describing a tasklet */ 54 typedef struct tasklet_descriptor { 45 typedef struct hcd_endpoint { 46 ed_t *ed; 47 td_t *td; 55 48 link_t link; 56 57 /** Callback to call */ 58 tasklet_callback_t callback; 59 60 /** Argument passed to the callback */ 61 void *arg; 62 63 /** State of the tasklet */ 64 tasklet_state_t state; 65 } tasklet_descriptor_t; 49 } hcd_endpoint_t; 66 50 51 hcd_endpoint_t * hcd_endpoint_assign(endpoint_t *ep); 67 52 68 extern void tasklet_init(void);53 hcd_endpoint_t * hcd_endpoint_get(endpoint_t *ep); 69 54 55 void hcd_endpoint_clear(endpoint_t *ep); 70 56 #endif 71 72 /** @}57 /** 58 * @} 73 59 */ -
uspace/drv/ohci/hw_struct/completion_codes.h
ref354b6 re50cd7f 35 35 #define DRV_OHCI_HW_STRUCT_COMPLETION_CODES_H 36 36 37 #include <errno.h> 38 37 39 #define CC_NOERROR (0x0) 38 40 #define CC_CRC (0x1) … … 50 52 #define CC_NOACCESS2 (0xf) 51 53 54 inline static int cc_to_rc(int cc) 55 { 56 switch (cc) { 57 case CC_NOERROR: 58 return EOK; 59 60 case CC_CRC: 61 return EBADCHECKSUM; 62 63 case CC_PIDUNEXPECTED: 64 case CC_PIDFAIL: 65 case CC_BITSTUFF: 66 return EIO; 67 68 case CC_TOGGLE: 69 case CC_STALL: 70 return ESTALL; 71 72 case CC_NORESPONSE: 73 return ETIMEOUT; 74 75 case CC_DATAOVERRRUN: 76 case CC_DATAUNDERRRUN: 77 case CC_BUFFEROVERRRUN: 78 case CC_BUFFERUNDERRUN: 79 return EOVERFLOW; 80 81 case CC_NOACCESS1: 82 case CC_NOACCESS2: 83 default: 84 return ENOTSUP; 85 } 86 } 87 52 88 #endif 53 89 /** -
uspace/drv/ohci/hw_struct/endpoint_descriptor.h
ref354b6 re50cd7f 35 35 #define DRV_OHCI_HW_STRUCT_ENDPOINT_DESCRIPTOR_H 36 36 37 #include <assert.h> 37 38 #include <stdint.h> 39 40 #include <usb/host/endpoint.h> 41 42 #include "utils/malloc32.h" 43 #include "transfer_descriptor.h" 38 44 39 45 #include "completion_codes.h" … … 44 50 #define ED_STATUS_FA_SHIFT (0) 45 51 #define ED_STATUS_EN_MASK (0xf) /* USB endpoint address */ 46 #define ED_STATUS_EN_SHIFT ( 6)52 #define ED_STATUS_EN_SHIFT (7) 47 53 #define ED_STATUS_D_MASK (0x3) /* direction */ 48 #define ED_STATUS_D_SHIFT (10) 49 #define ED_STATUS_D_IN (0x1) 50 #define ED_STATUS_D_OUT (0x2) 54 #define ED_STATUS_D_SHIFT (11) 55 #define ED_STATUS_D_OUT (0x1) 56 #define ED_STATUS_D_IN (0x2) 57 #define ED_STATUS_D_TRANSFER (0x3) 51 58 52 #define ED_STATUS_S_FLAG (1 << 13) /* speed flag */59 #define ED_STATUS_S_FLAG (1 << 13) /* speed flag: 1 = low */ 53 60 #define ED_STATUS_K_FLAG (1 << 14) /* skip flag (no not execute this ED) */ 54 61 #define ED_STATUS_F_FLAG (1 << 15) /* format: 1 = isochronous*/ … … 66 73 #define ED_TDHEAD_ZERO_SHIFT (2) 67 74 #define ED_TDHEAD_TOGGLE_CARRY (0x2) 75 #define ED_TDHEAD_HALTED_FLAG (0x1) 68 76 69 77 volatile uint32_t next; … … 71 79 #define ED_NEXT_PTR_SHIFT (0) 72 80 } __attribute__((packed)) ed_t; 81 82 void ed_init(ed_t *instance, endpoint_t *ep); 83 84 static inline void ed_set_td(ed_t *instance, td_t *td) 85 { 86 assert(instance); 87 uintptr_t pa = addr_to_phys(td); 88 instance->td_head = 89 ((pa & ED_TDHEAD_PTR_MASK) 90 | (instance->td_head & ~ED_TDHEAD_PTR_MASK)); 91 instance->td_tail = pa & ED_TDTAIL_PTR_MASK; 92 } 93 94 static inline void ed_set_end_td(ed_t *instance, td_t *td) 95 { 96 assert(instance); 97 uintptr_t pa = addr_to_phys(td); 98 instance->td_tail = pa & ED_TDTAIL_PTR_MASK; 99 } 100 101 static inline void ed_append_ed(ed_t *instance, ed_t *next) 102 { 103 assert(instance); 104 assert(next); 105 uint32_t pa = addr_to_phys(next); 106 assert((pa & ED_NEXT_PTR_MASK) << ED_NEXT_PTR_SHIFT == pa); 107 instance->next = pa; 108 } 109 110 static inline int ed_toggle_get(ed_t *instance) 111 { 112 assert(instance); 113 return (instance->td_head & ED_TDHEAD_TOGGLE_CARRY) ? 1 : 0; 114 } 115 116 static inline void ed_toggle_set(ed_t *instance, int toggle) 117 { 118 assert(instance); 119 assert(toggle == 0 || toggle == 1); 120 if (toggle == 1) { 121 instance->td_head |= ED_TDHEAD_TOGGLE_CARRY; 122 } else { 123 /* clear halted flag when reseting toggle */ 124 instance->td_head &= ~ED_TDHEAD_TOGGLE_CARRY; 125 instance->td_head &= ~ED_TDHEAD_HALTED_FLAG; 126 } 127 } 73 128 #endif 74 129 /** -
uspace/drv/ohci/hw_struct/hcca.h
ref354b6 re50cd7f 43 43 uint32_t done_head; 44 44 uint32_t reserved[29]; 45 } __attribute__((packed )) hcca_t;45 } __attribute__((packed, aligned)) hcca_t; 46 46 47 47 #endif -
uspace/drv/ohci/hw_struct/transfer_descriptor.h
ref354b6 re50cd7f 35 35 #define DRV_OHCI_HW_STRUCT_TRANSFER_DESCRIPTOR_H 36 36 37 #include <bool.h> 37 38 #include <stdint.h> 39 #include "utils/malloc32.h" 38 40 39 41 #include "completion_codes.h" 42 43 /* OHCI TDs can handle up to 8KB buffers */ 44 #define OHCI_TD_MAX_TRANSFER (8 * 1024) 40 45 41 46 typedef struct td { … … 45 50 #define TD_STATUS_DP_SHIFT (19) 46 51 #define TD_STATUS_DP_SETUP (0x0) 47 #define TD_STATUS_DP_ IN(0x1)48 #define TD_STATUS_DP_ OUT(0x2)52 #define TD_STATUS_DP_OUT (0x1) 53 #define TD_STATUS_DP_IN (0x2) 49 54 #define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */ 50 55 #define TD_STATUS_DI_SHIFT (21) … … 52 57 #define TD_STATUS_T_MASK (0x3) /* data toggle 1x = use ED toggle carry */ 53 58 #define TD_STATUS_T_SHIFT (24) 59 #define TD_STATUS_T_0 (0x2) 60 #define TD_STATUS_T_1 (0x3) 61 #define TD_STATUS_T_ED (0) 54 62 #define TD_STATUS_EC_MASK (0x3) /* error count */ 55 63 #define TD_STATUS_EC_SHIFT (26) … … 64 72 volatile uint32_t be; /* buffer end, address of the last byte */ 65 73 } __attribute__((packed)) td_t; 74 75 void td_init( 76 td_t *instance, usb_direction_t dir, void *buffer, size_t size, int toggle); 77 78 inline static void td_set_next(td_t *instance, td_t *next) 79 { 80 assert(instance); 81 instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK; 82 } 83 84 inline static bool td_is_finished(td_t *instance) 85 { 86 assert(instance); 87 int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK; 88 /* something went wrong, error code is set */ 89 if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) { 90 return true; 91 } 92 /* everything done */ 93 if (cc == CC_NOERROR && instance->cbp == 0) { 94 return true; 95 } 96 return false; 97 } 98 99 static inline int td_error(td_t *instance) 100 { 101 assert(instance); 102 int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK; 103 return cc_to_rc(cc); 104 } 105 106 static inline size_t td_remain_size(td_t *instance) 107 { 108 assert(instance); 109 if (instance->cbp == 0) 110 return 0; 111 return instance->be - instance->cbp + 1; 112 } 66 113 #endif 67 114 /** -
uspace/drv/ohci/iface.c
ref354b6 re50cd7f 1 1 /* 2 * Copyright (c) 2011 Vojtech Horky 2 * Copyright (c) 2011 Vojtech Horky, Jan Vesely 3 3 * All rights reserved. 4 4 * … … 30 30 */ 31 31 /** @file 32 * USB-HC interface implementation.32 * @brief OHCI driver hc interface implementation 33 33 */ 34 34 #include <ddf/driver.h> … … 36 36 37 37 #include <usb/debug.h> 38 #include <usb/host/endpoint.h> 38 39 39 40 #include "iface.h" 40 41 #include "hc.h" 41 42 42 #define UNSUPPORTED(methodname) \ 43 usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \ 44 methodname, __FILE__, __LINE__) 45 46 /** Reserve default address. 47 * 48 * This function may block the caller. 49 * 50 * @param[in] fun Device function the action was invoked on. 51 * @param[in] speed Speed of the device for which the default address is 52 * reserved. 53 * @return Error code. 54 */ 55 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 56 { 43 static inline int setup_batch( 44 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction, 45 void *data, size_t size, void * setup_data, size_t setup_size, 46 usbhc_iface_transfer_in_callback_t in, 47 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name, 48 hc_t **hc, usb_transfer_batch_t **batch) 49 { 50 assert(hc); 51 assert(batch); 57 52 assert(fun); 58 hc_t *hc = fun_to_hc(fun); 59 assert(hc); 60 usb_log_debug("Default address request with speed %d.\n", speed); 61 usb_device_keeper_reserve_default_address(&hc->manager, speed); 53 *hc = fun_to_hc(fun); 54 assert(*hc); 55 56 size_t res_bw; 57 endpoint_t *ep = hc_get_endpoint(*hc, 58 target.address, target.endpoint, direction, &res_bw); 59 if (ep == NULL) { 60 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 61 target.address, target.endpoint, name); 62 return ENOENT; 63 } 64 65 usb_log_debug("%s %d:%d %zu(%zu).\n", 66 name, target.address, target.endpoint, size, ep->max_packet_size); 67 68 const size_t bw = bandwidth_count_usb11( 69 ep->speed, ep->transfer_type, size, ep->max_packet_size); 70 if (res_bw < bw) { 71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 72 "but only %zu is reserved.\n", 73 target.address, target.endpoint, name, bw, res_bw); 74 return ENOSPC; 75 } 76 77 *batch = batch_get( 78 fun, ep, data, size, setup_data, setup_size, in, out, arg); 79 if (!*batch) 80 return ENOMEM; 62 81 return EOK; 63 82 } 64 83 /*----------------------------------------------------------------------------*/ 65 /** Release default address. 66 * 67 * @param[in] fun Device function the action was invoked on. 68 * @return Error code. 69 */ 70 static int release_default_address(ddf_fun_t *fun) 71 { 72 assert(fun); 73 hc_t *hc = fun_to_hc(fun); 74 assert(hc); 75 usb_log_debug("Default address release.\n"); 76 usb_device_keeper_release_default_address(&hc->manager); 77 return EOK; 78 } 79 /*----------------------------------------------------------------------------*/ 80 /** Found free USB address. 81 * 82 * @param[in] fun Device function the action was invoked on. 83 * @param[in] speed Speed of the device that will get this address. 84 * @param[out] address Non-null pointer where to store the free address. 84 /** Request address interface function 85 * 86 * @param[in] fun DDF function that was called. 87 * @param[in] speed Speed to associate with the new default address. 88 * @param[out] address Place to write a new address. 85 89 * @return Error code. 86 90 */ … … 101 105 } 102 106 /*----------------------------------------------------------------------------*/ 103 /** Bind USB address with device devman handle.104 * 105 * @param[in] fun D evice function the action was invoked on.106 * @param[in] address USB address of the device.107 * @param[in] handle Devman handle of the device .107 /** Bind address interface function 108 * 109 * @param[in] fun DDF function that was called. 110 * @param[in] address Address of the device 111 * @param[in] handle Devman handle of the device driver. 108 112 * @return Error code. 109 113 */ 110 114 static int bind_address( 111 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)115 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle) 112 116 { 113 117 assert(fun); … … 119 123 } 120 124 /*----------------------------------------------------------------------------*/ 121 /** Release previously requested address.122 * 123 * @param[in] fun D evice function the action was invoked on.125 /** Release address interface function 126 * 127 * @param[in] fun DDF function that was called. 124 128 * @param[in] address USB address to be released. 125 129 * @return Error code. … … 139 143 * @param[in] fun Device function the action was invoked on. 140 144 * @param[in] address USB address of the device. 145 * @param[in] ep_speed Endpoint speed (invalid means to use device one). 141 146 * @param[in] endpoint Endpoint number. 142 147 * @param[in] transfer_type USB transfer type. … … 146 151 * @return Error code. 147 152 */ 148 static int register_endpoint( 149 ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,153 static int register_endpoint(ddf_fun_t *fun, 154 usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint, 150 155 usb_transfer_type_t transfer_type, usb_direction_t direction, 151 156 size_t max_packet_size, unsigned int interval) 152 157 { 153 assert(fun);154 158 hc_t *hc = fun_to_hc(fun); 155 159 assert(hc); 156 if (address == hc->rh.address) 157 return EOK; 158 const usb_speed_t speed = 159 usb_device_keeper_get_speed(&hc->manager, address); 160 161 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address); 162 if (speed >= USB_SPEED_MAX) { 163 speed = ep_speed; 164 } 160 165 const size_t size = max_packet_size; 166 161 167 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n", 162 168 address, endpoint, usb_str_transfer_type(transfer_type), 163 169 usb_str_speed(speed), direction, size, max_packet_size, interval); 164 // TODO use real endpoint here! 165 return usb_endpoint_manager_register_ep(&hc->ep_manager,NULL, 0); 166 } 167 /*----------------------------------------------------------------------------*/ 168 /** Unregister endpoint (free some bandwidth reservation). 169 * 170 * @param[in] fun Device function the action was invoked on. 171 * @param[in] address USB address of the device. 172 * @param[in] endpoint Endpoint number. 173 * @param[in] direction Endpoint data direction. 174 * @return Error code. 175 */ 170 171 return hc_add_endpoint(hc, address, endpoint, speed, transfer_type, 172 direction, max_packet_size, size, interval); 173 } 174 /*----------------------------------------------------------------------------*/ 176 175 static int unregister_endpoint( 177 176 ddf_fun_t *fun, usb_address_t address, 178 177 usb_endpoint_t endpoint, usb_direction_t direction) 179 178 { 180 assert(fun);181 179 hc_t *hc = fun_to_hc(fun); 182 180 assert(hc); 183 181 usb_log_debug("Unregister endpoint %d:%d %d.\n", 184 182 address, endpoint, direction); 185 return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address, 186 endpoint, direction); 183 return hc_remove_endpoint(hc, address, endpoint, direction); 187 184 } 188 185 /*----------------------------------------------------------------------------*/ … … 196 193 * @param[in] fun Device function the action was invoked on. 197 194 * @param[in] target Target pipe (address and endpoint number) specification. 198 * @param[in] max_packet_size Max packet size for the transfer.199 195 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated 200 196 * by the caller). … … 205 201 */ 206 202 static int interrupt_out( 207 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,203 ddf_fun_t *fun, usb_target_t target, void *data, 208 204 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg) 209 205 { 210 assert(fun); 211 hc_t *hc = fun_to_hc(fun); 212 assert(hc); 213 usb_speed_t speed = 214 usb_device_keeper_get_speed(&hc->manager, target.address); 215 216 usb_log_debug("Interrupt OUT %d:%d %zu(%zu).\n", 217 target.address, target.endpoint, size, max_packet_size); 218 219 usb_transfer_batch_t *batch = 220 batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size, 221 speed, data, size, NULL, 0, NULL, callback, arg, &hc->manager); 222 if (!batch) 223 return ENOMEM; 206 usb_transfer_batch_t *batch = NULL; 207 hc_t *hc = NULL; 208 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size, 209 NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch); 210 if (ret != EOK) 211 return ret; 224 212 batch_interrupt_out(batch); 225 const intret = hc_schedule(hc, batch);226 if (ret != EOK) { 227 batch_dispose(batch);213 ret = hc_schedule(hc, batch); 214 if (ret != EOK) { 215 usb_transfer_batch_dispose(batch); 228 216 } 229 217 return ret; … … 239 227 * @param[in] fun Device function the action was invoked on. 240 228 * @param[in] target Target pipe (address and endpoint number) specification. 241 * @param[in] max_packet_size Max packet size for the transfer.242 229 * @param[in] data Buffer where to store the data (in USB endianess, 243 230 * allocated and deallocated by the caller). … … 248 235 */ 249 236 static int interrupt_in( 250 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,237 ddf_fun_t *fun, usb_target_t target, void *data, 251 238 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg) 252 239 { 253 assert(fun); 254 hc_t *hc = fun_to_hc(fun); 255 assert(hc); 256 usb_speed_t speed = 257 usb_device_keeper_get_speed(&hc->manager, target.address); 258 usb_log_debug("Interrupt IN %d:%d %zu(%zu).\n", 259 target.address, target.endpoint, size, max_packet_size); 260 261 usb_transfer_batch_t *batch = 262 batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size, 263 speed, data, size, NULL, 0, callback, NULL, arg, &hc->manager); 264 if (!batch) 265 return ENOMEM; 240 usb_transfer_batch_t *batch = NULL; 241 hc_t *hc = NULL; 242 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size, 243 NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch); 244 if (ret != EOK) 245 return ret; 266 246 batch_interrupt_in(batch); 267 const intret = hc_schedule(hc, batch);268 if (ret != EOK) { 269 batch_dispose(batch);247 ret = hc_schedule(hc, batch); 248 if (ret != EOK) { 249 usb_transfer_batch_dispose(batch); 270 250 } 271 251 return ret; … … 281 261 * @param[in] fun Device function the action was invoked on. 282 262 * @param[in] target Target pipe (address and endpoint number) specification. 283 * @param[in] max_packet_size Max packet size for the transfer.284 263 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated 285 264 * by the caller). … … 290 269 */ 291 270 static int bulk_out( 292 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,271 ddf_fun_t *fun, usb_target_t target, void *data, 293 272 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg) 294 273 { 295 assert(fun); 296 hc_t *hc = fun_to_hc(fun); 297 assert(hc); 298 usb_speed_t speed = 299 usb_device_keeper_get_speed(&hc->manager, target.address); 300 301 usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n", 302 target.address, target.endpoint, size, max_packet_size); 303 304 usb_transfer_batch_t *batch = 305 batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed, 306 data, size, NULL, 0, NULL, callback, arg, &hc->manager); 307 if (!batch) 308 return ENOMEM; 274 usb_transfer_batch_t *batch = NULL; 275 hc_t *hc = NULL; 276 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size, 277 NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch); 278 if (ret != EOK) 279 return ret; 309 280 batch_bulk_out(batch); 310 const intret = hc_schedule(hc, batch);311 if (ret != EOK) { 312 batch_dispose(batch);281 ret = hc_schedule(hc, batch); 282 if (ret != EOK) { 283 usb_transfer_batch_dispose(batch); 313 284 } 314 285 return ret; … … 324 295 * @param[in] fun Device function the action was invoked on. 325 296 * @param[in] target Target pipe (address and endpoint number) specification. 326 * @param[in] max_packet_size Max packet size for the transfer.327 297 * @param[in] data Buffer where to store the data (in USB endianess, 328 298 * allocated and deallocated by the caller). … … 333 303 */ 334 304 static int bulk_in( 335 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,305 ddf_fun_t *fun, usb_target_t target, void *data, 336 306 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg) 337 307 { 338 assert(fun); 339 hc_t *hc = fun_to_hc(fun); 340 assert(hc); 341 usb_speed_t speed = 342 usb_device_keeper_get_speed(&hc->manager, target.address); 343 usb_log_debug("Bulk IN %d:%d %zu(%zu).\n", 344 target.address, target.endpoint, size, max_packet_size); 345 346 usb_transfer_batch_t *batch = 347 batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed, 348 data, size, NULL, 0, callback, NULL, arg, &hc->manager); 349 if (!batch) 350 return ENOMEM; 308 usb_transfer_batch_t *batch = NULL; 309 hc_t *hc = NULL; 310 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size, 311 NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch); 312 if (ret != EOK) 313 return ret; 351 314 batch_bulk_in(batch); 352 const intret = hc_schedule(hc, batch);353 if (ret != EOK) { 354 batch_dispose(batch);315 ret = hc_schedule(hc, batch); 316 if (ret != EOK) { 317 usb_transfer_batch_dispose(batch); 355 318 } 356 319 return ret; … … 366 329 * @param[in] fun Device function the action was invoked on. 367 330 * @param[in] target Target pipe (address and endpoint number) specification. 368 * @param[in] max_packet_size Max packet size for the transfer.369 331 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 370 332 * and deallocated by the caller). 371 * @param[in] setup_ packet_size Size of @p setup_packet buffer in bytes.333 * @param[in] setup_size Size of @p setup_packet buffer in bytes. 372 334 * @param[in] data_buffer Data buffer (in USB endianess, allocated and 373 335 * deallocated by the caller). 374 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.336 * @param[in] size Size of @p data_buffer buffer in bytes. 375 337 * @param[in] callback Callback to be issued once the transfer is complete. 376 338 * @param[in] arg Pass-through argument to the callback. … … 378 340 */ 379 341 static int control_write( 380 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,342 ddf_fun_t *fun, usb_target_t target, 381 343 void *setup_data, size_t setup_size, void *data, size_t size, 382 344 usbhc_iface_transfer_out_callback_t callback, void *arg) 383 345 { 384 assert(fun); 385 hc_t *hc = fun_to_hc(fun); 386 assert(hc); 387 usb_speed_t speed = 388 usb_device_keeper_get_speed(&hc->manager, target.address); 389 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n", 390 speed, target.address, target.endpoint, size, max_packet_size); 391 392 if (setup_size != 8) 393 return EINVAL; 394 395 usb_transfer_batch_t *batch = 396 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size, 397 speed, data, size, setup_data, setup_size, NULL, callback, arg, 398 &hc->manager); 399 if (!batch) 400 return ENOMEM; 401 usb_device_keeper_reset_if_need(&hc->manager, target, setup_data); 346 usb_transfer_batch_t *batch = NULL; 347 hc_t *hc = NULL; 348 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size, 349 setup_data, setup_size, NULL, callback, arg, "Control WRITE", 350 &hc, &batch); 351 if (ret != EOK) 352 return ret; 353 usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data); 402 354 batch_control_write(batch); 403 const intret = hc_schedule(hc, batch);404 if (ret != EOK) { 405 batch_dispose(batch);355 ret = hc_schedule(hc, batch); 356 if (ret != EOK) { 357 usb_transfer_batch_dispose(batch); 406 358 } 407 359 return ret; … … 417 369 * @param[in] fun Device function the action was invoked on. 418 370 * @param[in] target Target pipe (address and endpoint number) specification. 419 * @param[in] max_packet_size Max packet size for the transfer.420 371 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 421 372 * and deallocated by the caller). 422 * @param[in] setup_ packet_size Size of @p setup_packet buffer in bytes.373 * @param[in] setup_size Size of @p setup_packet buffer in bytes. 423 374 * @param[in] data_buffer Buffer where to store the data (in USB endianess, 424 375 * allocated and deallocated by the caller). 425 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.376 * @param[in] size Size of @p data_buffer buffer in bytes. 426 377 * @param[in] callback Callback to be issued once the transfer is complete. 427 378 * @param[in] arg Pass-through argument to the callback. … … 429 380 */ 430 381 static int control_read( 431 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,382 ddf_fun_t *fun, usb_target_t target, 432 383 void *setup_data, size_t setup_size, void *data, size_t size, 433 384 usbhc_iface_transfer_in_callback_t callback, void *arg) 434 385 { 435 assert(fun); 436 hc_t *hc = fun_to_hc(fun); 437 assert(hc); 438 usb_speed_t speed = 439 usb_device_keeper_get_speed(&hc->manager, target.address); 440 441 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n", 442 speed, target.address, target.endpoint, size, max_packet_size); 443 usb_transfer_batch_t *batch = 444 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size, 445 speed, data, size, setup_data, setup_size, callback, NULL, arg, 446 &hc->manager); 447 if (!batch) 448 return ENOMEM; 386 usb_transfer_batch_t *batch = NULL; 387 hc_t *hc = NULL; 388 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size, 389 setup_data, setup_size, callback, NULL, arg, "Control READ", 390 &hc, &batch); 391 if (ret != EOK) 392 return ret; 449 393 batch_control_read(batch); 450 const int ret = hc_schedule(hc, batch); 451 if (ret != EOK) { 452 batch_dispose(batch); 453 } 454 return ret; 455 } 456 /*----------------------------------------------------------------------------*/ 457 /** Host controller interface implementation for OHCI. */ 394 ret = hc_schedule(hc, batch); 395 if (ret != EOK) { 396 usb_transfer_batch_dispose(batch); 397 } 398 return ret; 399 } 400 /*----------------------------------------------------------------------------*/ 458 401 usbhc_iface_t hc_iface = { 459 .reserve_default_address = reserve_default_address,460 .release_default_address = release_default_address,461 402 .request_address = request_address, 462 403 .bind_address = bind_address, … … 475 416 .control_read = control_read, 476 417 }; 477 478 418 /** 479 419 * @} -
uspace/drv/ohci/ohci.ma
ref354b6 re50cd7f 1 1 10 pci/ven=106b&dev=003f 2 10 pci/ven=10de&dev=0aa5 3 10 pci/ven=10de&dev=0aa5 -
uspace/drv/ohci/ohci_regs.h
ref354b6 re50cd7f 41 41 const volatile uint32_t revision; 42 42 volatile uint32_t control; 43 #define C_CSBR_MASK (0x3) 43 #define C_CSBR_MASK (0x3) /* Control-bulk service ratio */ 44 #define C_CSBR_1_1 (0x0) 45 #define C_CSBR_1_2 (0x1) 46 #define C_CSBR_1_3 (0x2) 47 #define C_CSBR_1_4 (0x3) 44 48 #define C_CSBR_SHIFT (0) 45 #define C_PLE (1 << 2) 46 #define C_IE (1 << 3) 47 #define C_CLE (1 << 4) 48 #define C_BLE (1 << 5) 49 50 #define C_HCFS_MASK (0x3) 51 #define C_HCFS_SHIFT (6) 52 #define C_HCFS_RESET (0x0) 53 #define C_HCFS_OPERATIONAL (0x1) 54 #define C_HCFS_RESUME (0x2) 55 #define C_HCFS_SUSPEND (0x3) 56 57 #define C_IR (1 << 8) 58 #define C_RWC (1 << 9) 59 #define C_RWE (1 << 10) 49 50 #define C_PLE (1 << 2) /* Periodic list enable */ 51 #define C_IE (1 << 3) /* Isochronous enable */ 52 #define C_CLE (1 << 4) /* Control list enable */ 53 #define C_BLE (1 << 5) /* Bulk list enable */ 54 55 #define C_HCFS_MASK (0x3) /* Host controller functional state */ 56 #define C_HCFS_RESET (0x0) 57 #define C_HCFS_RESUME (0x1) 58 #define C_HCFS_OPERATIONAL (0x2) 59 #define C_HCFS_SUSPEND (0x3) 60 #define C_HCFS_SHIFT (6) 61 62 #define C_IR (1 << 8) /* Interrupt routing, make sure it's 0 */ 63 #define C_RWC (1 << 9) /* Remote wakeup connected, host specific */ 64 #define C_RWE (1 << 10) /* Remote wakeup enable */ 60 65 61 66 volatile uint32_t command_status; 62 #define CS_HCR (1 << 0) 63 #define CS_CLF (1 << 1) 64 #define CS_BLF (1 << 2) 65 #define CS_OCR (1 << 3) 66 #define CS_SOC_MASK (0x3) 67 #define CS_HCR (1 << 0) /* Host controller reset */ 68 #define CS_CLF (1 << 1) /* Control list filled */ 69 #define CS_BLF (1 << 2) /* Bulk list filled */ 70 #define CS_OCR (1 << 3) /* Ownership change request */ 71 #define CS_SOC_MASK (0x3) /* Scheduling overrun count */ 67 72 #define CS_SOC_SHIFT (16) 68 73 69 74 volatile uint32_t interrupt_status; 70 #define IS_SO (1 << 0) 71 #define IS_WDH (1 << 1) 72 #define IS_SF (1 << 2) 73 #define IS_RD (1 << 3) 74 #define IS_UE (1 << 4) 75 #define IS_FNO (1 << 5) 76 #define IS_RHSC (1 << 6) 77 #define IS_OC (1 << 30) 78 79 volatile uint32_t interupt_enable; 80 #define IE_SO (1 << 0) 81 #define IE_WDH (1 << 1) 82 #define IE_SF (1 << 2) 83 #define IE_RD (1 << 3) 84 #define IE_UE (1 << 4) 85 #define IE_FNO (1 << 5) 86 #define IE_RHSC (1 << 6) 87 #define IE_OC (1 << 30) 88 #define IE_MIE (1 << 31) 89 75 #define IS_SO (1 << 0) /* Scheduling overrun */ 76 #define IS_WDH (1 << 1) /* Write-back done head */ 77 #define IS_SF (1 << 2) /* Start of frame */ 78 #define IS_RD (1 << 3) /* Resume detected */ 79 #define IS_UE (1 << 4) /* Unrecoverable error */ 80 #define IS_FNO (1 << 5) /* Frame number overflow */ 81 #define IS_RHSC (1 << 6) /* Root hub status change */ 82 #define IS_OC (1 << 30) /* Ownership change */ 83 84 /** Interupt enable/disable, reads give the same value, writing causes 85 * enable/disable */ 86 volatile uint32_t interrupt_enable; 90 87 volatile uint32_t interrupt_disable; 88 #define I_SO (1 << 0) /* Scheduling overrun */ 89 #define I_WDH (1 << 1) /* Done head write-back */ 90 #define I_SF (1 << 2) /* Start of frame */ 91 #define I_RD (1 << 3) /* Resume detect */ 92 #define I_UE (1 << 4) /* Unrecoverable error */ 93 #define I_FNO (1 << 5) /* Frame number overflow */ 94 #define I_RHSC (1 << 6) /* Root hub status change */ 95 #define I_OC (1 << 30) /* Ownership change */ 96 #define I_MI (1 << 31) /* Master interrupt (all/any interrupts) */ 97 98 /** HCCA pointer (see hw_struct hcca.h) */ 91 99 volatile uint32_t hcca; 92 volatile uint32_t period_corrent; 100 #define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */ 101 102 /** Currently executed periodic endpoint */ 103 const volatile uint32_t periodic_current; 104 105 /** The first control endpoint */ 93 106 volatile uint32_t control_head; 107 108 /** Currently executed control endpoint */ 94 109 volatile uint32_t control_current; 110 111 /** The first bulk endpoint */ 95 112 volatile uint32_t bulk_head; 113 114 /** Currently executed bulk endpoint */ 96 115 volatile uint32_t bulk_current; 97 volatile uint32_t done_head; 116 117 /** Done TD list, this value is periodically written to HCCA */ 118 const volatile uint32_t done_head; 119 120 /** Frame time and max packet size for all transfers */ 98 121 volatile uint32_t fm_interval; 99 volatile uint32_t fm_remaining; 100 volatile uint32_t fm_number; 122 #define FMI_FI_MASK (0x3fff) /* Frame interval in bit times (should be 11999)*/ 123 #define FMI_FI_SHIFT (0) 124 #define FMI_FSMPS_MASK (0x7fff) /* Full speed max packet size */ 125 #define FMI_FSMPS_SHIFT (16) 126 #define FMI_TOGGLE_FLAG (1 << 31) 127 128 /** Bit times remaining in current frame */ 129 const volatile uint32_t fm_remaining; 130 #define FMR_FR_MASK FMI_FI_MASK 131 #define FMR_FR_SHIFT FMI_FI_SHIFT 132 #define FMR_TOGGLE_FLAG FMI_TOGGLE_FLAG 133 134 /** Frame number */ 135 const volatile uint32_t fm_number; 136 #define FMN_NUMBER_MASK (0xffff) 137 138 /** Remaining bit time in frame to start periodic transfers */ 101 139 volatile uint32_t periodic_start; 140 #define PS_PS_MASK (0x3fff) /* bit time when periodic get priority (0x3e67) */ 141 142 /** Threshold for starting LS transaction */ 102 143 volatile uint32_t ls_threshold; 144 #define LST_LST_MASK (0x7fff) 145 146 /** The first root hub control register */ 103 147 volatile uint32_t rh_desc_a; 148 #define RHDA_NDS_MASK (0xff) /* Number of downstream ports, max 15 */ 149 #define RHDA_NDS_SHIFT (0) 150 #define RHDA_PSM_FLAG (1 << 8) /* Power switching mode: 0-global, 1-per port*/ 151 #define RHDA_NPS_FLAG (1 << 9) /* No power switch: 1-power on, 0-use PSM*/ 152 #define RHDA_DT_FLAG (1 << 10) /* 1-Compound device, must be 0 */ 153 #define RHDA_OCPM_FLAG (1 << 11) /* Over-current mode: 0-global, 1-per port */ 154 #define RHDA_NOCP (1 << 12) /* OC control: 0-use OCPM, 1-OC off */ 155 #define RHDA_POTPGT_MASK (0xff) /* Power on to power good time */ 156 #define RHDA_POTPGT_SHIFT (24) 157 158 /** The other root hub control register */ 104 159 volatile uint32_t rh_desc_b; 160 #define RHDB_DR_MASK (0xffff) /* Device removable mask */ 161 #define RHDB_DR_SHIFT (0) 162 #define RHDB_PCC_MASK (0xffff) /* Power control mask */ 163 #define RHDB_PCC_SHIFT (16) 164 165 /* Port device removable status */ 166 #define RHDB_DR_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT) 167 /* Port power control status: 1-per port power control, 0-global power switch */ 168 #define RHDB_PPC_FLAG(port) (((1 << port) & RHDB_DR_MASK) << RHDB_DR_SHIFT) 169 170 /** Root hub status register */ 105 171 volatile uint32_t rh_status; 172 #define RHS_LPS_FLAG (1 << 0)/* read: 0, 173 * write: 0-no effect, 174 * 1-turn off port power for ports 175 * specified in PPCM(RHDB), or all ports, 176 * if power is set globally */ 177 #define RHS_CLEAR_PORT_POWER RHS_LPS_FLAG /* synonym for the above */ 178 #define RHS_OCI_FLAG (1 << 1)/* Over-current indicator, if per-port: 0 */ 179 #define RHS_DRWE_FLAG (1 << 15)/* read: 0-connect status change does not wake HC 180 * 1-connect status change wakes HC 181 * write: 1-set DRWE, 0-no effect */ 182 #define RHS_SET_DRWE RHS_DRWE_FLAG 183 #define RHS_LPSC_FLAG (1 << 16)/* read: 0, 184 * write: 0-no effect 185 * 1-turn on port power for ports 186 * specified in PPCM(RHDB), or all ports, 187 * if power is set globally */ 188 #define RHS_SET_PORT_POWER RHS_LPSC_FLAG /* synonym for the above */ 189 #define RHS_OCIC_FLAG (1 << 17)/* Over-current indicator change */ 190 #define RHS_CLEAR_DRWE (1 << 31) 191 192 /** Root hub per port status */ 106 193 volatile uint32_t rh_port_status[]; 194 #define RHPS_CCS_FLAG (1 << 0) /* r: current connect status, 195 * w: 1-clear port enable, 0-nothing */ 196 #define RHPS_CLEAR_PORT_ENABLE RHPS_CCS_FLAG 197 #define RHPS_PES_FLAG (1 << 1) /* r: port enable status 198 * w: 1-set port enable, 0-nothing */ 199 #define RHPS_SET_PORT_ENABLE RHPS_PES_FLAG 200 #define RHPS_PSS_FLAG (1 << 2) /* r: port suspend status 201 * w: 1-set port suspend, 0-nothing */ 202 #define RHPS_SET_PORT_SUSPEND RHPS_PSS_FLAG 203 #define RHPS_POCI_FLAG (1 << 3) /* r: port over-current (if reports are per-port 204 * w: 1-clear port suspend (start resume 205 * if suspened) 206 * 0-nothing */ 207 #define RHPS_CLEAR_PORT_SUSPEND RHPS_POCI_FLAG 208 #define RHPS_PRS_FLAG (1 << 4) /* r: port reset status 209 * w: 1-set port reset, 0-nothing */ 210 #define RHPS_SET_PORT_RESET RHPS_PRS_FLAG 211 #define RHPS_PPS_FLAG (1 << 8) /* r: port power status 212 * w: 1-set port power, 0-nothing */ 213 #define RHPS_SET_PORT_POWER RHPS_PPS_FLAG 214 #define RHPS_LSDA_FLAG (1 << 9) /* r: low speed device attached 215 * w: 1-clear port power, 0-nothing */ 216 #define RHPS_CLEAR_PORT_POWER RHPS_LSDA_FLAG 217 #define RHPS_CSC_FLAG (1 << 16) /* connect status change Write-Clean */ 218 #define RHPS_PESC_FLAG (1 << 17) /* port enable status change WC */ 219 #define RHPS_PSSC_FLAG (1 << 18) /* port suspend status change WC */ 220 #define RHPS_OCIC_FLAG (1 << 19) /* port over-current change WC */ 221 #define RHPS_PRSC_FLAG (1 << 20) /* port reset status change WC */ 222 #define RHPS_CHANGE_WC_MASK 0x1f0000 107 223 } __attribute__((packed)) ohci_regs_t; 108 224 #endif -
uspace/drv/ohci/root_hub.c
ref354b6 re50cd7f 47 47 * standart device descriptor for ohci root hub 48 48 */ 49 static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = 50 { 51 .configuration_count = 1, 52 .descriptor_type = USB_DESCTYPE_DEVICE, 53 .device_class = USB_CLASS_HUB, 54 .device_protocol = 0, 55 .device_subclass = 0, 56 .device_version = 0, 57 .length = sizeof(usb_standard_device_descriptor_t), 58 /// \TODO this value is guessed 59 .max_packet_size = 8, 60 .vendor_id = 0x16db, 61 .product_id = 0x0001, 62 /// \TODO these values migt be different 63 .str_serial_number = 0, 64 .usb_spec_version = 0x110, 49 static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = { 50 .configuration_count = 1, 51 .descriptor_type = USB_DESCTYPE_DEVICE, 52 .device_class = USB_CLASS_HUB, 53 .device_protocol = 0, 54 .device_subclass = 0, 55 .device_version = 0, 56 .length = sizeof (usb_standard_device_descriptor_t), 57 /// \TODO this value is guessed 58 .max_packet_size = 8, 59 .vendor_id = 0x16db, 60 .product_id = 0x0001, 61 /// \TODO these values migt be different 62 .str_serial_number = 0, 63 .usb_spec_version = 0x110, 65 64 }; 66 65 … … 69 68 * for ohci root hubs 70 69 */ 71 static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor = 72 { 70 static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor = { 73 71 /// \TODO some values are default or guessed 74 .attributes = 1 <<7,72 .attributes = 1 << 7, 75 73 .configuration_number = 1, 76 74 .descriptor_type = USB_DESCTYPE_CONFIGURATION, 77 75 .interface_count = 1, 78 .length = sizeof (usb_standard_configuration_descriptor_t),76 .length = sizeof (usb_standard_configuration_descriptor_t), 79 77 .max_power = 100, 80 78 .str_configuration = 0, … … 84 82 * standart ohci root hub interface descriptor 85 83 */ 86 static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = 87 { 84 static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = { 88 85 .alternate_setting = 0, 89 86 .descriptor_type = USB_DESCTYPE_INTERFACE, … … 94 91 .interface_protocol = 0, 95 92 .interface_subclass = 0, 96 .length = sizeof (usb_standard_interface_descriptor_t),93 .length = sizeof (usb_standard_interface_descriptor_t), 97 94 .str_interface = 0, 98 95 }; … … 101 98 * standart ohci root hub endpoint descriptor 102 99 */ 103 static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = 104 { 100 static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = { 105 101 .attributes = USB_TRANSFER_INTERRUPT, 106 102 .descriptor_type = USB_DESCTYPE_ENDPOINT, 107 .endpoint_address = 1 + (1 <<7),108 .length = sizeof (usb_standard_endpoint_descriptor_t),103 .endpoint_address = 1 + (1 << 7), 104 .length = sizeof (usb_standard_endpoint_descriptor_t), 109 105 .max_packet_size = 8, 110 106 .poll_interval = 255, … … 112 108 113 109 static const uint32_t hub_clear_feature_valid_mask = 114 (1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) +115 (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT);110 (1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER) | 111 (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT); 116 112 117 113 static const uint32_t hub_clear_feature_by_writing_one_mask = … … 119 115 120 116 static const uint32_t hub_set_feature_valid_mask = 121 (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT); 122 123 117 (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT) | 118 (1 << USB_HUB_FEATURE_C_HUB_LOCAL_POWER); 119 120 124 121 static const uint32_t hub_set_feature_direct_mask = 125 122 (1 << USB_HUB_FEATURE_C_HUB_OVER_CURRENT); 126 123 127 124 static const uint32_t port_set_feature_valid_mask = 128 (1 << USB_HUB_FEATURE_PORT_ENABLE) +129 (1 << USB_HUB_FEATURE_PORT_SUSPEND) + 130 (1 << USB_HUB_FEATURE_PORT_RESET) + 131 (1 << USB_HUB_FEATURE_PORT_POWER);125 (1 << USB_HUB_FEATURE_PORT_ENABLE) | 126 (1 << USB_HUB_FEATURE_PORT_SUSPEND) | 127 (1 << USB_HUB_FEATURE_PORT_RESET) | 128 (1 << USB_HUB_FEATURE_PORT_POWER); 132 129 133 130 static const uint32_t port_clear_feature_valid_mask = 134 (1 << USB_HUB_FEATURE_PORT_CONNECTION) + 135 (1 << USB_HUB_FEATURE_PORT_SUSPEND) + 136 (1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) + 137 (1 << USB_HUB_FEATURE_PORT_POWER) + 138 (1 << USB_HUB_FEATURE_C_PORT_CONNECTION) + 139 (1 << USB_HUB_FEATURE_C_PORT_ENABLE) + 140 (1 << USB_HUB_FEATURE_C_PORT_SUSPEND) + 141 (1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) + 142 (1 << USB_HUB_FEATURE_C_PORT_RESET); 143 //note that USB_HUB_FEATURE_PORT_POWER bit is translated into USB_HUB_FEATURE_PORT_LOW_SPEED 144 145 146 131 (1 << USB_HUB_FEATURE_PORT_CONNECTION) | 132 (1 << USB_HUB_FEATURE_PORT_SUSPEND) | 133 (1 << USB_HUB_FEATURE_PORT_OVER_CURRENT) | 134 (1 << USB_HUB_FEATURE_PORT_POWER) | 135 (1 << USB_HUB_FEATURE_C_PORT_CONNECTION) | 136 (1 << USB_HUB_FEATURE_C_PORT_ENABLE) | 137 (1 << USB_HUB_FEATURE_C_PORT_SUSPEND) | 138 (1 << USB_HUB_FEATURE_C_PORT_OVER_CURRENT) | 139 (1 << USB_HUB_FEATURE_C_PORT_RESET); 140 //note that USB_HUB_FEATURE_PORT_POWER bit is translated into 141 //USB_HUB_FEATURE_PORT_LOW_SPEED 142 143 static const uint32_t port_status_change_mask = 144 (1<< USB_HUB_FEATURE_C_PORT_CONNECTION) | 145 (1<< USB_HUB_FEATURE_C_PORT_ENABLE) | 146 (1<< USB_HUB_FEATURE_C_PORT_OVER_CURRENT) | 147 (1<< USB_HUB_FEATURE_C_PORT_RESET) | 148 (1<< USB_HUB_FEATURE_C_PORT_SUSPEND); 149 150 151 static void usb_create_serialized_hub_descriptor(rh_t *instance, 152 uint8_t ** out_result, 153 size_t * out_size); 154 155 static void rh_init_descriptors(rh_t *instance); 156 157 static int process_get_port_status_request(rh_t *instance, uint16_t port, 158 usb_transfer_batch_t * request); 159 160 static int process_get_hub_status_request(rh_t *instance, 161 usb_transfer_batch_t * request); 162 163 static int process_get_status_request(rh_t *instance, 164 usb_transfer_batch_t * request); 165 166 static void create_interrupt_mask(rh_t *instance, void ** buffer, 167 size_t * buffer_size); 168 169 static int process_get_descriptor_request(rh_t *instance, 170 usb_transfer_batch_t *request); 171 172 static int process_get_configuration_request(rh_t *instance, 173 usb_transfer_batch_t *request); 174 175 static int process_hub_feature_set_request(rh_t *instance, uint16_t feature); 176 177 static int process_hub_feature_clear_request(rh_t *instance, 178 uint16_t feature); 179 180 static int process_port_feature_set_request(rh_t *instance, 181 uint16_t feature, uint16_t port); 182 183 static int process_port_feature_clear_request(rh_t *instance, 184 uint16_t feature, uint16_t port); 185 186 static int process_address_set_request(rh_t *instance, 187 uint16_t address); 188 189 static int process_request_with_output(rh_t *instance, 190 usb_transfer_batch_t *request); 191 192 static int process_request_with_input(rh_t *instance, 193 usb_transfer_batch_t *request); 194 195 static int process_request_without_data(rh_t *instance, 196 usb_transfer_batch_t *request); 197 198 static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request); 199 200 static int process_interrupt(rh_t *instance, usb_transfer_batch_t * request, 201 void * change_buffer, size_t buffe_size); 202 203 static bool is_zeros(void * buffer, size_t size); 204 205 206 207 /** Root hub initialization 208 * @return Error code. 209 */ 210 int rh_init(rh_t *instance, ohci_regs_t *regs) { 211 assert(instance); 212 instance->registers = regs; 213 instance->port_count = 214 (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK; 215 rh_init_descriptors(instance); 216 // set port power mode to no-power-switching 217 instance->registers->rh_desc_a |= RHDA_NPS_FLAG; 218 instance->unfinished_interrupt_transfer = NULL; 219 usb_log_info("OHCI root hub with %d ports.\n", instance->port_count); 220 return EOK; 221 } 222 /*----------------------------------------------------------------------------*/ 223 224 /** 225 * process root hub request 226 * 227 * @param instance root hub instance 228 * @param request structure containing both request and response information 229 * @return error code 230 */ 231 int rh_request(rh_t *instance, usb_transfer_batch_t *request) { 232 assert(instance); 233 assert(request); 234 int opResult; 235 if (request->ep->transfer_type == USB_TRANSFER_CONTROL) { 236 usb_log_info("Root hub got CONTROL packet\n"); 237 opResult = process_ctrl_request(instance, request); 238 usb_transfer_batch_finish_error(request, opResult); 239 } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) { 240 usb_log_info("Root hub got INTERRUPT packet\n"); 241 void * buffer; 242 size_t buffer_size; 243 create_interrupt_mask(instance, &buffer, 244 &buffer_size); 245 if(is_zeros(buffer,buffer_size)){ 246 usb_log_debug("no changes.."); 247 instance->unfinished_interrupt_transfer= 248 request; 249 //will be finished later 250 }else{ 251 usb_log_debug("processing changes.."); 252 process_interrupt(instance, request, 253 buffer, buffer_size); 254 } 255 free(buffer); 256 opResult = EOK; 257 } else { 258 opResult = EINVAL; 259 usb_transfer_batch_finish_error(request, opResult); 260 } 261 return EOK; 262 } 263 264 /*----------------------------------------------------------------------------*/ 265 266 267 void rh_interrupt(rh_t *instance) { 268 //usb_log_info("Whoa whoa wait, I`m not supposed to receive any " 269 // "interrupts, am I?\n"); 270 if(!instance->unfinished_interrupt_transfer){ 271 return; 272 } 273 size_t size; 274 void * buffer; 275 create_interrupt_mask(instance, &buffer, 276 &size); 277 process_interrupt(instance,instance->unfinished_interrupt_transfer, 278 buffer,size); 279 free(buffer); 280 } 281 /*----------------------------------------------------------------------------*/ 147 282 148 283 /** … … 157 292 */ 158 293 static void usb_create_serialized_hub_descriptor(rh_t *instance, 159 uint8_t ** out_result,160 size_t * out_size) {294 uint8_t ** out_result, 295 size_t * out_size) { 161 296 //base size 162 297 size_t size = 7; 163 298 //variable size according to port count 164 299 size_t var_size = instance->port_count / 8 + 165 ((instance->port_count % 8 > 0) ? 1 : 0);300 ((instance->port_count % 8 > 0) ? 1 : 0); 166 301 size += 2 * var_size; 167 302 uint8_t * result = (uint8_t*) malloc(size); 168 bzero(result, size);303 bzero(result, size); 169 304 //size 170 305 result[0] = size; … … 174 309 uint32_t hub_desc_reg = instance->registers->rh_desc_a; 175 310 result[3] = 176 ((hub_desc_reg >> 8) %2) +177 (((hub_desc_reg >> 9) %2) << 1) +178 (((hub_desc_reg >> 10) %2) << 2) +179 (((hub_desc_reg >> 11) %2) << 3) +180 (((hub_desc_reg >> 12) %2) << 4);311 ((hub_desc_reg >> 8) % 2) + 312 (((hub_desc_reg >> 9) % 2) << 1) + 313 (((hub_desc_reg >> 10) % 2) << 2) + 314 (((hub_desc_reg >> 11) % 2) << 3) + 315 (((hub_desc_reg >> 12) % 2) << 4); 181 316 result[4] = 0; 182 317 result[5] = /*descriptor->pwr_on_2_good_time*/ 50; … … 185 320 int port; 186 321 for (port = 1; port <= instance->port_count; ++port) { 187 result[7 + port/8] += 188 ((instance->registers->rh_desc_b >> port)%2) << (port%8); 322 uint8_t is_non_removable = 323 instance->registers->rh_desc_b >> port % 2; 324 result[7 + port / 8] += 325 is_non_removable << (port % 8); 189 326 } 190 327 size_t i; … … 195 332 (*out_size) = size; 196 333 } 197 334 /*----------------------------------------------------------------------------*/ 198 335 199 336 /** initialize hub descriptors … … 203 340 * @instance root hub instance 204 341 */ 205 static void rh_init_descriptors(rh_t *instance) {342 static void rh_init_descriptors(rh_t *instance) { 206 343 memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor, 207 sizeof (ohci_rh_device_descriptor)208 );344 sizeof (ohci_rh_device_descriptor) 345 ); 209 346 usb_standard_configuration_descriptor_t descriptor; 210 memcpy(&descriptor, &ohci_rh_conf_descriptor,211 sizeof(ohci_rh_conf_descriptor));347 memcpy(&descriptor, &ohci_rh_conf_descriptor, 348 sizeof (ohci_rh_conf_descriptor)); 212 349 uint8_t * hub_descriptor; 213 350 size_t hub_desc_size; 214 351 usb_create_serialized_hub_descriptor(instance, &hub_descriptor, 215 &hub_desc_size);352 &hub_desc_size); 216 353 217 354 descriptor.total_length = 218 sizeof(usb_standard_configuration_descriptor_t)+219 sizeof(usb_standard_endpoint_descriptor_t)+220 sizeof(usb_standard_interface_descriptor_t)+221 hub_desc_size;222 355 sizeof (usb_standard_configuration_descriptor_t) + 356 sizeof (usb_standard_endpoint_descriptor_t) + 357 sizeof (usb_standard_interface_descriptor_t) + 358 hub_desc_size; 359 223 360 uint8_t * full_config_descriptor = 224 (uint8_t*) malloc(descriptor.total_length);225 memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));226 memcpy(full_config_descriptor + sizeof (descriptor),227 &ohci_rh_iface_descriptor, sizeof(ohci_rh_iface_descriptor));228 memcpy(full_config_descriptor + sizeof (descriptor) +229 sizeof(ohci_rh_iface_descriptor),230 &ohci_rh_ep_descriptor, sizeof(ohci_rh_ep_descriptor));231 memcpy(full_config_descriptor + sizeof (descriptor) +232 sizeof(ohci_rh_iface_descriptor) +233 sizeof(ohci_rh_ep_descriptor),234 hub_descriptor, hub_desc_size);235 361 (uint8_t*) malloc(descriptor.total_length); 362 memcpy(full_config_descriptor, &descriptor, sizeof (descriptor)); 363 memcpy(full_config_descriptor + sizeof (descriptor), 364 &ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor)); 365 memcpy(full_config_descriptor + sizeof (descriptor) + 366 sizeof (ohci_rh_iface_descriptor), 367 &ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor)); 368 memcpy(full_config_descriptor + sizeof (descriptor) + 369 sizeof (ohci_rh_iface_descriptor) + 370 sizeof (ohci_rh_ep_descriptor), 371 hub_descriptor, hub_desc_size); 372 236 373 instance->descriptors.configuration = full_config_descriptor; 237 374 instance->descriptors.configuration_size = descriptor.total_length; 238 375 } 239 240 /** Root hub initialization241 * @return Error code.242 */243 int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs)244 {245 assert(instance);246 instance->address = -1;247 instance->registers = regs;248 instance->device = dev;249 instance->port_count = instance->registers->rh_desc_a & 0xff;250 rh_init_descriptors(instance);251 /// \TODO set port power mode252 253 254 usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);255 256 //start generic usb hub driver257 258 /* TODO: implement */259 return EOK;260 }261 376 /*----------------------------------------------------------------------------*/ 262 377 … … 272 387 */ 273 388 static int process_get_port_status_request(rh_t *instance, uint16_t port, 274 usb_transfer_batch_t * request){275 if (port<1 || port>instance->port_count)276 return EINVAL; 277 uint32_t * uint32_buffer = (uint32_t*) request->transport_buffer;389 usb_transfer_batch_t * request) { 390 if (port < 1 || port > instance->port_count) 391 return EINVAL; 392 uint32_t * uint32_buffer = (uint32_t*) request->data_buffer; 278 393 request->transfered_size = 4; 279 uint32_buffer[0] = instance->registers->rh_port_status[port -1]; 280 return EOK; 281 } 394 uint32_buffer[0] = instance->registers->rh_port_status[port - 1]; 395 #if 0 396 int i; 397 for (i = 0; i < instance->port_count; ++i) { 398 usb_log_debug("port status %d,x%x\n", 399 instance->registers->rh_port_status[i], 400 instance->registers->rh_port_status[i]); 401 } 402 #endif 403 return EOK; 404 } 405 /*----------------------------------------------------------------------------*/ 282 406 283 407 /** … … 291 415 */ 292 416 static int process_get_hub_status_request(rh_t *instance, 293 usb_transfer_batch_t * request){ 294 uint32_t * uint32_buffer = (uint32_t*)request->transport_buffer; 417 usb_transfer_batch_t * request) { 418 uint32_t * uint32_buffer = (uint32_t*) request->data_buffer; 419 request->transfered_size = 4; 295 420 //bits, 0,1,16,17 296 request->transfered_size = 4; 297 uint32_t mask = 1 & (1<<1) & (1<<16) & (1<<17); 421 uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17); 298 422 uint32_buffer[0] = mask & instance->registers->rh_status; 299 423 return EOK; 300 301 } 302 303 424 } 425 /*----------------------------------------------------------------------------*/ 304 426 305 427 /** … … 313 435 */ 314 436 static int process_get_status_request(rh_t *instance, 315 usb_transfer_batch_t * request) 316 { 437 usb_transfer_batch_t * request) { 317 438 size_t buffer_size = request->buffer_size; 318 439 usb_device_request_setup_packet_t * request_packet = 319 (usb_device_request_setup_packet_t*)320 request->setup_buffer;440 (usb_device_request_setup_packet_t*) 441 request->setup_buffer; 321 442 322 443 usb_hub_bm_request_type_t request_type = request_packet->request_type; 323 if (buffer_size<4/*request_packet->length*/){///\TODO444 if (buffer_size < 4/*request_packet->length*/) {///\TODO 324 445 usb_log_warning("requested more data than buffer size\n"); 325 446 return EINVAL; 326 447 } 327 448 328 if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)449 if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS) 329 450 return process_get_hub_status_request(instance, request); 330 if(request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS) 331 return process_get_port_status_request(instance, request_packet->index, 332 request); 451 if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS) 452 return process_get_port_status_request(instance, 453 request_packet->index, 454 request); 333 455 return ENOTSUP; 334 456 } 457 /*----------------------------------------------------------------------------*/ 335 458 336 459 /** … … 339 462 * Result contains bitmap where bit 0 indicates change on hub and 340 463 * bit i indicates change on i`th port (i>0). For more info see 341 * Hub and Port status bitmap specification in USB specification. 464 * Hub and Port status bitmap specification in USB specification 465 * (chapter 11.13.4) 342 466 * @param instance root hub instance 343 467 * @param@out buffer pointer to created interrupt mas … … 345 469 */ 346 470 static void create_interrupt_mask(rh_t *instance, void ** buffer, 347 size_t * buffer_size){471 size_t * buffer_size) { 348 472 int bit_count = instance->port_count + 1; 349 (*buffer_size) = (bit_count / 8) + (bit_count%8==0)?0:1; 473 (*buffer_size) = (bit_count / 8) + ((bit_count % 8 == 0) ? 0 : 1); 474 350 475 (*buffer) = malloc(*buffer_size); 351 uint8_t * bitmap = (uint8_t*)(*buffer); 352 uint32_t mask = (1<<16) + (1<<17); 353 bzero(bitmap,(*buffer_size)); 354 if(instance->registers->rh_status & mask){ 476 uint8_t * bitmap = (uint8_t*) (*buffer); 477 uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16)) 478 | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16)); 479 bzero(bitmap, (*buffer_size)); 480 if (instance->registers->rh_status & mask) { 355 481 bitmap[0] = 1; 356 482 } 357 483 int port; 358 mask = 0; 359 int i; 360 for(i=16;i<=20;++i) 361 mask += 1<<i; 362 for(port = 1; port<=instance->port_count;++port){ 363 if(mask & instance->registers->rh_port_status[port-1]){ 364 bitmap[(port+1)/8] += 1<<(port%8); 365 } 366 } 367 } 368 484 mask = port_status_change_mask; 485 for (port = 1; port <= instance->port_count; ++port) { 486 if (mask & instance->registers->rh_port_status[port - 1]) { 487 bitmap[(port) / 8] += 1 << (port % 8); 488 } 489 } 490 } 491 /*----------------------------------------------------------------------------*/ 492 369 493 /** 370 494 * create answer to a descriptor request … … 377 501 */ 378 502 static int process_get_descriptor_request(rh_t *instance, 379 usb_transfer_batch_t *request){503 usb_transfer_batch_t *request) { 380 504 usb_device_request_setup_packet_t * setup_request = 381 (usb_device_request_setup_packet_t*)request->setup_buffer;505 (usb_device_request_setup_packet_t*) request->setup_buffer; 382 506 size_t size; 383 507 const void * result_descriptor = NULL; 384 508 const uint16_t setup_request_value = setup_request->value_high; 385 //(setup_request->value_low << 8);509 //(setup_request->value_low << 8); 386 510 bool del = false; 387 switch (setup_request_value) 388 {389 case USB_DESCTYPE_HUB:{511 switch (setup_request_value) { 512 case USB_DESCTYPE_HUB: 513 { 390 514 uint8_t * descriptor; 391 515 usb_create_serialized_hub_descriptor( 392 516 instance, &descriptor, &size); 393 517 result_descriptor = descriptor; 394 if (result_descriptor) del = true;518 if (result_descriptor) del = true; 395 519 break; 396 520 } 397 case USB_DESCTYPE_DEVICE: { 521 case USB_DESCTYPE_DEVICE: 522 { 398 523 usb_log_debug("USB_DESCTYPE_DEVICE\n"); 399 524 result_descriptor = &ohci_rh_device_descriptor; 400 size = sizeof (ohci_rh_device_descriptor);525 size = sizeof (ohci_rh_device_descriptor); 401 526 break; 402 527 } 403 case USB_DESCTYPE_CONFIGURATION: { 528 case USB_DESCTYPE_CONFIGURATION: 529 { 404 530 usb_log_debug("USB_DESCTYPE_CONFIGURATION\n"); 405 531 result_descriptor = instance->descriptors.configuration; … … 407 533 break; 408 534 } 409 case USB_DESCTYPE_INTERFACE: { 535 case USB_DESCTYPE_INTERFACE: 536 { 410 537 usb_log_debug("USB_DESCTYPE_INTERFACE\n"); 411 538 result_descriptor = &ohci_rh_iface_descriptor; 412 size = sizeof (ohci_rh_iface_descriptor);539 size = sizeof (ohci_rh_iface_descriptor); 413 540 break; 414 541 } 415 case USB_DESCTYPE_ENDPOINT: { 542 case USB_DESCTYPE_ENDPOINT: 543 { 416 544 usb_log_debug("USB_DESCTYPE_ENDPOINT\n"); 417 545 result_descriptor = &ohci_rh_ep_descriptor; 418 size = sizeof (ohci_rh_ep_descriptor);546 size = sizeof (ohci_rh_ep_descriptor); 419 547 break; 420 548 } 421 default: { 422 usb_log_debug("USB_DESCTYPE_EINVAL %d \n",setup_request->value); 423 usb_log_debug("\ttype %d\n\trequest %d\n\tvalue %d\n\tindex %d\n\tlen %d\n ", 424 setup_request->request_type, 425 setup_request->request, 426 setup_request_value, 427 setup_request->index, 428 setup_request->length 429 ); 549 default: 550 { 551 usb_log_debug("USB_DESCTYPE_EINVAL %d \n", 552 setup_request->value); 553 usb_log_debug("\ttype %d\n\trequest %d\n\tvalue " 554 "%d\n\tindex %d\n\tlen %d\n ", 555 setup_request->request_type, 556 setup_request->request, 557 setup_request_value, 558 setup_request->index, 559 setup_request->length 560 ); 430 561 return EINVAL; 431 562 } 432 563 } 433 if (request->buffer_size < size){564 if (request->buffer_size < size) { 434 565 size = request->buffer_size; 435 566 } 436 567 request->transfered_size = size; 437 memcpy(request->transport_buffer,result_descriptor,size); 438 usb_log_debug("sent desctiptor: %s\n", 439 usb_debug_str_buffer((uint8_t*)request->transport_buffer,size,size)); 568 memcpy(request->data_buffer, result_descriptor, size); 440 569 if (del) 441 570 free(result_descriptor); 442 571 return EOK; 443 572 } 573 /*----------------------------------------------------------------------------*/ 444 574 445 575 /** … … 451 581 * @return error code 452 582 */ 453 static int process_get_configuration_request(rh_t *instance, 454 usb_transfer_batch_t *request){583 static int process_get_configuration_request(rh_t *instance, 584 usb_transfer_batch_t *request) { 455 585 //set and get configuration requests do not have any meaning, only dummy 456 586 //values are returned 457 if (request->buffer_size != 1)458 return EINVAL; 459 request-> transport_buffer[0] = 1;587 if (request->buffer_size != 1) 588 return EINVAL; 589 request->data_buffer[0] = 1; 460 590 request->transfered_size = 1; 461 591 return EOK; 462 592 } 593 /*----------------------------------------------------------------------------*/ 463 594 464 595 /** 465 596 * process feature-enabling request on hub 466 * 597 * 467 598 * @param instance root hub instance 468 599 * @param feature feature selector … … 470 601 */ 471 602 static int process_hub_feature_set_request(rh_t *instance, 472 uint16_t feature){ 473 if(! ((1<<feature) & hub_set_feature_valid_mask)) 474 return EINVAL; 603 uint16_t feature) { 604 if (!((1 << feature) & hub_set_feature_valid_mask)) 605 return EINVAL; 606 if(feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER) 607 feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16; 475 608 instance->registers->rh_status = 476 (instance->registers->rh_status | (1<<feature)) 477 & (~ hub_clear_feature_by_writing_one_mask); 478 return EOK; 479 } 609 (instance->registers->rh_status | (1 << feature)) 610 & (~hub_clear_feature_by_writing_one_mask); 611 return EOK; 612 } 613 /*----------------------------------------------------------------------------*/ 480 614 481 615 /** … … 487 621 */ 488 622 static int process_hub_feature_clear_request(rh_t *instance, 489 uint16_t feature){490 if (! ((1<<feature) & hub_clear_feature_valid_mask))623 uint16_t feature) { 624 if (!((1 << feature) & hub_clear_feature_valid_mask)) 491 625 return EINVAL; 492 626 //is the feature cleared directly? 493 if ((1 <<feature) & hub_set_feature_direct_mask){627 if ((1 << feature) & hub_set_feature_direct_mask) { 494 628 instance->registers->rh_status = 495 (instance->registers->rh_status & (~(1 <<feature)))496 & (~ hub_clear_feature_by_writing_one_mask);497 } else{//the feature is cleared by writing '1'629 (instance->registers->rh_status & (~(1 << feature))) 630 & (~hub_clear_feature_by_writing_one_mask); 631 } else {//the feature is cleared by writing '1' 498 632 instance->registers->rh_status = 499 (instance->registers->rh_status 500 & (~ hub_clear_feature_by_writing_one_mask)) 501 | (1<<feature); 502 } 503 return EOK; 504 } 505 506 633 (instance->registers->rh_status 634 & (~hub_clear_feature_by_writing_one_mask)) 635 | (1 << feature); 636 } 637 return EOK; 638 } 639 /*----------------------------------------------------------------------------*/ 507 640 508 641 /** 509 642 * process feature-enabling request on hub 510 * 643 * 511 644 * @param instance root hub instance 512 645 * @param feature feature selector … … 516 649 */ 517 650 static int process_port_feature_set_request(rh_t *instance, 518 uint16_t feature, uint16_t port){519 if (!((1<<feature) & port_set_feature_valid_mask))520 return EINVAL; 521 if (port<1 || port>instance->port_count)651 uint16_t feature, uint16_t port) { 652 if (!((1 << feature) & port_set_feature_valid_mask)) 653 return EINVAL; 654 if (port < 1 || port > instance->port_count) 522 655 return EINVAL; 523 656 instance->registers->rh_port_status[port - 1] = 524 (instance->registers->rh_port_status[port - 1] | (1<<feature))525 & (~port_clear_feature_valid_mask);657 (instance->registers->rh_port_status[port - 1] | (1 << feature)) 658 & (~port_clear_feature_valid_mask); 526 659 /// \TODO any error? 527 660 return EOK; 528 661 } 662 /*----------------------------------------------------------------------------*/ 529 663 530 664 /** … … 538 672 */ 539 673 static int process_port_feature_clear_request(rh_t *instance, 540 uint16_t feature, uint16_t port){541 if (!((1<<feature) & port_clear_feature_valid_mask))542 return EINVAL; 543 if (port<1 || port>instance->port_count)544 return EINVAL; 545 if (feature == USB_HUB_FEATURE_PORT_POWER)674 uint16_t feature, uint16_t port) { 675 if (!((1 << feature) & port_clear_feature_valid_mask)) 676 return EINVAL; 677 if (port < 1 || port > instance->port_count) 678 return EINVAL; 679 if (feature == USB_HUB_FEATURE_PORT_POWER) 546 680 feature = USB_HUB_FEATURE_PORT_LOW_SPEED; 547 if (feature == USB_HUB_FEATURE_PORT_SUSPEND)681 if (feature == USB_HUB_FEATURE_PORT_SUSPEND) 548 682 feature = USB_HUB_FEATURE_PORT_OVER_CURRENT; 549 683 instance->registers->rh_port_status[port - 1] = 550 (instance->registers->rh_port_status[port - 1]551 & (~port_clear_feature_valid_mask))552 | (1<<feature);684 (instance->registers->rh_port_status[port - 1] 685 & (~port_clear_feature_valid_mask)) 686 | (1 << feature); 553 687 /// \TODO any error? 554 688 return EOK; 555 689 } 556 690 /*----------------------------------------------------------------------------*/ 557 691 558 692 /** 559 693 * register address to this device 560 * 694 * 561 695 * @param instance root hub instance 562 696 * @param address new address … … 564 698 */ 565 699 static int process_address_set_request(rh_t *instance, 566 uint16_t address){700 uint16_t address) { 567 701 instance->address = address; 568 702 return EOK; 569 703 } 704 /*----------------------------------------------------------------------------*/ 570 705 571 706 /** … … 579 714 */ 580 715 static int process_request_with_output(rh_t *instance, 581 usb_transfer_batch_t *request){716 usb_transfer_batch_t *request) { 582 717 usb_device_request_setup_packet_t * setup_request = 583 (usb_device_request_setup_packet_t*)request->setup_buffer;584 if (setup_request->request == USB_DEVREQ_GET_STATUS){718 (usb_device_request_setup_packet_t*) request->setup_buffer; 719 if (setup_request->request == USB_DEVREQ_GET_STATUS) { 585 720 usb_log_debug("USB_DEVREQ_GET_STATUS\n"); 586 721 return process_get_status_request(instance, request); 587 722 } 588 if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR){723 if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) { 589 724 usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n"); 590 725 return process_get_descriptor_request(instance, request); 591 726 } 592 if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION){727 if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) { 593 728 usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n"); 594 729 return process_get_configuration_request(instance, request); … … 596 731 return ENOTSUP; 597 732 } 733 /*----------------------------------------------------------------------------*/ 598 734 599 735 /** … … 607 743 */ 608 744 static int process_request_with_input(rh_t *instance, 609 usb_transfer_batch_t *request){745 usb_transfer_batch_t *request) { 610 746 usb_device_request_setup_packet_t * setup_request = 611 (usb_device_request_setup_packet_t*)request->setup_buffer;747 (usb_device_request_setup_packet_t*) request->setup_buffer; 612 748 request->transfered_size = 0; 613 if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR){749 if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) { 614 750 return ENOTSUP; 615 751 } 616 if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION){752 if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) { 617 753 //set and get configuration requests do not have any meaning, 618 754 //only dummy values are returned … … 621 757 return ENOTSUP; 622 758 } 759 /*----------------------------------------------------------------------------*/ 623 760 624 761 /** … … 632 769 */ 633 770 static int process_request_without_data(rh_t *instance, 634 usb_transfer_batch_t *request){771 usb_transfer_batch_t *request) { 635 772 usb_device_request_setup_packet_t * setup_request = 636 (usb_device_request_setup_packet_t*)request->setup_buffer;773 (usb_device_request_setup_packet_t*) request->setup_buffer; 637 774 request->transfered_size = 0; 638 if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE){639 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){775 if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) { 776 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) { 640 777 usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n"); 641 778 return process_hub_feature_clear_request(instance, 642 setup_request->value);643 } 644 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){779 setup_request->value); 780 } 781 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) { 645 782 usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n"); 646 783 return process_port_feature_clear_request(instance, 647 setup_request->value,648 setup_request->index);784 setup_request->value, 785 setup_request->index); 649 786 } 650 787 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n", 651 setup_request->request_type);652 return EINVAL; 653 } 654 if (setup_request->request == USB_DEVREQ_SET_FEATURE){655 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){788 setup_request->request_type); 789 return EINVAL; 790 } 791 if (setup_request->request == USB_DEVREQ_SET_FEATURE) { 792 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) { 656 793 usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n"); 657 794 return process_hub_feature_set_request(instance, 658 setup_request->value);659 } 660 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){795 setup_request->value); 796 } 797 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) { 661 798 usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n"); 662 799 return process_port_feature_set_request(instance, 663 setup_request->value, 664 setup_request->index); 665 } 666 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",setup_request->request_type); 667 return EINVAL; 668 } 669 if(setup_request->request == USB_DEVREQ_SET_ADDRESS){ 800 setup_request->value, 801 setup_request->index); 802 } 803 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n", 804 setup_request->request_type); 805 return EINVAL; 806 } 807 if (setup_request->request == USB_DEVREQ_SET_ADDRESS) { 670 808 usb_log_debug("USB_DEVREQ_SET_ADDRESS\n"); 671 return process_address_set_request(instance, setup_request->value); 672 } 673 usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",setup_request->request_type); 809 return process_address_set_request(instance, 810 setup_request->value); 811 } 812 usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n", 813 setup_request->request_type); 674 814 return ENOTSUP; 675 815 } 816 /*----------------------------------------------------------------------------*/ 676 817 677 818 /** … … 693 834 * @return error code 694 835 */ 695 static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request){ 836 static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) { 837 if (!request->setup_buffer) { 838 usb_log_error("root hub received empty transaction?"); 839 return EINVAL; 840 } 696 841 int opResult; 697 if ( request->setup_buffer) {698 if(sizeof(usb_device_request_setup_packet_t)>request->setup_size){699 usb_log_error("setup packet too small\n");700 return EINVAL;701 }702 usb_ log_info("CTRL packet: %s.\n",703 usb_debug_str_buffer((const uint8_t *)request->setup_buffer, 8, 8));704 usb_device_request_setup_packet_t * setup_request =705 (usb_device_request_setup_packet_t*)request->setup_buffer;706 if(707 setup_request->request == USB_DEVREQ_GET_STATUS708 || setup_request->request == USB_DEVREQ_GET_DESCRIPTOR709 || setup_request->request == USB_DEVREQ_GET_CONFIGURATION710 ){842 if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) { 843 usb_log_error("setup packet too small\n"); 844 return EINVAL; 845 } 846 usb_log_info("CTRL packet: %s.\n", 847 usb_debug_str_buffer( 848 (const uint8_t *) request->setup_buffer, 8, 8)); 849 usb_device_request_setup_packet_t * setup_request = 850 (usb_device_request_setup_packet_t*) 851 request->setup_buffer; 852 switch (setup_request->request) { 853 case USB_DEVREQ_GET_STATUS: 854 case USB_DEVREQ_GET_DESCRIPTOR: 855 case USB_DEVREQ_GET_CONFIGURATION: 711 856 usb_log_debug("processing request with output\n"); 712 opResult = process_request_with_output(instance,request); 713 }else if( 714 setup_request->request == USB_DEVREQ_CLEAR_FEATURE 715 || setup_request->request == USB_DEVREQ_SET_FEATURE 716 || setup_request->request == USB_DEVREQ_SET_ADDRESS 717 ){ 718 usb_log_debug("processing request without additional data\n"); 719 opResult = process_request_without_data(instance,request); 720 }else if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR 721 || setup_request->request == USB_DEVREQ_SET_CONFIGURATION 722 ){ 723 usb_log_debug("processing request with input\n"); 724 opResult = process_request_with_input(instance,request); 725 }else{ 726 usb_log_warning("received unsuported request: %d\n", 727 setup_request->request 728 ); 857 opResult = process_request_with_output( 858 instance, request); 859 break; 860 case USB_DEVREQ_CLEAR_FEATURE: 861 case USB_DEVREQ_SET_FEATURE: 862 case USB_DEVREQ_SET_ADDRESS: 863 usb_log_debug("processing request without " 864 "additional data\n"); 865 opResult = process_request_without_data( 866 instance, request); 867 break; 868 case USB_DEVREQ_SET_DESCRIPTOR: 869 case USB_DEVREQ_SET_CONFIGURATION: 870 usb_log_debug("processing request with " 871 "input\n"); 872 opResult = process_request_with_input( 873 instance, request); 874 break; 875 default: 876 usb_log_warning("received unsuported request: " 877 "%d\n", 878 setup_request->request 879 ); 729 880 opResult = ENOTSUP; 730 }731 }else{732 usb_log_error("root hub received empty transaction?");733 opResult = EINVAL;734 881 } 735 882 return opResult; 736 883 } 737 738 /** 739 * process root hub request 740 * 741 * @param instance root hub instance 742 * @param request structure containing both request and response information 743 * @return error code 744 */ 745 int rh_request(rh_t *instance, usb_transfer_batch_t *request) 746 { 747 assert(instance); 748 assert(request); 749 int opResult; 750 if(request->transfer_type == USB_TRANSFER_CONTROL){ 751 usb_log_info("Root hub got CONTROL packet\n"); 752 opResult = process_ctrl_request(instance,request); 753 }else if(request->transfer_type == USB_TRANSFER_INTERRUPT){ 754 usb_log_info("Root hub got INTERRUPT packet\n"); 755 void * buffer; 756 create_interrupt_mask(instance, &buffer, 757 &(request->transfered_size)); 758 memcpy(request->transport_buffer,buffer, request->transfered_size); 759 opResult = EOK; 760 }else{ 761 opResult = EINVAL; 762 } 763 usb_transfer_batch_finish(request, opResult); 764 return EOK; 765 } 766 /*----------------------------------------------------------------------------*/ 767 768 769 void rh_interrupt(rh_t *instance) 770 { 771 usb_log_info("Whoa whoa wait, I`m not supposed to receive any interrupts, am I?\n"); 772 /* TODO: implement? */ 773 } 884 /*----------------------------------------------------------------------------*/ 885 886 /** 887 * process hanging interrupt request 888 * 889 * If an interrupt transfer has been received and there was no change, 890 * the driver stores the transfer information and waits for change to occcur. 891 * This routine is called when that happens and it finalizes the interrupt 892 * transfer. 893 * 894 * @param instance hub instance 895 * @param request batch request to be processed 896 * @param change_buffer chages on hub 897 * @param buffer_size size of change buffer 898 * 899 * @return 900 */ 901 static int process_interrupt(rh_t *instance, usb_transfer_batch_t * request, 902 void * change_buffer, size_t buffe_size){ 903 create_interrupt_mask(instance, &change_buffer, 904 &(request->transfered_size)); 905 memcpy(request->data_buffer, change_buffer,request->transfered_size); 906 instance->unfinished_interrupt_transfer = NULL; 907 usb_transfer_batch_finish_error(request, EOK); 908 return EOK; 909 } 910 911 /*----------------------------------------------------------------------------*/ 912 913 /** 914 * return whether the buffer is full of zeros 915 * 916 * Convenience function. 917 * @param buffer 918 * @param size 919 * @return 920 */ 921 static bool is_zeros(void * buffer, size_t size){ 922 if(!buffer) return true; 923 if(!size) return true; 924 size_t i; 925 for(i=0;i<size;++i){ 926 if(((char*)buffer)[i]) 927 return false; 928 } 929 return true; 930 } 931 774 932 /** 775 933 * @} -
uspace/drv/ohci/root_hub.h
ref354b6 re50cd7f 50 50 /** usb address of the root hub */ 51 51 usb_address_t address; 52 /** ddf device information */53 ddf_dev_t *device;54 52 /** hub port count */ 55 53 int port_count; 56 54 /** hubs descriptors */ 57 55 usb_device_descriptors_t descriptors; 56 /** interrupt transfer waiting for an actual interrupt to occur */ 57 usb_transfer_batch_t * unfinished_interrupt_transfer; 58 58 } rh_t; 59 59 60 int rh_init(rh_t *instance, ddf_dev_t *dev,ohci_regs_t *regs);60 int rh_init(rh_t *instance, ohci_regs_t *regs); 61 61 62 62 int rh_request(rh_t *instance, usb_transfer_batch_t *request); -
uspace/drv/ohci/utils/malloc32.h
ref354b6 re50cd7f 37 37 #include <assert.h> 38 38 #include <malloc.h> 39 #include <errno.h> 39 40 #include <mem.h> 40 41 #include <as.h> 41 42 42 #define UHCI_STRCUTURES_ALIGNMENT 1643 43 #define UHCI_REQUIRED_PAGE_SIZE 4096 44 44 … … 64 64 */ 65 65 static inline void * malloc32(size_t size) 66 { return memalign( UHCI_STRCUTURES_ALIGNMENT, size); }66 { return memalign(size, size); } 67 67 /*----------------------------------------------------------------------------*/ 68 68 /** Physical mallocator simulator -
uspace/drv/uhci-hcd/batch.c
ref354b6 re50cd7f 30 30 */ 31 31 /** @file 32 * @brief UHCI driver USB trans actionstructure32 * @brief UHCI driver USB transfer structure 33 33 */ 34 34 #include <errno.h> … … 45 45 #define DEFAULT_ERROR_COUNT 3 46 46 47 typedef struct uhci_ batch {47 typedef struct uhci_transfer_batch { 48 48 qh_t *qh; 49 49 td_t *tds; 50 size_t transfers; 51 } uhci_batch_t; 50 void *device_buffer; 51 size_t td_count; 52 } uhci_transfer_batch_t; 53 /*----------------------------------------------------------------------------*/ 54 static void uhci_transfer_batch_dispose(void *uhci_batch) 55 { 56 uhci_transfer_batch_t *instance = uhci_batch; 57 assert(instance); 58 free32(instance->device_buffer); 59 free(instance); 60 } 61 /*----------------------------------------------------------------------------*/ 52 62 53 63 static void batch_control(usb_transfer_batch_t *instance, 54 64 usb_packet_id data_stage, usb_packet_id status_stage); 55 65 static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid); 56 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);57 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);58 59 66 60 67 /** Allocate memory and initialize internal data structure. 61 68 * 62 69 * @param[in] fun DDF function to pass to callback. 63 * @param[in] target Device and endpoint target of the transaction. 64 * @param[in] transfer_type Interrupt, Control or Bulk. 65 * @param[in] max_packet_size maximum allowed size of data transfers. 66 * @param[in] speed Speed of the transaction. 70 * @param[in] ep Communication target 67 71 * @param[in] buffer Data source/destination. 68 72 * @param[in] size Size of the buffer. 69 73 * @param[in] setup_buffer Setup data source (if not NULL) 70 74 * @param[in] setup_size Size of setup_buffer (should be always 8) 71 * @param[in] func_in function to call on inbound trans actioncompletion72 * @param[in] func_out function to call on outbound trans actioncompletion75 * @param[in] func_in function to call on inbound transfer completion 76 * @param[in] func_out function to call on outbound transfer completion 73 77 * @param[in] arg additional parameter to func_in or func_out 74 * @param[in] ep Pointer to endpoint toggle management structure. 75 * @return Valid pointer if all substructures were successfully created, 78 * @return Valid pointer if all structures were successfully created, 76 79 * NULL otherwise. 77 80 * 78 * Determines the number of needed transfers (TDs). Prepares a transport buffer 79 * (that is accessible by the hardware). Initializes parameters needed for the 80 * transaction and callback. 81 */ 82 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, usb_target_t target, 83 usb_transfer_type_t transfer_type, size_t max_packet_size, 84 usb_speed_t speed, char *buffer, size_t buffer_size, 85 char* setup_buffer, size_t setup_size, 81 * Determines the number of needed transfer descriptors (TDs). 82 * Prepares a transport buffer (that is accessible by the hardware). 83 * Initializes parameters needed for the transfer and callback. 84 */ 85 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, 86 char *buffer, size_t buffer_size, char* setup_buffer, size_t setup_size, 86 87 usbhc_iface_transfer_in_callback_t func_in, 87 usbhc_iface_transfer_out_callback_t func_out, void *arg , endpoint_t *ep88 ) 89 { 88 usbhc_iface_transfer_out_callback_t func_out, void *arg) 89 { 90 assert(ep); 90 91 assert(func_in == NULL || func_out == NULL); 91 92 assert(func_in != NULL || func_out != NULL); … … 94 95 if (ptr == NULL) { \ 95 96 usb_log_error(message); \ 96 if ( instance) { \97 batch_dispose(instance); \97 if (uhci_data) { \ 98 uhci_transfer_batch_dispose(uhci_data); \ 98 99 } \ 99 100 return NULL; \ 100 101 } else (void)0 101 102 103 uhci_transfer_batch_t *uhci_data = 104 malloc(sizeof(uhci_transfer_batch_t)); 105 CHECK_NULL_DISPOSE_RETURN(uhci_data, 106 "Failed to allocate UHCI batch.\n"); 107 bzero(uhci_data, sizeof(uhci_transfer_batch_t)); 108 109 uhci_data->td_count = 110 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size; 111 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 112 uhci_data->td_count += 2; 113 } 114 115 assert((sizeof(td_t) % 16) == 0); 116 const size_t total_size = (sizeof(td_t) * uhci_data->td_count) 117 + sizeof(qh_t) + setup_size + buffer_size; 118 uhci_data->device_buffer = malloc32(total_size); 119 CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer, 120 "Failed to allocate UHCI buffer.\n"); 121 bzero(uhci_data->device_buffer, total_size); 122 123 uhci_data->tds = uhci_data->device_buffer; 124 uhci_data->qh = 125 (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)); 126 127 qh_init(uhci_data->qh); 128 qh_set_element_td(uhci_data->qh, uhci_data->tds); 129 102 130 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 103 131 CHECK_NULL_DISPOSE_RETURN(instance, 104 132 "Failed to allocate batch instance.\n"); 105 usb_transfer_batch_init(instance, target, 106 transfer_type, speed, max_packet_size, 107 buffer, NULL, buffer_size, NULL, setup_size, func_in, 108 func_out, arg, fun, ep, NULL); 109 110 111 uhci_batch_t *data = malloc(sizeof(uhci_batch_t)); 112 CHECK_NULL_DISPOSE_RETURN(instance, 113 "Failed to allocate batch instance.\n"); 114 bzero(data, sizeof(uhci_batch_t)); 115 instance->private_data = data; 116 117 data->transfers = (buffer_size + max_packet_size - 1) / max_packet_size; 118 if (transfer_type == USB_TRANSFER_CONTROL) { 119 data->transfers += 2; 120 } 121 122 data->tds = malloc32(sizeof(td_t) * data->transfers); 123 CHECK_NULL_DISPOSE_RETURN( 124 data->tds, "Failed to allocate transfer descriptors.\n"); 125 bzero(data->tds, sizeof(td_t) * data->transfers); 126 127 data->qh = malloc32(sizeof(qh_t)); 128 CHECK_NULL_DISPOSE_RETURN(data->qh, 129 "Failed to allocate batch queue head.\n"); 130 qh_init(data->qh); 131 qh_set_element_td(data->qh, addr_to_phys(data->tds)); 132 133 if (buffer_size > 0) { 134 instance->transport_buffer = malloc32(buffer_size); 135 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 136 "Failed to allocate device accessible buffer.\n"); 137 } 138 139 if (setup_size > 0) { 140 instance->setup_buffer = malloc32(setup_size); 141 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 142 "Failed to allocate device accessible setup buffer.\n"); 143 memcpy(instance->setup_buffer, setup_buffer, setup_size); 144 } 145 133 void *setup = 134 uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count) 135 + sizeof(qh_t); 136 void *data_buffer = setup + setup_size; 137 usb_target_t target = 138 { .address = ep->address, .endpoint = ep->endpoint }; 139 usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size, 140 setup, setup_size, func_in, func_out, arg, fun, 141 uhci_data, uhci_transfer_batch_dispose); 142 143 memcpy(instance->setup_buffer, setup_buffer, setup_size); 146 144 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 147 145 instance, target.address, target.endpoint); … … 155 153 * 156 154 * Walk all TDs. Stop with false if there is an active one (it is to be 157 * processed). Stop with true if an error is found. Return true if the last T S155 * processed). Stop with true if an error is found. Return true if the last TD 158 156 * is reached. 159 157 */ … … 161 159 { 162 160 assert(instance); 163 uhci_ batch_t *data = instance->private_data;161 uhci_transfer_batch_t *data = instance->private_data; 164 162 assert(data); 165 163 166 164 usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n", 167 instance, data->t ransfers);165 instance, data->td_count); 168 166 instance->transfered_size = 0; 169 167 size_t i = 0; 170 for (;i < data->t ransfers; ++i) {168 for (;i < data->td_count; ++i) { 171 169 if (td_is_active(&data->tds[i])) { 172 170 return false; … … 178 176 instance, i, data->tds[i].status); 179 177 td_print_status(&data->tds[i]); 180 if (instance->ep != NULL) 181 endpoint_toggle_set(instance->ep, 182 td_toggle(&data->tds[i])); 178 179 assert(instance->ep != NULL); 180 endpoint_toggle_set(instance->ep, 181 td_toggle(&data->tds[i])); 183 182 if (i > 0) 184 183 goto substract_ret; … … 195 194 } 196 195 /*----------------------------------------------------------------------------*/ 197 /** Prepares control write trans action.198 * 199 * @param[in] instance Batch structure to use. 200 * 201 * Uses gener circontrol function with pids OUT and IN.196 /** Prepares control write transfer. 197 * 198 * @param[in] instance Batch structure to use. 199 * 200 * Uses generic control function with pids OUT and IN. 202 201 */ 203 202 void batch_control_write(usb_transfer_batch_t *instance) … … 205 204 assert(instance); 206 205 /* We are data out, we are supposed to provide data */ 207 memcpy(instance->transport_buffer, instance->buffer, 208 instance->buffer_size); 206 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 209 207 batch_control(instance, USB_PID_OUT, USB_PID_IN); 210 instance->next_step = batch_call_out_and_dispose;208 instance->next_step = usb_transfer_batch_call_out_and_dispose; 211 209 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); 212 210 } 213 211 /*----------------------------------------------------------------------------*/ 214 /** Prepares control read trans action.212 /** Prepares control read transfer. 215 213 * 216 214 * @param[in] instance Batch structure to use. … … 222 220 assert(instance); 223 221 batch_control(instance, USB_PID_IN, USB_PID_OUT); 224 instance->next_step = batch_call_in_and_dispose;222 instance->next_step = usb_transfer_batch_call_in_and_dispose; 225 223 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); 226 224 } 227 225 /*----------------------------------------------------------------------------*/ 228 /** Prepare interrupt in trans action.229 * 230 * @param[in] instance Batch structure to use. 231 * 232 * Data trans actionwith PID_IN.226 /** Prepare interrupt in transfer. 227 * 228 * @param[in] instance Batch structure to use. 229 * 230 * Data transfer with PID_IN. 233 231 */ 234 232 void batch_interrupt_in(usb_transfer_batch_t *instance) 235 233 { 236 234 assert(instance); 237 instance->direction = USB_DIRECTION_IN;238 235 batch_data(instance, USB_PID_IN); 239 instance->next_step = batch_call_in_and_dispose;236 instance->next_step = usb_transfer_batch_call_in_and_dispose; 240 237 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 241 238 } 242 239 /*----------------------------------------------------------------------------*/ 243 /** Prepare interrupt out trans action.244 * 245 * @param[in] instance Batch structure to use. 246 * 247 * Data trans actionwith PID_OUT.240 /** Prepare interrupt out transfer. 241 * 242 * @param[in] instance Batch structure to use. 243 * 244 * Data transfer with PID_OUT. 248 245 */ 249 246 void batch_interrupt_out(usb_transfer_batch_t *instance) 250 247 { 251 248 assert(instance); 252 instance->direction = USB_DIRECTION_OUT;253 249 /* We are data out, we are supposed to provide data */ 254 memcpy(instance->transport_buffer, instance->buffer, 255 instance->buffer_size); 250 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 256 251 batch_data(instance, USB_PID_OUT); 257 instance->next_step = batch_call_out_and_dispose;252 instance->next_step = usb_transfer_batch_call_out_and_dispose; 258 253 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 259 254 } 260 255 /*----------------------------------------------------------------------------*/ 261 /** Prepare bulk in trans action.262 * 263 * @param[in] instance Batch structure to use. 264 * 265 * Data trans actionwith PID_IN.256 /** Prepare bulk in transfer. 257 * 258 * @param[in] instance Batch structure to use. 259 * 260 * Data transfer with PID_IN. 266 261 */ 267 262 void batch_bulk_in(usb_transfer_batch_t *instance) … … 269 264 assert(instance); 270 265 batch_data(instance, USB_PID_IN); 271 instance->direction = USB_DIRECTION_IN; 272 instance->next_step = batch_call_in_and_dispose; 266 instance->next_step = usb_transfer_batch_call_in_and_dispose; 273 267 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 274 268 } 275 269 /*----------------------------------------------------------------------------*/ 276 /** Prepare bulk out trans action.277 * 278 * @param[in] instance Batch structure to use. 279 * 280 * Data trans actionwith PID_OUT.270 /** Prepare bulk out transfer. 271 * 272 * @param[in] instance Batch structure to use. 273 * 274 * Data transfer with PID_OUT. 281 275 */ 282 276 void batch_bulk_out(usb_transfer_batch_t *instance) 283 277 { 284 278 assert(instance); 285 instance->direction = USB_DIRECTION_OUT;286 279 /* We are data out, we are supposed to provide data */ 287 memcpy(instance->transport_buffer, instance->buffer, 288 instance->buffer_size); 280 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 289 281 batch_data(instance, USB_PID_OUT); 290 instance->next_step = batch_call_out_and_dispose;282 instance->next_step = usb_transfer_batch_call_out_and_dispose; 291 283 usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance); 292 284 } 293 285 /*----------------------------------------------------------------------------*/ 294 /** Prepare generic data trans action295 * 296 * @param[in] instance Batch structure to use. 297 * @param[in] pid Pid to use for data trans fers.298 * 299 * Packets with alternating toggle bit and supplied pid value.286 /** Prepare generic data transfer 287 * 288 * @param[in] instance Batch structure to use. 289 * @param[in] pid Pid to use for data transactions. 290 * 291 * Transactions with alternating toggle bit and supplied pid value. 300 292 * The last transfer is marked with IOC flag. 301 293 */ … … 303 295 { 304 296 assert(instance); 305 uhci_ batch_t *data = instance->private_data;297 uhci_transfer_batch_t *data = instance->private_data; 306 298 assert(data); 307 299 308 const bool low_speed = instance-> speed == USB_SPEED_LOW;300 const bool low_speed = instance->ep->speed == USB_SPEED_LOW; 309 301 int toggle = endpoint_toggle_get(instance->ep); 310 302 assert(toggle == 0 || toggle == 1); 311 303 312 size_t t ransfer= 0;304 size_t td = 0; 313 305 size_t remain_size = instance->buffer_size; 306 char *buffer = instance->data_buffer; 314 307 while (remain_size > 0) { 315 char *trans_data =316 instance->transport_buffer + instance->buffer_size317 - remain_size;318 319 308 const size_t packet_size = 320 (instance->max_packet_size > remain_size) ? 321 remain_size : instance->max_packet_size; 322 323 td_t *next_transfer = (transfer + 1 < data->transfers) 324 ? &data->tds[transfer + 1] : NULL; 325 326 assert(transfer < data->transfers); 309 (instance->ep->max_packet_size > remain_size) ? 310 remain_size : instance->ep->max_packet_size; 311 312 td_t *next_td = (td + 1 < data->td_count) 313 ? &data->tds[td + 1] : NULL; 314 315 316 usb_target_t target = 317 { instance->ep->address, instance->ep->endpoint }; 318 319 assert(td < data->td_count); 320 td_init( 321 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size, 322 toggle, false, low_speed, target, pid, buffer, next_td); 323 324 ++td; 325 toggle = 1 - toggle; 326 buffer += packet_size; 327 327 assert(packet_size <= remain_size); 328 329 td_init(330 &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size,331 toggle, false, low_speed, instance->target, pid, trans_data,332 next_transfer);333 334 335 toggle = 1 - toggle;336 328 remain_size -= packet_size; 337 ++transfer;338 329 } 339 td_set_ioc(&data->tds[t ransfer- 1]);330 td_set_ioc(&data->tds[td - 1]); 340 331 endpoint_toggle_set(instance->ep, toggle); 341 332 } 342 333 /*----------------------------------------------------------------------------*/ 343 /** Prepare generic control trans action344 * 345 * @param[in] instance Batch structure to use. 346 * @param[in] data_stage Pid to use for data t ransfers.347 * @param[in] status_stage Pid to use for data t ransfers.334 /** Prepare generic control transfer 335 * 336 * @param[in] instance Batch structure to use. 337 * @param[in] data_stage Pid to use for data tds. 338 * @param[in] status_stage Pid to use for data tds. 348 339 * 349 340 * Setup stage with toggle 0 and USB_PID_SETUP. … … 356 347 { 357 348 assert(instance); 358 uhci_ batch_t *data = instance->private_data;349 uhci_transfer_batch_t *data = instance->private_data; 359 350 assert(data); 360 assert(data->transfers >= 2); 361 362 const bool low_speed = instance->speed == USB_SPEED_LOW; 363 int toggle = 0; 351 assert(data->td_count >= 2); 352 353 const bool low_speed = instance->ep->speed == USB_SPEED_LOW; 354 const usb_target_t target = 355 { instance->ep->address, instance->ep->endpoint }; 356 364 357 /* setup stage */ 365 358 td_init( 366 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, toggle, false,367 low_speed, instance->target, USB_PID_SETUP, instance->setup_buffer,359 data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false, 360 low_speed, target, USB_PID_SETUP, instance->setup_buffer, 368 361 &data->tds[1]); 369 362 370 363 /* data stage */ 371 size_t transfer = 1; 364 size_t td = 1; 365 unsigned toggle = 1; 372 366 size_t remain_size = instance->buffer_size; 367 char *buffer = instance->data_buffer; 373 368 while (remain_size > 0) { 374 char *control_data = 375 instance->transport_buffer + instance->buffer_size 376 - remain_size; 377 369 const size_t packet_size = 370 (instance->ep->max_packet_size > remain_size) ? 371 remain_size : instance->ep->max_packet_size; 372 373 td_init( 374 &data->tds[td], DEFAULT_ERROR_COUNT, packet_size, 375 toggle, false, low_speed, target, data_stage, 376 buffer, &data->tds[td + 1]); 377 378 ++td; 378 379 toggle = 1 - toggle; 379 380 const size_t packet_size = 381 (instance->max_packet_size > remain_size) ? 382 remain_size : instance->max_packet_size; 383 384 td_init( 385 &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size, 386 toggle, false, low_speed, instance->target, data_stage, 387 control_data, &data->tds[transfer + 1]); 388 389 ++transfer; 390 assert(transfer < data->transfers); 380 buffer += packet_size; 381 assert(td < data->td_count); 391 382 assert(packet_size <= remain_size); 392 383 remain_size -= packet_size; … … 394 385 395 386 /* status stage */ 396 assert(t ransfer == data->transfers- 1);387 assert(td == data->td_count - 1); 397 388 398 389 td_init( 399 &data->tds[t ransfer], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,400 instance->target, status_stage, NULL, NULL);401 td_set_ioc(&data->tds[t ransfer]);390 &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed, 391 target, status_stage, NULL, NULL); 392 td_set_ioc(&data->tds[td]); 402 393 403 394 usb_log_debug2("Control last TD status: %x.\n", 404 data->tds[transfer].status); 405 } 406 /*----------------------------------------------------------------------------*/ 395 data->tds[td].status); 396 } 397 /*----------------------------------------------------------------------------*/ 398 /** Provides access to QH data structure. 399 * @param[in] instance Batch pointer to use. 400 * @return Pointer to the QH used by the batch. 401 */ 407 402 qh_t * batch_qh(usb_transfer_batch_t *instance) 408 403 { 409 404 assert(instance); 410 uhci_ batch_t *data = instance->private_data;405 uhci_transfer_batch_t *data = instance->private_data; 411 406 assert(data); 412 407 return data->qh; 413 408 } 414 /*----------------------------------------------------------------------------*/415 /** Helper function calls callback and correctly disposes of batch structure.416 *417 * @param[in] instance Batch structure to use.418 */419 void batch_call_in_and_dispose(usb_transfer_batch_t *instance)420 {421 assert(instance);422 usb_transfer_batch_call_in(instance);423 batch_dispose(instance);424 }425 /*----------------------------------------------------------------------------*/426 /** Helper function calls callback and correctly disposes of batch structure.427 *428 * @param[in] instance Batch structure to use.429 */430 void batch_call_out_and_dispose(usb_transfer_batch_t *instance)431 {432 assert(instance);433 usb_transfer_batch_call_out(instance);434 batch_dispose(instance);435 }436 /*----------------------------------------------------------------------------*/437 /** Correctly dispose all used data structures.438 *439 * @param[in] instance Batch structure to use.440 */441 void batch_dispose(usb_transfer_batch_t *instance)442 {443 assert(instance);444 uhci_batch_t *data = instance->private_data;445 assert(data);446 usb_log_debug("Batch(%p) disposing.\n", instance);447 /* free32 is NULL safe */448 free32(data->tds);449 free32(data->qh);450 free32(instance->setup_buffer);451 free32(instance->transport_buffer);452 free(data);453 free(instance);454 }455 409 /** 456 410 * @} -
uspace/drv/uhci-hcd/batch.h
ref354b6 re50cd7f 30 30 */ 31 31 /** @file 32 * @brief UHCI driver USB tran saction structure32 * @brief UHCI driver USB tranfer helper functions 33 33 */ 34 34 #ifndef DRV_UHCI_BATCH_H … … 44 44 45 45 usb_transfer_batch_t * batch_get( 46 ddf_fun_t *fun, 47 usb_target_t target, 48 usb_transfer_type_t transfer_type, 49 size_t max_packet_size, 50 usb_speed_t speed, 51 char *buffer, 52 size_t size, 53 char *setup_buffer, 54 size_t setup_size, 46 ddf_fun_t *fun, endpoint_t *ep, char *buffer, size_t size, 47 char *setup_buffer, size_t setup_size, 55 48 usbhc_iface_transfer_in_callback_t func_in, 56 49 usbhc_iface_transfer_out_callback_t func_out, 57 void *arg, 58 endpoint_t *ep 59 ); 50 void *arg); 60 51 61 52 void batch_dispose(usb_transfer_batch_t *instance); -
uspace/drv/uhci-hcd/hc.c
ref354b6 re50cd7f 66 66 static int hc_interrupt_emulator(void *arg); 67 67 static int hc_debug_checker(void *arg); 68 #if 069 static bool usb_is_allowed(70 bool low_speed, usb_transfer_type_t transfer, size_t size);71 #endif72 68 /*----------------------------------------------------------------------------*/ 73 69 /** Initialize UHCI hcd driver structure … … 89 85 int ret; 90 86 91 #define CHECK_RET_ DEST_FUN_RETURN(ret, message...) \87 #define CHECK_RET_RETURN(ret, message...) \ 92 88 if (ret != EOK) { \ 93 89 usb_log_error(message); \ 94 if (instance->ddf_instance) \95 ddf_fun_destroy(instance->ddf_instance); \96 90 return ret; \ 97 91 } else (void) 0 … … 99 93 instance->hw_interrupts = interrupts; 100 94 instance->hw_failures = 0; 101 102 /* Setup UHCI function. */103 instance->ddf_instance = fun;104 95 105 96 /* allow access to hc control registers */ 106 97 regs_t *io; 107 98 ret = pio_enable(regs, reg_size, (void**)&io); 108 CHECK_RET_ DEST_FUN_RETURN(ret,99 CHECK_RET_RETURN(ret, 109 100 "Failed(%d) to gain access to registers at %p: %s.\n", 110 ret, str_error(ret), io);101 ret, io, str_error(ret)); 111 102 instance->registers = io; 112 103 usb_log_debug("Device registers at %p(%u) accessible.\n", … … 114 105 115 106 ret = hc_init_mem_structures(instance); 116 CHECK_RET_DEST_FUN_RETURN(ret, 117 "Failed to initialize UHCI memory structures.\n"); 107 CHECK_RET_RETURN(ret, 108 "Failed(%d) to initialize UHCI memory structures: %s.\n", 109 ret, str_error(ret)); 118 110 119 111 hc_init_hw(instance); 120 112 if (!interrupts) { 121 instance-> cleaner =113 instance->interrupt_emulator = 122 114 fibril_create(hc_interrupt_emulator, instance); 123 fibril_add_ready(instance->cleaner); 124 } else { 125 /* TODO: enable interrupts here */ 126 } 127 128 instance->debug_checker = 129 fibril_create(hc_debug_checker, instance); 130 // fibril_add_ready(instance->debug_checker); 115 fibril_add_ready(instance->interrupt_emulator); 116 } 117 (void)hc_debug_checker; 131 118 132 119 return EOK; … … 228 215 /* Set all frames to point to the first queue head */ 229 216 const uint32_t queue = 230 instance->transfers_interrupt.queue_head_pa231 | LINK_POINTER_QUEUE_HEAD_FLAG;217 LINK_POINTER_QH(addr_to_phys( 218 instance->transfers_interrupt.queue_head)); 232 219 233 220 unsigned i = 0; … … 236 223 } 237 224 238 /* Init device keeper */225 /* Init device keeper */ 239 226 usb_device_keeper_init(&instance->manager); 240 227 usb_log_debug("Initialized device manager.\n"); 241 228 242 ret = 243 usb_endpoint_manager_init(&instance->ep_manager, 244 BANDWIDTH_AVAILABLE_USB11); 229 ret = usb_endpoint_manager_init(&instance->ep_manager, 230 BANDWIDTH_AVAILABLE_USB11); 245 231 assert(ret == EOK); 246 232 … … 261 247 { 262 248 assert(instance); 263 #define CHECK_RET_CLEAR_RETURN(ret, message...) \ 249 #define SETUP_TRANSFER_LIST(type, name) \ 250 do { \ 251 int ret = transfer_list_init(&instance->transfers_##type, name); \ 264 252 if (ret != EOK) { \ 265 usb_log_error(message); \ 253 usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \ 254 ret, name, str_error(ret)); \ 266 255 transfer_list_fini(&instance->transfers_bulk_full); \ 267 256 transfer_list_fini(&instance->transfers_control_full); \ … … 269 258 transfer_list_fini(&instance->transfers_interrupt); \ 270 259 return ret; \ 271 } else (void) 0 272 273 /* initialize TODO: check errors */ 274 int ret; 275 ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL"); 276 CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list."); 277 278 ret = transfer_list_init( 279 &instance->transfers_control_full, "CONTROL_FULL"); 280 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list."); 281 282 ret = transfer_list_init( 283 &instance->transfers_control_slow, "CONTROL_SLOW"); 284 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list."); 285 286 ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT"); 287 CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list."); 288 260 } \ 261 } while (0) 262 263 SETUP_TRANSFER_LIST(bulk_full, "BULK FULL"); 264 SETUP_TRANSFER_LIST(control_full, "CONTROL FULL"); 265 SETUP_TRANSFER_LIST(control_slow, "CONTROL LOW"); 266 SETUP_TRANSFER_LIST(interrupt, "INTERRUPT"); 267 #undef SETUP_TRANSFER_LIST 268 /* Connect lists into one schedule */ 289 269 transfer_list_set_next(&instance->transfers_control_full, 290 270 &instance->transfers_bulk_full); … … 330 310 331 311 transfer_list_t *list = 332 instance->transfers[batch-> speed][batch->transfer_type];312 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 333 313 assert(list); 334 if (batch->transfer_type == USB_TRANSFER_CONTROL) {335 usb_device_keeper_use_control(336 &instance->manager, batch->target);337 }338 314 transfer_list_add_batch(list, batch); 339 315 … … 355 331 assert(instance); 356 332 // status |= 1; //Uncomment to work around qemu hang 357 /* TODO: Resume interrupts are not supported */358 333 /* Lower 2 bits are transaction error and transaction complete */ 359 if (status & 0x3) {334 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 360 335 LIST_INITIALIZE(done); 361 336 transfer_list_remove_finished( … … 373 348 usb_transfer_batch_t *batch = 374 349 list_get_instance(item, usb_transfer_batch_t, link); 375 switch (batch->transfer_type) 376 { 377 case USB_TRANSFER_CONTROL: 378 usb_device_keeper_release_control( 379 &instance->manager, batch->target); 380 break; 381 case USB_TRANSFER_INTERRUPT: 382 case USB_TRANSFER_ISOCHRONOUS: { 383 /* 384 int ret = bandwidth_free(&instance->bandwidth, 385 batch->target.address, 386 batch->target.endpoint, 387 batch->direction); 388 if (ret != EOK) 389 usb_log_warning("Failed(%d) to free " 390 "reserved bw: %s.\n", ret, 391 str_error(ret)); 392 */ 393 } 394 default: 395 break; 396 } 397 batch->next_step(batch); 398 } 399 } 400 /* bits 4 and 5 indicate hc error */ 401 if (status & 0x18) { 350 usb_transfer_batch_finish(batch); 351 } 352 } 353 /* Resume interrupts are not supported */ 354 355 /* Bits 4 and 5 indicate hc error */ 356 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 402 357 usb_log_error("UHCI hardware failure!.\n"); 403 358 ++instance->hw_failures; … … 429 384 430 385 while (1) { 431 /* read and ack interrupts*/386 /* Readd and clear status register */ 432 387 uint16_t status = pio_read_16(&instance->registers->usbsts); 433 pio_write_16(&instance->registers->usbsts, 0x1f);388 pio_write_16(&instance->registers->usbsts, status); 434 389 if (status != 0) 435 390 usb_log_debug2("UHCI status: %x.\n", status); 436 391 hc_interrupt(instance, status); 437 async_usleep(UHCI_ CLEANER_TIMEOUT);392 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); 438 393 } 439 394 return EOK; … … 506 461 #undef QH 507 462 } 508 /*----------------------------------------------------------------------------*/509 /** Check transfers for USB validity510 *511 * @param[in] low_speed Transfer speed.512 * @param[in] transfer Transer type513 * @param[in] size Size of data packets514 * @return True if transaction is allowed by USB specs, false otherwise515 */516 #if 0517 bool usb_is_allowed(518 bool low_speed, usb_transfer_type_t transfer, size_t size)519 {520 /* see USB specification chapter 5.5-5.8 for magic numbers used here */521 switch(transfer)522 {523 case USB_TRANSFER_ISOCHRONOUS:524 return (!low_speed && size < 1024);525 case USB_TRANSFER_INTERRUPT:526 return size <= (low_speed ? 8 : 64);527 case USB_TRANSFER_CONTROL: /* device specifies its own max size */528 return (size <= (low_speed ? 8 : 64));529 case USB_TRANSFER_BULK: /* device specifies its own max size */530 return (!low_speed && size <= 64);531 }532 return false;533 }534 #endif535 463 /** 536 464 * @} -
uspace/drv/uhci-hcd/hc.h
ref354b6 re50cd7f 48 48 #include "transfer_list.h" 49 49 50 /** UHCI I/O registers layout */ 50 51 typedef struct uhci_regs { 52 /** Command register, controls HC behaviour */ 51 53 uint16_t usbcmd; 52 54 #define UHCI_CMD_MAX_PACKET (1 << 7) … … 59 61 #define UHCI_CMD_RUN_STOP (1 << 0) 60 62 63 /** Status register, 1 means interrupt is asserted (if enabled) */ 61 64 uint16_t usbsts; 62 65 #define UHCI_STATUS_HALTED (1 << 5) … … 67 70 #define UHCI_STATUS_INTERRUPT (1 << 0) 68 71 72 /** Interrupt enabled registers */ 69 73 uint16_t usbintr; 70 74 #define UHCI_INTR_SHORT_PACKET (1 << 3) … … 73 77 #define UHCI_INTR_CRC (1 << 0) 74 78 79 /** Register stores frame number used in SOF packet */ 75 80 uint16_t frnum; 81 82 /** Pointer(physical) to the Frame List */ 76 83 uint32_t flbaseadd; 84 85 /** SOF modification to match external timers */ 77 86 uint8_t sofmod; 78 87 } regs_t; 79 88 80 89 #define UHCI_FRAME_LIST_COUNT 1024 81 #define UHCI_ CLEANER_TIMEOUT 1000090 #define UHCI_INT_EMULATOR_TIMEOUT 10000 82 91 #define UHCI_DEBUGER_TIMEOUT 5000000 83 92 #define UHCI_ALLOWED_HW_FAIL 5 84 93 94 /* Main HC driver structure */ 85 95 typedef struct hc { 96 /** USB bus driver, devices and addresses */ 86 97 usb_device_keeper_t manager; 98 /** USB bus driver, endpoints */ 87 99 usb_endpoint_manager_t ep_manager; 88 100 101 /** Addresses of I/O registers */ 89 102 regs_t *registers; 90 103 104 /** Frame List contains 1024 link pointers */ 91 105 link_pointer_t *frame_list; 92 106 107 /** List and queue of interrupt transfers */ 108 transfer_list_t transfers_interrupt; 109 /** List and queue of low speed control transfers */ 110 transfer_list_t transfers_control_slow; 111 /** List and queue of full speed bulk transfers */ 93 112 transfer_list_t transfers_bulk_full; 113 /** List and queue of full speed control transfers */ 94 114 transfer_list_t transfers_control_full; 95 transfer_list_t transfers_control_slow;96 transfer_list_t transfers_interrupt;97 115 116 /** Pointer table to the above lists, helps during scheduling */ 98 117 transfer_list_t *transfers[2][4]; 99 118 119 /** Code to be executed in kernel interrupt handler */ 100 120 irq_code_t interrupt_code; 101 121 102 fid_t cleaner; 103 fid_t debug_checker; 122 /** Fibril periodically checking status register*/ 123 fid_t interrupt_emulator; 124 125 /** Indicator of hw interrupts availability */ 104 126 bool hw_interrupts; 127 128 /** Number of hw failures detected. */ 105 129 unsigned hw_failures; 106 107 ddf_fun_t *ddf_instance;108 130 } hc_t; 109 131 -
uspace/drv/uhci-hcd/hw_struct/queue_head.h
ref354b6 re50cd7f 34 34 #ifndef DRV_UHCI_QH_H 35 35 #define DRV_UHCI_QH_H 36 37 /* libc */38 36 #include <assert.h> 39 37 40 38 #include "link_pointer.h" 39 #include "transfer_descriptor.h" 40 #include "utils/malloc32.h" 41 41 42 /** This structure is defined in UHCI design guide p. 31 */ 42 43 typedef struct queue_head { 44 /** Pointer to the next entity (another QH or TD */ 43 45 volatile link_pointer_t next; 46 /** Pointer to the contained entities (execution controlled by vertical flag*/ 44 47 volatile link_pointer_t element; 45 48 } __attribute__((packed)) qh_t; … … 64 67 * @param[in] pa Physical address of the next queue head. 65 68 * 66 * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal 67 * NULL. 69 * Adds proper flag. If the pointer is NULL, sets next to terminal NULL. 68 70 */ 69 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)71 static inline void qh_set_next_qh(qh_t *instance, qh_t *next) 70 72 { 71 /* Address is valid and not terminal */72 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {73 uint32_t pa = addr_to_phys(next); 74 if (pa) { 73 75 instance->next = LINK_POINTER_QH(pa); 74 76 } else { … … 80 82 * 81 83 * @param[in] instance qh_t structure to initialize. 82 * @param[in] pa Physical address of the next queue head.83 *84 * Adds proper flag. If the pointer is NULL or terminal, sets element85 * to terminal NULL.86 */87 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)88 {89 /* Address is valid and not terminal */90 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {91 instance->element = LINK_POINTER_QH(pa);92 } else {93 instance->element = LINK_POINTER_TERM;94 }95 }96 /*----------------------------------------------------------------------------*/97 /** Set queue head element pointer98 *99 * @param[in] instance qh_t structure to initialize.100 84 * @param[in] pa Physical address of the TD structure. 101 85 * 102 * Adds proper flag. If the pointer is NULL or terminal, sets element 103 * to terminal NULL. 86 * Adds proper flag. If the pointer is NULL, sets element to terminal NULL. 104 87 */ 105 static inline void qh_set_element_td(qh_t *instance, uint32_t pa)88 static inline void qh_set_element_td(qh_t *instance, td_t *td) 106 89 { 107 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 90 uint32_t pa = addr_to_phys(td); 91 if (pa) { 108 92 instance->element = LINK_POINTER_TD(pa); 109 93 } else { … … 111 95 } 112 96 } 113 114 97 #endif 115 98 /** -
uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.c
ref354b6 re50cd7f 77 77 78 78 instance->status = 0 79 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS) 79 | ((err_count & TD_STATUS_ERROR_COUNT_MASK) 80 << TD_STATUS_ERROR_COUNT_POS) 80 81 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0) 81 82 | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0) … … 89 90 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS) 90 91 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0) 91 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS) 92 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS) 92 | ((target.address & TD_DEVICE_ADDRESS_MASK) 93 << TD_DEVICE_ADDRESS_POS) 94 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) 95 << TD_DEVICE_ENDPOINT_POS) 93 96 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS); 94 97 … … 114 117 assert(instance); 115 118 116 /* this is hc internal error it should never be reported*/119 /* This is hc internal error it should never be reported. */ 117 120 if ((instance->status & TD_STATUS_ERROR_BIT_STUFF) != 0) 118 121 return EAGAIN; … … 123 126 return EBADCHECKSUM; 124 127 125 /* hc does not end transactionon these, it should never be reported */128 /* HC does not end transactions on these, it should never be reported */ 126 129 if ((instance->status & TD_STATUS_ERROR_NAK) != 0) 127 130 return EAGAIN; 128 131 129 /* buffer overrun or underrun */132 /* Buffer overrun or underrun */ 130 133 if ((instance->status & TD_STATUS_ERROR_BUFFER) != 0) 131 134 return ERANGE; 132 135 133 /* device babble is something serious */136 /* Device babble is something serious */ 134 137 if ((instance->status & TD_STATUS_ERROR_BABBLE) != 0) 135 138 return EIO; 136 139 137 /* stall might represent err count reaching zero or stall response from138 * the device , iserr count reached zero, one of the above is reported*/140 /* Stall might represent err count reaching zero or stall response from 141 * the device. If err count reached zero, one of the above is reported*/ 139 142 if ((instance->status & TD_STATUS_ERROR_STALLED) != 0) 140 143 return ESTALL; -
uspace/drv/uhci-hcd/hw_struct/transfer_descriptor.h
ref354b6 re50cd7f 40 40 #include "link_pointer.h" 41 41 42 /** UHCI Transfer Descriptor*/42 /** Transfer Descriptor, defined in UHCI design guide p. 26 */ 43 43 typedef struct transfer_descriptor { 44 /** Pointer to the next entity (TD or QH) */ 44 45 link_pointer_t next; 45 46 47 /** Status doubleword */ 46 48 volatile uint32_t status; 47 49 #define TD_STATUS_RESERVED_MASK 0xc000f800 48 #define TD_STATUS_SPD_FLAG ( 1 << 29)49 #define TD_STATUS_ERROR_COUNT_POS ( 27 )50 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )51 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26)52 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25)53 #define TD_STATUS_IOC_FLAG ( 1 << 24)50 #define TD_STATUS_SPD_FLAG (1 << 29) 51 #define TD_STATUS_ERROR_COUNT_POS 27 52 #define TD_STATUS_ERROR_COUNT_MASK 0x3 53 #define TD_STATUS_LOW_SPEED_FLAG (1 << 26) 54 #define TD_STATUS_ISOCHRONOUS_FLAG (1 << 25) 55 #define TD_STATUS_IOC_FLAG (1 << 24) 54 56 55 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23)56 #define TD_STATUS_ERROR_STALLED ( 1 << 22)57 #define TD_STATUS_ERROR_BUFFER ( 1 << 21)58 #define TD_STATUS_ERROR_BABBLE ( 1 << 20)59 #define TD_STATUS_ERROR_NAK ( 1 << 19)60 #define TD_STATUS_ERROR_CRC ( 1 << 18)61 #define TD_STATUS_ERROR_BIT_STUFF ( 1 << 17)62 #define TD_STATUS_ERROR_RESERVED ( 1 << 16)57 #define TD_STATUS_ERROR_ACTIVE (1 << 23) 58 #define TD_STATUS_ERROR_STALLED (1 << 22) 59 #define TD_STATUS_ERROR_BUFFER (1 << 21) 60 #define TD_STATUS_ERROR_BABBLE (1 << 20) 61 #define TD_STATUS_ERROR_NAK (1 << 19) 62 #define TD_STATUS_ERROR_CRC (1 << 18) 63 #define TD_STATUS_ERROR_BIT_STUFF (1 << 17) 64 #define TD_STATUS_ERROR_RESERVED (1 << 16) 63 65 #define TD_STATUS_ERROR_POS 16 64 #define TD_STATUS_ERROR_MASK ( 0xff )66 #define TD_STATUS_ERROR_MASK 0xff 65 67 66 68 #define TD_STATUS_ACTLEN_POS 0 67 69 #define TD_STATUS_ACTLEN_MASK 0x7ff 68 70 71 /* double word with USB device specific info */ 69 72 volatile uint32_t device; 70 73 #define TD_DEVICE_MAXLEN_POS 21 71 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff )72 #define TD_DEVICE_RESERVED_FLAG ( 1 << 20)73 #define TD_DEVICE_DATA_TOGGLE_ONE_FLAG ( 1 << 19)74 #define TD_DEVICE_MAXLEN_MASK 0x7ff 75 #define TD_DEVICE_RESERVED_FLAG (1 << 20) 76 #define TD_DEVICE_DATA_TOGGLE_ONE_FLAG (1 << 19) 74 77 #define TD_DEVICE_ENDPOINT_POS 15 75 #define TD_DEVICE_ENDPOINT_MASK ( 0xf )78 #define TD_DEVICE_ENDPOINT_MASK 0xf 76 79 #define TD_DEVICE_ADDRESS_POS 8 77 #define TD_DEVICE_ADDRESS_MASK ( 0x7f )80 #define TD_DEVICE_ADDRESS_MASK 0x7f 78 81 #define TD_DEVICE_PID_POS 0 79 #define TD_DEVICE_PID_MASK ( 0xff )82 #define TD_DEVICE_PID_MASK 0xff 80 83 84 /** Pointer(physical) to the beginning of the transaction's buffer */ 81 85 volatile uint32_t buffer_ptr; 82 86 83 /* there is 16 bytes of data available here, according to UHCI 84 * Design guide, according to linux kernel the hardware does not care, 85 * it just needs to be aligned, we don't use it anyway 87 /* According to UHCI design guide, there is 16 bytes of 88 * data available here. 89 * According to linux kernel the hardware does not care, 90 * it just needs to be aligned. We don't use it anyway. 86 91 */ 87 92 } __attribute__((packed)) td_t; -
uspace/drv/uhci-hcd/iface.c
ref354b6 re50cd7f 41 41 #include "hc.h" 42 42 43 /** Reserve default address interface function 44 * 45 * @param[in] fun DDF function that was called. 46 * @param[in] speed Speed to associate with the new default address. 47 * @return Error code. 48 */ 49 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed) 50 { 43 static inline int setup_batch( 44 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction, 45 void *data, size_t size, void * setup_data, size_t setup_size, 46 usbhc_iface_transfer_in_callback_t in, 47 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name, 48 hc_t **hc, usb_transfer_batch_t **batch) 49 { 50 assert(hc); 51 assert(batch); 51 52 assert(fun); 52 hc_t *hc = fun_to_hc(fun); 53 assert(hc); 54 usb_log_debug("Default address request with speed %d.\n", speed); 55 usb_device_keeper_reserve_default_address(&hc->manager, speed); 56 return EOK; 57 #if 0 58 endpoint_t *ep = malloc(sizeof(endpoint_t)); 59 if (ep == NULL) 53 *hc = fun_to_hc(fun); 54 assert(*hc); 55 56 size_t res_bw; 57 endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager, 58 target.address, target.endpoint, direction, &res_bw); 59 if (ep == NULL) { 60 usb_log_error("Endpoint(%d:%d) not registered for %s.\n", 61 target.address, target.endpoint, name); 62 return ENOENT; 63 } 64 65 usb_log_debug("%s %d:%d %zu(%zu).\n", 66 name, target.address, target.endpoint, size, ep->max_packet_size); 67 68 const size_t bw = bandwidth_count_usb11( 69 ep->speed, ep->transfer_type, size, ep->max_packet_size); 70 if (res_bw < bw) { 71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 72 "but only %zu is reserved.\n", 73 target.address, target.endpoint, name, bw, res_bw); 74 return ENOSPC; 75 } 76 77 *batch = batch_get( 78 fun, ep, data, size, setup_data, setup_size, in, out, arg); 79 if (!*batch) 60 80 return ENOMEM; 61 const size_t max_packet_size = speed == USB_SPEED_LOW ? 8 : 64;62 endpoint_init(ep, USB_TRANSFER_CONTROL, speed, max_packet_size);63 int ret;64 try_retgister:65 ret = usb_endpoint_manager_register_ep(&hc->ep_manager,66 USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH, ep, endpoint_destroy, 0);67 if (ret == EEXISTS) {68 async_usleep(1000);69 goto try_retgister;70 }71 if (ret != EOK) {72 endpoint_destroy(ep);73 }74 return ret;75 #endif76 }77 /*----------------------------------------------------------------------------*/78 /** Release default address interface function79 *80 * @param[in] fun DDF function that was called.81 * @return Error code.82 */83 static int release_default_address(ddf_fun_t *fun)84 {85 assert(fun);86 hc_t *hc = fun_to_hc(fun);87 assert(hc);88 usb_log_debug("Default address release.\n");89 // return usb_endpoint_manager_unregister_ep(&hc->ep_manager,90 // USB_ADDRESS_DEFAULT, 0, USB_DIRECTION_BOTH);91 usb_device_keeper_release_default_address(&hc->manager);92 81 return EOK; 93 82 } … … 151 140 /*----------------------------------------------------------------------------*/ 152 141 static int register_endpoint( 153 ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint, 142 ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed, 143 usb_endpoint_t endpoint, 154 144 usb_transfer_type_t transfer_type, usb_direction_t direction, 155 145 size_t max_packet_size, unsigned int interval) … … 157 147 hc_t *hc = fun_to_hc(fun); 158 148 assert(hc); 159 const usb_speed_t speed = 160 usb_device_keeper_get_speed(&hc->manager, address); 161 const size_t size = 162 (transfer_type == USB_TRANSFER_INTERRUPT 163 || transfer_type == USB_TRANSFER_ISOCHRONOUS) ? 164 max_packet_size : 0; 165 int ret; 166 167 endpoint_t *ep = malloc(sizeof(endpoint_t)); 168 if (ep == NULL) 169 return ENOMEM; 170 ret = endpoint_init(ep, address, endpoint, direction, 171 transfer_type, speed, max_packet_size); 172 if (ret != EOK) { 173 free(ep); 174 return ret; 175 } 176 149 const size_t size = max_packet_size; 150 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address); 151 if (speed >= USB_SPEED_MAX) { 152 speed = ep_speed; 153 } 177 154 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n", 178 155 address, endpoint, usb_str_transfer_type(transfer_type), 179 156 usb_str_speed(speed), direction, size, max_packet_size, interval); 180 157 181 ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size); 182 if (ret != EOK) { 183 endpoint_destroy(ep); 184 } else { 185 usb_device_keeper_add_ep(&hc->manager, address, ep); 186 } 187 return ret; 158 return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint, 159 direction, transfer_type, speed, max_packet_size, size); 188 160 } 189 161 /*----------------------------------------------------------------------------*/ … … 204 176 * @param[in] fun DDF function that was called. 205 177 * @param[in] target USB device to write to. 206 * @param[in] max_packet_size maximum size of data packet the device accepts207 178 * @param[in] data Source of data. 208 179 * @param[in] size Size of data source. … … 212 183 */ 213 184 static int interrupt_out( 214 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,185 ddf_fun_t *fun, usb_target_t target, void *data, 215 186 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg) 216 187 { 217 assert(fun); 218 hc_t *hc = fun_to_hc(fun); 219 assert(hc); 220 221 usb_log_debug("Interrupt OUT %d:%d %zu(%zu).\n", 222 target.address, target.endpoint, size, max_packet_size); 223 224 size_t res_bw; 225 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 226 target.address, target.endpoint, USB_DIRECTION_OUT, &res_bw); 227 if (ep == NULL) { 228 usb_log_error("Endpoint(%d:%d) not registered for INT OUT.\n", 229 target.address, target.endpoint); 230 return ENOENT; 231 } 232 const size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type, 233 size, ep->max_packet_size); 234 if (res_bw < bw) 235 { 236 usb_log_error("Endpoint(%d:%d) INT IN needs %zu bw " 237 "but only %zu is reserved.\n", 238 target.address, target.endpoint, bw, res_bw); 239 return ENOENT; 240 } 241 assert(ep->speed == 242 usb_device_keeper_get_speed(&hc->manager, target.address)); 243 assert(ep->max_packet_size == max_packet_size); 244 assert(ep->transfer_type == USB_TRANSFER_INTERRUPT); 245 246 usb_transfer_batch_t *batch = 247 batch_get(fun, target, ep->transfer_type, ep->max_packet_size, 248 ep->speed, data, size, NULL, 0, NULL, callback, arg, ep); 249 if (!batch) 250 return ENOMEM; 188 usb_transfer_batch_t *batch = NULL; 189 hc_t *hc = NULL; 190 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size, 191 NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch); 192 if (ret != EOK) 193 return ret; 251 194 batch_interrupt_out(batch); 252 const intret = hc_schedule(hc, batch);253 if (ret != EOK) { 254 batch_dispose(batch);195 ret = hc_schedule(hc, batch); 196 if (ret != EOK) { 197 usb_transfer_batch_dispose(batch); 255 198 } 256 199 return ret; … … 261 204 * @param[in] fun DDF function that was called. 262 205 * @param[in] target USB device to write to. 263 * @param[in] max_packet_size maximum size of data packet the device accepts264 206 * @param[out] data Data destination. 265 207 * @param[in] size Size of data source. … … 269 211 */ 270 212 static int interrupt_in( 271 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,213 ddf_fun_t *fun, usb_target_t target, void *data, 272 214 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg) 273 215 { 274 assert(fun); 275 hc_t *hc = fun_to_hc(fun); 276 assert(hc); 277 278 usb_log_debug("Interrupt IN %d:%d %zu(%zu).\n", 279 target.address, target.endpoint, size, max_packet_size); 280 281 size_t res_bw; 282 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 283 target.address, target.endpoint, USB_DIRECTION_IN, &res_bw); 284 if (ep == NULL) { 285 usb_log_error("Endpoint(%d:%d) not registered for INT IN.\n", 286 target.address, target.endpoint); 287 return ENOENT; 288 } 289 const size_t bw = bandwidth_count_usb11(ep->speed, ep->transfer_type, 290 size, ep->max_packet_size); 291 if (res_bw < bw) 292 { 293 usb_log_error("Endpoint(%d:%d) INT IN needs %zu bw " 294 "but only %zu bw is reserved.\n", 295 target.address, target.endpoint, bw, res_bw); 296 return ENOENT; 297 } 298 299 assert(ep->speed == 300 usb_device_keeper_get_speed(&hc->manager, target.address)); 301 assert(ep->max_packet_size == max_packet_size); 302 assert(ep->transfer_type == USB_TRANSFER_INTERRUPT); 303 304 usb_transfer_batch_t *batch = 305 batch_get(fun, target, ep->transfer_type, ep->max_packet_size, 306 ep->speed, data, size, NULL, 0, callback, NULL, arg, ep); 307 if (!batch) 308 return ENOMEM; 216 usb_transfer_batch_t *batch = NULL; 217 hc_t *hc = NULL; 218 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size, 219 NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch); 220 if (ret != EOK) 221 return ret; 309 222 batch_interrupt_in(batch); 310 const intret = hc_schedule(hc, batch);311 if (ret != EOK) { 312 batch_dispose(batch);223 ret = hc_schedule(hc, batch); 224 if (ret != EOK) { 225 usb_transfer_batch_dispose(batch); 313 226 } 314 227 return ret; … … 319 232 * @param[in] fun DDF function that was called. 320 233 * @param[in] target USB device to write to. 321 * @param[in] max_packet_size maximum size of data packet the device accepts322 234 * @param[in] data Source of data. 323 235 * @param[in] size Size of data source. … … 327 239 */ 328 240 static int bulk_out( 329 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,241 ddf_fun_t *fun, usb_target_t target, void *data, 330 242 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg) 331 243 { 332 assert(fun); 333 hc_t *hc = fun_to_hc(fun); 334 assert(hc); 335 336 usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n", 337 target.address, target.endpoint, size, max_packet_size); 338 339 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 340 target.address, target.endpoint, USB_DIRECTION_OUT, NULL); 341 if (ep == NULL) { 342 usb_log_error("Endpoint(%d:%d) not registered for BULK OUT.\n", 343 target.address, target.endpoint); 344 return ENOENT; 345 } 346 assert(ep->speed == 347 usb_device_keeper_get_speed(&hc->manager, target.address)); 348 assert(ep->max_packet_size == max_packet_size); 349 assert(ep->transfer_type == USB_TRANSFER_BULK); 350 351 usb_transfer_batch_t *batch = 352 batch_get(fun, target, ep->transfer_type, ep->max_packet_size, 353 ep->speed, data, size, NULL, 0, NULL, callback, arg, ep); 354 if (!batch) 355 return ENOMEM; 244 usb_transfer_batch_t *batch = NULL; 245 hc_t *hc = NULL; 246 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size, 247 NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch); 248 if (ret != EOK) 249 return ret; 356 250 batch_bulk_out(batch); 357 const intret = hc_schedule(hc, batch);358 if (ret != EOK) { 359 batch_dispose(batch);251 ret = hc_schedule(hc, batch); 252 if (ret != EOK) { 253 usb_transfer_batch_dispose(batch); 360 254 } 361 255 return ret; … … 366 260 * @param[in] fun DDF function that was called. 367 261 * @param[in] target USB device to write to. 368 * @param[in] max_packet_size maximum size of data packet the device accepts369 262 * @param[out] data Data destination. 370 263 * @param[in] size Size of data source. … … 374 267 */ 375 268 static int bulk_in( 376 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,void *data,269 ddf_fun_t *fun, usb_target_t target, void *data, 377 270 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg) 378 271 { 379 assert(fun); 380 hc_t *hc = fun_to_hc(fun); 381 assert(hc); 382 usb_log_debug("Bulk IN %d:%d %zu(%zu).\n", 383 target.address, target.endpoint, size, max_packet_size); 384 385 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 386 target.address, target.endpoint, USB_DIRECTION_IN, NULL); 387 if (ep == NULL) { 388 usb_log_error("Endpoint(%d:%d) not registered for BULK IN.\n", 389 target.address, target.endpoint); 390 return ENOENT; 391 } 392 assert(ep->speed == 393 usb_device_keeper_get_speed(&hc->manager, target.address)); 394 assert(ep->max_packet_size == max_packet_size); 395 assert(ep->transfer_type == USB_TRANSFER_BULK); 396 397 usb_transfer_batch_t *batch = 398 batch_get(fun, target, ep->transfer_type, ep->max_packet_size, 399 ep->speed, data, size, NULL, 0, callback, NULL, arg, ep); 400 if (!batch) 401 return ENOMEM; 272 usb_transfer_batch_t *batch = NULL; 273 hc_t *hc = NULL; 274 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size, 275 NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch); 276 if (ret != EOK) 277 return ret; 402 278 batch_bulk_in(batch); 403 const intret = hc_schedule(hc, batch);404 if (ret != EOK) { 405 batch_dispose(batch);279 ret = hc_schedule(hc, batch); 280 if (ret != EOK) { 281 usb_transfer_batch_dispose(batch); 406 282 } 407 283 return ret; … … 412 288 * @param[in] fun DDF function that was called. 413 289 * @param[in] target USB device to write to. 414 * @param[in] max_packet_size maximum size of data packet the device accepts.415 290 * @param[in] setup_data Data to send with SETUP transfer. 416 291 * @param[in] setup_size Size of data to send with SETUP transfer (always 8B). … … 422 297 */ 423 298 static int control_write( 424 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,299 ddf_fun_t *fun, usb_target_t target, 425 300 void *setup_data, size_t setup_size, void *data, size_t size, 426 301 usbhc_iface_transfer_out_callback_t callback, void *arg) 427 302 { 428 assert(fun); 429 hc_t *hc = fun_to_hc(fun); 430 assert(hc); 431 usb_speed_t speed = 432 usb_device_keeper_get_speed(&hc->manager, target.address); 433 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n", 434 speed, target.address, target.endpoint, size, max_packet_size); 435 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 436 target.address, target.endpoint, USB_DIRECTION_BOTH, NULL); 437 if (ep == NULL) { 438 usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n", 439 target.address, target.endpoint); 440 } 441 442 if (setup_size != 8) 443 return EINVAL; 444 445 usb_transfer_batch_t *batch = 446 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size, speed, 447 data, size, setup_data, setup_size, NULL, callback, arg, ep); 448 if (!batch) 449 return ENOMEM; 450 usb_device_keeper_reset_if_need(&hc->manager, target, setup_data); 303 usb_transfer_batch_t *batch = NULL; 304 hc_t *hc = NULL; 305 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size, 306 setup_data, setup_size, NULL, callback, arg, "Control WRITE", 307 &hc, &batch); 308 if (ret != EOK) 309 return ret; 310 usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data); 451 311 batch_control_write(batch); 452 const intret = hc_schedule(hc, batch);453 if (ret != EOK) { 454 batch_dispose(batch);312 ret = hc_schedule(hc, batch); 313 if (ret != EOK) { 314 usb_transfer_batch_dispose(batch); 455 315 } 456 316 return ret; … … 461 321 * @param[in] fun DDF function that was called. 462 322 * @param[in] target USB device to write to. 463 * @param[in] max_packet_size maximum size of data packet the device accepts.464 323 * @param[in] setup_data Data to send with SETUP packet. 465 324 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B). … … 471 330 */ 472 331 static int control_read( 473 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,332 ddf_fun_t *fun, usb_target_t target, 474 333 void *setup_data, size_t setup_size, void *data, size_t size, 475 334 usbhc_iface_transfer_in_callback_t callback, void *arg) 476 335 { 477 assert(fun); 478 hc_t *hc = fun_to_hc(fun); 479 assert(hc); 480 usb_speed_t speed = 481 usb_device_keeper_get_speed(&hc->manager, target.address); 482 483 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n", 484 speed, target.address, target.endpoint, size, max_packet_size); 485 endpoint_t *ep = usb_endpoint_manager_get_ep(&hc->ep_manager, 486 target.address, target.endpoint, USB_DIRECTION_BOTH, NULL); 487 if (ep == NULL) { 488 usb_log_warning("Endpoint(%d:%d) not registered for CONTROL.\n", 489 target.address, target.endpoint); 490 } 491 usb_transfer_batch_t *batch = 492 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size, speed, 493 data, size, setup_data, setup_size, callback, NULL, arg, ep); 494 if (!batch) 495 return ENOMEM; 336 usb_transfer_batch_t *batch = NULL; 337 hc_t *hc = NULL; 338 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size, 339 setup_data, setup_size, callback, NULL, arg, "Control READ", 340 &hc, &batch); 341 if (ret != EOK) 342 return ret; 496 343 batch_control_read(batch); 497 const intret = hc_schedule(hc, batch);498 if (ret != EOK) { 499 batch_dispose(batch);344 ret = hc_schedule(hc, batch); 345 if (ret != EOK) { 346 usb_transfer_batch_dispose(batch); 500 347 } 501 348 return ret; … … 503 350 /*----------------------------------------------------------------------------*/ 504 351 usbhc_iface_t hc_iface = { 505 .reserve_default_address = reserve_default_address,506 .release_default_address = release_default_address,507 352 .request_address = request_address, 508 353 .bind_address = bind_address, -
uspace/drv/uhci-hcd/main.c
ref354b6 re50cd7f 39 39 #include <usb/debug.h> 40 40 41 #include "iface.h"42 41 #include "uhci.h" 43 42 … … 62 61 int uhci_add_device(ddf_dev_t *device) 63 62 { 64 usb_log_debug ("uhci_add_device() called\n");63 usb_log_debug2("uhci_add_device() called\n"); 65 64 assert(device); 65 66 66 uhci_t *uhci = malloc(sizeof(uhci_t)); 67 67 if (uhci == NULL) { … … 72 72 int ret = uhci_init(uhci, device); 73 73 if (ret != EOK) { 74 usb_log_error("Failed to initialize UHCI driver: %s.\n",75 str_error(ret));74 usb_log_error("Failed(%d) to initialize UHCI driver: %s.\n", 75 ret, str_error(ret)); 76 76 return ret; 77 77 } 78 78 device->driver_data = uhci; 79 79 80 usb_log_info("Controlling new UHCI device `%s'.\n", device->name);80 usb_log_info("Controlling new UHCI device '%s'.\n", device->name); 81 81 82 82 return EOK; … … 85 85 /** Initialize global driver structures (NONE). 86 86 * 87 * @param[in] argc N mber of arguments in argv vector (ignored).87 * @param[in] argc Number of arguments in argv vector (ignored). 88 88 * @param[in] argv Cmdline argument vector (ignored). 89 89 * @return Error code. … … 94 94 { 95 95 printf(NAME ": HelenOS UHCI driver.\n"); 96 97 sleep(3); /* TODO: remove in final version */98 96 usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME); 99 97 -
uspace/drv/uhci-hcd/pci.c
ref354b6 re50cd7f 44 44 #include "pci.h" 45 45 46 /** Get address of registers and IRQ for given device.46 /** Get I/O address of registers and IRQ for given device. 47 47 * 48 48 * @param[in] dev Device asking for the addresses. … … 53 53 */ 54 54 int pci_get_my_registers(ddf_dev_t *dev, 55 uintptr_t *io_reg_address, size_t *io_reg_size, 56 int *irq_no) 55 uintptr_t *io_reg_address, size_t *io_reg_size, int *irq_no) 57 56 { 58 57 assert(dev != NULL); 59 58 60 int parent_phone = devman_parent_device_connect(dev->handle,61 IPC_FLAG_BLOCKING);59 int parent_phone = 60 devman_parent_device_connect(dev->handle, IPC_FLAG_BLOCKING); 62 61 if (parent_phone < 0) { 63 62 return parent_phone; 64 63 } 65 64 66 int rc;67 65 hw_resource_list_t hw_resources; 68 rc = hw_res_get_resource_list(parent_phone, &hw_resources);66 int rc = hw_res_get_resource_list(parent_phone, &hw_resources); 69 67 if (rc != EOK) { 70 68 goto leave; … … 95 93 res->res.io_range.address, res->res.io_range.size); 96 94 io_found = true; 95 break; 97 96 98 97 default: … … 113 112 leave: 114 113 async_hangup(parent_phone); 115 116 114 return rc; 117 115 } … … 145 143 } 146 144 147 /* See UHCI design guide for these values ,145 /* See UHCI design guide for these values p.45, 148 146 * write all WC bits in USB legacy register */ 149 147 sysarg_t address = 0xc0; -
uspace/drv/uhci-hcd/root_hub.c
ref354b6 re50cd7f 55 55 int ret = asprintf(&match_str, "usb&uhci&root-hub"); 56 56 if (ret < 0) { 57 usb_log_error("Failed to create root hub match string.\n"); 58 return ENOMEM; 57 usb_log_error( 58 "Failed(%d) to create root hub match string: %s.\n", 59 ret, str_error(ret)); 60 return ret; 59 61 } 60 62 61 63 ret = ddf_fun_add_match_id(fun, match_str, 100); 62 64 if (ret != EOK) { 65 free(match_str); 63 66 usb_log_error("Failed(%d) to add root hub match id: %s\n", 64 67 ret, str_error(ret)); … … 66 69 } 67 70 68 hw_resource_list_t *resource_list = &instance->resource_list;69 resource_list->count = 1;70 resource_list->resources = &instance->io_regs;71 assert(resource_list->resources); 71 /* Initialize resource structure */ 72 instance->resource_list.count = 1; 73 instance->resource_list.resources = &instance->io_regs; 74 72 75 instance->io_regs.type = IO_RANGE; 73 76 instance->io_regs.res.io_range.address = reg_addr; -
uspace/drv/uhci-hcd/root_hub.h
ref354b6 re50cd7f 39 39 #include <ops/hw_res.h> 40 40 41 /** DDF support structure for uhci-rhd driver, provides I/O resources */ 41 42 typedef struct rh { 43 /** List of resources available to the root hub. */ 42 44 hw_resource_list_t resource_list; 45 /** The only resource in the above list */ 43 46 hw_resource_t io_regs; 44 47 } rh_t; -
uspace/drv/uhci-hcd/transfer_list.c
ref354b6 re50cd7f 57 57 return ENOMEM; 58 58 } 59 instance->queue_head_pa = addr_to_phys(instance->queue_head);59 uint32_t queue_head_pa = addr_to_phys(instance->queue_head); 60 60 usb_log_debug2("Transfer list %s setup with QH: %p(%p).\n", 61 name, instance->queue_head, instance->queue_head_pa);61 name, instance->queue_head, queue_head_pa); 62 62 63 63 qh_init(instance->queue_head); … … 67 67 } 68 68 /*----------------------------------------------------------------------------*/ 69 /** Dispose transfer list structures. 70 * 71 * @param[in] instance Memory place to use. 72 * 73 * Frees memory for internal qh_t structure. 74 */ 75 void transfer_list_fini(transfer_list_t *instance) 76 { 77 assert(instance); 78 free32(instance->queue_head); 79 } 69 80 /** Set the next list in transfer list chain. 70 81 * … … 81 92 if (!instance->queue_head) 82 93 return; 83 /* Set bothqueue_head.next to point to the follower */84 qh_set_next_qh(instance->queue_head, next->queue_head _pa);85 } 86 /*----------------------------------------------------------------------------*/ 87 /** Submittransfer batch to the list and queue.94 /* Set queue_head.next to point to the follower */ 95 qh_set_next_qh(instance->queue_head, next->queue_head); 96 } 97 /*----------------------------------------------------------------------------*/ 98 /** Add transfer batch to the list and queue. 88 99 * 89 100 * @param[in] instance List to use. 90 101 * @param[in] batch Transfer batch to submit. 91 * @return Error code92 102 * 93 103 * The batch is added to the end of the list and queue. … … 109 119 } else { 110 120 /* There is something scheduled */ 111 usb_transfer_batch_t *last = list_get_instance(112 instance->batch_list.prev, usb_transfer_batch_t, link);121 usb_transfer_batch_t *last = 122 usb_transfer_batch_from_link(instance->batch_list.prev); 113 123 last_qh = batch_qh(last); 114 124 } … … 118 128 /* keep link */ 119 129 batch_qh(batch)->next = last_qh->next; 120 qh_set_next_qh(last_qh, pa);130 qh_set_next_qh(last_qh, batch_qh(batch)); 121 131 122 132 asm volatile ("": : :"memory"); … … 132 142 } 133 143 /*----------------------------------------------------------------------------*/ 134 /** Check list for finished batches. 135 * 136 * @param[in] instance List to use. 137 * @return Error code 138 * 139 * Creates a local list of finished batches and calls next_step on each and 140 * every one. This is safer because next_step may theoretically access 141 * this transfer list leading to the deadlock if its done inline. 144 /** Add completed bantches to the provided list. 145 * 146 * @param[in] instance List to use. 147 * @param[in] done list to fill 142 148 */ 143 149 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done) … … 151 157 link_t *next = current->next; 152 158 usb_transfer_batch_t *batch = 153 list_get_instance(current, usb_transfer_batch_t, link);159 usb_transfer_batch_from_link(current); 154 160 155 161 if (batch_is_complete(batch)) { 156 /* Save for p ost-processing */162 /* Save for processing */ 157 163 transfer_list_remove_batch(instance, batch); 158 164 list_append(current, done); … … 161 167 } 162 168 fibril_mutex_unlock(&instance->guard); 163 164 } 165 /*----------------------------------------------------------------------------*/ 166 /** Walk the list and abort all batches. 169 } 170 /*----------------------------------------------------------------------------*/ 171 /** Walk the list and finish all batches with EINTR. 167 172 * 168 173 * @param[in] instance List to use. … … 174 179 link_t *current = instance->batch_list.next; 175 180 usb_transfer_batch_t *batch = 176 list_get_instance(current, usb_transfer_batch_t, link);181 usb_transfer_batch_from_link(current); 177 182 transfer_list_remove_batch(instance, batch); 178 usb_transfer_batch_finish (batch, EIO);183 usb_transfer_batch_finish_error(batch, EINTR); 179 184 } 180 185 fibril_mutex_unlock(&instance->guard); … … 185 190 * @param[in] instance List to use. 186 191 * @param[in] batch Transfer batch to remove. 187 * @return Error code188 192 * 189 193 * Does not lock the transfer list, caller is responsible for that. … … 202 206 203 207 const char *qpos = NULL; 208 qh_t *prev_qh = NULL; 204 209 /* Remove from the hardware queue */ 205 210 if (instance->batch_list.next == &batch->link) { 206 211 /* I'm the first one here */ 207 assert((instance->queue_head->next & LINK_POINTER_ADDRESS_MASK) 208 == addr_to_phys(batch_qh(batch))); 209 instance->queue_head->next = batch_qh(batch)->next; 212 prev_qh = instance->queue_head; 210 213 qpos = "FIRST"; 211 214 } else { 215 /* The thing before me is a batch too */ 212 216 usb_transfer_batch_t *prev = 213 list_get_instance( 214 batch->link.prev, usb_transfer_batch_t, link); 215 assert((batch_qh(prev)->next & LINK_POINTER_ADDRESS_MASK) 216 == addr_to_phys(batch_qh(batch))); 217 batch_qh(prev)->next = batch_qh(batch)->next; 217 usb_transfer_batch_from_link(batch->link.prev); 218 prev_qh = batch_qh(prev); 218 219 qpos = "NOT FIRST"; 219 220 } 221 assert((prev_qh->next & LINK_POINTER_ADDRESS_MASK) 222 == addr_to_phys(batch_qh(batch))); 223 prev_qh->next = batch_qh(batch)->next; 220 224 asm volatile ("": : :"memory"); 221 225 /* Remove from the batch list */ 222 226 list_remove(&batch->link); 223 usb_log_debug("Batch(%p) removed (%s) from %s, next %x.\n",227 usb_log_debug("Batch(%p) removed (%s) from %s, next: %x.\n", 224 228 batch, qpos, instance->name, batch_qh(batch)->next); 225 229 } -
uspace/drv/uhci-hcd/transfer_list.h
ref354b6 re50cd7f 39 39 #include "batch.h" 40 40 #include "hw_struct/queue_head.h" 41 #include "utils/malloc32.h"42 41 42 /** Structure maintaining both hw queue and software list 43 * of currently executed transfers 44 */ 43 45 typedef struct transfer_list 44 46 { 47 /** Guard against multiple add/remove races */ 45 48 fibril_mutex_t guard; 49 /** UHCI hw structure represeting this queue */ 46 50 qh_t *queue_head; 47 uint32_t queue_head_pa;51 /** Assigned name, for nicer debug output */ 48 52 const char *name; 53 /** List of all batches in this list */ 49 54 link_t batch_list; 50 55 } transfer_list_t; 51 56 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 } 63 57 void transfer_list_fini(transfer_list_t *instance); 64 58 int transfer_list_init(transfer_list_t *instance, const char *name); 65 66 59 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next); 67 68 void transfer_list_add_batch(transfer_list_t *instance, usb_transfer_batch_t *batch); 69 60 void transfer_list_add_batch( 61 transfer_list_t *instance, usb_transfer_batch_t *batch); 70 62 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done); 71 72 63 void transfer_list_abort_all(transfer_list_t *instance); 73 64 #endif -
uspace/drv/uhci-hcd/uhci.c
ref354b6 re50cd7f 44 44 #include "pci.h" 45 45 46 /** IRQ handling callback, identifies device46 /** IRQ handling callback, forward status from call to diver structure. 47 47 * 48 48 * @param[in] dev DDF instance of the device to use. 49 49 * @param[in] iid (Unused). 50 * @param[in] call Pointer to the call that represents interrupt.50 * @param[in] call Pointer to the call from kernel. 51 51 */ 52 52 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) … … 61 61 /** Get address of the device identified by handle. 62 62 * 63 * @param[in] dev DDF instance of the deviceto use.64 * @param[in] iid (Unused).65 * @param[ in] call Pointer to the call that represents interrupt.63 * @param[in] fun DDF instance of the function to use. 64 * @param[in] handle DDF handle of the driver seeking its USB address. 65 * @param[out] address Found address. 66 66 */ 67 67 static int usb_iface_get_address( … … 69 69 { 70 70 assert(fun); 71 usb_device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.manager; 71 usb_device_keeper_t *manager = 72 &((uhci_t*)fun->dev->driver_data)->hc.manager; 72 73 73 74 usb_address_t addr = usb_device_keeper_find(manager, handle); … … 83 84 } 84 85 /*----------------------------------------------------------------------------*/ 85 /** Gets handle of the respective hc (this or parent device).86 * 87 * @param[in] root_hub_fun Root hub function seeking hc handle.88 * @param[out] handle Place to write thehandle.86 /** Gets handle of the respective hc. 87 * 88 * @param[in] fun DDF function of uhci device. 89 * @param[out] handle Host cotnroller handle. 89 90 * @return Error code. 90 91 */ … … 100 101 } 101 102 /*----------------------------------------------------------------------------*/ 102 /** This iface is generic for both RH and HC.*/103 /** USB interface implementation used by RH */ 103 104 static usb_iface_t usb_iface = { 104 105 .get_hc_handle = usb_iface_get_hc_handle, … … 106 107 }; 107 108 /*----------------------------------------------------------------------------*/ 109 /** Operations supported by the HC driver */ 108 110 static ddf_dev_ops_t hc_ops = { 109 // .interfaces[USB_DEV_IFACE] = &usb_iface,110 111 .interfaces[USBHC_DEV_IFACE] = &hc_iface, /* see iface.h/c */ 111 112 }; … … 122 123 } 123 124 /*----------------------------------------------------------------------------*/ 125 /** Interface to provide the root hub driver with hw info */ 124 126 static hw_res_ops_t hw_res_iface = { 125 127 .get_resource_list = get_resource_list, … … 127 129 }; 128 130 /*----------------------------------------------------------------------------*/ 131 /** RH function support for uhci-rhd */ 129 132 static ddf_dev_ops_t rh_ops = { 130 133 .interfaces[USB_DEV_IFACE] = &usb_iface, … … 132 135 }; 133 136 /*----------------------------------------------------------------------------*/ 134 /** Initialize hc and rh ddfstructures and their respective drivers.137 /** Initialize hc and rh DDF structures and their respective drivers. 135 138 * 136 139 * @param[in] instance UHCI structure to use. … … 138 141 * 139 142 * This function does all the preparatory work for hc and rh drivers: 140 * - gets device hw resources141 * - disables UHCI legacy support 143 * - gets device's hw resources 144 * - disables UHCI legacy support (PCI config space) 142 145 * - asks for interrupt 143 146 * - registers interrupt handler … … 193 196 ret = (instance->hc_fun == NULL) ? ENOMEM : EOK; 194 197 CHECK_RET_DEST_FUN_RETURN(ret, 195 "Failed(%d) to create HC function .\n", ret);198 "Failed(%d) to create HC function: %s.\n", ret, str_error(ret)); 196 199 197 200 ret = hc_init(&instance->hc, instance->hc_fun, 198 201 (void*)io_reg_base, io_reg_size, interrupts); 199 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 202 CHECK_RET_DEST_FUN_RETURN(ret, 203 "Failed(%d) to init uhci-hcd: %s.\n", ret, str_error(ret)); 204 200 205 instance->hc_fun->ops = &hc_ops; 201 206 instance->hc_fun->driver_data = &instance->hc; … … 221 226 &instance->hc.interrupt_code); 222 227 CHECK_RET_FINI_RETURN(ret, 223 "Failed(%d) to register interrupt handler.\n", ret); 228 "Failed(%d) to register interrupt handler: %s.\n", 229 ret, str_error(ret)); 224 230 225 231 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh"); 226 232 ret = (instance->rh_fun == NULL) ? ENOMEM : EOK; 227 233 CHECK_RET_FINI_RETURN(ret, 228 "Failed(%d) to create root hub function.\n", ret); 234 "Failed(%d) to create root hub function: %s.\n", 235 ret, str_error(ret)); 229 236 230 237 ret = rh_init(&instance->rh, instance->rh_fun, 231 238 (uintptr_t)instance->hc.registers + 0x10, 4); 232 239 CHECK_RET_FINI_RETURN(ret, 233 "Failed(%d) to setup UHCI root hub .\n", ret);240 "Failed(%d) to setup UHCI root hub: %s.\n", ret, str_error(ret)); 234 241 235 242 instance->rh_fun->ops = &rh_ops; … … 237 244 ret = ddf_fun_bind(instance->rh_fun); 238 245 CHECK_RET_FINI_RETURN(ret, 239 "Failed(%d) to register UHCI root hub .\n", ret);246 "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret)); 240 247 241 248 return EOK; -
uspace/drv/uhci-hcd/uhci.h
ref354b6 re50cd7f 41 41 #include "root_hub.h" 42 42 43 /** Structure representing both functions of UHCI hc, USB host controller 44 * and USB root hub */ 43 45 typedef struct uhci { 46 /** Pointer to DDF represenation of UHCI host controller */ 44 47 ddf_fun_t *hc_fun; 48 /** Pointer to DDF represenation of UHCI root hub */ 45 49 ddf_fun_t *rh_fun; 46 50 51 /** Internal driver's represenation of UHCI host controller */ 47 52 hc_t hc; 53 /** Internal driver's represenation of UHCI root hub */ 48 54 rh_t rh; 49 55 } uhci_t; 50 56 51 57 int uhci_init(uhci_t *instance, ddf_dev_t *device); 52 53 58 #endif 54 59 /** -
uspace/drv/uhci-rhd/port.c
ref354b6 re50cd7f 68 68 * @return Error code. (Always EOK) 69 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); 70 static inline void uhci_port_write_status(uhci_port_t *port, port_status_t val) 71 { 72 assert(port); 73 pio_write_16(port->address, val); 75 74 } 76 75 /*----------------------------------------------------------------------------*/ … … 101 100 port->rh = rh; 102 101 103 int r c = usb_hc_connection_initialize_from_device(104 &port->hc_connection, rh);105 if (r c!= EOK) {102 int ret = 103 usb_hc_connection_initialize_from_device(&port->hc_connection, rh); 104 if (ret != EOK) { 106 105 usb_log_error("Failed to initialize connection to HC."); 107 return r c;106 return ret; 108 107 } 109 108 … … 238 237 /* Enable the port. */ 239 238 uhci_port_set_enabled(port, true); 240 241 239 return EOK; 242 240 } … … 271 269 usb_log_info("New device at port %u, address %d (handle %llu).\n", 272 270 port->number, dev_addr, port->attached_device); 273 274 271 return EOK; 275 272 } … … 313 310 /* Write new value. */ 314 311 uhci_port_write_status(port, port_status); 312 313 /* Wait for port to become enabled */ 314 do { 315 async_usleep(1000); 316 port_status = uhci_port_read_status(port); 317 } while ((port_status & STATUS_CONNECTED) && 318 !(port_status & STATUS_ENABLED)); 315 319 316 320 usb_log_debug("%s: %sabled port.\n", -
uspace/drv/uhci-rhd/port.h
ref354b6 re50cd7f 54 54 #define STATUS_SUSPEND (1 << 12) 55 55 56 /** UHCI port structure */ 56 57 typedef struct uhci_port 57 58 { -
uspace/drv/uhci-rhd/root_hub.c
ref354b6 re50cd7f 33 33 */ 34 34 #include <errno.h> 35 #include <str_error.h> 35 36 #include <ddi.h> 36 37 #include <usb/debug.h> … … 43 44 * @param[in] addr Address of I/O registers. 44 45 * @param[in] size Size of available I/O space. 45 * @param[in] rh Pointer to ddfinstance of the root hub driver.46 * @param[in] rh Pointer to DDF instance of the root hub driver. 46 47 * @return Error code. 47 48 */ … … 58 59 if (ret < 0) { 59 60 usb_log_error( 60 "Failed(%d) to gain access to port registers at %p \n",61 ret, regs );61 "Failed(%d) to gain access to port registers at %p: %s.\n", 62 ret, regs, str_error(ret)); 62 63 return ret; 63 64 } … … 66 67 unsigned i = 0; 67 68 for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) { 68 /* NOTE: mind pointer arithmetics here */69 69 ret = uhci_port_init( 70 &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);70 &instance->ports[i], ®s[i], i, ROOT_HUB_WAIT_USEC, rh); 71 71 if (ret != EOK) { 72 72 unsigned j = 0; -
uspace/drv/uhci-rhd/root_hub.h
ref354b6 re50cd7f 40 40 41 41 #define UHCI_ROOT_HUB_PORT_COUNT 2 42 #define ROOT_HUB_WAIT_USEC 5000000 /* 5seconds */42 #define ROOT_HUB_WAIT_USEC 250000 /* 250 miliseconds */ 43 43 44 /** UHCI root hub drvier structure */ 44 45 typedef struct root_hub { 46 /** Ports provided by the hub */ 45 47 uhci_port_t ports[UHCI_ROOT_HUB_PORT_COUNT]; 46 devman_handle_t hc_handle;47 48 } uhci_root_hub_t; 48 49 49 50 int uhci_root_hub_init( 50 uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh);51 uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh); 51 52 52 53 void uhci_root_hub_fini(uhci_root_hub_t *instance); -
uspace/drv/usbhid/generic/hiddev.h
ref354b6 re50cd7f 1 1 /* 2 * Copyright (c) 2007 Jan Hudecek 3 * Copyright (c) 2008 Martin Decky 2 * Copyright (c) 2011 Lubos Slovak 4 3 * All rights reserved. 5 4 * … … 28 27 */ 29 28 30 /** @addtogroup genericproc29 /** @addtogroup drvusbhid 31 30 * @{ 32 31 */ 33 /** @file tasklet.c34 * @brief Tasklet implementation32 /** @file 33 * USB HID driver API. 35 34 */ 36 35 37 #include <proc/tasklet.h> 38 #include <synch/spinlock.h> 39 #include <mm/slab.h> 40 #include <config.h> 36 #ifndef USB_HID_HIDDDEV_H_ 37 #define USB_HID_HIDDDEV_H_ 41 38 42 /** Spinlock protecting list of tasklets */ 43 SPINLOCK_INITIALIZE(tasklet_lock); 39 #include <usb/devdrv.h> 44 40 45 /** Array of tasklet lists for every CPU */ 46 tasklet_descriptor_t **tasklet_list; 41 struct usb_hid_dev; 47 42 48 void tasklet_init(void) 49 { 50 unsigned int i; 51 52 tasklet_list = malloc(sizeof(tasklet_descriptor_t *) * config.cpu_count, 0); 53 if (!tasklet_list) 54 panic("Error initializing tasklets."); 55 56 for (i = 0; i < config.cpu_count; i++) 57 tasklet_list[i] = NULL; 58 59 spinlock_initialize(&tasklet_lock, "tasklet_lock"); 60 } 43 usb_endpoint_description_t usb_hid_generic_poll_endpoint_description; 61 44 45 const char *HID_GENERIC_FUN_NAME; 46 const char *HID_GENERIC_CLASS_NAME; 62 47 63 /** @} 48 bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, 49 uint8_t *buffer, size_t buffer_size); 50 51 #endif // USB_HID_HIDDDEV_H_ 52 53 /** 54 * @} 64 55 */ -
uspace/drv/usbhub/Makefile
ref354b6 re50cd7f 34 34 SOURCES = \ 35 35 main.c \ 36 ports.c \37 36 utils.c \ 38 usbhub.c 37 usbhub.c \ 38 ports.c 39 39 40 40 include $(USPACE_PREFIX)/Makefile.common -
uspace/drv/usbhub/port_status.h
ref354b6 re50cd7f 49 49 50 50 /** 51 * structure holding hub status and changes flags. 52 * should not be accessed directly, use supplied getter/setter methods. 53 * 54 * For more information refer to table 11.16.2.5 in 55 * "Universal Serial Bus Specification Revision 1.1" 56 * 57 */ 58 typedef uint32_t usb_hub_status_t; 59 60 /** 51 61 * set values in request to be it a port status request 52 62 * @param request … … 54 64 */ 55 65 static inline void usb_hub_set_port_status_request( 56 usb_device_request_setup_packet_t * request, uint16_t port57 ){66 usb_device_request_setup_packet_t * request, uint16_t port 67 ) { 58 68 request->index = port; 59 69 request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS; … … 63 73 } 64 74 75 /** 76 * set values in request to be it a port status request 77 * @param request 78 * @param port 79 */ 80 static inline void usb_hub_set_hub_status_request( 81 usb_device_request_setup_packet_t * request 82 ) { 83 request->index = 0; 84 request->request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS; 85 request->request = USB_HUB_REQUEST_GET_STATUS; 86 request->value = 0; 87 request->length = 4; 88 } 65 89 66 90 /** … … 70 94 */ 71 95 static inline usb_device_request_setup_packet_t * 72 usb_hub_create_port_status_request(uint16_t port) {96 usb_hub_create_port_status_request(uint16_t port) { 73 97 usb_device_request_setup_packet_t * result = 74 usb_new(usb_device_request_setup_packet_t);75 usb_hub_set_port_status_request(result, port);98 malloc(sizeof(usb_device_request_setup_packet_t)); 99 usb_hub_set_port_status_request(result, port); 76 100 return result; 77 101 } 78 102 79 80 103 /** 81 104 * set the device request to be a port feature enable request … … 85 108 */ 86 109 static inline void usb_hub_set_enable_port_feature_request( 87 usb_device_request_setup_packet_t * request, uint16_t port,88 uint16_t feature_selector89 ){110 usb_device_request_setup_packet_t * request, uint16_t port, 111 uint16_t feature_selector 112 ) { 90 113 request->index = port; 91 114 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 102 125 */ 103 126 static inline void usb_hub_set_disable_port_feature_request( 104 usb_device_request_setup_packet_t * request, uint16_t port,105 uint16_t feature_selector106 ){127 usb_device_request_setup_packet_t * request, uint16_t port, 128 uint16_t feature_selector 129 ) { 107 130 request->index = port; 108 131 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 118 141 */ 119 142 static inline void usb_hub_set_enable_port_request( 120 usb_device_request_setup_packet_t * request, uint16_t port121 ){143 usb_device_request_setup_packet_t * request, uint16_t port 144 ) { 122 145 request->index = port; 123 146 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 133 156 */ 134 157 static inline usb_device_request_setup_packet_t * 135 usb_hub_create_enable_port_request(uint16_t port) {158 usb_hub_create_enable_port_request(uint16_t port) { 136 159 usb_device_request_setup_packet_t * result = 137 usb_new(usb_device_request_setup_packet_t);138 usb_hub_set_enable_port_request(result, port);160 malloc(sizeof(usb_device_request_setup_packet_t)); 161 usb_hub_set_enable_port_request(result, port); 139 162 return result; 140 163 } … … 146 169 */ 147 170 static inline void usb_hub_set_disable_port_request( 148 usb_device_request_setup_packet_t * request, uint16_t port149 ){171 usb_device_request_setup_packet_t * request, uint16_t port 172 ) { 150 173 request->index = port; 151 174 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 161 184 */ 162 185 static inline usb_device_request_setup_packet_t * 163 usb_hub_create_disable_port_request(uint16_t port) {186 usb_hub_create_disable_port_request(uint16_t port) { 164 187 usb_device_request_setup_packet_t * result = 165 usb_new(usb_device_request_setup_packet_t);166 usb_hub_set_disable_port_request(result, port);188 malloc(sizeof(usb_device_request_setup_packet_t)); 189 usb_hub_set_disable_port_request(result, port); 167 190 return result; 168 191 } … … 174 197 */ 175 198 static inline void usb_hub_set_reset_port_request( 176 usb_device_request_setup_packet_t * request, uint16_t port177 ){199 usb_device_request_setup_packet_t * request, uint16_t port 200 ) { 178 201 request->index = port; 179 202 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 189 212 */ 190 213 static inline usb_device_request_setup_packet_t * 191 usb_hub_create_reset_port_request(uint16_t port) {214 usb_hub_create_reset_port_request(uint16_t port) { 192 215 usb_device_request_setup_packet_t * result = 193 usb_new(usb_device_request_setup_packet_t);194 usb_hub_set_reset_port_request(result, port);216 malloc(sizeof(usb_device_request_setup_packet_t)); 217 usb_hub_set_reset_port_request(result, port); 195 218 return result; 196 219 } … … 202 225 */ 203 226 static inline void usb_hub_set_power_port_request( 204 usb_device_request_setup_packet_t * request, uint16_t port205 ){227 usb_device_request_setup_packet_t * request, uint16_t port 228 ) { 206 229 request->index = port; 207 230 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 217 240 */ 218 241 static inline void usb_hub_unset_power_port_request( 219 usb_device_request_setup_packet_t * request, uint16_t port220 ){242 usb_device_request_setup_packet_t * request, uint16_t port 243 ) { 221 244 request->index = port; 222 245 request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE; … … 226 249 } 227 250 228 229 /** get i`th bit of port status */ 230 static inline bool usb_port_get_bit(usb_port_status_t * status, int idx) 231 { 232 return (((*status)>>(idx))%2); 233 } 234 235 /** set i`th bit of port status */ 236 static inline void usb_port_set_bit( 237 usb_port_status_t * status, int idx, bool value) 238 { 239 (*status) = value? 240 ((*status)|(1<<(idx))): 241 ((*status)&(~(1<<(idx)))); 242 } 243 244 //device connnected on port 245 static inline bool usb_port_dev_connected(usb_port_status_t * status){ 246 return usb_port_get_bit(status,0); 247 } 248 249 static inline void usb_port_set_dev_connected(usb_port_status_t * status,bool connected){ 250 usb_port_set_bit(status,0,connected); 251 /** 252 * get i`th bit of port status 253 * 254 * @param status 255 * @param idx 256 * @return 257 */ 258 static inline bool usb_port_is_status(usb_port_status_t status, int idx) { 259 return (status&(1 << idx))!=0; 260 } 261 262 /** 263 * set i`th bit of port status 264 * 265 * @param status 266 * @param idx 267 * @param value 268 */ 269 static inline void usb_port_status_set_bit( 270 usb_port_status_t * status, int idx, bool value) { 271 (*status) = value ? 272 ((*status) | (1 << (idx))) : 273 ((*status)&(~(1 << (idx)))); 274 } 275 276 /** 277 * get i`th bit of hub status 278 * 279 * @param status 280 * @param idx 281 * @return 282 */ 283 static inline bool usb_hub_is_status(usb_hub_status_t status, int idx) { 284 return (status&(1 << idx))!=0; 285 } 286 287 /** 288 * set i`th bit of hub status 289 * 290 * @param status 291 * @param idx 292 * @param value 293 */ 294 static inline void usb_hub_status_set_bit( 295 usb_hub_status_t * status, int idx, bool value) { 296 (*status) = value ? 297 ((*status) | (1 << (idx))) : 298 ((*status)&(~(1 << (idx)))); 299 } 300 301 302 #if 0 303 /** 304 * connection status geter for port status 305 * 306 * @param status 307 * @return true if there is something connected 308 */ 309 static inline bool usb_port_dev_connected(usb_port_status_t * status) { 310 return usb_port_get_bit(status, 0); 311 } 312 313 /** 314 * set device connected bit in port status 315 * 316 * @param status 317 * @param connected value of the bit 318 */ 319 static inline void usb_port_set_dev_connected(usb_port_status_t * status, bool connected) { 320 usb_port_set_bit(status, 0, connected); 251 321 } 252 322 253 323 //port enabled 254 static inline bool usb_port_enabled(usb_port_status_t * status){ 255 return usb_port_get_bit(status,1); 256 } 257 258 static inline void usb_port_set_enabled(usb_port_status_t * status,bool enabled){ 259 usb_port_set_bit(status,1,enabled); 324 325 /** 326 * port enabled getter for port status 327 * 328 * @param status 329 * @return true if the port is enabled 330 */ 331 static inline bool usb_port_enabled(usb_port_status_t * status) { 332 return usb_port_get_bit(status, 1); 333 } 334 335 /** 336 * set port enabled bit in port status 337 * 338 * @param status 339 * @param enabled value of the bit 340 */ 341 static inline void usb_port_set_enabled(usb_port_status_t * status, bool enabled) { 342 usb_port_set_bit(status, 1, enabled); 260 343 } 261 344 262 345 //port suspended 263 static inline bool usb_port_suspended(usb_port_status_t * status){ 264 return usb_port_get_bit(status,2); 265 } 266 267 static inline void usb_port_set_suspended(usb_port_status_t * status,bool suspended){ 268 usb_port_set_bit(status,2,suspended); 346 /** 347 * port suspended getter for port status 348 * 349 * @param status 350 * @return true if port is suspended 351 */ 352 static inline bool usb_port_suspended(usb_port_status_t * status) { 353 return usb_port_get_bit(status, 2); 354 } 355 356 /** 357 * set port suspended bit in port status 358 * 359 * @param status 360 * @param suspended value of the bit 361 */ 362 static inline void usb_port_set_suspended(usb_port_status_t * status, bool suspended) { 363 usb_port_set_bit(status, 2, suspended); 269 364 } 270 365 271 366 //over currect 272 static inline bool usb_port_over_current(usb_port_status_t * status){ 273 return usb_port_get_bit(status,3); 274 } 275 276 static inline void usb_port_set_over_current(usb_port_status_t * status,bool value){ 277 usb_port_set_bit(status,3,value); 367 /** 368 * over current condition indicator getter for port status 369 * 370 * @param status 371 * @return true if there is opver-current condition on the hub 372 */ 373 static inline bool usb_port_over_current(usb_port_status_t * status) { 374 return usb_port_get_bit(status, 3); 375 } 376 377 /** 378 * set over current indicator bit in port status 379 * 380 * @param status 381 * @param value value of the bit 382 */ 383 static inline void usb_port_set_over_current(usb_port_status_t * status, bool value) { 384 usb_port_set_bit(status, 3, value); 278 385 } 279 386 280 387 //port reset 281 static inline bool usb_port_reset(usb_port_status_t * status){ 282 return usb_port_get_bit(status,4); 283 } 284 285 static inline void usb_port_set_reset(usb_port_status_t * status,bool value){ 286 usb_port_set_bit(status,4,value); 388 /** 389 * port reset indicator getter for port status 390 * 391 * @param status 392 * @return true if port is reset 393 */ 394 static inline bool usb_port_reset(usb_port_status_t * status) { 395 return usb_port_get_bit(status, 4); 396 } 397 398 /** 399 * set port reset bit in port status 400 * 401 * @param status 402 * @param value value of the bit 403 */ 404 static inline void usb_port_set_reset(usb_port_status_t * status, bool value) { 405 usb_port_set_bit(status, 4, value); 287 406 } 288 407 289 408 //powered 290 static inline bool usb_port_powered(usb_port_status_t * status){ 291 return usb_port_get_bit(status,8); 292 } 293 294 static inline void usb_port_set_powered(usb_port_status_t * status,bool powered){ 295 usb_port_set_bit(status,8,powered); 296 } 409 /** 410 * power state getter for port status 411 * 412 * @param status 413 * @return true if port is powered 414 */ 415 static inline bool usb_port_powered(usb_port_status_t * status) { 416 return usb_port_get_bit(status, 8); 417 } 418 419 /** 420 * set port powered bit in port status 421 * 422 * @param status 423 * @param powered value of the bit 424 */ 425 static inline void usb_port_set_powered(usb_port_status_t * status, bool powered) { 426 usb_port_set_bit(status, 8, powered); 427 } 428 429 #endif 297 430 298 431 //low speed device attached 299 static inline bool usb_port_low_speed(usb_port_status_t * status){ 300 return usb_port_get_bit(status,9); 301 } 302 303 static inline void usb_port_set_low_speed(usb_port_status_t * status,bool low_speed){ 304 usb_port_set_bit(status,9,low_speed); 305 } 306 307 //low speed device attached 308 static inline bool usb_port_high_speed(usb_port_status_t * status){ 309 return usb_port_get_bit(status,10); 310 } 311 312 static inline void usb_port_set_high_speed(usb_port_status_t * status,bool high_speed){ 313 usb_port_set_bit(status,10,high_speed); 314 } 315 316 static inline usb_speed_t usb_port_speed(usb_port_status_t * status){ 317 if(usb_port_low_speed(status)) 432 /** 433 * low speed device on the port indicator 434 * 435 * @param status 436 * @return true if low speed device is attached 437 */ 438 static inline bool usb_port_low_speed(usb_port_status_t status) { 439 return usb_port_is_status(status, 9); 440 } 441 442 /** 443 * set low speed device connected bit in port status 444 * 445 * @param status 446 * @param low_speed value of the bit 447 */ 448 static inline void usb_port_set_low_speed(usb_port_status_t * status, bool low_speed) { 449 usb_port_status_set_bit(status, 9, low_speed); 450 } 451 452 //high speed device attached 453 /** 454 * high speed device on the port indicator 455 * 456 * @param status 457 * @return true if high speed device is on port 458 */ 459 static inline bool usb_port_high_speed(usb_port_status_t status) { 460 return usb_port_is_status(status, 10); 461 } 462 463 /** 464 * set high speed device bit in port status 465 * 466 * @param status 467 * @param high_speed value of the bit 468 */ 469 static inline void usb_port_set_high_speed(usb_port_status_t * status, bool high_speed) { 470 usb_port_status_set_bit(status, 10, high_speed); 471 } 472 473 /** 474 * speed getter for port status 475 * 476 * @param status 477 * @return speed of usb device (for more see usb specification) 478 */ 479 static inline usb_speed_t usb_port_speed(usb_port_status_t status) { 480 if (usb_port_low_speed(status)) 318 481 return USB_SPEED_LOW; 319 if (usb_port_high_speed(status))482 if (usb_port_high_speed(status)) 320 483 return USB_SPEED_HIGH; 321 484 return USB_SPEED_FULL; 322 485 } 323 486 324 487 #if 0 325 488 //connect change 326 static inline bool usb_port_connect_change(usb_port_status_t * status){ 327 return usb_port_get_bit(status,16); 328 } 329 330 static inline void usb_port_set_connect_change(usb_port_status_t * status,bool change){ 331 usb_port_set_bit(status,16,change); 489 /** 490 * port connect change indicator 491 * 492 * @param status 493 * @return true if connection has changed 494 */ 495 static inline bool usb_port_connect_change(usb_port_status_t * status) { 496 return usb_port_get_bit(status, 16); 497 } 498 499 /** 500 * set connection change bit in port status 501 * @param status 502 * @param change value of the bit 503 */ 504 static inline void usb_port_set_connect_change(usb_port_status_t * status, bool change) { 505 usb_port_set_bit(status, 16, change); 332 506 } 333 507 334 508 //port enable change 335 static inline bool usb_port_enabled_change(usb_port_status_t * status){ 336 return usb_port_get_bit(status,17); 337 } 338 339 static inline void usb_port_set_enabled_change(usb_port_status_t * status,bool change){ 340 usb_port_set_bit(status,17,change); 509 /** 510 * port enable change for port status 511 * 512 * @param status 513 * @return true if the port has been enabled/disabled 514 */ 515 static inline bool usb_port_enabled_change(usb_port_status_t * status) { 516 return usb_port_get_bit(status, 17); 517 } 518 519 /** 520 * set port enable change bit in port status 521 * 522 * @param status 523 * @param change value of the bit 524 */ 525 static inline void usb_port_set_enabled_change(usb_port_status_t * status, bool change) { 526 usb_port_set_bit(status, 17, change); 341 527 } 342 528 343 529 //suspend change 344 static inline bool usb_port_suspend_change(usb_port_status_t * status){ 345 return usb_port_get_bit(status,18); 346 } 347 348 static inline void usb_port_set_suspend_change(usb_port_status_t * status,bool change){ 349 usb_port_set_bit(status,18,change); 530 /** 531 * port suspend change for port status 532 * 533 * @param status 534 * @return ture if suspend status has changed 535 */ 536 static inline bool usb_port_suspend_change(usb_port_status_t * status) { 537 return usb_port_get_bit(status, 18); 538 } 539 540 /** 541 * set port suspend change bit in port status 542 * 543 * @param status 544 * @param change value of the bit 545 */ 546 static inline void usb_port_set_suspend_change(usb_port_status_t * status, bool change) { 547 usb_port_set_bit(status, 18, change); 350 548 } 351 549 352 550 //over current change 353 static inline bool usb_port_overcurrent_change(usb_port_status_t * status){ 354 return usb_port_get_bit(status,19); 355 } 356 357 static inline void usb_port_set_overcurrent_change(usb_port_status_t * status,bool change){ 358 usb_port_set_bit(status,19,change); 551 /** 552 * over current change indicator 553 * 554 * @param status 555 * @return true if over-current condition on port has changed 556 */ 557 static inline bool usb_port_overcurrent_change(usb_port_status_t * status) { 558 return usb_port_get_bit(status, 19); 559 } 560 561 /** 562 * set port over current change bit in port status 563 * 564 * @param status 565 * @param change value of the bit 566 */ 567 static inline void usb_port_set_overcurrent_change(usb_port_status_t * status, bool change) { 568 usb_port_set_bit(status, 19, change); 359 569 } 360 570 361 571 //reset change 362 static inline bool usb_port_reset_completed(usb_port_status_t * status){ 363 return usb_port_get_bit(status,20); 364 } 365 366 static inline void usb_port_set_reset_completed(usb_port_status_t * status,bool completed){ 367 usb_port_set_bit(status,20,completed); 368 } 369 572 /** 573 * port reset change indicator 574 * @param status 575 * @return true if port has been reset 576 */ 577 static inline bool usb_port_reset_completed(usb_port_status_t * status) { 578 return usb_port_get_bit(status, 20); 579 } 580 581 /** 582 * set port reset completed bit in port status 583 * 584 * @param status 585 * @param change value of the bit 586 */ 587 static inline void usb_port_set_reset_completed(usb_port_status_t * status, bool completed) { 588 usb_port_set_bit(status, 20, completed); 589 } 590 591 //local power status 592 /** 593 * local power lost indicator for hub status 594 * 595 * @param status 596 * @return true if hub is not powered 597 */ 598 static inline bool usb_hub_local_power_lost(usb_hub_status_t * status) { 599 return usb_hub_get_bit(status, 0); 600 } 601 602 /** 603 * set hub power lost bit in hub status 604 * 605 * @param status 606 * @param change value of the bit 607 */ 608 static inline void usb_hub_set_local_power_lost(usb_port_status_t * status, 609 bool power_lost) { 610 usb_hub_set_bit(status, 0, power_lost); 611 } 612 613 //over current ocndition 614 /** 615 * hub over-current indicator 616 * 617 * @param status 618 * @return true if over-current condition occurred on hub 619 */ 620 static inline bool usb_hub_over_current(usb_hub_status_t * status) { 621 return usb_hub_get_bit(status, 1); 622 } 623 624 /** 625 * set hub over current bit in hub status 626 * 627 * @param status 628 * @param change value of the bit 629 */ 630 static inline void usb_hub_set_over_current(usb_port_status_t * status, 631 bool over_current) { 632 usb_hub_set_bit(status, 1, over_current); 633 } 634 635 //local power change 636 /** 637 * hub power change indicator 638 * 639 * @param status 640 * @return true if local power status has been changed - power has been 641 * dropped or re-established 642 */ 643 static inline bool usb_hub_local_power_change(usb_hub_status_t * status) { 644 return usb_hub_get_bit(status, 16); 645 } 646 647 /** 648 * set hub power change bit in hub status 649 * 650 * @param status 651 * @param change value of the bit 652 */ 653 static inline void usb_hub_set_local_power_change(usb_port_status_t * status, 654 bool change) { 655 usb_hub_set_bit(status, 16, change); 656 } 657 658 //local power status 659 /** 660 * hub over-current condition change indicator 661 * 662 * @param status 663 * @return true if over-current condition has changed 664 */ 665 static inline bool usb_hub_over_current_change(usb_hub_status_t * status) { 666 return usb_hub_get_bit(status, 17); 667 } 668 669 /** 670 * set hub over current change bit in hub status 671 * 672 * @param status 673 * @param change value of the bit 674 */ 675 static inline void usb_hub_set_over_current_change(usb_port_status_t * status, 676 bool change) { 677 usb_hub_set_bit(status, 17, change); 678 } 679 #endif 370 680 371 681 -
uspace/drv/usbhub/ports.c
ref354b6 re50cd7f 33 33 * Hub ports functions. 34 34 */ 35 #include "port_status.h" 36 #include < inttypes.h>35 36 #include <bool.h> 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <usb/request.h> 39 #include <inttypes.h> 40 #include <fibril_synch.h> 41 40 42 #include <usb/debug.h> 43 44 #include "ports.h" 45 #include "usbhub.h" 46 #include "usbhub_private.h" 47 #include "port_status.h" 48 49 50 /** Information for fibril for device discovery. */ 51 struct add_device_phase1 { 52 usb_hub_info_t *hub; 53 size_t port; 54 usb_speed_t speed; 55 }; 56 57 static void usb_hub_removed_device( 58 usb_hub_info_t * hub, uint16_t port); 59 60 static void usb_hub_port_reset_completed(usb_hub_info_t * hub, 61 uint16_t port, uint32_t status); 62 63 static void usb_hub_port_over_current(usb_hub_info_t * hub, 64 uint16_t port, uint32_t status); 65 66 static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port, 67 usb_port_status_t *status); 68 69 static int enable_port_callback(int port_no, void *arg); 70 71 static int add_device_phase1_worker_fibril(void *arg); 72 73 static int create_add_device_fibril(usb_hub_info_t *hub, size_t port, 74 usb_speed_t speed); 75 76 /** 77 * Process interrupts on given hub port 78 * 79 * Accepts connection, over current and port reset change. 80 * @param hub hub representation 81 * @param port port number, starting from 1 82 */ 83 void usb_hub_process_interrupt(usb_hub_info_t * hub, 84 uint16_t port) { 85 usb_log_debug("interrupt at port %d\n", port); 86 //determine type of change 87 //usb_pipe_t *pipe = hub->control_pipe; 88 89 int opResult; 90 91 usb_port_status_t status; 92 opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status); 93 if (opResult != EOK) { 94 usb_log_error("Failed to get port %zu status: %s.\n", 95 port, str_error(opResult)); 96 return; 97 } 98 //connection change 99 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) { 100 bool device_connected = usb_port_is_status(status, 101 USB_HUB_FEATURE_PORT_CONNECTION); 102 usb_log_debug("Connection change on port %zu: %s.\n", port, 103 device_connected ? "device attached" : "device removed"); 104 105 if (device_connected) { 106 opResult = create_add_device_fibril(hub, port, 107 usb_port_speed(status)); 108 if (opResult != EOK) { 109 usb_log_error( 110 "Cannot handle change on port %zu: %s.\n", 111 str_error(opResult)); 112 } 113 } else { 114 usb_hub_removed_device(hub, port); 115 } 116 } 117 //over current 118 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) { 119 //check if it was not auto-resolved 120 usb_log_debug("overcurrent change on port\n"); 121 usb_hub_port_over_current(hub, port, status); 122 } 123 //port reset 124 if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) { 125 usb_hub_port_reset_completed(hub, port, status); 126 } 127 usb_log_debug("status x%x : %d\n ", status, status); 128 129 usb_port_status_set_bit( 130 &status, USB_HUB_FEATURE_C_PORT_CONNECTION,false); 131 usb_port_status_set_bit( 132 &status, USB_HUB_FEATURE_PORT_RESET,false); 133 usb_port_status_set_bit( 134 &status, USB_HUB_FEATURE_C_PORT_RESET,false); 135 usb_port_status_set_bit( 136 &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT,false); 137 /// \TODO what about port power change? 138 if (status >> 16) { 139 usb_log_info("there was unsupported change on port %d: %X\n", 140 port, status); 141 142 } 143 } 144 145 146 /** 147 * routine called when a device on port has been removed 148 * 149 * If the device on port had default address, it releases default address. 150 * Otherwise does not do anything, because DDF does not allow to remove device 151 * from it`s device tree. 152 * @param hub hub representation 153 * @param port port number, starting from 1 154 */ 155 static void usb_hub_removed_device( 156 usb_hub_info_t * hub, uint16_t port) { 157 158 int opResult = usb_hub_clear_port_feature(hub->control_pipe, 159 port, USB_HUB_FEATURE_C_PORT_CONNECTION); 160 if (opResult != EOK) { 161 usb_log_warning("could not clear port-change-connection flag\n"); 162 } 163 /** \TODO remove device from device manager - not yet implemented in 164 * devide manager 165 */ 166 167 //close address 168 //if (hub->attached_devs[port].address != 0) { 169 if(hub->ports[port].attached_device.address >= 0){ 170 /*uncomment this code to use it when DDF allows device removal 171 opResult = usb_hc_unregister_device( 172 &hub->connection, 173 hub->attached_devs[port].address); 174 if(opResult != EOK) { 175 dprintf(USB_LOG_LEVEL_WARNING, "could not release " 176 "address of " 177 "removed device: %d", opResult); 178 } 179 hub->attached_devs[port].address = 0; 180 hub->attached_devs[port].handle = 0; 181 */ 182 } else { 183 // TODO: is this really reason to print a warning? 184 usb_log_warning("Device removed before being registered.\n"); 185 186 /* 187 * Device was removed before port reset completed. 188 * We will announce a failed port reset to unblock the 189 * port reset callback from new device wrapper. 190 */ 191 usb_hub_port_t *the_port = hub->ports + port; 192 fibril_mutex_lock(&the_port->reset_mutex); 193 the_port->reset_completed = true; 194 the_port->reset_okay = false; 195 fibril_condvar_broadcast(&the_port->reset_cv); 196 fibril_mutex_unlock(&the_port->reset_mutex); 197 } 198 } 199 200 201 /** 202 * Process port reset change 203 * 204 * After this change port should be enabled, unless some problem occured. 205 * This functions triggers second phase of enabling new device. 206 * @param hub 207 * @param port 208 * @param status 209 */ 210 static void usb_hub_port_reset_completed(usb_hub_info_t * hub, 211 uint16_t port, uint32_t status){ 212 usb_log_debug("Port %zu reset complete.\n", port); 213 if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) { 214 /* Finalize device adding. */ 215 usb_hub_port_t *the_port = hub->ports + port; 216 fibril_mutex_lock(&the_port->reset_mutex); 217 the_port->reset_completed = true; 218 the_port->reset_okay = true; 219 fibril_condvar_broadcast(&the_port->reset_cv); 220 fibril_mutex_unlock(&the_port->reset_mutex); 221 } else { 222 usb_log_warning( 223 "Port %zu reset complete but port not enabled.\n", 224 port); 225 } 226 } 227 228 /** 229 * Process over current condition on port. 230 * 231 * Turn off the power on the port. 232 * 233 * @param hub hub representation 234 * @param port port number, starting from 1 235 */ 236 static void usb_hub_port_over_current(usb_hub_info_t * hub, 237 uint16_t port, uint32_t status) { 238 int opResult; 239 if(usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)){ 240 opResult = usb_hub_clear_port_feature(hub->control_pipe, 241 port, USB_HUB_FEATURE_PORT_POWER); 242 if (opResult != EOK) { 243 usb_log_error("cannot power off port %d; %d\n", 244 port, opResult); 245 } 246 }else{ 247 opResult = usb_hub_set_port_feature(hub->control_pipe, 248 port, USB_HUB_FEATURE_PORT_POWER); 249 if (opResult != EOK) { 250 usb_log_error("cannot power on port %d; %d\n", 251 port, opResult); 252 } 253 } 254 } 41 255 42 256 /** Retrieve port status. … … 73 287 } 74 288 75 /** Information for fibril for device discovery. */76 struct add_device_phase1 {77 usb_hub_info_t *hub;78 size_t port;79 usb_speed_t speed;80 };81 82 289 /** Callback for enabling a specific port. 83 290 * … … 91 298 static int enable_port_callback(int port_no, void *arg) 92 299 { 93 usb_hub_info_t *hub = (usb_hub_info_t *)arg;300 usb_hub_info_t *hub = arg; 94 301 int rc; 95 302 usb_device_request_setup_packet_t request; … … 122 329 } 123 330 124 return EOK; 331 if (my_port->reset_okay) { 332 return EOK; 333 } else { 334 return ESTALL; 335 } 125 336 } 126 337 … … 156 367 data->hub->ports[data->port].attached_device.address = new_address; 157 368 158 usb_log_info("Detected new device on `%s' (port %zu), " \369 usb_log_info("Detected new device on `%s' (port %zu), " 159 370 "address %d (handle %" PRIun ").\n", 160 371 data->hub->usb_device->ddf_dev->name, data->port, … … 166 377 return EOK; 167 378 } 379 168 380 169 381 /** Start device adding when connection change is detected. … … 176 388 * @return Error code. 177 389 */ 178 static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,390 static int create_add_device_fibril(usb_hub_info_t *hub, size_t port, 179 391 usb_speed_t speed) 180 392 { … … 213 425 } 214 426 215 /** Process change on a single port.216 *217 * @param hub Hub to which the port belongs.218 * @param port Port index (starting at 1).219 */220 static void process_port_change(usb_hub_info_t *hub, size_t port)221 {222 int rc;223 224 usb_port_status_t port_status;225 226 rc = get_port_status(&hub->usb_device->ctrl_pipe, port, &port_status);227 if (rc != EOK) {228 usb_log_error("Failed to get port %zu status: %s.\n",229 port, str_error(rc));230 return;231 }232 233 /*234 * Check exact nature of the change.235 */236 usb_log_debug("Port %zu change status: %x.\n", port,237 (unsigned int) port_status);238 239 if (usb_port_connect_change(&port_status)) {240 bool device_connected = usb_port_dev_connected(&port_status);241 usb_log_debug("Connection change on port %zu: %s.\n", port,242 device_connected ? "device attached" : "device removed");243 244 if (device_connected) {245 rc = add_device_phase1_new_fibril(hub, port,246 usb_port_speed(&port_status));247 if (rc != EOK) {248 usb_log_error(249 "Cannot handle change on port %zu: %s.\n",250 str_error(rc));251 }252 } else {253 usb_hub_removed_device(hub, port);254 }255 }256 257 if (usb_port_overcurrent_change(&port_status)) {258 if (usb_port_over_current(&port_status)) {259 usb_log_warning("Overcurrent on port %zu.\n", port);260 usb_hub_over_current(hub, port);261 } else {262 usb_log_debug("Overcurrent on port %zu autoresolved.\n",263 port);264 }265 }266 267 if (usb_port_reset_completed(&port_status)) {268 usb_log_debug("Port %zu reset complete.\n", port);269 if (usb_port_enabled(&port_status)) {270 /* Finalize device adding. */271 usb_hub_port_t *the_port = hub->ports + port;272 fibril_mutex_lock(&the_port->reset_mutex);273 the_port->reset_completed = true;274 fibril_condvar_broadcast(&the_port->reset_cv);275 fibril_mutex_unlock(&the_port->reset_mutex);276 } else {277 usb_log_warning(278 "Port %zu reset complete but port not enabled.\n",279 port);280 }281 }282 283 usb_port_set_connect_change(&port_status, false);284 usb_port_set_reset(&port_status, false);285 usb_port_set_reset_completed(&port_status, false);286 usb_port_set_dev_connected(&port_status, false);287 if (port_status >> 16) {288 usb_log_warning("Unsupported change on port %zu: %x.\n",289 port, (unsigned int) port_status);290 }291 }292 293 294 /** Callback for polling hub for port changes.295 *296 * @param dev Device where the change occured.297 * @param change_bitmap Bitmap of changed ports.298 * @param change_bitmap_size Size of the bitmap in bytes.299 * @param arg Custom argument, points to @c usb_hub_info_t.300 * @return Whether to continue polling.301 */302 bool hub_port_changes_callback(usb_device_t *dev,303 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)304 {305 usb_hub_info_t *hub = (usb_hub_info_t *) arg;306 307 /* FIXME: check that we received enough bytes. */308 if (change_bitmap_size == 0) {309 goto leave;310 }311 312 size_t port;313 for (port = 1; port < hub->port_count + 1; port++) {314 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;315 if (change) {316 process_port_change(hub, port);317 }318 }319 320 321 leave:322 /* FIXME: proper interval. */323 async_usleep(1000 * 1000 * 10 );324 325 return true;326 }327 328 329 427 /** 330 428 * @} -
uspace/drv/usbhub/ports.h
ref354b6 re50cd7f 36 36 #define DRV_USBHUB_PORTS_H 37 37 38 #include <ipc/devman.h> 39 #include <usb/usb.h> 40 #include <ddf/driver.h> 41 #include <fibril_synch.h> 42 38 #include <usb/devdrv.h> 43 39 #include <usb/hub.h> 44 40 45 #include <usb/pipes.h> 46 #include <usb/devdrv.h> 41 typedef struct usb_hub_info_t usb_hub_info_t; 47 42 48 43 /** Information about single port on a hub. */ … … 56 51 */ 57 52 bool reset_completed; 53 /** Whether to announce the port reset as successful. */ 54 bool reset_okay; 58 55 59 56 /** Information about attached device. */ … … 72 69 } 73 70 74 bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *); 71 72 void usb_hub_process_interrupt(usb_hub_info_t * hub, 73 uint16_t port); 74 75 75 76 76 -
uspace/drv/usbhub/usbhub.c
ref354b6 re50cd7f 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <inttypes.h> 39 40 40 41 #include <usb_iface.h> … … 44 45 #include <usb/request.h> 45 46 #include <usb/classes/hub.h> 47 #include <usb/devpoll.h> 46 48 #include <stdio.h> 47 49 … … 53 55 #include "usb/classes/classes.h" 54 56 55 static int usb_hub_trigger_connecting_non_removable_devices( 56 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor); 57 57 58 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev); 59 60 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info); 61 62 static int usb_hub_set_configuration(usb_hub_info_t * hub_info); 63 64 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info); 65 66 static int usb_process_hub_over_current(usb_hub_info_t * hub_info, 67 usb_hub_status_t status); 68 69 static int usb_process_hub_power_change(usb_hub_info_t * hub_info, 70 usb_hub_status_t status); 71 72 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info); 73 74 75 /// \TODO malloc checking 58 76 59 77 //********************************************* 60 78 // 61 79 // hub driver code, initialization 80 // 81 //********************************************* 82 83 /** 84 * Initialize hub device driver fibril 85 * 86 * Creates hub representation and fibril that periodically checks hub`s status. 87 * Hub representation is passed to the fibril. 88 * @param usb_dev generic usb device information 89 * @return error code 90 */ 91 int usb_hub_add_device(usb_device_t * usb_dev) { 92 if (!usb_dev) return EINVAL; 93 usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev); 94 //create hc connection 95 usb_log_debug("Initializing USB wire abstraction.\n"); 96 int opResult = usb_hc_connection_initialize_from_device( 97 &hub_info->connection, 98 hub_info->usb_device->ddf_dev); 99 if (opResult != EOK) { 100 usb_log_error("could not initialize connection to device, " 101 "errno %d\n", 102 opResult); 103 free(hub_info); 104 return opResult; 105 } 106 107 //usb_pipe_start_session(hub_info->control_pipe); 108 //set hub configuration 109 opResult = usb_hub_set_configuration(hub_info); 110 if (opResult != EOK) { 111 usb_log_error("could not set hub configuration, errno %d\n", 112 opResult); 113 free(hub_info); 114 return opResult; 115 } 116 //get port count and create attached_devs 117 opResult = usb_hub_process_hub_specific_info(hub_info); 118 if (opResult != EOK) { 119 usb_log_error("could process hub specific info, errno %d\n", 120 opResult); 121 free(hub_info); 122 return opResult; 123 } 124 //usb_pipe_end_session(hub_info->control_pipe); 125 126 127 usb_log_debug("Creating 'hub' function in DDF.\n"); 128 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 129 fun_exposed, "hub"); 130 assert(hub_fun != NULL); 131 hub_fun->ops = NULL; 132 133 opResult = ddf_fun_bind(hub_fun); 134 assert(opResult == EOK); 135 opResult = ddf_fun_add_to_class(hub_fun, "hub"); 136 assert(opResult == EOK); 137 138 opResult = usb_hub_start_hub_fibril(hub_info); 139 if(opResult!=EOK) 140 free(hub_info); 141 return opResult; 142 } 143 144 145 /** Callback for polling hub for changes. 146 * 147 * @param dev Device where the change occured. 148 * @param change_bitmap Bitmap of changed ports. 149 * @param change_bitmap_size Size of the bitmap in bytes. 150 * @param arg Custom argument, points to @c usb_hub_info_t. 151 * @return Whether to continue polling. 152 */ 153 bool hub_port_changes_callback(usb_device_t *dev, 154 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) { 155 usb_log_debug("hub_port_changes_callback\n"); 156 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 157 158 /* FIXME: check that we received enough bytes. */ 159 if (change_bitmap_size == 0) { 160 goto leave; 161 } 162 163 bool change; 164 change = ((uint8_t*) change_bitmap)[0] & 1; 165 if (change) { 166 usb_hub_process_global_interrupt(hub); 167 } 168 169 size_t port; 170 for (port = 1; port < hub->port_count + 1; port++) { 171 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2; 172 if (change) { 173 usb_hub_process_interrupt(hub, port); 174 } 175 } 176 leave: 177 /* FIXME: proper interval. */ 178 async_usleep(1000 * 1000 * 10); 179 180 return true; 181 } 182 183 184 //********************************************* 185 // 186 // support functions 62 187 // 63 188 //********************************************* … … 71 196 */ 72 197 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) { 73 usb_hub_info_t * result = usb_new(usb_hub_info_t);74 if (!result) return NULL;198 usb_hub_info_t * result = malloc(sizeof(usb_hub_info_t)); 199 if (!result) return NULL; 75 200 result->usb_device = usb_dev; 76 201 result->status_change_pipe = usb_dev->pipes[0].pipe; … … 90 215 * @return error code 91 216 */ 92 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {217 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) { 93 218 // get hub descriptor 94 219 usb_log_debug("creating serialized descriptor\n"); 95 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE); 220 //void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE); 221 uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE]; 96 222 usb_hub_descriptor_t * descriptor; 97 98 /* this was one fix of some bug, should not be needed anymore 99 * these lines allow to reset hub once more, it can be used as 100 * brute-force initialization for non-removable devices 101 int opResult = usb_request_set_configuration(&result->endpoints.control, 1); 102 if(opResult!=EOK){ 103 usb_log_error("could not set default configuration, errno %d",opResult); 104 return opResult; 105 } 106 */ 223 int opResult; 224 107 225 size_t received_size; 108 int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,109 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,110 USB_DESCTYPE_HUB,111 0, 0, serialized_descriptor,112 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size); 113 114 if (opResult != EOK) {115 usb_log_error("failed when receiving hub descriptor,badcode = %d\n",116 opResult);226 opResult = usb_request_get_descriptor(hub_info->control_pipe, 227 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 228 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor, 229 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size); 230 231 if (opResult != EOK) { 232 usb_log_error("failed when receiving hub descriptor, " 233 "badcode = %d\n", 234 opResult); 117 235 free(serialized_descriptor); 118 236 return opResult; 119 237 } 120 238 usb_log_debug2("deserializing descriptor\n"); 121 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor); 122 if(descriptor==NULL){ 239 descriptor = usb_create_deserialized_hub_desriptor( 240 serialized_descriptor); 241 if (descriptor == NULL) { 123 242 usb_log_warning("could not deserialize descriptor \n"); 124 return opResult;125 } 126 usb_log_debug("setting port count to %d\n", descriptor->ports_count);243 return ENOMEM; 244 } 245 usb_log_debug("setting port count to %d\n", descriptor->ports_count); 127 246 hub_info->port_count = descriptor->ports_count; 128 hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1)); 247 /// \TODO this is not semantically correct 248 bool is_power_switched = 249 ((descriptor->hub_characteristics & 1) ==0); 250 bool has_individual_port_powering = 251 ((descriptor->hub_characteristics & 1) !=0); 252 hub_info->ports = malloc( 253 sizeof (usb_hub_port_t) * (hub_info->port_count + 1)); 129 254 size_t port; 130 255 for (port = 0; port < hub_info->port_count + 1; port++) { 131 256 usb_hub_port_init(&hub_info->ports[port]); 132 257 } 133 //handle non-removable devices 134 usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor); 258 if(is_power_switched){ 259 usb_log_debug("is_power_switched\n"); 260 if(has_individual_port_powering){ 261 usb_log_debug("has_individual_port_powering\n"); 262 for (port = 0; port < hub_info->port_count; port++) { 263 opResult = usb_hub_set_port_feature(hub_info->control_pipe, 264 port+1, USB_HUB_FEATURE_PORT_POWER); 265 if (opResult != EOK) { 266 usb_log_error("cannot power on port %d; %d\n", 267 port+1, opResult); 268 } 269 } 270 }else{ 271 usb_log_debug("!has_individual_port_powering\n"); 272 opResult = usb_hub_set_feature(hub_info->control_pipe, 273 USB_HUB_FEATURE_C_HUB_LOCAL_POWER); 274 if (opResult != EOK) { 275 usb_log_error("cannot power hub; %d\n", 276 opResult); 277 } 278 } 279 }else{ 280 usb_log_debug("!is_power_switched\n"); 281 } 135 282 usb_log_debug2("freeing data\n"); 136 free(serialized_descriptor);137 free(descriptor->devices_removable);283 //free(serialized_descriptor); 284 //free(descriptor->devices_removable); 138 285 free(descriptor); 139 286 return EOK; 140 287 } 288 141 289 /** 142 290 * Set configuration of hub … … 147 295 * @return error code 148 296 */ 149 static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {297 static int usb_hub_set_configuration(usb_hub_info_t * hub_info) { 150 298 //device descriptor 151 299 usb_standard_device_descriptor_t *std_descriptor … … 153 301 usb_log_debug("hub has %d configurations\n", 154 302 std_descriptor->configuration_count); 155 if (std_descriptor->configuration_count<1){303 if (std_descriptor->configuration_count < 1) { 156 304 usb_log_error("there are no configurations available\n"); 157 305 return EINVAL; … … 173 321 } 174 322 usb_log_debug("\tused configuration %d\n", 175 config_descriptor->configuration_number);323 config_descriptor->configuration_number); 176 324 177 325 return EOK; … … 179 327 180 328 /** 181 * Initialize hub device driver fibril 182 * 183 * Creates hub representation and fibril that periodically checks hub`s status. 184 * Hub representation is passed to the fibril. 185 * @param usb_dev generic usb device information 186 * @return error code 187 */ 188 int usb_hub_add_device(usb_device_t * usb_dev){ 189 if(!usb_dev) return EINVAL; 190 usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev); 191 //create hc connection 192 usb_log_debug("Initializing USB wire abstraction.\n"); 193 int opResult = usb_hc_connection_initialize_from_device( 194 &hub_info->connection, 195 hub_info->usb_device->ddf_dev); 196 if(opResult != EOK){ 197 usb_log_error("could not initialize connection to device, errno %d\n", 198 opResult); 199 free(hub_info); 200 return opResult; 201 } 202 203 usb_pipe_start_session(hub_info->control_pipe); 204 //set hub configuration 205 opResult = usb_hub_set_configuration(hub_info); 206 if(opResult!=EOK){ 207 usb_log_error("could not set hub configuration, errno %d\n",opResult); 208 free(hub_info); 209 return opResult; 210 } 211 //get port count and create attached_devs 212 opResult = usb_hub_process_hub_specific_info(hub_info); 213 if(opResult!=EOK){ 214 usb_log_error("could not set hub configuration, errno %d\n",opResult); 215 free(hub_info); 216 return opResult; 217 } 218 usb_pipe_end_session(hub_info->control_pipe); 219 220 221 /// \TODO what is this? 222 usb_log_debug("Creating `hub' function.\n"); 223 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 224 fun_exposed, "hub"); 225 assert(hub_fun != NULL); 226 hub_fun->ops = NULL; 227 228 int rc = ddf_fun_bind(hub_fun); 229 assert(rc == EOK); 230 rc = ddf_fun_add_to_class(hub_fun, "hub"); 231 assert(rc == EOK); 232 329 * create and start fibril with hub control loop 330 * 331 * Before the fibril is started, the control pipe and host controller 332 * connection of the hub is open. 333 * 334 * @param hub_info hub representing structure 335 * @return error code 336 */ 337 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info){ 233 338 /* 234 339 * The processing will require opened control pipe and connection … … 239 344 * auto destruction, this could work better. 240 345 */ 241 rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);346 int rc = usb_hc_connection_open(&hub_info->connection); 242 347 if (rc != EOK) { 243 usb_log_error("Failed to start session on control pipe: %s.\n", 244 str_error(rc)); 245 goto leave; 246 } 247 rc = usb_hc_connection_open(&hub_info->connection); 248 if (rc != EOK) { 249 usb_pipe_end_session(&usb_dev->ctrl_pipe); 348 //usb_pipe_end_session(hub_info->control_pipe); 250 349 usb_log_error("Failed to open connection to HC: %s.\n", 251 350 str_error(rc)); 252 goto leave;351 return rc; 253 352 } 254 353 255 354 rc = usb_device_auto_poll(hub_info->usb_device, 0, 256 hub_port_changes_callback, ((hub_info->port_count +1) / 8) + 1,355 hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1, 257 356 NULL, hub_info); 258 357 if (rc != EOK) { … … 266 365 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 267 366 return EOK; 268 269 leave: 270 free(hub_info); 271 272 return rc; 273 } 274 275 276 //********************************************* 277 // 278 // hub driver code, main loop and port handling 279 // 280 //********************************************* 281 282 /** 283 * triggers actions to connect non0removable devices 284 * 285 * This will trigger operations leading to activated non-removable device. 286 * Control pipe of the hub must be open fo communication. 287 * @param hub hub representation 288 * @param descriptor usb hub descriptor 289 * @return error code 290 */ 291 static int usb_hub_trigger_connecting_non_removable_devices(usb_hub_info_t * hub, 292 usb_hub_descriptor_t * descriptor) 293 { 294 usb_log_info("attaching non-removable devices(if any)\n"); 367 } 368 369 //********************************************* 370 // 371 // change handling functions 372 // 373 //********************************************* 374 375 376 /** 377 * process hub over current change 378 * 379 * This means either to power off the hub or power it on. 380 * @param hub_info hub instance 381 * @param status hub status bitmask 382 * @return error code 383 */ 384 static int usb_process_hub_over_current(usb_hub_info_t * hub_info, 385 usb_hub_status_t status) { 386 int opResult; 387 if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_OVER_CURRENT)){ 388 opResult = usb_hub_clear_feature(hub_info->control_pipe, 389 USB_HUB_FEATURE_HUB_LOCAL_POWER); 390 if (opResult != EOK) { 391 usb_log_error("cannot power off hub: %d\n", 392 opResult); 393 } 394 } else { 395 opResult = usb_hub_set_feature(hub_info->control_pipe, 396 USB_HUB_FEATURE_HUB_LOCAL_POWER); 397 if (opResult != EOK) { 398 usb_log_error("cannot power on hub: %d\n", 399 opResult); 400 } 401 } 402 return opResult; 403 } 404 405 /** 406 * process hub power change 407 * 408 * If the power has been lost, reestablish it. 409 * If it was reestablished, re-power all ports. 410 * @param hub_info hub instance 411 * @param status hub status bitmask 412 * @return error code 413 */ 414 static int usb_process_hub_power_change(usb_hub_info_t * hub_info, 415 usb_hub_status_t status) { 416 int opResult; 417 if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_LOCAL_POWER)) { 418 //restart power on hub 419 opResult = usb_hub_set_feature(hub_info->control_pipe, 420 USB_HUB_FEATURE_HUB_LOCAL_POWER); 421 if (opResult != EOK) { 422 usb_log_error("cannot power on hub: %d\n", 423 opResult); 424 } 425 } else {//power reestablished on hub- restart ports 426 size_t port; 427 for (port = 0; port < hub_info->port_count; ++port) { 428 opResult = usb_hub_set_port_feature( 429 hub_info->control_pipe, 430 port, USB_HUB_FEATURE_PORT_POWER); 431 if (opResult != EOK) { 432 usb_log_error("cannot power on port %d; %d\n", 433 port, opResult); 434 } 435 } 436 } 437 return opResult; 438 } 439 440 /** 441 * process hub interrupts 442 * 443 * The change can be either in the over-current condition or 444 * local-power lost condition. 445 * @param hub_info hub instance 446 */ 447 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info) { 448 usb_log_debug("global interrupt on a hub\n"); 449 usb_pipe_t *pipe = hub_info->control_pipe; 450 int opResult; 451 452 usb_port_status_t status; 453 size_t rcvd_size; 295 454 usb_device_request_setup_packet_t request; 296 int opResult; 297 size_t rcvd_size; 298 usb_port_status_t status; 299 uint8_t * non_removable_dev_bitmap = descriptor->devices_removable; 300 int port; 301 for(port=1;port<=descriptor->ports_count;++port){ 302 bool is_non_removable = 303 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2; 304 if(is_non_removable){ 305 usb_log_debug("non-removable device on port %d\n",port); 306 usb_hub_set_port_status_request(&request, port); 307 opResult = usb_pipe_control_read( 308 hub->control_pipe, 309 &request, sizeof(usb_device_request_setup_packet_t), 310 &status, 4, &rcvd_size 311 ); 312 if (opResult != EOK) { 313 usb_log_error("could not get port status of port %d errno:%d\n", 314 port, opResult); 315 return opResult; 316 } 317 //set the status change bit, so it will be noticed in driver loop 318 if(usb_port_dev_connected(&status)){ 319 usb_hub_set_disable_port_feature_request(&request, port, 320 USB_HUB_FEATURE_PORT_CONNECTION); 321 opResult = usb_pipe_control_read( 322 hub->control_pipe, 323 &request, sizeof(usb_device_request_setup_packet_t), 324 &status, 4, &rcvd_size 325 ); 326 if (opResult != EOK) { 327 usb_log_warning( 328 "could not clear port connection on port %d errno:%d\n", 329 port, opResult); 330 } 331 usb_log_debug("cleared port connection\n"); 332 usb_hub_set_enable_port_feature_request(&request, port, 333 USB_HUB_FEATURE_PORT_ENABLE); 334 opResult = usb_pipe_control_read( 335 hub->control_pipe, 336 &request, sizeof(usb_device_request_setup_packet_t), 337 &status, 4, &rcvd_size 338 ); 339 if (opResult != EOK) { 340 usb_log_warning( 341 "could not set port enabled on port %d errno:%d\n", 342 port, opResult); 343 } 344 usb_log_debug("port set to enabled - should lead to connection change\n"); 345 } 346 } 347 } 348 /// \TODO this is just a debug code 349 for(port=1;port<=descriptor->ports_count;++port){ 350 bool is_non_removable = 351 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2; 352 if(is_non_removable){ 353 usb_log_debug("port %d is non-removable\n",port); 354 usb_port_status_t status; 355 size_t rcvd_size; 356 usb_device_request_setup_packet_t request; 357 //int opResult; 358 usb_hub_set_port_status_request(&request, port); 359 //endpoint 0 360 opResult = usb_pipe_control_read( 361 hub->control_pipe, 362 &request, sizeof(usb_device_request_setup_packet_t), 363 &status, 4, &rcvd_size 364 ); 365 if (opResult != EOK) { 366 usb_log_error("could not get port status %d\n",opResult); 367 } 368 if (rcvd_size != sizeof (usb_port_status_t)) { 369 usb_log_error("received status has incorrect size\n"); 370 } 371 //something connected/disconnected 372 if (usb_port_connect_change(&status)) { 373 usb_log_debug("some connection changed\n"); 374 } 375 usb_log_debug("status: %s\n",usb_debug_str_buffer( 376 (uint8_t *)&status,4,4)); 377 } 378 } 379 return EOK; 380 } 381 382 383 /** 384 * release default address used by given hub 385 * 386 * Also unsets hub->is_default_address_used. Convenience wrapper function. 387 * @note hub->connection MUST be open for communication 388 * @param hub hub representation 389 * @return error code 390 */ 391 static int usb_hub_release_default_address(usb_hub_info_t * hub){ 392 int opResult = usb_hc_release_default_address(&hub->connection); 393 if(opResult!=EOK){ 394 usb_log_error("could not release default address, errno %d\n",opResult); 395 return opResult; 396 } 397 hub->is_default_address_used = false; 398 return EOK; 399 } 400 401 /** 402 * routine called when a device on port has been removed 403 * 404 * If the device on port had default address, it releases default address. 405 * Otherwise does not do anything, because DDF does not allow to remove device 406 * from it`s device tree. 407 * @param hub hub representation 408 * @param port port number, starting from 1 409 */ 410 void usb_hub_removed_device( 411 usb_hub_info_t * hub,uint16_t port) { 412 413 int opResult = usb_hub_clear_port_feature(hub->control_pipe, 414 port, USB_HUB_FEATURE_C_PORT_CONNECTION); 415 if(opResult != EOK){ 416 usb_log_warning("could not clear port-change-connection flag\n"); 417 } 418 /** \TODO remove device from device manager - not yet implemented in 419 * devide manager 420 */ 421 422 //close address 423 if(hub->ports[port].attached_device.address >= 0){ 424 /*uncomment this code to use it when DDF allows device removal 425 opResult = usb_hc_unregister_device( 426 &hub->connection, hub->attached_devs[port].address); 427 if(opResult != EOK) { 428 dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \ 429 "removed device: %d", opResult); 430 } 431 hub->attached_devs[port].address = 0; 432 hub->attached_devs[port].handle = 0; 433 */ 434 }else{ 435 usb_log_warning("this is strange, disconnected device had no address\n"); 436 //device was disconnected before it`s port was reset - return default address 437 usb_hub_release_default_address(hub); 438 } 439 } 440 441 442 /** 443 * Process over current condition on port. 444 * 445 * Turn off the power on the port. 446 * 447 * @param hub hub representation 448 * @param port port number, starting from 1 449 */ 450 void usb_hub_over_current( usb_hub_info_t * hub, 451 uint16_t port){ 452 int opResult; 453 opResult = usb_hub_clear_port_feature(hub->control_pipe, 454 port, USB_HUB_FEATURE_PORT_POWER); 455 if(opResult!=EOK){ 456 usb_log_error("cannot power off port %d; %d\n", 457 port, opResult); 458 } 459 } 460 455 //int opResult; 456 usb_hub_set_hub_status_request(&request); 457 //endpoint 0 458 459 opResult = usb_pipe_control_read( 460 pipe, 461 &request, sizeof (usb_device_request_setup_packet_t), 462 &status, 4, &rcvd_size 463 ); 464 if (opResult != EOK) { 465 usb_log_error("could not get hub status\n"); 466 return; 467 } 468 if (rcvd_size != sizeof (usb_port_status_t)) { 469 usb_log_error("received status has incorrect size\n"); 470 return; 471 } 472 //port reset 473 if ( 474 usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) { 475 usb_process_hub_over_current(hub_info, status); 476 } 477 if ( 478 usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) { 479 usb_process_hub_power_change(hub_info, status); 480 } 481 } 461 482 462 483 /** -
uspace/drv/usbhub/usbhub.h
ref354b6 re50cd7f 37 37 38 38 #include <ipc/devman.h> 39 #include <usb/usb.h>40 39 #include <ddf/driver.h> 41 40 42 #define NAME "usbhub"43 44 41 #include <usb/hub.h> 42 #include <usb/classes/hub.h> 45 43 46 44 #include <usb/pipes.h> 47 45 #include <usb/devdrv.h> 46 47 #include <fibril_synch.h> 48 49 #define NAME "usbhub" 48 50 49 51 #include "ports.h" … … 52 54 53 55 /** Information about attached hub. */ 54 typedef struct{56 struct usb_hub_info_t{ 55 57 /** Number of ports. */ 56 58 size_t port_count; 57 59 58 /** Ports.*/60 /** attached device handles, for each port one */ 59 61 usb_hub_port_t *ports; 60 62 61 63 /** connection to hcd */ 62 64 usb_hc_connection_t connection; … … 87 89 /** generic usb device data*/ 88 90 usb_device_t * usb_device; 89 } usb_hub_info_t;91 }; 90 92 91 /** 92 * function running the hub-controlling loop. 93 * @param hub_info_param hub info pointer 94 */ 95 int usb_hub_control_loop(void * hub_info_param); 96 97 /** 98 * Check changes on specified hub 99 * @param hub_info_param pointer to usb_hub_info_t structure 100 * @return error code if there is problem when initializing communication with 101 * hub, EOK otherwise 102 */ 103 int usb_hub_check_hub_changes(usb_hub_info_t * hub_info_param); 104 105 void usb_hub_removed_device(usb_hub_info_t *, uint16_t); 106 void usb_hub_over_current(usb_hub_info_t *, uint16_t); 93 //int usb_hub_control_loop(void * hub_info_param); 107 94 108 95 int usb_hub_add_device(usb_device_t * usb_dev); 96 97 bool hub_port_changes_callback(usb_device_t *dev, 98 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg); 109 99 110 100 #endif -
uspace/drv/usbhub/usbhub_private.h
ref354b6 re50cd7f 54 54 // 55 55 //************ 56 #define usb_new(type) (type*)malloc(sizeof(type))57 56 58 57 59 /**60 * Create hub structure instance61 *62 * Set the address and port count information most importantly.63 *64 * @param device65 * @param hc host controller phone66 * @return67 */68 58 usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device); 69 59 … … 110 100 111 101 /** 112 * create uint8_t array with serialized descriptor102 * Clear feature on hub port. 113 103 * 114 * @param descriptor 115 * @return newly created serializd descriptor pointer 104 * @param hc Host controller telephone 105 * @param address Hub address 106 * @param port_index Port 107 * @param feature Feature selector 108 * @return Operation result 116 109 */ 117 void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor); 110 static inline int usb_hub_set_port_feature(usb_pipe_t *pipe, 111 int port_index, 112 usb_hub_class_feature_t feature) { 113 114 usb_device_request_setup_packet_t clear_request = { 115 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 116 .request = USB_DEVREQ_SET_FEATURE, 117 .length = 0, 118 .index = port_index 119 }; 120 clear_request.value = feature; 121 return usb_pipe_control_write(pipe, &clear_request, 122 sizeof(clear_request), NULL, 0); 123 } 124 118 125 119 126 /** 120 * create deserialized desriptor structure out of serialized descriptor127 * Clear feature on hub port. 121 128 * 122 * The serialized descriptor must be proper usb hub descriptor, 123 * otherwise an eerror might occur. 129 * @param pipe pipe to hub control endpoint 130 * @param feature Feature selector 131 * @return Operation result 132 */ 133 static inline int usb_hub_clear_feature(usb_pipe_t *pipe, 134 usb_hub_class_feature_t feature) { 135 136 usb_device_request_setup_packet_t clear_request = { 137 .request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE, 138 .request = USB_DEVREQ_CLEAR_FEATURE, 139 .length = 0, 140 .index = 0 141 }; 142 clear_request.value = feature; 143 return usb_pipe_control_write(pipe, &clear_request, 144 sizeof(clear_request), NULL, 0); 145 } 146 147 /** 148 * Clear feature on hub port. 124 149 * 125 * @param sdescriptor serialized descriptor 126 * @return newly created deserialized descriptor pointer 150 * @param pipe pipe to hub control endpoint 151 * @param feature Feature selector 152 * @return Operation result 127 153 */ 128 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * sdescriptor); 154 static inline int usb_hub_set_feature(usb_pipe_t *pipe, 155 usb_hub_class_feature_t feature) { 156 157 usb_device_request_setup_packet_t clear_request = { 158 .request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE, 159 .request = USB_DEVREQ_SET_FEATURE, 160 .length = 0, 161 .index = 0 162 }; 163 clear_request.value = feature; 164 return usb_pipe_control_write(pipe, &clear_request, 165 sizeof(clear_request), NULL, 0); 166 } 167 168 169 void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor); 170 171 void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor, 172 void * serialized_descriptor); 173 174 usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor( 175 void * serialized_descriptor); 176 177 void usb_deserialize_hub_desriptor(void * serialized_descriptor, 178 usb_hub_descriptor_t * descriptor); 129 179 130 180 -
uspace/drv/usbhub/utils.c
ref354b6 re50cd7f 56 56 //hub descriptor utils 57 57 58 void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) { 58 /** 59 * create uint8_t array with serialized descriptor 60 * 61 * @param descriptor 62 * @return newly created serializd descriptor pointer 63 */ 64 void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor) { 59 65 //base size 60 66 size_t size = 7; 61 67 //variable size according to port count 62 size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);68 size_t var_size = (descriptor->ports_count+7)/8; 63 69 size += 2 * var_size; 64 uint8_t * result = (uint8_t*)malloc(size);70 uint8_t * result = malloc(size); 65 71 //size 66 result[0] = size; 72 if(result) 73 usb_serialize_hub_descriptor(descriptor,result); 74 return result; 75 } 76 77 /** 78 * serialize descriptor into given buffer 79 * 80 * The buffer size is not checked. 81 * @param descriptor 82 * @param serialized_descriptor 83 */ 84 void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor, 85 void * serialized_descriptor) { 86 //base size 87 uint8_t * sdescriptor = serialized_descriptor; 88 size_t size = 7; 89 //variable size according to port count 90 size_t var_size = (descriptor->ports_count+7)/8; 91 size += 2 * var_size; 92 //size 93 sdescriptor[0] = size; 67 94 //descriptor type 68 result[1] = USB_DESCTYPE_HUB;69 result[2] = descriptor->ports_count;95 sdescriptor[1] = USB_DESCTYPE_HUB; 96 sdescriptor[2] = descriptor->ports_count; 70 97 /// @fixme handling of endianness?? 71 result[3] = descriptor->hub_characteristics / 256;72 result[4] = descriptor->hub_characteristics % 256;73 result[5] = descriptor->pwr_on_2_good_time;74 result[6] = descriptor->current_requirement;98 sdescriptor[3] = descriptor->hub_characteristics / 256; 99 sdescriptor[4] = descriptor->hub_characteristics % 256; 100 sdescriptor[5] = descriptor->pwr_on_2_good_time; 101 sdescriptor[6] = descriptor->current_requirement; 75 102 76 103 size_t i; 77 104 for (i = 0; i < var_size; ++i) { 78 result[7 + i] = descriptor->devices_removable[i];105 sdescriptor[7 + i] = descriptor->devices_removable[i]; 79 106 } 80 107 for (i = 0; i < var_size; ++i) { 81 result[7 + var_size + i] = 255;108 sdescriptor[7 + var_size + i] = 255; 82 109 } 110 } 111 112 113 /** 114 * create deserialized desriptor structure out of serialized descriptor 115 * 116 * The serialized descriptor must be proper usb hub descriptor, 117 * otherwise an eerror might occur. 118 * 119 * @param sdescriptor serialized descriptor 120 * @return newly created deserialized descriptor pointer 121 */ 122 usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor( 123 void * serialized_descriptor) { 124 uint8_t * sdescriptor = serialized_descriptor; 125 126 if (sdescriptor[1] != USB_DESCTYPE_HUB) { 127 usb_log_warning("trying to deserialize wrong descriptor %x\n", 128 sdescriptor[1]); 129 return NULL; 130 } 131 132 usb_hub_descriptor_t * result = malloc(sizeof(usb_hub_descriptor_t)); 133 if(result) 134 usb_deserialize_hub_desriptor(serialized_descriptor,result); 83 135 return result; 84 136 } 85 137 86 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) { 87 uint8_t * sdescriptor = (uint8_t*) serialized_descriptor; 88 89 if (sdescriptor[1] != USB_DESCTYPE_HUB) { 90 usb_log_warning("trying to deserialize wrong descriptor %x\n",sdescriptor[1]); 91 return NULL; 92 } 93 94 usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t); 95 96 97 result->ports_count = sdescriptor[2]; 138 /** 139 * deserialize descriptor into given pointer 140 * 141 * @param serialized_descriptor 142 * @param descriptor 143 * @return 144 */ 145 void usb_deserialize_hub_desriptor( 146 void * serialized_descriptor, usb_hub_descriptor_t * descriptor) { 147 uint8_t * sdescriptor = serialized_descriptor; 148 descriptor->ports_count = sdescriptor[2]; 98 149 /// @fixme handling of endianness?? 99 result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3]; 100 result->pwr_on_2_good_time = sdescriptor[5]; 101 result->current_requirement = sdescriptor[6]; 102 size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) 103 ? 1 : 0); 104 result->devices_removable = (uint8_t*) malloc(var_size); 150 descriptor->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3]; 151 descriptor->pwr_on_2_good_time = sdescriptor[5]; 152 descriptor->current_requirement = sdescriptor[6]; 153 size_t var_size = (descriptor->ports_count+7) / 8; 154 //descriptor->devices_removable = (uint8_t*) malloc(var_size); 105 155 106 156 size_t i; 107 157 for (i = 0; i < var_size; ++i) { 108 result->devices_removable[i] = sdescriptor[7 + i];158 descriptor->devices_removable[i] = sdescriptor[7 + i]; 109 159 } 110 return result;111 160 } 112 113 114 161 115 162 /** -
uspace/drv/usbkbd/kbddev.c
ref354b6 re50cd7f 268 268 static void usb_kbd_set_led(usb_kbd_t *kbd_dev) 269 269 { 270 if (kbd_dev->output_size == 0) { 271 return; 272 } 273 270 274 unsigned i = 0; 271 275 … … 544 548 * according to HID Usage Tables. 545 549 * @param count Number of key codes in report (size of the report). 546 * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI).550 * @param report_id 547 551 * @param arg User-specified argument. Expects pointer to the keyboard device 548 552 * structure representing the keyboard. … … 551 555 */ 552 556 static void usb_kbd_process_keycodes(const uint8_t *key_codes, size_t count, 553 uint8_t modifiers, void *arg)557 uint8_t report_id, void *arg) 554 558 { 555 559 if (arg == NULL) { … … 562 566 assert(kbd_dev != NULL); 563 567 564 usb_log_debug("Got keys from parser (report id: %d): %s\n", modifiers,568 usb_log_debug("Got keys from parser (report id: %d): %s\n", report_id, 565 569 usb_debug_str_buffer(key_codes, count, 0)); 566 570 … … 763 767 usb_hid_report_path_t *path = usb_hid_report_path(); 764 768 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0); 769 770 usb_hid_report_path_set_report_id(path, 0); 771 765 772 kbd_dev->key_count = usb_hid_report_input_length( 766 773 kbd_dev->parser, path, USB_HID_PATH_COMPARE_END); … … 796 803 797 804 kbd_dev->led_output_size = usb_hid_report_output_size(kbd_dev->parser, 798 kbd_dev->led_path, USB_HID_PATH_COMPARE_END); 805 kbd_dev->led_path, 806 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY); 799 807 800 808 usb_log_debug("Output report size (in items): %zu\n", -
uspace/drv/usbkbd/main.c
ref354b6 re50cd7f 33 33 /** 34 34 * @file 35 * Main routines of USB HID driver.35 * Main routines of USB KBD driver. 36 36 */ 37 37 … … 42 42 43 43 #include <usb/devdrv.h> 44 #include <usb/devpoll.h> 44 45 45 46 #include "kbddev.h" … … 75 76 * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril() 76 77 */ 77 static int usb hid_try_add_device(usb_device_t *dev)78 static int usb_kbd_try_add_device(usb_device_t *dev) 78 79 { 79 80 /* Create the function exposed under /dev/devices. */ … … 105 106 usb_kbd_free(&kbd_dev); 106 107 return rc; 107 } 108 } 108 109 109 110 usb_log_debug("USB/HID KBD device structure initialized.\n"); … … 195 196 * @retval EREFUSED if the device is not supported. 196 197 */ 197 static int usb hid_add_device(usb_device_t *dev)198 static int usb_kbd_add_device(usb_device_t *dev) 198 199 { 199 usb_log_debug("usb hid_add_device()\n");200 usb_log_debug("usb_kbd_add_device()\n"); 200 201 201 202 if (dev->interface_no < 0) { 202 203 usb_log_warning("Device is not a supported keyboard.\n"); 203 usb_log_error("Failed to add HID device: endpoint not found."204 " \n");204 usb_log_error("Failed to add USB KBD device: endpoint not " 205 "found.\n"); 205 206 return ENOTSUP; 206 207 } 207 208 208 int rc = usb hid_try_add_device(dev);209 int rc = usb_kbd_try_add_device(dev); 209 210 210 211 if (rc != EOK) { 211 212 usb_log_warning("Device is not a supported keyboard.\n"); 212 usb_log_error("Failed to add HID device: %s.\n",213 usb_log_error("Failed to add KBD device: %s.\n", 213 214 str_error(rc)); 214 215 return rc; … … 224 225 /* Currently, the framework supports only device adding. Once the framework 225 226 * supports unplug, more callbacks will be added. */ 226 static usb_driver_ops_t usb hid_driver_ops = {227 .add_device = usb hid_add_device,227 static usb_driver_ops_t usb_kbd_driver_ops = { 228 .add_device = usb_kbd_add_device, 228 229 }; 229 230 230 231 231 232 /* The driver itself. */ 232 static usb_driver_t usb hid_driver = {233 static usb_driver_t usb_kbd_driver = { 233 234 .name = NAME, 234 .ops = &usb hid_driver_ops,235 .ops = &usb_kbd_driver_ops, 235 236 .endpoints = usb_kbd_endpoints 236 237 }; … … 238 239 /*----------------------------------------------------------------------------*/ 239 240 240 //static driver_ops_t kbd_driver_ops = {241 // .add_device = usbhid_add_device,242 //};243 244 ///*----------------------------------------------------------------------------*/245 246 //static driver_t kbd_driver = {247 // .name = NAME,248 // .driver_ops = &kbd_driver_ops249 //};250 251 /*----------------------------------------------------------------------------*/252 253 241 int main(int argc, char *argv[]) 254 242 { 255 printf(NAME ": HelenOS USB HID driver.\n");243 printf(NAME ": HelenOS USB KBD driver.\n"); 256 244 257 245 usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME); 258 246 259 return usb_driver_main(&usb hid_driver);247 return usb_driver_main(&usb_kbd_driver); 260 248 } 261 249 -
uspace/drv/usbkbd/usbkbd.ma
ref354b6 re50cd7f 1 100 usb&interface&class=HID&subclass=0x01&protocol=0x01 2 10 usb&interface&class=HID 1 10 usb&interface&class=HID&subclass=0x01&protocol=0x01 -
uspace/drv/usbmid/main.c
ref354b6 re50cd7f 55 55 int rc; 56 56 57 rc = usb_pipe_start_ session(&dev->ctrl_pipe);57 rc = usb_pipe_start_long_transfer(&dev->ctrl_pipe); 58 58 if (rc != EOK) { 59 usb_log_error("Failed to start sessionon control pipe: %s.\n",59 usb_log_error("Failed to start transfer on control pipe: %s.\n", 60 60 str_error(rc)); 61 61 return rc; … … 64 64 bool accept = usbmid_explore_device(dev); 65 65 66 rc = usb_pipe_end_session(&dev->ctrl_pipe); 67 if (rc != EOK) { 68 usb_log_warning("Failed to end session on control pipe: %s.\n", 69 str_error(rc)); 70 } 66 usb_pipe_end_long_transfer(&dev->ctrl_pipe); 71 67 72 68 if (!accept) { -
uspace/drv/usbmouse/main.c
ref354b6 re50cd7f 36 36 #include "mouse.h" 37 37 #include <usb/debug.h> 38 #include <usb/devpoll.h> 38 39 #include <errno.h> 39 40 #include <str_error.h> -
uspace/drv/vhc/connhost.c
ref354b6 re50cd7f 257 257 258 258 static int interrupt_out(ddf_fun_t *fun, usb_target_t target, 259 size_t max_packet_size,260 259 void *data, size_t size, 261 260 usbhc_iface_transfer_out_callback_t callback, void *arg) … … 267 266 268 267 static int interrupt_in(ddf_fun_t *fun, usb_target_t target, 269 size_t max_packet_size,270 268 void *data, size_t size, 271 269 usbhc_iface_transfer_in_callback_t callback, void *arg) … … 277 275 278 276 static int control_write(ddf_fun_t *fun, usb_target_t target, 279 size_t max_packet_size,280 277 void *setup_packet, size_t setup_packet_size, 281 278 void *data, size_t data_size, … … 295 292 296 293 static int control_read(ddf_fun_t *fun, usb_target_t target, 297 size_t max_packet_size,298 294 void *setup_packet, size_t setup_packet_size, 299 295 void *data, size_t data_size, … … 328 324 } 329 325 330 static int reserve_default_address(ddf_fun_t *fun, usb_speed_t ignored)331 {332 usb_address_keeping_reserve_default(&addresses);333 return EOK;334 }335 336 static int release_default_address(ddf_fun_t *fun)337 {338 usb_address_keeping_release_default(&addresses);339 return EOK;340 }341 342 326 static int request_address(ddf_fun_t *fun, usb_speed_t ignored, 343 327 usb_address_t *address) … … 392 376 393 377 usbhc_iface_t vhc_iface = { 394 .reserve_default_address = reserve_default_address,395 .release_default_address = release_default_address,396 378 .request_address = request_address, 397 379 .bind_address = bind_address,
Note:
See TracChangeset
for help on using the changeset viewer.
