1/** 2 * \brief this file contains functions to manipulate the usb device 3 * 4 */ 5 6/* 7 * Copyright (c) 2007-2013 ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdlib.h> 16#include <stdio.h> 17#include <barrelfish/barrelfish.h> 18 19#include <if/usb_manager_defs.h> 20#include <if/usb_manager_defs.h> 21 22#include <usb/usb.h> 23#include <usb/usb_device.h> 24#include <usb/usb_xfer.h> 25#include <usb/usb_parse.h> 26 27#include "usb_manager_client.h" 28 29usb_device_t device; 30 31static uint8_t is_init = 0; 32 33/** 34 * \brief this function frees an allocated configuration tree i.e. the allocated 35 * interfaces and endpoints 36 * 37 * \param dev the device for which the configuration should be freed 38 */ 39static void usb_device_cfg_free(struct usb_device *dev) 40{ 41 if (dev->ifaces != NULL) { 42 free(dev->ifaces); 43 } 44 45 if (dev->endpoints != NULL) { 46 free(dev->endpoints); 47 } 48 dev->ifaces = NULL; 49 dev->iface_max = 0; 50 dev->endpoints = NULL; 51 dev->ep_max = 0; 52} 53 54 55/** 56 * \brief this function initializes an endpoint structure 57 * 58 * \param iface_index the index of the interface 59 * \param desc the endpoint descriptor used as data source 60 * \param ep the endpoint to initalize 61 */ 62static void usb_device_init_endpoint(uint8_t iface_index, 63 struct usb_endpoint_descriptor *desc, 64 struct usb_endpoint *ep) 65{ 66 USB_DEBUG_TR_ENTER; 67 ep->ep_direction = desc->bEndpointAddress.direction; 68 ep->ep_number = desc->bEndpointAddress.ep_number; 69 ep->ep_type = desc->bmAttributes.xfer_type; 70 ep->ep_usage = desc->bmAttributes.usage_type; 71 ep->ep_sync = desc->bmAttributes.sync_type; 72 ep->iface_index = iface_index; 73} 74 75/** 76 * \brief processes a configuration descriptor and allocates the interface 77 * and endpoint structures 78 * 79 * \param dev the device to process the configuration 80 * \param iface the interface number 81 * \param init flag indicating if allocation or initialization 82 * \param config the configuration descriptor 83 */ 84static usb_error_t usb_device_cfg_process(struct usb_device *dev, uint8_t iface, 85 uint8_t init, struct usb_config_descriptor *config) 86{ 87 USB_DEBUG_TR_ENTER; 88 89 struct usb_iface_parse_state iface_ps; 90 struct usb_endpoint *ep; 91 uint8_t ep_max, ep_current; 92 uint8_t alt_index = 0; 93 usb_error_t err = USB_ERR_OK; 94 95 /* this is an parameter override, when setting an alternate interface */ 96 if (iface != USB_INTERFACE_INDEX_ANY) { 97 alt_index = init; 98 init = 2; 99 } 100 101 102 if (init) { 103 /* check if an endpoint reset is needed */ 104 ep = dev->endpoints; 105 ep_max = dev->ep_max; 106 107 while (ep_max--) { 108 if ((iface == USB_INTERFACE_INDEX_ANY) 109 || (iface == ep->iface_index)) { 110 /* perform EP reset */ 111 memset(ep, 0, sizeof(*ep)); 112 ep->iface_index = USB_INTERFACE_INDEX_ANY; 113 114 } 115 ep++; 116 } 117 if (err != USB_ERR_OK) { 118 return (err); 119 } 120 } 121 122 /* reset the parse state */ 123 memset(&iface_ps, 0, sizeof(iface_ps)); 124 ep_current = 0; 125 ep_max = 0; 126 uint8_t ep_tmp = 0; 127 128 struct usb_interface_descriptor *idesc; 129 struct usb_interface *interface; 130 struct usb_endpoint_descriptor *edesc; 131 uint8_t iface_index = 0; 132 133 /* loop over all interfaces of this configuration descirptor */ 134 while ((idesc = usb_parse_next_iface(config, &iface_ps))) { 135 136 if (iface_ps.iface_index == 32) { 137 /* the maximium ifaces */ 138 break; 139 } 140 141 /* get the next interface */ 142 interface = dev->ifaces + iface_ps.iface_index; 143 144 uint8_t do_init = 0; 145 146 if (init) { 147 /* check if we have to initialize the iface or endpoints */ 148 if ((iface_index != USB_INTERFACE_INDEX_ANY) 149 && (iface_index != iface_ps.iface_index)) { 150 do_init = 0; 151 } else if (alt_index != iface_ps.iface_index_alt) { 152 do_init = 0; 153 } else { 154 do_init = 1; 155 } 156 } 157 158 if (iface_ps.iface_index_alt == 0) { 159 ep_current = ep_max; 160 } 161 162 if (do_init) { 163 /* initialize the interface */ 164 assert(interface != NULL); 165 interface->iface_number = idesc->bInterfaceNumber; 166 interface->iface_class = idesc->bInterfaceClass; 167 interface->iface_subclass = idesc->bInterfaceSubClass; 168 interface->iface_protocol = idesc->bInterfaceProtocol; 169 interface->num_endpoints = idesc->bNumEndpoints; 170 interface->config = config->bConfigurationValue; 171 interface->parent_iface_index = USB_INTERFACE_INDEX_ANY; 172 interface->alt_setting = alt_index; 173 } 174 175 /* 176 * get the address of the endpoint descriptor 177 * the parse_next function will look one descriptor after this 178 * so we have to initialize it with the interface descriptor 179 * */ 180 edesc = (struct usb_endpoint_descriptor *) idesc; 181 182 ep_tmp = ep_current; 183 184 /* loop over all endpoints of this interface descriptor */ 185 while ((edesc = usb_parse_next_edesc(config, edesc))) { 186 187 if (ep_tmp == 32) { 188 /* maximum endpoints */ 189 break; 190 } 191 192 /* get the endpoint */ 193 ep = dev->endpoints + ep_tmp; 194 195 if (do_init) { 196 /* initialize the endpoint */ 197 usb_device_init_endpoint(iface_ps.iface_index, edesc, ep); 198 ep->iface = interface; 199 } 200 ep_tmp++; 201 202 if (ep_max < ep_tmp) { 203 ep_max = ep_tmp; 204 } 205 /* the last endpoint descriptor will be stored at the iface again */ 206 idesc = (struct usb_interface_descriptor *) edesc; 207 } 208 209 } 210 211 if (!init) { 212 /* 213 * we know how many interfaces / endpoints we have to allocate so 214 * get some memory for this 215 */ 216 dev->iface_max = iface_ps.iface_index; 217 dev->ifaces = NULL; 218 219 if (dev->iface_max != 0) { 220 dev->ifaces = malloc(sizeof(*interface) * dev->iface_max); 221 if (dev->ifaces == NULL) { 222 usb_device_cfg_free(dev); 223 return (USB_ERR_NOMEM); 224 } 225 } 226 227 if (ep_max != 0) { 228 dev->endpoints = malloc(sizeof(*ep) * ep_max); 229 if (dev->endpoints == NULL) { 230 usb_device_cfg_free(dev); 231 return (USB_ERR_NOMEM); 232 } 233 dev->ep_max = ep_max; 234 } 235 } 236 237 return (USB_ERR_OK); 238} 239 240 241 242 243void usb_device_init(void *desc) 244{ 245 memset(&device, 0, sizeof(device)); 246 247 struct usb_device_descriptor *ddesc = (struct usb_device_descriptor*) desc; 248 struct usb_config_descriptor *config = (struct usb_config_descriptor *) (ddesc + 1); 249 250 device.config_desc = config; 251 device.dev_class = ddesc->bDeviceClass; 252 device.dev_subclass = ddesc->bDeviceSubClass; 253 device.dev_protocol = ddesc->bDeviceProtocol; 254 device.vendor = ddesc->idVendor; 255 device.product = ddesc->idProduct; 256 device.version = ddesc->bcdDevice; 257 device.num_config = ddesc->bNumConfigurations; 258 device.current_config = config->bConfigurationValue; 259 260 usb_device_cfg_process(&device, USB_INTERFACE_INDEX_ANY, 0, config); 261 usb_device_cfg_process(&device, USB_INTERFACE_INDEX_ANY, 1, config); 262 263 is_init = 1; 264} 265 266 267/** 268 * \brief this function returns the interface count of the current configuration 269 * 270 * \param ret_count the number of interfaces 271 */ 272usb_error_t usb_device_get_iface_count(uint8_t *ret_count) 273{ 274 if (!is_init) { 275 return (USB_ERR_NOT_CONFIGURED); 276 } 277 *ret_count = device.config_desc->bNumInterfaces; 278 return (USB_ERR_OK); 279 280} 281 282/** 283 * \brief this function returns the speed of the device 284 * 285 * \param ret_speed the speed identifier 286 */ 287usb_error_t usb_device_get_speed(usb_speed_t *ret_speed) 288{ 289 if (!is_init) { 290 return (USB_ERR_NOT_CONFIGURED); 291 } 292 assert(!"NYI: Getting the device speed."); 293 return (USB_ERR_OK); 294} 295 296 297/** 298 * \brief suspend the USB device on the bus 299 */ 300usb_error_t usb_device_suspend(void) 301{ 302 assert(!"NYI: Suspending a device"); 303 return (USB_ERR_OK); 304} 305 306/** 307 * \brief resumes the USB device on the bus 308 */ 309usb_error_t usb_device_resume(void) 310{ 311 assert(!"NYI: Resuming a device"); 312 return (USB_ERR_OK); 313} 314 315/** 316 * \brief returns the number of available configurations 317 */ 318uint8_t usb_device_get_num_config(void) { 319 assert(is_init); 320 return (device.num_config); 321} 322 323/** 324 * \brief returns the configuration descriptor of the device 325 */ 326struct usb_config_descriptor *usb_device_get_cfg_desc(void) 327{ 328 return (device.config_desc); 329} 330 331/** 332 * \brief returns the interface of a given interface number 333 * 334 * \param iface the interface number to look for 335 * 336 * \return interface if one is found, NULL otherwise 337 */ 338struct usb_interface *usb_device_get_iface(uint8_t iface) 339{ 340 struct usb_interface *interface, *ret = NULL; 341 342 /* loop over all interfaces and return the one with the matching number */ 343 for (uint8_t i = 0; i < device.iface_max; i++) { 344 interface = (device.ifaces + i); 345 if (interface->iface_number == iface) { 346 ret = interface; 347 break; 348 } 349 } 350 return (ret); 351} 352 353