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