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