Changeset d8b275d in mainline for uspace/drv
- Timestamp:
- 2011-04-14T08:24:29Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5e07e2b5
- Parents:
- 3f2af64 (diff), 34e8bab (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:
-
- 4 added
- 46 edited
- 4 moved
-
isa/isa.c (modified) (1 diff)
-
ohci/Makefile (modified) (2 diffs)
-
ohci/batch.c (modified) (13 diffs)
-
ohci/batch.h (modified) (1 diff)
-
ohci/endpoint_list.c (moved) (moved from uspace/drv/ohci/transfer_list.c ) (7 diffs)
-
ohci/endpoint_list.h (moved) (moved from uspace/drv/ohci/transfer_list.h ) (4 diffs)
-
ohci/hc.c (modified) (11 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/endpoint_descriptor.c (modified) (1 diff)
-
ohci/hw_struct/endpoint_descriptor.h (modified) (3 diffs)
-
ohci/hw_struct/hcca.h (modified) (1 diff)
-
ohci/hw_struct/transfer_descriptor.c (modified) (1 diff)
-
ohci/hw_struct/transfer_descriptor.h (modified) (2 diffs)
-
ohci/iface.c (modified) (14 diffs)
-
ohci/ohci.ma (modified) (1 diff)
-
ohci/ohci_regs.h (modified) (1 diff)
-
ohci/root_hub.c (modified) (6 diffs)
-
ohci/root_hub.h (modified) (2 diffs)
-
ohci/utils/malloc32.h (modified) (2 diffs)
-
uhci-hcd/batch.c (modified) (13 diffs)
-
uhci-hcd/batch.h (modified) (1 diff)
-
uhci-hcd/hc.c (modified) (8 diffs)
-
uhci-hcd/hc.h (modified) (5 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) (9 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)
-
usbhid/Makefile (modified) (1 diff)
-
usbhid/generic/hiddev.c (modified) (2 diffs)
-
usbhid/generic/hiddev.h (modified) (2 diffs)
-
usbhid/kbd/conv.h (modified) (1 diff)
-
usbhid/kbd/kbddev.c (modified) (3 diffs)
-
usbhid/kbd/kbddev.h (modified) (8 diffs)
-
usbhid/kbd/kbdrepeat.h (modified) (2 diffs)
-
usbhid/layout.h (modified) (1 diff)
-
usbhid/main.c (modified) (3 diffs)
-
usbhid/mouse/mousedev.c (added)
-
usbhid/mouse/mousedev.h (added)
-
usbhid/subdrivers.c (moved) (moved from kernel/generic/src/proc/tasklet.c ) (2 diffs)
-
usbhid/subdrivers.h (added)
-
usbhid/usbhid.c (modified) (11 diffs)
-
usbhid/usbhid.h (modified) (5 diffs)
-
usbhid/usbhid.ma (modified) (1 diff)
-
usbhub/usbhub.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/isa/isa.c
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 34 34 SOURCES = \ 35 35 batch.c \ 36 endpoint_list.c \ 36 37 hc.c \ 38 hcd_endpoint.c \ 37 39 iface.c \ 38 40 main.c \ … … 40 42 pci.c \ 41 43 root_hub.c \ 42 transfer_list.c \43 44 hw_struct/endpoint_descriptor.c \ 44 45 hw_struct/transfer_descriptor.c -
uspace/drv/ohci/batch.c
r3f2af64 rd8b275d 39 39 40 40 #include "batch.h" 41 #include "hcd_endpoint.h" 41 42 #include "utils/malloc32.h" 42 43 #include "hw_struct/endpoint_descriptor.h" 43 44 #include "hw_struct/transfer_descriptor.h" 44 45 45 typedef struct ohci_ batch {46 typedef struct ohci_transfer_batch { 46 47 ed_t *ed; 47 td_t * tds;48 td_t **tds; 48 49 size_t td_count; 49 } ohci_batch_t; 50 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 /*----------------------------------------------------------------------------*/ 51 71 static void batch_control(usb_transfer_batch_t *instance, 52 72 usb_direction_t data_dir, usb_direction_t status_dir); 53 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance); 54 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance); 55 56 #define DEFAULT_ERROR_COUNT 3 73 static void batch_data(usb_transfer_batch_t *instance); 74 /*----------------------------------------------------------------------------*/ 57 75 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, 58 76 char *buffer, size_t buffer_size, char* setup_buffer, size_t setup_size, … … 64 82 usb_log_error(message); \ 65 83 if (instance) { \ 66 batch_dispose(instance); \84 usb_transfer_batch_dispose(instance); \ 67 85 } \ 68 86 return NULL; \ … … 72 90 CHECK_NULL_DISPOSE_RETURN(instance, 73 91 "Failed to allocate batch instance.\n"); 74 usb_target_t target = 75 { .address = ep->address, .endpoint = ep->endpoint }; 76 usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed, 77 ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size, 78 func_in, func_out, arg, fun, ep, NULL); 79 80 ohci_batch_t *data = malloc(sizeof(ohci_batch_t)); 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); 81 100 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n"); 82 bzero(data, sizeof(ohci_batch_t));83 101 instance->private_data = data; 84 102 85 /* we needs + 1 transfer descriptor as the last one won't be executed */ 86 data->td_count = 1 + 103 data->td_count = 87 104 ((buffer_size + OHCI_TD_MAX_TRANSFER - 1) / OHCI_TD_MAX_TRANSFER); 88 105 if (ep->transfer_type == USB_TRANSFER_CONTROL) { … … 90 107 } 91 108 92 data->tds = malloc32(sizeof(td_t) * data->td_count); 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); 93 111 CHECK_NULL_DISPOSE_RETURN(data->tds, 94 112 "Failed to allocate transfer descriptors.\n"); 95 bzero(data->tds, sizeof(td_t) * data->td_count); 96 97 data->ed = malloc32(sizeof(ed_t)); 98 CHECK_NULL_DISPOSE_RETURN(data->ed, 99 "Failed to allocate endpoint descriptor.\n"); 100 101 if (buffer_size > 0) { 102 instance->transport_buffer = malloc32(buffer_size); 103 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 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, 104 128 "Failed to allocate device accessible buffer.\n"); 105 } 106 107 if (setup_size > 0) { 108 instance->setup_buffer = malloc32(setup_size); 109 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 110 "Failed to allocate device accessible setup buffer.\n"); 129 instance->setup_buffer = data->device_buffer; 130 instance->data_buffer = data->device_buffer + setup_size; 111 131 memcpy(instance->setup_buffer, setup_buffer, setup_size); 112 132 } … … 115 135 } 116 136 /*----------------------------------------------------------------------------*/ 117 void batch_dispose(usb_transfer_batch_t *instance)118 {119 assert(instance);120 ohci_batch_t *data = instance->private_data;121 assert(data);122 free32(data->ed);123 free32(data->tds);124 free32(instance->setup_buffer);125 free32(instance->transport_buffer);126 free(data);127 free(instance);128 }129 /*----------------------------------------------------------------------------*/130 137 bool batch_is_complete(usb_transfer_batch_t *instance) 131 138 { 132 139 assert(instance); 133 ohci_ batch_t *data = instance->private_data;134 assert(data); 135 size_t tds = data->td_count - 1;136 usb_log_debug 2("Batch(%p) checking %d td(s) for completion.\n",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", 137 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); 138 148 size_t i = 0; 139 149 for (; i < tds; ++i) { 140 if (!td_is_finished(&data->tds[i])) 150 assert(data->tds[i] != NULL); 151 usb_log_debug("TD %d: %x:%x:%x:%x.\n", i, 152 data->tds[i]->status, data->tds[i]->cbp, data->tds[i]->next, 153 data->tds[i]->be); 154 if (!td_is_finished(data->tds[i])) { 141 155 return false; 142 instance->error = td_error(&data->tds[i]); 156 } 157 instance->error = td_error(data->tds[i]); 143 158 /* FIXME: calculate real transfered size */ 144 159 instance->transfered_size = instance->buffer_size; 145 160 if (instance->error != EOK) { 146 161 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 147 instance, i, data->tds[i].status); 148 return true; 149 // endpoint_toggle_set(instance->ep, 162 instance, i, data->tds[i]->status); 163 break; 150 164 } 151 165 } 166 data->leave_td = i; 167 assert(data->leave_td <= data->td_count); 168 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(instance->ep); 169 assert(hcd_ep); 170 hcd_ep->td = data->tds[i]; 171 152 172 return true; 153 173 } 154 174 /*----------------------------------------------------------------------------*/ 175 void batch_commit(usb_transfer_batch_t *instance) 176 { 177 assert(instance); 178 ohci_transfer_batch_t *data = instance->private_data; 179 assert(data); 180 ed_set_end_td(data->ed, data->tds[data->td_count]); 181 } 182 /*----------------------------------------------------------------------------*/ 155 183 void batch_control_write(usb_transfer_batch_t *instance) 156 184 { 157 185 assert(instance); 158 186 /* We are data out, we are supposed to provide data */ 159 memcpy(instance->transport_buffer, instance->buffer, 160 instance->buffer_size); 161 instance->next_step = batch_call_out_and_dispose; 187 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 188 instance->next_step = usb_transfer_batch_call_out_and_dispose; 162 189 batch_control(instance, USB_DIRECTION_OUT, USB_DIRECTION_IN); 163 190 usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance); … … 167 194 { 168 195 assert(instance); 169 instance->next_step = batch_call_in_and_dispose;196 instance->next_step = usb_transfer_batch_call_in_and_dispose; 170 197 batch_control(instance, USB_DIRECTION_IN, USB_DIRECTION_OUT); 171 198 usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance); … … 175 202 { 176 203 assert(instance); 177 assert(instance->direction == USB_DIRECTION_IN); 178 instance->next_step = batch_call_in_and_dispose; 179 /* TODO: implement */ 204 instance->next_step = usb_transfer_batch_call_in_and_dispose; 205 batch_data(instance); 180 206 usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance); 181 207 } … … 184 210 { 185 211 assert(instance); 186 assert(instance->direction == USB_DIRECTION_OUT);187 212 /* We are data out, we are supposed to provide data */ 188 memcpy(instance->transport_buffer, instance->buffer, 189 instance->buffer_size); 190 instance->next_step = batch_call_out_and_dispose; 191 /* TODO: implement */ 213 memcpy(instance->data_buffer, instance->buffer, instance->buffer_size); 214 instance->next_step = usb_transfer_batch_call_out_and_dispose; 215 batch_data(instance); 192 216 usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance); 193 217 } … … 196 220 { 197 221 assert(instance); 198 instance->direction = USB_DIRECTION_IN; 199 instance->next_step = batch_call_in_and_dispose; 200 /* TODO: implement */ 222 instance->next_step = usb_transfer_batch_call_in_and_dispose; 223 batch_data(instance); 201 224 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 202 225 } … … 205 228 { 206 229 assert(instance); 207 instance->direction = USB_DIRECTION_IN; 208 instance->next_step = batch_call_in_and_dispose; 209 /* TODO: implement */ 230 instance->next_step = usb_transfer_batch_call_in_and_dispose; 231 batch_data(instance); 210 232 usb_log_debug("Batch(%p) BULK IN initialized.\n", instance); 211 233 } … … 214 236 { 215 237 assert(instance); 216 ohci_ batch_t *data = instance->private_data;238 ohci_transfer_batch_t *data = instance->private_data; 217 239 assert(data); 218 240 return data->ed; … … 223 245 { 224 246 assert(instance); 225 ohci_batch_t *data = instance->private_data; 226 assert(data); 227 ed_init(data->ed, instance->ep); 228 ed_add_tds(data->ed, &data->tds[0], &data->tds[data->td_count - 1]); 229 usb_log_debug("Created ED(%p): %x:%x:%x:%x.\n", data->ed, 247 ohci_transfer_batch_t *data = instance->private_data; 248 assert(data); 249 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed, 230 250 data->ed->status, data->ed->td_tail, data->ed->td_head, 231 251 data->ed->next); 232 252 int toggle = 0; 233 253 /* setup stage */ 234 td_init( &data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer,254 td_init(data->tds[0], USB_DIRECTION_BOTH, instance->setup_buffer, 235 255 instance->setup_size, toggle); 236 td_set_next( &data->tds[0], &data->tds[1]);237 usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0] .status,238 data->tds[0] .cbp, data->tds[0].next, data->tds[0].be);256 td_set_next(data->tds[0], data->tds[1]); 257 usb_log_debug("Created SETUP TD: %x:%x:%x:%x.\n", data->tds[0]->status, 258 data->tds[0]->cbp, data->tds[0]->next, data->tds[0]->be); 239 259 240 260 /* data stage */ 241 261 size_t td_current = 1; 242 262 size_t remain_size = instance->buffer_size; 243 char * transfer_buffer = instance->transport_buffer;263 char *buffer = instance->data_buffer; 244 264 while (remain_size > 0) { 245 265 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ? … … 247 267 toggle = 1 - toggle; 248 268 249 td_init( &data->tds[td_current], data_dir, transfer_buffer,269 td_init(data->tds[td_current], data_dir, buffer, 250 270 transfer_size, toggle); 251 td_set_next( &data->tds[td_current], &data->tds[td_current + 1]);271 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 252 272 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n", 253 data->tds[td_current] .status, data->tds[td_current].cbp,254 data->tds[td_current] .next, data->tds[td_current].be);255 256 transfer_buffer += transfer_size;273 data->tds[td_current]->status, data->tds[td_current]->cbp, 274 data->tds[td_current]->next, data->tds[td_current]->be); 275 276 buffer += transfer_size; 257 277 remain_size -= transfer_size; 258 assert(td_current < data->td_count - 2);278 assert(td_current < data->td_count - 1); 259 279 ++td_current; 260 280 } 261 281 262 282 /* status stage */ 263 assert(td_current == data->td_count - 2); 264 td_init(&data->tds[td_current], status_dir, NULL, 0, 1); 283 assert(td_current == data->td_count - 1); 284 td_init(data->tds[td_current], status_dir, NULL, 0, 1); 285 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 265 286 usb_log_debug("Created STATUS TD: %x:%x:%x:%x.\n", 266 data->tds[td_current].status, data->tds[td_current].cbp, 267 data->tds[td_current].next, data->tds[td_current].be); 268 } 269 /*----------------------------------------------------------------------------*/ 270 /** Helper function calls callback and correctly disposes of batch structure. 271 * 272 * @param[in] instance Batch structure to use. 273 */ 274 void batch_call_in_and_dispose(usb_transfer_batch_t *instance) 275 { 276 assert(instance); 277 usb_transfer_batch_call_in(instance); 278 batch_dispose(instance); 279 } 280 /*----------------------------------------------------------------------------*/ 281 /** Helper function calls callback and correctly disposes of batch structure. 282 * 283 * @param[in] instance Batch structure to use. 284 */ 285 void batch_call_out_and_dispose(usb_transfer_batch_t *instance) 286 { 287 assert(instance); 288 usb_transfer_batch_call_out(instance); 289 batch_dispose(instance); 287 data->tds[td_current]->status, data->tds[td_current]->cbp, 288 data->tds[td_current]->next, data->tds[td_current]->be); 289 } 290 /*----------------------------------------------------------------------------*/ 291 void batch_data(usb_transfer_batch_t *instance) 292 { 293 assert(instance); 294 ohci_transfer_batch_t *data = instance->private_data; 295 assert(data); 296 usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", data->ed, 297 data->ed->status, data->ed->td_tail, data->ed->td_head, 298 data->ed->next); 299 300 size_t td_current = 0; 301 size_t remain_size = instance->buffer_size; 302 char *buffer = instance->data_buffer; 303 while (remain_size > 0) { 304 size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ? 305 OHCI_TD_MAX_TRANSFER : remain_size; 306 307 td_init(data->tds[td_current], instance->ep->direction, 308 buffer, transfer_size, -1); 309 td_set_next(data->tds[td_current], data->tds[td_current + 1]); 310 usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n", 311 data->tds[td_current]->status, data->tds[td_current]->cbp, 312 data->tds[td_current]->next, data->tds[td_current]->be); 313 314 buffer += transfer_size; 315 remain_size -= transfer_size; 316 assert(td_current < data->td_count); 317 ++td_current; 318 } 290 319 } 291 320 /** -
uspace/drv/ohci/batch.h
r3f2af64 rd8b275d 50 50 void *arg); 51 51 52 void batch_dispose(usb_transfer_batch_t *instance);52 bool batch_is_complete(usb_transfer_batch_t *instance); 53 53 54 bool batch_is_complete(usb_transfer_batch_t *instance);54 void batch_commit(usb_transfer_batch_t *instance); 55 55 56 56 void batch_control_write(usb_transfer_batch_t *instance); -
uspace/drv/ohci/endpoint_list.c
r3f2af64 rd8b275d 35 35 #include <usb/debug.h> 36 36 37 #include "transfer_list.h" 38 39 static void transfer_list_remove_batch( 40 transfer_list_t *instance, usb_transfer_batch_t *batch); 41 /*----------------------------------------------------------------------------*/ 37 #include "endpoint_list.h" 38 42 39 /** Initialize transfer list structures. 43 40 * … … 48 45 * Allocates memory for internal qh_t structure. 49 46 */ 50 int transfer_list_init(transfer_list_t *instance, const char *name)47 int endpoint_list_init(endpoint_list_t *instance, const char *name) 51 48 { 52 49 assert(instance); … … 62 59 63 60 ed_init(instance->list_head, NULL); 64 list_initialize(&instance-> batch_list);61 list_initialize(&instance->endpoint_list); 65 62 fibril_mutex_initialize(&instance->guard); 66 63 return EOK; … … 75 72 * Does not check whether this replaces an existing list . 76 73 */ 77 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)74 void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next) 78 75 { 79 76 assert(instance); 80 77 assert(next); 81 /* Set both queue_head.next to point to the follower */82 78 ed_append_ed(instance->list_head, next->list_head); 83 79 } 84 80 /*----------------------------------------------------------------------------*/ 85 /** Submit transfer batchto the list and queue.86 * 87 * @param[in] instance List to use. 88 * @param[in] batch Transfer batchto submit.89 * @return Error code 90 * 91 * The batchis added to the end of the list and queue.92 */ 93 void transfer_list_add_batch(94 transfer_list_t *instance, usb_transfer_batch_t *batch) 95 { 96 assert( instance);97 assert(batch);98 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);81 /** Submit transfer endpoint to the list and queue. 82 * 83 * @param[in] instance List to use. 84 * @param[in] endpoint Transfer endpoint to submit. 85 * @return Error code 86 * 87 * The endpoint is added to the end of the list and queue. 88 */ 89 void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep) 90 { 91 assert(instance); 92 assert(hcd_ep); 93 usb_log_debug2("Queue %s: Adding endpoint(%p).\n", 94 instance->name, hcd_ep); 99 95 100 96 fibril_mutex_lock(&instance->guard); … … 102 98 ed_t *last_ed = NULL; 103 99 /* Add to the hardware queue. */ 104 if (list_empty(&instance-> batch_list)) {100 if (list_empty(&instance->endpoint_list)) { 105 101 /* There is nothing scheduled */ 106 102 last_ed = instance->list_head; 107 103 } else { 108 104 /* There is something scheduled */ 109 usb_transfer_batch_t *last = list_get_instance(110 instance-> batch_list.prev, usb_transfer_batch_t, link);111 last_ed = batch_ed(last);105 hcd_endpoint_t *last = list_get_instance( 106 instance->endpoint_list.prev, hcd_endpoint_t, link); 107 last_ed = last->ed; 112 108 } 113 109 /* keep link */ 114 batch_ed(batch)->next = last_ed->next;115 ed_append_ed(last_ed, batch_ed(batch));110 hcd_ep->ed->next = last_ed->next; 111 ed_append_ed(last_ed, hcd_ep->ed); 116 112 117 113 asm volatile ("": : :"memory"); 118 114 119 115 /* Add to the driver list */ 120 list_append(& batch->link, &instance->batch_list);121 122 usb_transfer_batch_t *first = list_get_instance(123 instance-> batch_list.next, usb_transfer_batch_t, link);124 usb_log_debug(" Batch(%p) added to list %s, first is %p(%p).\n",125 batch, instance->name, first, batch_ed(first));116 list_append(&hcd_ep->link, &instance->endpoint_list); 117 118 hcd_endpoint_t *first = list_get_instance( 119 instance->endpoint_list.next, hcd_endpoint_t, link); 120 usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n", 121 hcd_ep, instance->name, first, first->ed); 126 122 if (last_ed == instance->list_head) { 127 usb_log_debug2("%s head ED: %x:%x:%x:%x.\n", instance->name, 128 last_ed->status, last_ed->td_tail, last_ed->td_head, 129 last_ed->next); 130 } 131 fibril_mutex_unlock(&instance->guard); 132 } 133 /*----------------------------------------------------------------------------*/ 134 /** Create list for finished batches. 123 usb_log_debug2("%s head ED(%p-%p): %x:%x:%x:%x.\n", 124 instance->name, last_ed, instance->list_head_pa, 125 last_ed->status, last_ed->td_tail, last_ed->td_head, 126 last_ed->next); 127 } 128 fibril_mutex_unlock(&instance->guard); 129 } 130 /*----------------------------------------------------------------------------*/ 131 #if 0 132 /** Create list for finished endpoints. 135 133 * 136 134 * @param[in] instance List to use. 137 135 * @param[in] done list to fill 138 136 */ 139 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done)137 void endpoint_list_remove_finished(endpoint_list_t *instance, link_t *done) 140 138 { 141 139 assert(instance); … … 143 141 144 142 fibril_mutex_lock(&instance->guard); 145 link_t *current = instance->batch_list.next; 146 while (current != &instance->batch_list) { 143 usb_log_debug2("Checking list %s for completed endpointes(%d).\n", 144 instance->name, list_count(&instance->endpoint_list)); 145 link_t *current = instance->endpoint_list.next; 146 while (current != &instance->endpoint_list) { 147 147 link_t *next = current->next; 148 usb_transfer_batch_t *batch=149 list_get_instance(current, usb_transfer_batch_t, link);150 151 if ( batch_is_complete(batch)) {148 hcd_endpoint_t *endpoint = 149 list_get_instance(current, hcd_endpoint_t, link); 150 151 if (endpoint_is_complete(endpoint)) { 152 152 /* Save for post-processing */ 153 transfer_list_remove_batch(instance, batch);153 endpoint_list_remove_endpoint(instance, endpoint); 154 154 list_append(current, done); 155 155 } … … 159 159 } 160 160 /*----------------------------------------------------------------------------*/ 161 /** Walk the list and abort all batches. 162 * 163 * @param[in] instance List to use. 164 */ 165 void transfer_list_abort_all(transfer_list_t *instance) 166 { 167 fibril_mutex_lock(&instance->guard); 168 while (!list_empty(&instance->batch_list)) { 169 link_t *current = instance->batch_list.next; 170 usb_transfer_batch_t *batch = 171 list_get_instance(current, usb_transfer_batch_t, link); 172 transfer_list_remove_batch(instance, batch); 173 usb_transfer_batch_finish_error(batch, EIO); 174 } 175 fibril_mutex_unlock(&instance->guard); 176 } 177 /*----------------------------------------------------------------------------*/ 178 /** Remove a transfer batch from the list and queue. 179 * 180 * @param[in] instance List to use. 181 * @param[in] batch Transfer batch to remove. 161 /** Walk the list and abort all endpointes. 162 * 163 * @param[in] instance List to use. 164 */ 165 void endpoint_list_abort_all(endpoint_list_t *instance) 166 { 167 fibril_mutex_lock(&instance->guard); 168 while (!list_empty(&instance->endpoint_list)) { 169 link_t *current = instance->endpoint_list.next; 170 hcd_endpoint_t *endpoint = 171 list_get_instance(current, hcd_endpoint_t, link); 172 endpoint_list_remove_endpoint(instance, endpoint); 173 hcd_endpoint_finish_error(endpoint, EIO); 174 } 175 fibril_mutex_unlock(&instance->guard); 176 } 177 #endif 178 /*----------------------------------------------------------------------------*/ 179 /** Remove a transfer endpoint from the list and queue. 180 * 181 * @param[in] instance List to use. 182 * @param[in] endpoint Transfer endpoint to remove. 182 183 * @return Error code 183 184 * 184 185 * Does not lock the transfer list, caller is responsible for that. 185 186 */ 186 void transfer_list_remove_batch( 187 transfer_list_t *instance, usb_transfer_batch_t *batch) 187 void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep) 188 188 { 189 189 assert(instance); 190 190 assert(instance->list_head); 191 assert(batch); 192 assert(batch_ed(batch)); 193 assert(fibril_mutex_is_locked(&instance->guard)); 191 assert(hcd_ep); 192 assert(hcd_ep->ed); 193 194 fibril_mutex_lock(&instance->guard); 194 195 195 196 usb_log_debug2( 196 "Queue %s: removing batch(%p).\n", instance->name, batch);197 "Queue %s: removing endpoint(%p).\n", instance->name, hcd_ep); 197 198 198 199 const char *qpos = NULL; 200 ed_t *prev_ed; 199 201 /* Remove from the hardware queue */ 200 if (instance-> batch_list.next == &batch->link) {202 if (instance->endpoint_list.next == &hcd_ep->link) { 201 203 /* I'm the first one here */ 202 assert((instance->list_head->next & ED_NEXT_PTR_MASK) 203 == addr_to_phys(batch_ed(batch))); 204 instance->list_head->next = batch_ed(batch)->next; 204 prev_ed = instance->list_head; 205 205 qpos = "FIRST"; 206 206 } else { 207 usb_transfer_batch_t *prev = 208 list_get_instance( 209 batch->link.prev, usb_transfer_batch_t, link); 210 assert((batch_ed(prev)->next & ED_NEXT_PTR_MASK) 211 == addr_to_phys(batch_ed(batch))); 212 batch_ed(prev)->next = batch_ed(batch)->next; 207 hcd_endpoint_t *prev = 208 list_get_instance(hcd_ep->link.prev, hcd_endpoint_t, link); 209 prev_ed = prev->ed; 213 210 qpos = "NOT FIRST"; 214 211 } 212 assert((prev_ed->next & ED_NEXT_PTR_MASK) == addr_to_phys(hcd_ep->ed)); 213 prev_ed->next = hcd_ep->ed->next; 214 215 215 asm volatile ("": : :"memory"); 216 usb_log_debug("Batch(%p) removed (%s) from %s, next %x.\n", 217 batch, qpos, instance->name, batch_ed(batch)->next); 218 219 /* Remove from the batch list */ 220 list_remove(&batch->link); 216 usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.\n", 217 hcd_ep, qpos, instance->name, hcd_ep->ed->next); 218 219 /* Remove from the endpoint list */ 220 list_remove(&hcd_ep->link); 221 fibril_mutex_unlock(&instance->guard); 221 222 } 222 223 /** -
uspace/drv/ohci/endpoint_list.h
r3f2af64 rd8b275d 32 32 * @brief OHCI driver transfer list structure 33 33 */ 34 #ifndef DRV_OHCI_ TRANSFER_LIST_H35 #define DRV_OHCI_ TRANSFER_LIST_H34 #ifndef DRV_OHCI_ENDPOINT_LIST_H 35 #define DRV_OHCI_ENDPOINT_LIST_H 36 36 37 37 #include <fibril_synch.h> 38 38 39 #include " batch.h"39 #include "hcd_endpoint.h" 40 40 #include "hw_struct/endpoint_descriptor.h" 41 41 #include "utils/malloc32.h" 42 42 43 typedef struct transfer_list43 typedef struct endpoint_list 44 44 { 45 45 fibril_mutex_t guard; … … 47 47 uint32_t list_head_pa; 48 48 const char *name; 49 link_t batch_list;50 } transfer_list_t;49 link_t endpoint_list; 50 } endpoint_list_t; 51 51 52 52 /** Dispose transfer list structures. … … 56 56 * Frees memory for internal qh_t structure. 57 57 */ 58 static inline void transfer_list_fini(transfer_list_t *instance)58 static inline void endpoint_list_fini(endpoint_list_t *instance) 59 59 { 60 60 assert(instance); … … 62 62 } 63 63 64 int transfer_list_init(transfer_list_t *instance, const char *name);64 int endpoint_list_init(endpoint_list_t *instance, const char *name); 65 65 66 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);66 void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next); 67 67 68 void transfer_list_add_batch(transfer_list_t *instance, usb_transfer_batch_t *batch);68 void endpoint_list_add_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep); 69 69 70 void transfer_list_remove_finished(transfer_list_t *instance, link_t *done); 70 void endpoint_list_remove_ep(endpoint_list_t *instance, hcd_endpoint_t *hcd_ep); 71 #if 0 72 void endpoint_list_remove_finished(endpoint_list_t *instance, link_t *done); 71 73 72 void transfer_list_abort_all(transfer_list_t *instance); 74 void endpoint_list_abort_all(endpoint_list_t *instance); 75 #endif 73 76 #endif 74 77 /** -
uspace/drv/ohci/hc.c
r3f2af64 rd8b275d 43 43 44 44 #include "hc.h" 45 #include "hcd_endpoint.h" 45 46 46 47 static int interrupt_emulator(hc_t *instance); … … 55 56 assert(hub_fun); 56 57 58 int ret; 59 57 60 usb_address_t hub_address = 58 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 } 59 66 instance->rh.address = hub_address; 60 67 usb_device_keeper_bind( 61 68 &instance->manager, hub_address, hub_fun->handle); 62 69 63 endpoint_t *ep = malloc(sizeof(endpoint_t));64 assert(ep);65 i nt ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,66 USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);67 assert(ret == EOK);68 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);69 assert(ret == EOK);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 } 70 77 71 78 char *match_str = NULL; 79 /* DDF needs heap allocated string */ 72 80 ret = asprintf(&match_str, "usb&class=hub"); 73 // ret = (match_str == NULL) ? ret : EOK;74 81 if (ret < 0) { 75 82 usb_log_error( 76 83 "Failed(%d) to create root hub match-id string.\n", ret); 84 usb_device_keeper_release(&instance->manager, hub_address); 77 85 return ret; 78 86 } … … 80 88 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 81 89 if (ret != EOK) { 82 usb_log_error("Failed add createroot hub match-id.\n");90 usb_log_error("Failed add root hub match-id.\n"); 83 91 } 84 92 return ret; … … 101 109 ret, str_error(ret)); 102 110 103 instance->ddf_instance = fun;104 111 usb_device_keeper_init(&instance->manager); 105 112 ret = usb_endpoint_manager_init(&instance->ep_manager, … … 113 120 ret, str_error(ret)); 114 121 hc_init_hw(instance); 115 116 rh_init(&instance->rh, dev, instance->registers); 122 fibril_mutex_initialize(&instance->guard); 123 124 rh_init(&instance->rh, instance->registers); 117 125 118 126 if (!interrupts) { … … 122 130 } 123 131 124 return EOK; 125 } 126 /*----------------------------------------------------------------------------*/ 127 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 128 { 129 assert(instance); 130 assert(batch); 131 132 /* check for root hub communication */ 133 if (batch->target.address == instance->rh.address) { 134 return rh_request(&instance->rh, batch); 135 } 136 137 transfer_list_add_batch( 138 instance->transfers[batch->transfer_type], batch); 139 140 switch (batch->transfer_type) { 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) { 141 167 case USB_TRANSFER_CONTROL: 142 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; 253 } 254 /*----------------------------------------------------------------------------*/ 255 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 256 { 257 assert(instance); 258 assert(batch); 259 assert(batch->ep); 260 261 /* check for root hub communication */ 262 if (batch->ep->address == instance->rh.address) { 263 return rh_request(&instance->rh, batch); 264 } 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: 143 271 instance->registers->command_status |= CS_CLF; 144 usb_log_debug2("Set control transfer filled: %x.\n",145 instance->registers->command_status);146 instance->registers->control |= C_CLE;147 272 break; 148 273 case USB_TRANSFER_BULK: 149 274 instance->registers->command_status |= CS_BLF; 150 usb_log_debug2("Set bulk transfer filled: %x.\n",151 instance->registers->command_status);152 275 break; 153 276 default: 154 277 break; 155 278 } 279 280 fibril_mutex_unlock(&instance->guard); 156 281 return EOK; 157 282 } … … 165 290 rh_interrupt(&instance->rh); 166 291 167 usb_log_info("OHCI interrupt: %x.\n", status); 168 169 170 LIST_INITIALIZE(done); 171 transfer_list_remove_finished(&instance->transfers_interrupt, &done); 172 transfer_list_remove_finished(&instance->transfers_isochronous, &done); 173 transfer_list_remove_finished(&instance->transfers_control, &done); 174 transfer_list_remove_finished(&instance->transfers_bulk, &done); 175 176 while (!list_empty(&done)) { 177 link_t *item = done.next; 178 list_remove(item); 179 usb_transfer_batch_t *batch = 180 list_get_instance(item, usb_transfer_batch_t, link); 181 usb_transfer_batch_finish(batch); 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); 182 314 } 183 315 } … … 191 323 instance->registers->interrupt_status = status; 192 324 hc_interrupt(instance, status); 193 async_usleep( 1000);325 async_usleep(50000); 194 326 } 195 327 return EOK; … … 267 399 instance->registers->control); 268 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 269 417 /* Enable queues */ 270 418 instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE); … … 296 444 assert(instance); 297 445 298 #define SETUP_ TRANSFER_LIST(type, name) \446 #define SETUP_ENDPOINT_LIST(type) \ 299 447 do { \ 300 int ret = transfer_list_init(&instance->type, name); \ 448 const char *name = usb_str_transfer_type(type); \ 449 int ret = endpoint_list_init(&instance->lists[type], name); \ 301 450 if (ret != EOK) { \ 302 usb_log_error("Failed(%d) to setup %s transferlist.\n", \451 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \ 303 452 ret, name); \ 304 transfer_list_fini(&instance->transfers_isochronous); \305 transfer_list_fini(&instance->transfers_interrupt); \306 transfer_list_fini(&instance->transfers_control); \307 transfer_list_fini(&instance->transfers_bulk); \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]); \ 308 457 } \ 309 458 } while (0) 310 459 311 SETUP_TRANSFER_LIST(transfers_isochronous, "ISOCHRONOUS"); 312 SETUP_TRANSFER_LIST(transfers_interrupt, "INTERRUPT"); 313 SETUP_TRANSFER_LIST(transfers_control, "CONTROL"); 314 SETUP_TRANSFER_LIST(transfers_bulk, "BULK"); 315 316 transfer_list_set_next(&instance->transfers_interrupt, 317 &instance->transfers_isochronous); 318 319 /* Assign pointers to be used during scheduling */ 320 instance->transfers[USB_TRANSFER_INTERRUPT] = 321 &instance->transfers_interrupt; 322 instance->transfers[USB_TRANSFER_ISOCHRONOUS] = 323 &instance->transfers_interrupt; 324 instance->transfers[USB_TRANSFER_CONTROL] = 325 &instance->transfers_control; 326 instance->transfers[USB_TRANSFER_BULK] = 327 &instance->transfers_bulk; 328 329 return EOK; 330 #undef CHECK_RET_CLEAR_RETURN 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; 331 469 } 332 470 /*----------------------------------------------------------------------------*/ … … 342 480 return ENOMEM; 343 481 bzero(instance->hcca, sizeof(hcca_t)); 344 instance->registers->hcca = addr_to_phys(instance->hcca); 345 usb_log_debug2("OHCI HCCA initialized at %p(%p).\n", 346 instance->hcca, instance->registers->hcca); 347 348 /* Use queues */ 349 instance->registers->bulk_head = instance->transfers_bulk.list_head_pa; 350 usb_log_debug2("Bulk HEAD set to: %p(%p).\n", 351 instance->transfers_bulk.list_head, 352 instance->transfers_bulk.list_head_pa); 353 354 instance->registers->control_head = 355 instance->transfers_control.list_head_pa; 356 usb_log_debug2("Control HEAD set to: %p(%p).\n", 357 instance->transfers_control.list_head, 358 instance->transfers_control.list_head_pa); 482 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 359 483 360 484 unsigned i = 0; 361 485 for (; i < 32; ++i) { 362 486 instance->hcca->int_ep[i] = 363 instance-> transfers_interrupt.list_head_pa;487 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa; 364 488 } 365 489 usb_log_debug2("Interrupt HEADs set to: %p(%p).\n", 366 instance-> transfers_interrupt.list_head,367 instance-> transfers_interrupt.list_head_pa);490 instance->lists[USB_TRANSFER_INTERRUPT].list_head, 491 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 368 492 369 493 return EOK; -
uspace/drv/ohci/hc.h
r3f2af64 rd8b275d 48 48 #include "ohci_regs.h" 49 49 #include "root_hub.h" 50 #include " transfer_list.h"50 #include "endpoint_list.h" 51 51 #include "hw_struct/hcca.h" 52 52 53 53 typedef struct hc { 54 54 ohci_regs_t *registers; 55 hcca_t *hcca; 56 55 57 usb_address_t rh_address; 56 58 rh_t rh; 57 59 58 hcca_t *hcca; 60 endpoint_list_t lists[4]; 61 link_t pending_batches; 59 62 60 transfer_list_t transfers_isochronous;61 transfer_list_t transfers_interrupt;62 transfer_list_t transfers_control;63 transfer_list_t transfers_bulk;64 65 transfer_list_t *transfers[4];66 67 ddf_fun_t *ddf_instance;68 63 usb_device_keeper_t manager; 69 64 usb_endpoint_manager_t ep_manager; 70 65 fid_t interrupt_emulator; 66 fibril_mutex_t guard; 71 67 } hc_t; 72 68 … … 76 72 uintptr_t regs, size_t reg_size, bool interrupts); 77 73 78 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);79 80 void hc_interrupt(hc_t *instance, uint32_t status);81 82 74 /** Safely dispose host controller internal structures 83 75 * … … 85 77 */ 86 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); 87 93 88 94 /** Get and cast pointer to the driver data -
uspace/drv/ohci/hcd_endpoint.h
r3f2af64 rd8b275d 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/endpoint_descriptor.c
r3f2af64 rd8b275d 53 53 << ED_STATUS_MPS_SHIFT); 54 54 55 55 56 if (ep->speed == USB_SPEED_LOW) 56 57 instance->status |= ED_STATUS_S_FLAG; 57 58 if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS) 58 59 instance->status |= ED_STATUS_F_FLAG; 60 61 if (ep->toggle) 62 instance->td_head |= ED_TDHEAD_TOGGLE_CARRY; 59 63 } 60 64 /** -
uspace/drv/ohci/hw_struct/endpoint_descriptor.h
r3f2af64 rd8b275d 53 53 #define ED_STATUS_D_MASK (0x3) /* direction */ 54 54 #define ED_STATUS_D_SHIFT (11) 55 #define ED_STATUS_D_ IN(0x1)56 #define ED_STATUS_D_ OUT(0x2)55 #define ED_STATUS_D_OUT (0x1) 56 #define ED_STATUS_D_IN (0x2) 57 57 #define ED_STATUS_D_TRANSFER (0x3) 58 58 … … 81 81 void ed_init(ed_t *instance, endpoint_t *ep); 82 82 83 static inline void ed_ add_tds(ed_t *instance, td_t *head, td_t *tail)83 static inline void ed_set_td(ed_t *instance, td_t *td) 84 84 { 85 85 assert(instance); 86 instance->td_head = addr_to_phys(head) & ED_TDHEAD_PTR_MASK; 87 instance->td_tail = addr_to_phys(tail) & ED_TDTAIL_PTR_MASK; 86 uintptr_t pa = addr_to_phys(td); 87 instance->td_head = 88 ((pa & ED_TDHEAD_PTR_MASK) 89 | (instance->td_head & ~ED_TDHEAD_PTR_MASK)); 90 instance->td_tail = pa & ED_TDTAIL_PTR_MASK; 91 } 92 93 static inline void ed_set_end_td(ed_t *instance, td_t *td) 94 { 95 assert(instance); 96 uintptr_t pa = addr_to_phys(td); 97 instance->td_tail = pa & ED_TDTAIL_PTR_MASK; 88 98 } 89 99 … … 96 106 instance->next = pa; 97 107 } 98 99 108 #endif 100 109 /** -
uspace/drv/ohci/hw_struct/hcca.h
r3f2af64 rd8b275d 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.c
r3f2af64 rd8b275d 53 53 } 54 54 if (buffer != NULL) { 55 assert(size != 0); 55 56 instance->cbp = addr_to_phys(buffer); 56 57 instance->be = addr_to_phys(buffer + size - 1); -
uspace/drv/ohci/hw_struct/transfer_descriptor.h
r3f2af64 rd8b275d 50 50 #define TD_STATUS_DP_SHIFT (19) 51 51 #define TD_STATUS_DP_SETUP (0x0) 52 #define TD_STATUS_DP_ IN(0x1)53 #define TD_STATUS_DP_ OUT(0x2)52 #define TD_STATUS_DP_OUT (0x1) 53 #define TD_STATUS_DP_IN (0x2) 54 54 #define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */ 55 55 #define TD_STATUS_DI_SHIFT (21) … … 86 86 int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK; 87 87 /* something went wrong, error code is set */ 88 if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2 && cc != CC_NOERROR) {88 if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) { 89 89 return true; 90 90 } -
uspace/drv/ohci/iface.c
r3f2af64 rd8b275d 55 55 56 56 size_t res_bw; 57 endpoint_t *ep = usb_endpoint_manager_get_ep(&(*hc)->ep_manager,57 endpoint_t *ep = hc_get_endpoint(*hc, 58 58 target.address, target.endpoint, direction, &res_bw); 59 59 if (ep == NULL) { … … 63 63 } 64 64 65 usb_log_debug("%s %d:%d %zu(%zu).\n", 66 name, target.address, target.endpoint, size, ep->max_packet_size); 67 65 68 const size_t bw = bandwidth_count_usb11( 66 69 ep->speed, ep->transfer_type, size, ep->max_packet_size); … … 68 71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 69 72 "but only %zu is reserved.\n", 70 name, target.address, target.endpoint, bw, res_bw);73 target.address, target.endpoint, name, bw, res_bw); 71 74 return ENOSPC; 72 75 } 73 usb_log_debug("%s %d:%d %zu(%zu).\n",74 name, target.address, target.endpoint, size, ep->max_packet_size);75 76 76 77 *batch = batch_get( … … 157 158 hc_t *hc = fun_to_hc(fun); 158 159 assert(hc); 159 if (address == hc->rh.address) 160 return EOK; 160 161 161 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address); 162 162 if (speed >= USB_SPEED_MAX) { 163 163 speed = ep_speed; 164 164 } 165 const size_t size = 166 (transfer_type == USB_TRANSFER_INTERRUPT 167 || transfer_type == USB_TRANSFER_ISOCHRONOUS) ? 168 max_packet_size : 0; 169 int ret; 170 171 endpoint_t *ep = malloc(sizeof(endpoint_t)); 172 if (ep == NULL) 173 return ENOMEM; 174 ret = endpoint_init(ep, address, endpoint, direction, 175 transfer_type, speed, max_packet_size); 176 if (ret != EOK) { 177 free(ep); 178 return ret; 179 } 165 const size_t size = max_packet_size; 180 166 181 167 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n", … … 183 169 usb_str_speed(speed), direction, size, max_packet_size, interval); 184 170 185 ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size); 186 if (ret != EOK) { 187 endpoint_destroy(ep); 188 } 189 return ret; 171 return hc_add_endpoint(hc, address, endpoint, speed, transfer_type, 172 direction, max_packet_size, size, interval); 190 173 } 191 174 /*----------------------------------------------------------------------------*/ … … 198 181 usb_log_debug("Unregister endpoint %d:%d %d.\n", 199 182 address, endpoint, direction); 200 return usb_endpoint_manager_unregister_ep(&hc->ep_manager, address, 201 endpoint, direction); 183 return hc_remove_endpoint(hc, address, endpoint, direction); 202 184 } 203 185 /*----------------------------------------------------------------------------*/ … … 231 213 ret = hc_schedule(hc, batch); 232 214 if (ret != EOK) { 233 batch_dispose(batch);215 usb_transfer_batch_dispose(batch); 234 216 } 235 217 return ret; … … 265 247 ret = hc_schedule(hc, batch); 266 248 if (ret != EOK) { 267 batch_dispose(batch);249 usb_transfer_batch_dispose(batch); 268 250 } 269 251 return ret; … … 299 281 ret = hc_schedule(hc, batch); 300 282 if (ret != EOK) { 301 batch_dispose(batch);283 usb_transfer_batch_dispose(batch); 302 284 } 303 285 return ret; … … 333 315 ret = hc_schedule(hc, batch); 334 316 if (ret != EOK) { 335 batch_dispose(batch);317 usb_transfer_batch_dispose(batch); 336 318 } 337 319 return ret; … … 349 331 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 350 332 * and deallocated by the caller). 351 * @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. 352 334 * @param[in] data_buffer Data buffer (in USB endianess, allocated and 353 335 * deallocated by the caller). 354 * @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. 355 337 * @param[in] callback Callback to be issued once the transfer is complete. 356 338 * @param[in] arg Pass-through argument to the callback. … … 373 355 ret = hc_schedule(hc, batch); 374 356 if (ret != EOK) { 375 batch_dispose(batch);357 usb_transfer_batch_dispose(batch); 376 358 } 377 359 return ret; … … 389 371 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated 390 372 * and deallocated by the caller). 391 * @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. 392 374 * @param[in] data_buffer Buffer where to store the data (in USB endianess, 393 375 * allocated and deallocated by the caller). 394 * @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. 395 377 * @param[in] callback Callback to be issued once the transfer is complete. 396 378 * @param[in] arg Pass-through argument to the callback. … … 412 394 ret = hc_schedule(hc, batch); 413 395 if (ret != EOK) { 414 batch_dispose(batch);396 usb_transfer_batch_dispose(batch); 415 397 } 416 398 return ret; -
uspace/drv/ohci/ohci.ma
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 100 100 #define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */ 101 101 102 /** Currently executed period endpoint */103 const volatile uint32_t period _current;102 /** Currently executed periodic endpoint */ 103 const volatile uint32_t periodic_current; 104 104 105 105 /** The first control endpoint */ -
uspace/drv/ohci/root_hub.c
r3f2af64 rd8b275d 205 205 * @return Error code. 206 206 */ 207 int rh_init(rh_t *instance, ddf_dev_t *dev,ohci_regs_t *regs) {207 int rh_init(rh_t *instance, ohci_regs_t *regs) { 208 208 assert(instance); 209 //instance->address = -1;210 209 instance->registers = regs; 211 instance->device = dev;212 210 instance->port_count = 213 211 (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK; 214 212 rh_init_descriptors(instance); 215 213 // set port power mode to no-power-switching 216 instance->registers->rh_desc_a = 217 instance->registers->rh_desc_a | (1<<9); 214 instance->registers->rh_desc_a |= RHDA_NPS_FLAG; 218 215 219 216 usb_log_info("OHCI root hub with %d ports.\n", instance->port_count); 220 221 //start generic usb hub driver222 223 /* TODO: implement */224 217 return EOK; 225 218 } … … 237 230 assert(request); 238 231 int opResult; 239 if (request-> transfer_type == USB_TRANSFER_CONTROL) {232 if (request->ep->transfer_type == USB_TRANSFER_CONTROL) { 240 233 usb_log_info("Root hub got CONTROL packet\n"); 241 234 opResult = process_ctrl_request(instance, request); 242 } else if (request-> transfer_type == USB_TRANSFER_INTERRUPT) {235 } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) { 243 236 usb_log_info("Root hub got INTERRUPT packet\n"); 244 237 void * buffer; 245 238 create_interrupt_mask(instance, &buffer, 246 239 &(request->transfered_size)); 247 memcpy(request-> transport_buffer, buffer,240 memcpy(request->data_buffer, buffer, 248 241 request->transfered_size); 249 242 opResult = EOK; … … 374 367 if (port < 1 || port > instance->port_count) 375 368 return EINVAL; 376 uint32_t * uint32_buffer = (uint32_t*) request-> transport_buffer;369 uint32_t * uint32_buffer = (uint32_t*) request->data_buffer; 377 370 request->transfered_size = 4; 378 371 uint32_buffer[0] = instance->registers->rh_port_status[port - 1]; … … 400 393 static int process_get_hub_status_request(rh_t *instance, 401 394 usb_transfer_batch_t * request) { 402 uint32_t * uint32_buffer = (uint32_t*) request-> transport_buffer;395 uint32_t * uint32_buffer = (uint32_t*) request->data_buffer; 403 396 request->transfered_size = 4; 404 397 //bits, 0,1,16,17 … … 550 543 } 551 544 request->transfered_size = size; 552 memcpy(request-> transport_buffer, result_descriptor, size);545 memcpy(request->data_buffer, result_descriptor, size); 553 546 if (del) 554 547 free(result_descriptor); … … 571 564 if (request->buffer_size != 1) 572 565 return EINVAL; 573 request-> transport_buffer[0] = 1;566 request->data_buffer[0] = 1; 574 567 request->transfered_size = 1; 575 568 return EOK; -
uspace/drv/ohci/root_hub.h
r3f2af64 rd8b275d 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; … … 58 56 } rh_t; 59 57 60 int rh_init(rh_t *instance, ddf_dev_t *dev,ohci_regs_t *regs);58 int rh_init(rh_t *instance, ohci_regs_t *regs); 61 59 62 60 int rh_request(rh_t *instance, usb_transfer_batch_t *request); -
uspace/drv/ohci/utils/malloc32.h
r3f2af64 rd8b275d 41 41 #include <as.h> 42 42 43 #define UHCI_STRCUTURES_ALIGNMENT 1644 43 #define UHCI_REQUIRED_PAGE_SIZE 4096 45 44 … … 65 64 */ 66 65 static inline void * malloc32(size_t size) 67 { return memalign( UHCI_STRCUTURES_ALIGNMENT, size); }66 { return memalign(size, size); } 68 67 /*----------------------------------------------------------------------------*/ 69 68 /** Physical mallocator simulator -
uspace/drv/uhci-hcd/batch.c
r3f2af64 rd8b275d 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 transfer s (TDs). Prepares a transport buffer79 * (that is accessible by the hardware). Initializes parameters needed for the80 * transactionand callback.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. 81 84 */ 82 85 usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep, … … 92 95 if (ptr == NULL) { \ 93 96 usb_log_error(message); \ 94 if ( instance) { \95 batch_dispose(instance); \97 if (uhci_data) { \ 98 uhci_transfer_batch_dispose(uhci_data); \ 96 99 } \ 97 100 return NULL; \ 98 101 } else (void)0 99 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 100 130 usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t)); 101 131 CHECK_NULL_DISPOSE_RETURN(instance, 102 132 "Failed to allocate batch instance.\n"); 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; 103 137 usb_target_t target = 104 138 { .address = ep->address, .endpoint = ep->endpoint }; 105 usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed, 106 ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size, 107 func_in, func_out, arg, fun, ep, NULL); 108 109 110 uhci_batch_t *data = malloc(sizeof(uhci_batch_t)); 111 CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n"); 112 bzero(data, sizeof(uhci_batch_t)); 113 instance->private_data = data; 114 115 data->transfers = 116 (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size; 117 if (ep->transfer_type == USB_TRANSFER_CONTROL) { 118 data->transfers += 2; 119 } 120 121 data->tds = malloc32(sizeof(td_t) * data->transfers); 122 CHECK_NULL_DISPOSE_RETURN( 123 data->tds, "Failed to allocate transfer descriptors.\n"); 124 bzero(data->tds, sizeof(td_t) * data->transfers); 125 126 data->qh = malloc32(sizeof(qh_t)); 127 CHECK_NULL_DISPOSE_RETURN(data->qh, 128 "Failed to allocate batch queue head.\n"); 129 qh_init(data->qh); 130 qh_set_element_td(data->qh, addr_to_phys(data->tds)); 131 132 if (buffer_size > 0) { 133 instance->transport_buffer = malloc32(buffer_size); 134 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer, 135 "Failed to allocate device accessible buffer.\n"); 136 } 137 138 if (setup_size > 0) { 139 instance->setup_buffer = malloc32(setup_size); 140 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer, 141 "Failed to allocate device accessible setup buffer.\n"); 142 memcpy(instance->setup_buffer, setup_buffer, setup_size); 143 } 144 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); 145 144 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", 146 145 instance, target.address, target.endpoint); … … 154 153 * 155 154 * Walk all TDs. Stop with false if there is an active one (it is to be 156 * 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 157 156 * is reached. 158 157 */ … … 160 159 { 161 160 assert(instance); 162 uhci_ batch_t *data = instance->private_data;161 uhci_transfer_batch_t *data = instance->private_data; 163 162 assert(data); 164 163 165 164 usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n", 166 instance, data->t ransfers);165 instance, data->td_count); 167 166 instance->transfered_size = 0; 168 167 size_t i = 0; 169 for (;i < data->t ransfers; ++i) {168 for (;i < data->td_count; ++i) { 170 169 if (td_is_active(&data->tds[i])) { 171 170 return false; … … 177 176 instance, i, data->tds[i].status); 178 177 td_print_status(&data->tds[i]); 178 179 179 assert(instance->ep != NULL); 180 181 180 endpoint_toggle_set(instance->ep, 182 181 td_toggle(&data->tds[i])); … … 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
r3f2af64 rd8b275d 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 -
uspace/drv/uhci-hcd/hc.c
r3f2af64 rd8b275d 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"); … … 329 316 330 317 transfer_list_t *list = 331 instance->transfers[batch-> speed][batch->transfer_type];318 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 332 319 assert(list); 333 320 transfer_list_add_batch(list, batch); … … 479 466 #undef QH 480 467 } 481 /*----------------------------------------------------------------------------*/482 /** Check transfers for USB validity483 *484 * @param[in] low_speed Transfer speed.485 * @param[in] transfer Transer type486 * @param[in] size Size of data packets487 * @return True if transaction is allowed by USB specs, false otherwise488 */489 #if 0490 bool usb_is_allowed(491 bool low_speed, usb_transfer_type_t transfer, size_t size)492 {493 /* see USB specification chapter 5.5-5.8 for magic numbers used here */494 switch(transfer)495 {496 case USB_TRANSFER_ISOCHRONOUS:497 return (!low_speed && size < 1024);498 case USB_TRANSFER_INTERRUPT:499 return size <= (low_speed ? 8 : 64);500 case USB_TRANSFER_CONTROL: /* device specifies its own max size */501 return (size <= (low_speed ? 8 : 64));502 case USB_TRANSFER_BULK: /* device specifies its own max size */503 return (!low_speed && size <= 64);504 }505 return false;506 }507 #endif508 468 /** 509 469 * @} -
uspace/drv/uhci-hcd/hc.h
r3f2af64 rd8b275d 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; … … 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 63 63 } 64 64 65 usb_log_debug("%s %d:%d %zu(%zu).\n", 66 name, target.address, target.endpoint, size, ep->max_packet_size); 67 65 68 const size_t bw = bandwidth_count_usb11( 66 69 ep->speed, ep->transfer_type, size, ep->max_packet_size); … … 68 71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw " 69 72 "but only %zu is reserved.\n", 70 name, target.address, target.endpoint, bw, res_bw);73 target.address, target.endpoint, name, bw, res_bw); 71 74 return ENOSPC; 72 75 } 73 usb_log_debug("%s %d:%d %zu(%zu).\n",74 name, target.address, target.endpoint, size, ep->max_packet_size);75 76 76 77 *batch = batch_get( … … 146 147 hc_t *hc = fun_to_hc(fun); 147 148 assert(hc); 149 const size_t size = max_packet_size; 148 150 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address); 149 151 if (speed >= USB_SPEED_MAX) { 150 152 speed = ep_speed; 151 153 } 152 const size_t size =153 (transfer_type == USB_TRANSFER_INTERRUPT154 || transfer_type == USB_TRANSFER_ISOCHRONOUS) ?155 max_packet_size : 0;156 int ret;157 158 endpoint_t *ep = malloc(sizeof(endpoint_t));159 if (ep == NULL)160 return ENOMEM;161 ret = endpoint_init(ep, address, endpoint, direction,162 transfer_type, speed, max_packet_size);163 if (ret != EOK) {164 free(ep);165 return ret;166 }167 168 154 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n", 169 155 address, endpoint, usb_str_transfer_type(transfer_type), 170 156 usb_str_speed(speed), direction, size, max_packet_size, interval); 171 157 172 ret = usb_endpoint_manager_register_ep(&hc->ep_manager, ep, size); 173 if (ret != EOK) { 174 endpoint_destroy(ep); 175 } 176 return ret; 158 return usb_endpoint_manager_add_ep(&hc->ep_manager, address, endpoint, 159 direction, transfer_type, speed, max_packet_size, size); 177 160 } 178 161 /*----------------------------------------------------------------------------*/ … … 212 195 ret = hc_schedule(hc, batch); 213 196 if (ret != EOK) { 214 batch_dispose(batch);197 usb_transfer_batch_dispose(batch); 215 198 } 216 199 return ret; … … 240 223 ret = hc_schedule(hc, batch); 241 224 if (ret != EOK) { 242 batch_dispose(batch);225 usb_transfer_batch_dispose(batch); 243 226 } 244 227 return ret; … … 268 251 ret = hc_schedule(hc, batch); 269 252 if (ret != EOK) { 270 batch_dispose(batch);253 usb_transfer_batch_dispose(batch); 271 254 } 272 255 return ret; … … 296 279 ret = hc_schedule(hc, batch); 297 280 if (ret != EOK) { 298 batch_dispose(batch);281 usb_transfer_batch_dispose(batch); 299 282 } 300 283 return ret; … … 329 312 ret = hc_schedule(hc, batch); 330 313 if (ret != EOK) { 331 batch_dispose(batch);314 usb_transfer_batch_dispose(batch); 332 315 } 333 316 return ret; … … 361 344 ret = hc_schedule(hc, batch); 362 345 if (ret != EOK) { 363 batch_dispose(batch);346 usb_transfer_batch_dispose(batch); 364 347 } 365 348 return ret; -
uspace/drv/uhci-hcd/main.c
r3f2af64 rd8b275d 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 } … … 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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 /** Create list for finished batches.144 /** Add completed bantches to the provided list. 135 145 * 136 146 * @param[in] instance List to use. … … 147 157 link_t *next = current->next; 148 158 usb_transfer_batch_t *batch = 149 list_get_instance(current, usb_transfer_batch_t, link);159 usb_transfer_batch_from_link(current); 150 160 151 161 if (batch_is_complete(batch)) { 152 /* Save for p ost-processing */162 /* Save for processing */ 153 163 transfer_list_remove_batch(instance, batch); 154 164 list_append(current, done); … … 159 169 } 160 170 /*----------------------------------------------------------------------------*/ 161 /** Walk the list and abort all batches.171 /** Walk the list and finish all batches with EINTR. 162 172 * 163 173 * @param[in] instance List to use. … … 169 179 link_t *current = instance->batch_list.next; 170 180 usb_transfer_batch_t *batch = 171 list_get_instance(current, usb_transfer_batch_t, link);181 usb_transfer_batch_from_link(current); 172 182 transfer_list_remove_batch(instance, batch); 173 usb_transfer_batch_finish_error(batch, EI O);183 usb_transfer_batch_finish_error(batch, EINTR); 174 184 } 175 185 fibril_mutex_unlock(&instance->guard); … … 180 190 * @param[in] instance List to use. 181 191 * @param[in] batch Transfer batch to remove. 182 * @return Error code183 192 * 184 193 * Does not lock the transfer list, caller is responsible for that. … … 197 206 198 207 const char *qpos = NULL; 208 qh_t *prev_qh = NULL; 199 209 /* Remove from the hardware queue */ 200 210 if (instance->batch_list.next == &batch->link) { 201 211 /* I'm the first one here */ 202 assert((instance->queue_head->next & LINK_POINTER_ADDRESS_MASK) 203 == addr_to_phys(batch_qh(batch))); 204 instance->queue_head->next = batch_qh(batch)->next; 212 prev_qh = instance->queue_head; 205 213 qpos = "FIRST"; 206 214 } else { 215 /* The thing before me is a batch too */ 207 216 usb_transfer_batch_t *prev = 208 list_get_instance( 209 batch->link.prev, usb_transfer_batch_t, link); 210 assert((batch_qh(prev)->next & LINK_POINTER_ADDRESS_MASK) 211 == addr_to_phys(batch_qh(batch))); 212 batch_qh(prev)->next = batch_qh(batch)->next; 217 usb_transfer_batch_from_link(batch->link.prev); 218 prev_qh = batch_qh(prev); 213 219 qpos = "NOT FIRST"; 214 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; 215 224 asm volatile ("": : :"memory"); 216 225 /* Remove from the batch list */ 217 226 list_remove(&batch->link); 218 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", 219 228 batch, qpos, instance->name, batch_qh(batch)->next); 220 229 } -
uspace/drv/uhci-hcd/transfer_list.h
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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
r3f2af64 rd8b275d 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/usbhid/Makefile
r3f2af64 rd8b275d 40 40 main.c \ 41 41 usbhid.c \ 42 subdrivers.c \ 42 43 kbd/conv.c \ 43 44 kbd/kbddev.c \ 44 45 kbd/kbdrepeat.c \ 45 46 generic/hiddev.c \ 47 mouse/mousedev.c \ 46 48 $(STOLEN_LAYOUT_SOURCES) 47 49 -
uspace/drv/usbhid/generic/hiddev.c
r3f2af64 rd8b275d 39 39 40 40 #include "hiddev.h" 41 #include "usbhid.h" 41 42 42 43 /*----------------------------------------------------------------------------*/ … … 54 55 /*----------------------------------------------------------------------------*/ 55 56 56 bool usb_ hid_polling_callback(usb_device_t *dev, uint8_t *buffer,57 size_t buffer_size, void *arg)57 bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, 58 uint8_t *buffer, size_t buffer_size) 58 59 { 59 usb_log_debug("usb_hid_polling_callback()\n"); 60 usb_log_debug("usb_hid_polling_callback(%p, %p, %zu)\n", 61 hid_dev, buffer, buffer_size); 60 62 usb_debug_str_buffer(buffer, buffer_size, 0); 61 63 return true; -
uspace/drv/usbhid/generic/hiddev.h
r3f2af64 rd8b275d 34 34 */ 35 35 36 #ifndef USB_HID D_H_37 #define USB_HID D_H_36 #ifndef USB_HID_HIDDDEV_H_ 37 #define USB_HID_HIDDDEV_H_ 38 38 39 39 #include <usb/devdrv.h> 40 41 struct usb_hid_dev; 40 42 41 43 usb_endpoint_description_t usb_hid_generic_poll_endpoint_description; … … 44 46 const char *HID_GENERIC_CLASS_NAME; 45 47 46 bool usb_ hid_polling_callback(usb_device_t *dev, uint8_t *buffer,47 size_t buffer_size, void *arg);48 bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, 49 uint8_t *buffer, size_t buffer_size); 48 50 49 #endif // USB_HID D_H_51 #endif // USB_HID_HIDDDEV_H_ 50 52 51 53 /** -
uspace/drv/usbhid/kbd/conv.h
r3f2af64 rd8b275d 34 34 */ 35 35 36 #ifndef USB_ KBD_CONV_H_37 #define USB_ KBD_CONV_H_36 #ifndef USB_HID_CONV_H_ 37 #define USB_HID_CONV_H_ 38 38 39 39 unsigned int usbhid_parse_scancode(int scancode); 40 40 41 #endif /* USB_ KBD_CONV_H_ */41 #endif /* USB_HID_CONV_H_ */ 42 42 43 43 /** -
uspace/drv/usbhid/kbd/kbddev.c
r3f2af64 rd8b275d 238 238 * @param icall Call data. 239 239 */ 240 void default_connection_handler(ddf_fun_t *fun,240 static void default_connection_handler(ddf_fun_t *fun, 241 241 ipc_callid_t icallid, ipc_call_t *icall) 242 242 { … … 856 856 /*----------------------------------------------------------------------------*/ 857 857 858 bool usb_kbd_polling_callback(usb_ device_t *dev, uint8_t *buffer,859 size_t buffer_size , void *arg)860 { 861 if ( dev == NULL || buffer == NULL || arg== NULL) {858 bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, uint8_t *buffer, 859 size_t buffer_size) 860 { 861 if (hid_dev == NULL || buffer == NULL) { 862 862 // do not continue polling (???) 863 863 return false; 864 864 } 865 866 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;867 865 868 866 // TODO: add return value from this function … … 916 914 /*----------------------------------------------------------------------------*/ 917 915 918 void usb_kbd_deinit( structusb_hid_dev_t *hid_dev)916 void usb_kbd_deinit(usb_hid_dev_t *hid_dev) 919 917 { 920 918 if (hid_dev == NULL) { -
uspace/drv/usbhid/kbd/kbddev.h
r3f2af64 rd8b275d 34 34 */ 35 35 36 #ifndef USB_ KBDDEV_H_37 #define USB_ KBDDEV_H_36 #ifndef USB_HID_KBDDEV_H_ 37 #define USB_HID_KBDDEV_H_ 38 38 39 39 #include <stdint.h> … … 49 49 #include "kbdrepeat.h" 50 50 51 struct usb_hid_dev _t;51 struct usb_hid_dev; 52 52 53 53 /*----------------------------------------------------------------------------*/ … … 65 65 */ 66 66 typedef struct usb_kbd_t { 67 /** Structure holding generic USB device information. */68 //usbhid_dev_t *hid_dev;69 //usb_device_t *usb_dev;70 71 67 /** Currently pressed keys (not translated to key codes). */ 72 68 uint8_t *keys; … … 91 87 fibril_mutex_t *repeat_mtx; 92 88 93 /** Report descriptor. */94 //uint8_t *report_desc;95 96 /** Report descriptor size. */97 //size_t report_desc_size;98 99 89 uint8_t *output_buffer; 100 90 … … 106 96 107 97 int32_t *led_data; 108 109 /** HID Report parser. */110 //usb_hid_report_parser_t *parser;111 98 112 99 /** State of the structure (for checking before use). … … 121 108 /*----------------------------------------------------------------------------*/ 122 109 123 //enum {124 // USB_KBD_POLL_EP_NO = 0,125 // USB_HID_POLL_EP_NO = 1,126 // USB_KBD_POLL_EP_COUNT = 2127 //};128 129 //usb_endpoint_description_t *usb_kbd_endpoints[USB_KBD_POLL_EP_COUNT + 1];130 131 //ddf_dev_ops_t keyboard_ops;132 133 110 usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description; 134 111 … … 138 115 /*----------------------------------------------------------------------------*/ 139 116 140 //usb_kbd_t *usb_kbd_new(void);117 int usb_kbd_init(struct usb_hid_dev *hid_dev); 141 118 142 int usb_kbd_init(struct usb_hid_dev_t *hid_dev); 143 144 bool usb_kbd_polling_callback(usb_device_t *dev, uint8_t *buffer, 145 size_t buffer_size, void *arg); 146 147 //void usb_kbd_polling_ended_callback(usb_device_t *dev, bool reason, 148 // void *arg); 119 bool usb_kbd_polling_callback(struct usb_hid_dev *hid_dev, uint8_t *buffer, 120 size_t buffer_size); 149 121 150 122 int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev); … … 154 126 void usb_kbd_free(usb_kbd_t **kbd_dev); 155 127 156 void usb_kbd_push_ev(struct usb_hid_dev _t*hid_dev, usb_kbd_t *kbd_dev,128 void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev, 157 129 int type, unsigned int key); 158 130 131 void usb_kbd_deinit(struct usb_hid_dev *hid_dev); 159 132 160 void usb_kbd_deinit(struct usb_hid_dev_t*hid_dev);133 int usb_kbd_set_boot_protocol(struct usb_hid_dev *hid_dev); 161 134 162 int usb_kbd_set_boot_protocol(struct usb_hid_dev_t *hid_dev); 163 164 #endif /* USB_KBDDEV_H_ */ 135 #endif /* USB_HID_KBDDEV_H_ */ 165 136 166 137 /** -
uspace/drv/usbhid/kbd/kbdrepeat.h
r3f2af64 rd8b275d 34 34 */ 35 35 36 #ifndef USB_ KBDREPEAT_H_37 #define USB_ KBDREPEAT_H_36 #ifndef USB_HID_KBDREPEAT_H_ 37 #define USB_HID_KBDREPEAT_H_ 38 38 39 39 struct usb_kbd_t; … … 62 62 void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key); 63 63 64 #endif /* USB_ KBDREPEAT_H_ */64 #endif /* USB_HID_KBDREPEAT_H_ */ 65 65 66 66 /** -
uspace/drv/usbhid/layout.h
r3f2af64 rd8b275d 36 36 */ 37 37 38 #ifndef USB_ KBD_LAYOUT_H_39 #define USB_ KBD_LAYOUT_H_38 #ifndef USB_HID_LAYOUT_H_ 39 #define USB_HID_LAYOUT_H_ 40 40 41 41 #include <sys/types.h> -
uspace/drv/usbhid/main.c
r3f2af64 rd8b275d 98 98 /* Create the function exposed under /dev/devices. */ 99 99 ddf_fun_t *hid_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 100 usb_hid_get_function_name(hid_dev ->device_type));100 usb_hid_get_function_name(hid_dev)); 101 101 if (hid_fun == NULL) { 102 102 usb_log_error("Could not create DDF function node.\n"); … … 122 122 } 123 123 124 rc = ddf_fun_add_to_class(hid_fun, 125 usb_hid_get_class_name(hid_dev->device_type)); 124 rc = ddf_fun_add_to_class(hid_fun, usb_hid_get_class_name(hid_dev)); 126 125 if (rc != EOK) { 127 126 usb_log_error( … … 142 141 hid_dev->poll_pipe_index, 143 142 /* Callback when data arrives. */ 144 hid_dev->poll_callback,143 usb_hid_polling_callback, 145 144 /* How much data to request. */ 146 145 dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size, -
uspace/drv/usbhid/subdrivers.c
r3f2af64 rd8b275d 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 subdriver mappings. 35 34 */ 36 35 37 #include <proc/tasklet.h> 38 #include <synch/spinlock.h> 39 #include <mm/slab.h> 40 #include <config.h> 36 #include "subdrivers.h" 37 #include "usb/classes/hidut.h" 41 38 42 /** Spinlock protecting list of tasklets */ 43 SPINLOCK_INITIALIZE(tasklet_lock); 39 static usb_hid_subdriver_usage_t path_kbd[] = {{USB_HIDUT_PAGE_KEYBOARD, 0}}; 44 40 45 /** Array of tasklet lists for every CPU */ 46 tasklet_descriptor_t **tasklet_list; 41 const usb_hid_subdriver_mapping_t usb_hid_subdrivers[] = { 42 { 43 path_kbd, 44 1, 45 USB_HID_PATH_COMPARE_END 46 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 47 NULL, 48 NULL, 49 { 50 usb_kbd_init, 51 usb_kbd_deinit, 52 usb_kbd_polling_callback, 53 NULL 54 }, 55 56 }, 57 {NULL, 0, 0, NULL, NULL, {NULL, NULL, NULL, NULL}} 58 }; 47 59 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 } 61 62 63 /** @} 60 /** 61 * @} 64 62 */ -
uspace/drv/usbhid/usbhid.c
r3f2af64 rd8b275d 42 42 #include <usb/classes/hidreq.h> 43 43 #include <errno.h> 44 #include <str_error.h> 44 45 45 46 #include "usbhid.h" … … 47 48 #include "kbd/kbddev.h" 48 49 #include "generic/hiddev.h" 49 50 /*----------------------------------------------------------------------------*/ 51 52 /** Mouse polling endpoint description for boot protocol class. */ 53 static usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = { 54 .transfer_type = USB_TRANSFER_INTERRUPT, 55 .direction = USB_DIRECTION_IN, 56 .interface_class = USB_CLASS_HID, 57 .interface_subclass = USB_HID_SUBCLASS_BOOT, 58 .interface_protocol = USB_HID_PROTOCOL_MOUSE, 59 .flags = 0 60 }; 50 #include "mouse/mousedev.h" 51 #include "subdrivers.h" 52 53 /*----------------------------------------------------------------------------*/ 61 54 62 55 /* Array of endpoints expected on the device, NULL terminated. */ … … 68 61 }; 69 62 70 static const char *HID_MOUSE_FUN_NAME = "mouse"; 71 static const char *HID_MOUSE_CLASS_NAME = "mouse"; 63 static const int USB_HID_MAX_SUBDRIVERS = 10; 64 65 /*----------------------------------------------------------------------------*/ 66 67 static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev) 68 { 69 assert(hid_dev->subdriver_count == 0); 70 71 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc( 72 sizeof(usb_hid_subdriver_t)); 73 if (hid_dev->subdrivers == NULL) { 74 return ENOMEM; 75 } 76 77 // set the init callback 78 hid_dev->subdrivers[0].init = usb_kbd_init; 79 80 // set the polling callback 81 hid_dev->subdrivers[0].poll = usb_kbd_polling_callback; 82 83 // set the polling ended callback 84 hid_dev->subdrivers[0].poll_end = NULL; 85 86 // set the deinit callback 87 hid_dev->subdrivers[0].deinit = usb_kbd_deinit; 88 89 // set subdriver count 90 hid_dev->subdriver_count = 1; 91 92 return EOK; 93 } 94 95 /*----------------------------------------------------------------------------*/ 96 97 static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev) 98 { 99 assert(hid_dev->subdriver_count == 0); 100 101 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc( 102 sizeof(usb_hid_subdriver_t)); 103 if (hid_dev->subdrivers == NULL) { 104 return ENOMEM; 105 } 106 107 // set the init callback 108 hid_dev->subdrivers[0].init = usb_mouse_init; 109 110 // set the polling callback 111 hid_dev->subdrivers[0].poll = usb_mouse_polling_callback; 112 113 // set the polling ended callback 114 hid_dev->subdrivers[0].poll_end = NULL; 115 116 // set the deinit callback 117 hid_dev->subdrivers[0].deinit = usb_mouse_deinit; 118 119 // set subdriver count 120 hid_dev->subdriver_count = 1; 121 122 return EOK; 123 } 124 125 /*----------------------------------------------------------------------------*/ 126 127 static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev) 128 { 129 assert(hid_dev->subdriver_count == 0); 130 131 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc( 132 sizeof(usb_hid_subdriver_t)); 133 if (hid_dev->subdrivers == NULL) { 134 return ENOMEM; 135 } 136 137 // set the init callback 138 hid_dev->subdrivers[0].init = NULL; 139 140 // set the polling callback 141 hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback; 142 143 // set the polling ended callback 144 hid_dev->subdrivers[0].poll_end = NULL; 145 146 // set the deinit callback 147 hid_dev->subdrivers[0].deinit = NULL; 148 149 // set subdriver count 150 hid_dev->subdriver_count = 1; 151 152 return EOK; 153 } 154 155 /*----------------------------------------------------------------------------*/ 156 157 static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev, 158 const usb_hid_subdriver_mapping_t *mapping) 159 { 160 return false; 161 } 162 163 /*----------------------------------------------------------------------------*/ 164 165 static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev, 166 const usb_hid_subdriver_usage_t *path, int path_size, int compare) 167 { 168 assert(hid_dev != NULL); 169 assert(path != NULL); 170 171 usb_hid_report_path_t *usage_path = usb_hid_report_path(); 172 if (usage_path == NULL) { 173 usb_log_debug("Failed to create usage path.\n"); 174 return false; 175 } 176 int i; 177 for (i = 0; i < path_size; ++i) { 178 if (usb_hid_report_path_append_item(usage_path, 179 path[i].usage_page, path[i].usage) != EOK) { 180 usb_log_debug("Failed to append to usage path.\n"); 181 usb_hid_report_path_free(usage_path); 182 return false; 183 } 184 } 185 186 assert(hid_dev->parser != NULL); 187 188 usb_log_debug("Compare flags: %d\n", compare); 189 size_t size = usb_hid_report_input_length(hid_dev->parser, usage_path, 190 compare); 191 usb_log_debug("Size of the input report: %d\n", size); 192 193 usb_hid_report_path_free(usage_path); 194 195 return (size > 0); 196 } 197 198 /*----------------------------------------------------------------------------*/ 199 200 static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev, 201 const usb_hid_subdriver_t **subdrivers, int count) 202 { 203 int i; 204 205 if (count <= 0) { 206 hid_dev->subdriver_count = 0; 207 hid_dev->subdrivers = NULL; 208 return EOK; 209 } 210 211 hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(count * 212 sizeof(usb_hid_subdriver_t)); 213 if (hid_dev->subdrivers == NULL) { 214 return ENOMEM; 215 } 216 217 for (i = 0; i < count; ++i) { 218 hid_dev->subdrivers[i].init = subdrivers[i]->init; 219 hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit; 220 hid_dev->subdrivers[i].poll = subdrivers[i]->poll; 221 hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end; 222 } 223 224 hid_dev->subdriver_count = count; 225 226 return EOK; 227 } 228 229 /*----------------------------------------------------------------------------*/ 230 231 static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev) 232 { 233 const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS]; 234 235 int i = 0, count = 0; 236 const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i]; 237 238 while (count < USB_HID_MAX_SUBDRIVERS && 239 (mapping->usage_path != NULL 240 || mapping->vendor_id != NULL 241 || mapping->product_id != NULL)) { 242 // check the vendor & product ID 243 if (mapping->vendor_id != NULL && mapping->product_id == NULL) { 244 usb_log_warning("Missing Product ID for Vendor ID %s\n", 245 mapping->vendor_id); 246 return EINVAL; 247 } 248 if (mapping->product_id != NULL && mapping->vendor_id == NULL) { 249 usb_log_warning("Missing Vendor ID for Product ID %s\n", 250 mapping->product_id); 251 return EINVAL; 252 } 253 254 if (mapping->vendor_id != NULL) { 255 assert(mapping->product_id != NULL); 256 usb_log_debug("Comparing device against vendor ID %s" 257 " and product ID %s.\n", mapping->vendor_id, 258 mapping->product_id); 259 if (usb_hid_ids_match(hid_dev, mapping)) { 260 usb_log_debug("Matched.\n"); 261 subdrivers[count++] = &mapping->subdriver; 262 // skip the checking of usage path 263 goto next; 264 } 265 } 266 267 if (mapping->usage_path != NULL) { 268 usb_log_debug("Comparing device against usage path.\n"); 269 if (usb_hid_path_matches(hid_dev, 270 mapping->usage_path, mapping->path_size, 271 mapping->compare)) { 272 subdrivers[count++] = &mapping->subdriver; 273 } else { 274 usb_log_debug("Not matched.\n"); 275 } 276 } 277 next: 278 mapping = &usb_hid_subdrivers[++i]; 279 } 280 281 // we have all subdrivers determined, save them into the hid device 282 return usb_hid_save_subdrivers(hid_dev, subdrivers, count); 283 } 284 285 /*----------------------------------------------------------------------------*/ 286 287 static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev) 288 { 289 int rc = EOK; 290 291 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) { 292 usb_log_debug("Found keyboard endpoint.\n"); 293 // save the pipe index 294 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO; 295 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) { 296 usb_log_debug("Found mouse endpoint.\n"); 297 // save the pipe index 298 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO; 299 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) { 300 usb_log_debug("Found generic HID endpoint.\n"); 301 // save the pipe index 302 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO; 303 } else { 304 usb_log_error("None of supported endpoints found - probably" 305 " not a supported device.\n"); 306 rc = ENOTSUP; 307 } 308 309 return rc; 310 } 72 311 73 312 /*----------------------------------------------------------------------------*/ … … 91 330 } 92 331 332 hid_dev->poll_pipe_index = -1; 333 93 334 return hid_dev; 94 335 } … … 96 337 /*----------------------------------------------------------------------------*/ 97 338 98 static bool usb_dummy_polling_callback(usb_device_t *dev, uint8_t *buffer,99 size_t buffer_size, void *arg)100 {101 usb_log_debug("Dummy polling callback.\n");102 return false;103 }104 105 /*----------------------------------------------------------------------------*/106 107 static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)108 {109 if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {110 usb_log_debug("Found keyboard endpoint.\n");111 112 // save the pipe index and device type113 hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;114 hid_dev->device_type = USB_HID_PROTOCOL_KEYBOARD;115 116 // set the polling callback117 hid_dev->poll_callback = usb_kbd_polling_callback;118 119 } else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {120 usb_log_debug("Found mouse endpoint.\n");121 122 // save the pipe index and device type123 hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;124 hid_dev->device_type = USB_HID_PROTOCOL_MOUSE;125 126 // set the polling callback127 hid_dev->poll_callback = usb_dummy_polling_callback;128 129 } else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {130 usb_log_debug("Found generic HID endpoint.\n");131 132 // save the pipe index and device type133 hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;134 hid_dev->device_type = USB_HID_PROTOCOL_NONE;135 136 // set the polling callback137 hid_dev->poll_callback = usb_hid_polling_callback;138 139 } else {140 usb_log_warning("None of supported endpoints found - probably"141 " not a supported device.\n");142 return ENOTSUP;143 }144 145 return EOK;146 }147 148 /*----------------------------------------------------------------------------*/149 150 static int usb_hid_init_parser(usb_hid_dev_t *hid_dev)151 {152 /* Initialize the report parser. */153 int rc = usb_hid_parser_init(hid_dev->parser);154 if (rc != EOK) {155 usb_log_error("Failed to initialize report parser.\n");156 return rc;157 }158 159 /* Get the report descriptor and parse it. */160 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,161 hid_dev->parser);162 163 if (rc != EOK) {164 usb_log_warning("Could not process report descriptor.\n");165 166 if (hid_dev->device_type == USB_HID_PROTOCOL_KEYBOARD) {167 usb_log_warning("Falling back to boot protocol.\n");168 169 rc = usb_kbd_set_boot_protocol(hid_dev);170 171 } else if (hid_dev->device_type == USB_HID_PROTOCOL_MOUSE) {172 usb_log_warning("No boot protocol for mouse yet.\n");173 rc = ENOTSUP;174 }175 }176 177 return rc;178 }179 180 /*----------------------------------------------------------------------------*/181 182 339 int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev) 183 340 { 184 int rc ;341 int rc, i; 185 342 186 343 usb_log_debug("Initializing HID structure...\n"); … … 203 360 rc = usb_hid_check_pipes(hid_dev, dev); 204 361 if (rc != EOK) { 362 usb_hid_free(&hid_dev); 205 363 return rc; 206 364 } 207 365 208 rc = usb_hid_init_parser(hid_dev); 366 /* Initialize the report parser. */ 367 rc = usb_hid_parser_init(hid_dev->parser); 209 368 if (rc != EOK) { 210 usb_log_error("Failed to initialize HID parser.\n"); 369 usb_log_error("Failed to initialize report parser.\n"); 370 usb_hid_free(&hid_dev); 211 371 return rc; 212 372 } 213 373 214 switch (hid_dev->device_type) { 215 case USB_HID_PROTOCOL_KEYBOARD: 216 // initialize the keyboard structure 217 rc = usb_kbd_init(hid_dev); 218 if (rc != EOK) { 219 usb_log_warning("Failed to initialize KBD structure." 220 "\n"); 221 } 222 break; 223 case USB_HID_PROTOCOL_MOUSE: 224 break; 225 default: 226 // usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 227 // hid_dev->usb_dev->interface_no, 0); 228 break; 374 /* Get the report descriptor and parse it. */ 375 rc = usb_hid_process_report_descriptor(hid_dev->usb_dev, 376 hid_dev->parser); 377 378 bool fallback = false; 379 380 if (rc == EOK) { 381 // try to find subdrivers that may want to handle this device 382 rc = usb_hid_find_subdrivers(hid_dev); 383 if (rc != EOK || hid_dev->subdriver_count == 0) { 384 // try to fall back to the boot protocol if available 385 usb_log_info("No subdrivers found to handle this" 386 " device.\n"); 387 fallback = true; 388 } 389 } else { 390 usb_log_error("Failed to parse Report descriptor.\n"); 391 // try to fall back to the boot protocol if available 392 fallback = true; 393 } 394 395 // TODO: remove the mouse hack 396 if (hid_dev->poll_pipe_index == USB_HID_MOUSE_POLL_EP_NO || 397 fallback) { 398 // fall back to boot protocol 399 switch (hid_dev->poll_pipe_index) { 400 case USB_HID_KBD_POLL_EP_NO: 401 usb_log_info("Falling back to kbd boot protocol.\n"); 402 rc = usb_kbd_set_boot_protocol(hid_dev); 403 if (rc == EOK) { 404 rc = usb_hid_set_boot_kbd_subdriver(hid_dev); 405 } 406 break; 407 case USB_HID_MOUSE_POLL_EP_NO: 408 usb_log_info("Falling back to mouse boot protocol.\n"); 409 rc = usb_mouse_set_boot_protocol(hid_dev); 410 if (rc == EOK) { 411 rc = usb_hid_set_boot_mouse_subdriver(hid_dev); 412 } 413 break; 414 default: 415 assert(hid_dev->poll_pipe_index 416 == USB_HID_GENERIC_POLL_EP_NO); 417 418 /* TODO: this has no meaning if the report descriptor 419 is not parsed */ 420 usb_log_info("Falling back to generic HID driver.\n"); 421 rc = usb_hid_set_generic_hid_subdriver(hid_dev); 422 } 423 } 424 425 if (rc != EOK) { 426 usb_log_error("No subdriver for handling this device could be" 427 " initialized: %s.\n", str_error(rc)); 428 usb_hid_free(&hid_dev); 429 } else { 430 bool ok = false; 431 432 usb_log_debug("Subdriver count: %d\n", 433 hid_dev->subdriver_count); 434 435 for (i = 0; i < hid_dev->subdriver_count; ++i) { 436 if (hid_dev->subdrivers[i].init != NULL) { 437 usb_log_debug("Initializing subdriver %d.\n",i); 438 rc = hid_dev->subdrivers[i].init(hid_dev); 439 if (rc != EOK) { 440 usb_log_warning("Failed to initialize" 441 " HID subdriver structure.\n"); 442 } else { 443 // at least one subdriver initialized 444 ok = true; 445 } 446 } else { 447 ok = true; 448 } 449 } 450 451 rc = (ok) ? EOK : -1; // what error to report 229 452 } 230 453 231 454 return rc; 455 } 456 457 /*----------------------------------------------------------------------------*/ 458 459 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 460 size_t buffer_size, void *arg) 461 { 462 int i; 463 464 if (dev == NULL || arg == NULL || buffer == NULL) { 465 usb_log_error("Missing arguments to polling callback.\n"); 466 return false; 467 } 468 469 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg; 470 471 bool cont = false; 472 473 // continue if at least one of the subdrivers want to continue 474 for (i = 0; i < hid_dev->subdriver_count; ++i) { 475 if (hid_dev->subdrivers[i].poll != NULL 476 && hid_dev->subdrivers[i].poll(hid_dev, buffer, 477 buffer_size)) { 478 cont = true; 479 } 480 } 481 482 return cont; 232 483 } 233 484 … … 237 488 void *arg) 238 489 { 490 int i; 491 239 492 if (dev == NULL || arg == NULL) { 240 493 return; … … 243 496 usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg; 244 497 498 for (i = 0; i < hid_dev->subdriver_count; ++i) { 499 if (hid_dev->subdrivers[i].poll_end != NULL) { 500 hid_dev->subdrivers[i].poll_end(hid_dev, reason); 501 } 502 } 503 245 504 usb_hid_free(&hid_dev); 246 505 } … … 248 507 /*----------------------------------------------------------------------------*/ 249 508 250 const char *usb_hid_get_function_name( usb_hid_iface_protocol_t device_type)251 { 252 switch ( device_type) {253 case USB_HID_ PROTOCOL_KEYBOARD:509 const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev) 510 { 511 switch (hid_dev->poll_pipe_index) { 512 case USB_HID_KBD_POLL_EP_NO: 254 513 return HID_KBD_FUN_NAME; 255 514 break; 256 case USB_HID_ PROTOCOL_MOUSE:515 case USB_HID_MOUSE_POLL_EP_NO: 257 516 return HID_MOUSE_FUN_NAME; 258 517 break; … … 264 523 /*----------------------------------------------------------------------------*/ 265 524 266 const char *usb_hid_get_class_name(usb_hid_iface_protocol_t device_type) 267 { 268 switch (device_type) { 269 case USB_HID_PROTOCOL_KEYBOARD: 525 const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev) 526 { 527 // this means that only boot protocol keyboards will be connected 528 // to the console; there is probably no better way to do this 529 530 switch (hid_dev->poll_pipe_index) { 531 case USB_HID_KBD_POLL_EP_NO: 270 532 return HID_KBD_CLASS_NAME; 271 533 break; 272 case USB_HID_ PROTOCOL_MOUSE:534 case USB_HID_MOUSE_POLL_EP_NO: 273 535 return HID_MOUSE_CLASS_NAME; 274 536 break; … … 282 544 void usb_hid_free(usb_hid_dev_t **hid_dev) 283 545 { 546 int i; 547 284 548 if (hid_dev == NULL || *hid_dev == NULL) { 285 549 return; 286 550 } 287 551 288 switch ((*hid_dev)->device_type) { 289 case USB_HID_PROTOCOL_KEYBOARD: 290 usb_kbd_deinit(*hid_dev); 291 break; 292 case USB_HID_PROTOCOL_MOUSE: 293 break; 294 default: 295 break; 552 assert((*hid_dev)->subdrivers != NULL 553 || (*hid_dev)->subdriver_count == 0); 554 555 for (i = 0; i < (*hid_dev)->subdriver_count; ++i) { 556 if ((*hid_dev)->subdrivers[i].deinit != NULL) { 557 (*hid_dev)->subdrivers[i].deinit(*hid_dev); 558 } 559 } 560 561 // free the subdrivers info 562 if ((*hid_dev)->subdrivers != NULL) { 563 free((*hid_dev)->subdrivers); 296 564 } 297 565 -
uspace/drv/usbhid/usbhid.h
r3f2af64 rd8b275d 34 34 */ 35 35 36 #ifndef USB_ USBHID_H_37 #define USB_ USBHID_H_36 #ifndef USB_HID_USBHID_H_ 37 #define USB_HID_USBHID_H_ 38 38 39 39 #include <stdint.h> … … 45 45 #include <usb/classes/hid.h> 46 46 47 struct usb_hid_dev; 48 49 typedef int (*usb_hid_driver_init_t)(struct usb_hid_dev *); 50 typedef void (*usb_hid_driver_deinit_t)(struct usb_hid_dev *); 51 typedef bool (*usb_hid_driver_poll)(struct usb_hid_dev *, uint8_t *, size_t); 52 typedef int (*usb_hid_driver_poll_ended)(struct usb_hid_dev *, bool reason); 53 54 // TODO: add function and class name?? 55 typedef struct usb_hid_subdriver { 56 /** Function to be called when initializing HID device. */ 57 usb_hid_driver_init_t init; 58 /** Function to be called when destroying the HID device structure. */ 59 usb_hid_driver_deinit_t deinit; 60 /** Function to be called when data arrives from the device. */ 61 usb_hid_driver_poll poll; 62 /** Function to be called when polling ends. */ 63 usb_hid_driver_poll_ended poll_end; 64 } usb_hid_subdriver_t; 65 47 66 /*----------------------------------------------------------------------------*/ 48 67 /** 49 68 * Structure for holding general HID device data. 50 69 */ 51 typedef struct usb_hid_dev _t{70 typedef struct usb_hid_dev { 52 71 /** Structure holding generic USB device information. */ 53 72 usb_device_t *usb_dev; … … 59 78 int poll_pipe_index; 60 79 61 /** Function to be called when data arrives from the device. */ 62 usb_polling_callback_t poll_callback; 80 /** Subdrivers. */ 81 usb_hid_subdriver_t *subdrivers; 82 83 /** Number of subdrivers. */ 84 int subdriver_count; 63 85 64 86 /** Report descriptor. */ … … 73 95 /** Arbitrary data (e.g. a special structure for handling keyboard). */ 74 96 void *data; 75 76 /** Type of the device (keyboard, mouse, generic HID device). */77 usb_hid_iface_protocol_t device_type;78 97 } usb_hid_dev_t; 79 98 … … 95 114 int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev); 96 115 116 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 117 size_t buffer_size, void *arg); 118 97 119 void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 98 120 void *arg); 99 121 100 const char *usb_hid_get_function_name( usb_hid_iface_protocol_t device_type);122 const char *usb_hid_get_function_name(const usb_hid_dev_t *hid_dev); 101 123 102 const char *usb_hid_get_class_name( usb_hid_iface_protocol_t device_type);124 const char *usb_hid_get_class_name(const usb_hid_dev_t *hid_dev); 103 125 104 126 void usb_hid_free(usb_hid_dev_t **hid_dev); 105 127 106 #endif /* USB_ USBHID_H_ */128 #endif /* USB_HID_USBHID_H_ */ 107 129 108 130 /** -
uspace/drv/usbhid/usbhid.ma
r3f2af64 rd8b275d 1 1 100 usb&interface&class=HID&subclass=0x01&protocol=0x01 2 100 usb&interface&class=HID&subclass=0x01&protocol=0x022 1000 usb&interface&class=HID&subclass=0x01&protocol=0x02 3 3 100 usb&interface&class=HID -
uspace/drv/usbhub/usbhub.c
r3f2af64 rd8b275d 247 247 for (port = 0; port < hub_info->port_count + 1; port++) { 248 248 usb_hub_port_init(&hub_info->ports[port]); 249 } 250 for (port = 0; port < hub_info->port_count; port++) { 251 opResult = usb_hub_set_port_feature(hub_info->control_pipe, 252 port+1, USB_HUB_FEATURE_PORT_POWER); 253 if (opResult != EOK) { 254 usb_log_error("cannot power on port %d; %d\n", 255 port+1, opResult); 256 } 249 257 } 250 258 usb_log_debug2("freeing data\n");
Note:
See TracChangeset
for help on using the changeset viewer.
