Fix the USB code that was destroying my shell.
[barrelfish] / usr / drivers / usb / usb_manager / usb_manager.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <barrelfish/barrelfish.h>
6 #include <barrelfish/nameservice_client.h>
7 #include <barrelfish/inthandler.h>
8 #include <driverkit/driverkit.h>
9
10 #include <usb/usb.h>
11
12 #include <if/usb_driver_defs.h>
13 #include <if/usb_manager_defs.h>
14 #include <if/usb_manager_rpcclient_defs.h>
15
16 #include <usb_controller.h>
17 #include <usb_request.h>
18 #include <usb_device.h>
19 #include <usb_transfer.h>
20 #include <usb_driver.h>
21
22 /*
23  * ========================================================================
24  * Flounder callbacks and service connect handling
25  * ========================================================================
26  */
27
28 /**
29  * struct representing the state of a new USB driver connection
30  */
31 struct usb_manager_connect_state {
32     struct usb_manager_binding *b;      ///< the usb_manager_binding struct
33     struct usb_driver_binding *driver;  ///< the usb drivers service
34     void *desc;                         ///< configuration descriptor
35     uint32_t length;                    ///< length of the descirptor
36     usb_error_t error;                  ///< the outcome of the initial setup
37     iref_t driver_iref;                 ///< the drivers iref
38 };
39
40 /**
41  * \brief callback for USB driver binding
42  *
43  * \param st the supplied state
44  * \param err the outcome of the binding process
45  * \param b the driver binding
46  *
47  * This function is the last step in the setup procedure and frees up the state
48  */
49 static void usb_driver_bind_cb(void *st, errval_t err,
50         struct usb_driver_binding *b)
51 {
52     USB_DEBUG_IDC("usb_driver_bind_cb\n");
53
54     if (err_is_fail(err)) {
55         USB_DEBUG("driver binding failed..\n");
56     }
57
58     struct usb_manager_connect_state *cs = st;
59
60     cs->driver = b;
61     struct usb_device *dev = cs->b->st;
62     dev->usb_driver_binding = b;
63
64     free(cs->desc);
65     free(cs);
66 }
67
68 /*
69  * \brief callback for successful sent replies to the connect rpc
70  *
71  * \param a the state of the connection call
72  *
73  * This function binds to the USB driver iref
74  */
75 static void usb_driver_connect_cb(void *a)
76 {
77     USB_DEBUG_IDC("usb_driver_connect_cb->binding...\n");
78     struct usb_manager_connect_state *st = a;
79     errval_t err = usb_driver_bind(st->driver_iref, usb_driver_bind_cb, st,
80             get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
81     if (err_is_fail(err)) {
82         DEBUG_ERR(err, "usb driver bind failed");
83         usb_device_free(st->b->st, 0);
84         free(st->desc);
85         free(st);
86     }
87 }
88
89 /*
90  * \brief sends the response to the connect rpc
91  *
92  * \param a the connection state
93  */
94 static void usb_driver_connect_response(void *a)
95 {
96     errval_t err;
97     struct usb_manager_connect_state *st = a;
98
99     struct event_closure txcont = MKCONT(usb_driver_connect_cb, st);
100
101     err = usb_manager_connect_response__tx(st->b, txcont, st->error, st->desc,
102             st->length);
103
104     if (err_is_fail(err)) {
105         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
106             // try to resend
107             txcont = MKCONT(usb_driver_connect_response, st);
108             err = st->b->register_send(st->b, get_default_waitset(), txcont);
109             if (err_is_fail(err)) {
110                 DEBUG_ERR(err, "failed to register send");
111             }
112         } else {
113             // error
114             DEBUG_ERR(err, "error while seniding driver connect response");
115             /* free the device */
116             usb_device_free(st->b->st, 0);
117             free(st->desc);
118             free(st);
119         }
120     }
121 }
122
123 /**
124  * \brief this function handles connections of new USB device driver processes
125  *
126  * \param bind  the binding which we received the connect cal
127  * \param driver_iref the iref of the usb driver
128  * \param init_config the initial configuration to set the device
129  *
130  * This function associates the USB device with an flounder binding. Further
131  * the usb manager connects to the usb drivers service for notifications
132  */
133 static void usb_rx_connect_call(struct usb_manager_binding *bind,
134         iref_t driver_iref, uint16_t init_config)
135 {
136     struct usb_manager_connect_state *st;
137
138     st = malloc(sizeof(struct usb_manager_connect_state));
139
140     if (st == NULL) {
141         USER_PANIC("cannot reply, out of memory!");
142     }
143
144     st->b = bind;
145     st->driver_iref = driver_iref;
146
147     // associate the bindings with the usb device
148     usb_driver_connected(bind, st->driver, init_config);
149
150     if (bind->st == NULL) {
151         /* if the connection fails, there will not be an association */
152         debug_printf("ERROR: no state associated..\n");
153         st->error = USB_ERR_IOERROR;
154         usb_driver_connect_response(st);
155         return;
156     }
157
158     /*
159      * all went fine so the binding state pointer is now refering to the
160      * usb device and we can setup the reply
161      */
162
163     struct usb_device *dev = bind->st;
164
165     /* we reply with the initial configuration descriptor */
166     st->length = sizeof((dev->device_desc)) + dev->config_desc_size;
167     st->desc = malloc(st->length);
168
169     memcpy(st->desc, &(dev->device_desc), sizeof((dev->device_desc)));
170     memcpy(st->desc + sizeof((dev->device_desc)), dev->config_desc,
171             dev->config_desc_size);
172
173     st->error = USB_ERR_OK;
174
175     // send response
176     usb_driver_connect_response(st);
177 }
178
179 /// the receive function handles
180 static struct usb_manager_rx_vtbl usb_manager_handle_fn = {
181     .request_read_call = usb_rx_request_read_call,
182     .request_write_call = usb_rx_request_write_call,
183     .request_call = usb_rx_request_call,
184     .connect_call = usb_rx_connect_call,
185     .transfer_setup_call = usb_rx_transfer_setup_call,
186     .transfer_unsetup_call = usb_rx_transfer_unsetup_call,
187     .transfer_start_call = usb_rx_transfer_start_call,
188     .transfer_stop_call = usb_rx_transfer_stop_call,
189     .transfer_status_call = usb_rx_transfer_status_call,
190     .transfer_state_call = usb_rx_transfer_state_call,
191     .transfer_clear_stall_call = usb_rx_transfer_clear_stall_call,
192 };
193
194 /**
195  * \brief this function sets the receive handlers for a newly connected
196  *        USB driver process
197  *
198  * \param st the state (currently NULL)
199  * \param b  the binding of the new connection
200  */
201 static errval_t service_connected_cb(void *st, struct usb_manager_binding *b)
202 {
203     USB_DEBUG_IDC("service_connected_cb(): Setting handler functions.\n");
204
205     b->rx_vtbl = usb_manager_handle_fn;
206
207     return (SYS_ERR_OK);
208 }
209
210 /// state variable for the usb manager service
211 static volatile uint8_t usb_manager_service_exported = 0;
212
213 /**
214  * \brief call back function for the export of the USB manager service
215  *
216  * \param st   the supplied state (currently NULL)
217  * \param err  the outcome of the service export
218  * \param iref the iref which the service is associated with
219  *
220  * NOTE: the usb manager blocks untill the service is exported and the
221  *       and registered with the name service.
222  */
223 static void service_exported_cb(void *st, errval_t err, iref_t iref)
224 {
225     if (err_is_fail(err)) {
226         USER_PANIC_ERR(err, "service export failed.");
227     }
228
229     err = nameservice_register(USB_MANAGER_SERVICE, iref);
230     if (err_is_fail(err)) {
231         USER_PANIC_ERR(err, "registration with name server failed");
232     }
233
234     usb_manager_service_exported = 1;
235
236 }
237
238 #if 0
239 /**
240  * \brief this function maps the supplied device capability in our memory
241  *
242  * The capability is expected to be in the argcn slot of the rootcn. The
243  * spawning domain has to ensure that the needed capability is at the right
244  * location.
245  *
246  * XXX: Maybe it would be better to move the caps into the inheritcn slot
247  *      to support one device capability per host controller.
248  */
249 static uintptr_t map_device_cap(void)
250 {
251     errval_t err;
252
253     struct capref dev_cap = {
254         .cnode = cnode_root,
255         .slot = ROOTCN_SLOT_ARGCN
256     };
257
258     struct frame_identity frameid;
259
260     err = invoke_frame_identify(dev_cap, &frameid);
261     if (err_is_fail(err)) {
262         USER_PANIC_ERR(err, "could not identify the frame.\n");
263         return (0);
264     }
265
266     void *ret_addr = NULL;
267     size_t size = (1UL << frameid.bits); /* bytes */
268
269     err = vspace_map_one_frame_attr(&ret_addr, size, dev_cap,
270             VREGION_FLAGS_READ_WRITE_NOCACHE, NULL, NULL);
271
272     if (err_is_fail(err)) {
273         USER_PANIC_ERR(err, "failed to create a vspace mapping.\n");
274         return (0);
275     }
276
277     return ((uintptr_t) ret_addr);
278 }
279 #endif
280 /*
281  * =========================================================================
282  * ARM and PandaBoard specific functions
283  * =========================================================================
284  */
285 #if __pandaboard__
286
287 // the offset into the supplied capability
288 #define USB_CAPABILITY_OFFSET (0x00000C00)
289
290 // the EHCI interrupt number on the pandaboard
291 #define USB_ARM_EHCI_IRQ 109
292
293 /**
294  * \brief this is a quick check function if everything is all right
295  *
296  * NOTE: there is just one specific setting possible on the PandaBoard
297  *       EHCI controller, with the specific capability and the specific offset
298  *       This function checks if these values match to ensure functionality
299  *       If you change something with the startup of the USB manager domain
300  *       you may need to change the values in this function!
301  */
302 static usb_error_t pandaboard_checkup(uintptr_t base, int argc, char *argv[])
303 {
304     USB_DEBUG("performing pandaboard integrity check.\n");
305
306     /* checking the host controller type */
307     if (strcmp(argv[0], "ehci")) {
308         debug_printf("wrong host controller type: %s\n", argv[0]);
309         return (USB_ERR_INVAL);
310     }
311
312     /* checking the memory offset */
313     if (strtoul(argv[1], NULL, 10) != ((uint32_t) USB_CAPABILITY_OFFSET)) {
314         debug_printf("wrong offset!: %x (%s)\n", strtoul(argv[1], NULL, 10),
315                 argv[1]);
316         return (USB_ERR_INVAL);
317     }
318
319     /* checking the IRQ number */
320     if (strtoul(argv[2], NULL, 10) != USB_ARM_EHCI_IRQ) {
321         debug_printf("wrong interrupt number: %s, %x", argv[2],
322                 strtoul(argv[2], NULL, 10));
323         return (USB_ERR_INVAL);
324     }
325
326     /*
327      * here we read some values from the ULPI register of the PandaBoards
328      * additional ULPI interface on the EHCI controller.
329      *
330      * The request are forwarded to the external ULPI receiver on the
331      * PandaBoard.
332      *
333      * NOTE: Not every EHCI controller has those register!
334      */
335
336     uint32_t tmp = USB_CAPABILITY_OFFSET + (uint32_t) base;
337     printf("address of ehci base = %p\n", tmp);
338
339     /*
340      * This request reads the debug register of the ULPI receiver. The values
341      * returned are the line state. If the returned value is 0x1 this means
342      * there is connection i.e. the USB hub on the PandaBoard is reachable.
343      */
344     *((volatile uint32_t*) (tmp + 0x00A4)) = (uint32_t) ((0x15 << 16)
345             | (0x3 << 22) | (0x1 << 24) | (0x1 << 31));
346
347     /* wait till the request is done */
348     while (*((volatile uint32_t*) (tmp + 0x00A4)) & (1 << 31)) {
349     }
350
351     /* compare the result */
352     if (!(*(((volatile uint32_t*) (tmp + 0x00A4))) & 0x1)) {
353         return (USB_ERR_INVAL);
354     }
355
356     /*
357      * This request reads out the low part of the vendor id from the ULPI
358      * receiver on the PandaBoard. This should be 0x24.
359      *
360      * XXX: Assuming that all the Pandaboards have the same ULPI receiver
361      */
362     *((volatile uint32_t*) (tmp + 0x00A4)) = (uint32_t) ((0x00 << 16)
363             | (0x3 << 22) | (0x1 << 24) | (0x1 << 31));
364
365     /* wait till request is done */
366     while (*((volatile uint32_t*) (tmp + 0x00A4)) & (1 << 31)) {
367     }
368
369     /* compare the values */
370     if (0x24 != ((*((volatile uint32_t*) (tmp + 0x00A4))) & 0xFF)) {
371         return (USB_ERR_INVAL);
372     }
373
374     return (USB_ERR_OK);
375 }
376
377 #endif /* __pandaboard__ */
378
379 /*
380  * ========================================================================
381  * MAIN
382  * ========================================================================
383  */
384
385 /*
386  * \brief   main function of the usb manager
387  *
388  * The USB manager must be called with very the necessary arguments and supplied
389  * with the needed capability to access the device registers.
390  *
391  * On x86:
392  * On ARM:
393  */
394 int main(int argc, char *argv[])
395 {
396     errval_t err;
397
398     debug_printf("USB Manager started.\n");
399
400     /* starting the usb manager service */
401     err = usb_manager_export(NULL, service_exported_cb, service_connected_cb,
402             get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
403
404     if (err_is_fail(err)) {
405         USER_PANIC_ERR(err, "failed to start the usb manager service.");
406         return (err);
407     }
408
409     /* wait till the service is exported */
410     while (!usb_manager_service_exported) {
411         event_dispatch(get_default_waitset());
412     }
413
414     /* map de device capability into our address space */
415     uintptr_t base; // = map_device_cap();
416     // TODO: Change when new API is ready!
417     err = map_device_register(0x4A064000, 0x1000, &base);
418     assert(err_is_ok(err));
419
420     if (base == 0) {
421         USER_PANIC("failed to map the device capability");
422     }
423
424     /* the default tuple size is 2, since on x86 the interrupts can be routed */
425     uint8_t arg_tuple_size = 2;
426
427 #if __pandaboard__
428
429     /* ARM / PandaBoard related setup and checks */
430
431     if (pandaboard_checkup(base, argc, argv) != USB_ERR_OK) {
432         USER_PANIC("Pandaboard checkup failed!\n");
433     }
434
435     /*
436      * the argument tuple size must be 3, i.e. the host usb manager expects
437      * [host-controller offset interrupt] as arguments, because the interrupts
438      * are fixed and cannot be allocated as we like.
439      */
440     arg_tuple_size = 3;
441
442     /* checking the command line parameter count */
443     if (argc != 3) {
444         debug_printf("Usage: usb_manager [host-controller offset interrupt]\n");
445     }
446
447     uint32_t irq = strtoul(argv[2], NULL, 10);
448
449     /*
450      * setting up interrupt handler for the EHCI interrupt
451      * XXX: this should be done for each host controller eventually...
452      */
453     err = inthandler_setup_arm(usb_hc_intr_handler, NULL, irq);
454     if (err_is_fail(err)) {
455         DEBUG_ERR(err, "failed to enable interrupt. Step 16.\n");
456     }
457
458 #else
459     if (argc == 0 || argc % 2) {
460         debug_printf("Usage: usb_manager [host-controller offset]\n");
461     }
462     uint32_t intr_vector;
463     err = inthandler_setup(usb_hc_intr_handler, NULL,
464             &intr_vector);
465     /* TODO: register interrupt routing.. */
466 #endif
467
468     usb_error_t uerr = USB_ERR_INVAL;
469
470     /*
471      * start initializing the host controllers supplied by the arguments
472      * XXX: Currently just one
473      */
474     for (uint16_t i = 0; i < argc; i += arg_tuple_size) {
475
476         /* allocate the general host controller */
477         uerr = USB_ERR_INVAL;
478         usb_host_controller_t *hc = malloc(sizeof(*hc));
479         memset(hc, 0, sizeof(*hc));
480
481         uintptr_t controller_base = base + strtoul(argv[i + 1], NULL, 10);
482
483         /* -------------------------------------------------------------------
484          * EHCI Controller
485          * -------------------------------------------------------------------
486          */
487         if (strcmp(argv[i], "ehci") == 0) {
488             uerr = usb_hc_init(hc, USB_EHCI, controller_base);
489         }
490
491         /* -------------------------------------------------------------------
492          * OHCI Controller
493          * -------------------------------------------------------------------
494          */
495         if (strcmp(argv[i], "ohci") == 0) {
496             uerr = usb_hc_init(hc, USB_OHCI, controller_base);
497         }
498
499         /* -------------------------------------------------------------------
500          * UHCI Controller
501          * -------------------------------------------------------------------
502          */
503         if (strcmp(argv[i], "uhci") == 0) {
504             uerr = usb_hc_init(hc, USB_UHCI, controller_base);
505         }
506
507         /* -------------------------------------------------------------------
508          * XHCI Controller
509          * -------------------------------------------------------------------
510          */
511         if (strcmp(argv[i], "xhci") == 0) {
512             uerr = usb_hc_init(hc, USB_XHCI, controller_base);
513         }
514
515         if (uerr != USB_ERR_OK && hc != NULL) {
516             free(hc);
517             continue;
518         }
519     }
520
521     messages_handler_loop();
522 }