1/* 2 * Copyright (c) 2007-2013 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdio.h> 11#include <string.h> 12 13#include <barrelfish/barrelfish.h> 14#include <barrelfish/nameservice_client.h> 15 16#include <usb/usb.h> 17#include <usb/usb_driver.h> 18#include <usb/usb_device.h> 19 20#include "usb_manager_client.h" 21 22 23/// the usb manager RPC client structure 24struct usb_manager_binding *usb_manager; 25 26/* 27 * ------------------------------------------------------------------------- 28 * USB driver service functions 29 * ------------------------------------------------------------------------- 30 */ 31 32 33/** 34 * \brief this function is called when the client driver receives a detach 35 * notification 36 */ 37void usb_driver_rx_detach_notify(struct usb_driver_binding *b) 38{ 39 debug_printf("device detached... exiting driver."); 40 exit(0); 41} 42 43/** 44 * vtable with callbacks for received messages 45 */ 46static struct usb_driver_rx_vtbl drv_rx_vtbl = { 47 .device_detach_notify = usb_driver_rx_detach_notify, 48 .transfer_done_notify = usb_driver_rx_done_notify, 49}; 50 51static void usb_bind_cb(void *st, errval_t err, struct usb_manager_binding *b); 52 53/** 54 * \brief callback when the service export is successful 55 */ 56static void usb_driver_export_cb(void *st, errval_t err, iref_t iref) 57{ 58 struct usb_client_st *client_st = st; 59 USB_DEBUG_IDC("libusb: export cb completed\n"); 60 if (err_is_fail(err)) { 61 USER_PANIC_ERR(err, "export failed"); 62 } 63 /* no need to register with name server */ 64 client_st->usb_driver_iref = iref; 65 66 iref_t usb_manager_iref; 67 68 err = nameservice_blocking_lookup(USB_MANAGER_SERVICE, &usb_manager_iref); 69 if (err_is_fail(err)) { 70 USER_PANIC_ERR(err, "USB manager service lookup failed"); 71 } 72 73 // usb_bind_cb sets bound 74 err = usb_manager_bind(usb_manager_iref, usb_bind_cb, 75 st /* state for bind_cb */, get_default_waitset(), 76 IDC_BIND_FLAGS_DEFAULT); 77 78 if (err_is_fail(err)) { 79 USER_PANIC_ERR(err, "USB manager binding failed"); 80 } 81} 82 83/** 84 * \brief this is the callback function when the USB Manager binds to the client 85 * driver upon library initialization 86 */ 87static errval_t usb_driver_connect_cb(void *st, struct usb_driver_binding *b) 88{ 89 struct usb_client_st *client_st = st; 90 USB_DEBUG_IDC("libusb: usb_driver_connect_cb\b"); 91 92 client_st->driver_binding = b; 93 94 b->rx_vtbl = drv_rx_vtbl; 95 96 client_st->manager_connected = 1; 97 98 return (SYS_ERR_OK); 99} 100 101 102/** 103 * \brief this is the callback function when the binding with the USB Manager 104 * is completed 105 */ 106static void usb_bind_cb(void *st, errval_t err, struct usb_manager_binding *b) 107{ 108 struct usb_client_st *client_st = st; 109 USB_DEBUG_IDC("libusb: bind callback complete\n"); 110 111 if (err_is_fail(err)) { 112 USER_PANIC_ERR(err, "USB manager binding failed"); 113 } 114 115 usb_manager = b; 116 usb_manager_rpc_client_init(usb_manager); 117 debug_printf("vtbl.connect=%p\n", usb_manager->rpc_tx_vtbl.connect); 118 119 uint32_t ret_status; 120 121 size_t length; 122 uint8_t tmp[2048]; 123 124 /* connect with the USB Manager */ 125 err = usb_manager->rpc_tx_vtbl.connect(usb_manager, client_st->usb_driver_iref, client_st->init_config, 126 &ret_status, tmp, &length); 127 128 if (((usb_error_t) ret_status) != USB_ERR_OK) { 129 debug_printf("libusb: ERROR connecting to the USB manager\n"); 130 client_st->callback(client_st->st, ret_status); 131 return; 132 } 133 134 /* check if we got enough data for an generic descriptor */ 135 if (length < sizeof(struct usb_generic_descriptor)) { 136 debug_printf("libusb: ERROR received to less data for the generic " 137 "descriptor\n"); 138 client_st->callback(client_st->st, USB_ERR_BAD_BUFSIZE); 139 return; 140 } 141 142 // TODO: This needs to be removed, but that requires changing the connect rpc 143 // to a message... 144 /* wait until the USB Manager connects with us. */ 145 while(!(volatile uint8_t) client_st->manager_connected) { 146 err = event_dispatch(get_default_waitset()); 147 } 148 149 /* 150 * initialize the devices with the descriptors 151 */ 152 usb_device_init(tmp); 153 154 USB_DEBUG_IDC("libusb: driver connected (status=%i)\n", ret_status); 155 156 client_st->callback(client_st->st, err); 157} 158 159/** 160 * \brief does the initialization of the USB library and the binding to the 161 * USB manager service 162 * 163 * \param init_config the configuration to update 164 */ 165usb_error_t usb_lib_init(uint16_t init_config, lib_usb_callback cb, void* st) 166{ 167 errval_t err; 168 169 debug_printf("libusb: initialization.\n"); 170 171 struct usb_client_st *client_st = malloc(sizeof(*client_st)); 172 if (!client_st) { 173 return USB_ERR_NOMEM; 174 } 175 client_st->callback = cb; 176 client_st->st = st; 177 client_st->init_config = init_config; 178 179 // driver_export_cb sets exported 180 err = usb_driver_export(client_st, usb_driver_export_cb, usb_driver_connect_cb, 181 get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT); 182 if (err_is_fail(err)) { 183 USER_PANIC_ERR(err, "could not export the driver interface"); 184 } 185 186 return (USB_ERR_OK); 187} 188