1219019Sgabor/*
2219019Sgabor * Copyright (c) 2007-2013 ETH Zurich.
3219019Sgabor * All rights reserved.
4219019Sgabor *
5219019Sgabor * This file is distributed under the terms in the attached LICENSE file.
6219019Sgabor * If you do not find this file, copies can be found by writing to:
7219019Sgabor * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8219019Sgabor */
9219019Sgabor
10219019Sgabor#include <stdlib.h>
11219019Sgabor#include <stdio.h>
12219019Sgabor#include <string.h>
13219019Sgabor#include <barrelfish/barrelfish.h>
14219019Sgabor
15219019Sgabor#include "ohci_device.h"
16219019Sgabor
17219019Sgabor#include <usb/usb.h>
18219019Sgabor#include <usb/usb_descriptor.h>
19219019Sgabor#include <usb/usb_error.h>
20219019Sgabor#include <usb/usb_request.h>
21219019Sgabor#include <usb_device.h>
22219019Sgabor#include <usb_hub.h>
23219019Sgabor#include <usb_controller.h>
24219019Sgabor#include "usb_ohci.h"
25219019Sgabor#include "usb_ohci_root_hub.h"
26219019Sgabor
27219019Sgabor
28219019Sgaborstatic const struct usb_device_descriptor usb_ohci_root_hub_device_desc = {
29219019Sgabor        .bLength = sizeof(struct usb_device_descriptor),
30219019Sgabor        .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE,
31219019Sgabor        .bcdUSB = 0x0100,
32219019Sgabor        .bDeviceClass = USB_HUB_CLASS_CODE,
33219019Sgabor        .bDeviceSubClass = USB_HUB_SUBCLASS_CODE,
34219019Sgabor        .bDeviceProtocol = USB_HUB_PROTOCOL_FSHUB,
35219019Sgabor        .bMaxPacketSize0 = 64,
36219019Sgabor        .idVendor = 0,
37219019Sgabor        .idProduct = 0,
38219019Sgabor        .bcdDevice = 0x0100,
39219019Sgabor        .iManufacturer = 1,
40219019Sgabor        .iProduct = 2,
41219019Sgabor        .iSerialNumber = 0,
42219019Sgabor        .bNumConfigurations = 1,
43219019Sgabor};
44219019Sgabor
45219019Sgaborstatic const struct usb_ohci_config_desc usb_ohci_root_hub_config_desc = {
46219019Sgabor.config_desc = {
47219019Sgabor        .bLength = sizeof(struct usb_config_descriptor),
48219019Sgabor        .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIG,
49219019Sgabor        .wTotalLength = sizeof(usb_ohci_root_hub_config_desc),
50219019Sgabor        .bNumInterfaces = 1,
51219019Sgabor        .bConfigurationValue = 1,
52219019Sgabor        .iConfiguration = 0,
53219019Sgabor        .bmAttributes = USB_CONFIG_SELF_POWERED,
54219019Sgabor        .bMaxPower = 0,
55219019Sgabor}, .iface_desc = {
56219019Sgabor.bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType =
57219019Sgabor        USB_DESCRIPTOR_TYPE_INTERFACE, .bNumEndpoints = 1, .bInterfaceClass =
58219019Sgabor        USB_HUB_IFACE_CLASS_CODE, .bInterfaceSubClass =
59219019Sgabor        USB_HUB_IFACE_SUBCLASS_CODE, .bInterfaceProtocol = 0,
60219019Sgabor}, .ep_desc = {
61219019Sgabor        .bLength = sizeof(struct usb_endpoint_descriptor),
62219019Sgabor        .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
63219019Sgabor        .bEndpointAddress = {USB_ENDPOINT_DIRECTION_IN,0,1},
64219019Sgabor        .bmAttributes = {0,0,0,USB_ENDPOINT_TYPE_INTR},
65219019Sgabor        .wMaxPacketSize = 32,
66219019Sgabor        .bInterval = 255,
67219019Sgabor},
68219019Sgabor};
69219019Sgabor
70219019Sgaborstatic const struct usb_hub_descriptor usb_ohci_root_hub_desc = {
71219019Sgabor        .bDescLength = 0,
72219019Sgabor        .bDescriptorType = USB_DESCRIPTOR_TYPE_HUB,
73219019Sgabor        .bNbrPorts = 0,
74219019Sgabor        .wHubCharacteristics = {0, 0, 0, 0, 0, 0},
75219019Sgabor        .bPwrOn2PwrGood = 0,
76219019Sgabor        .bHubContrCurrent = 0,
77219019Sgabor        .bDeviceRemovable =     {0}
78219019Sgabor};
79219019Sgabor
80219019Sgabor/**
81219019Sgabor * \brief   this function clears the old interrupt data and reads the
82219019Sgabor *          status from the ports
83260003Sdim *
84219019Sgabor * \param   hc  the host controller
85219019Sgabor */
86219019Sgaborvoid usb_ohci_root_hub_interrupt(usb_ohci_hc_t *hc)
87219019Sgabor{
88219019Sgabor    /* clear old interrupt data */
89219019Sgabor    memset(hc->root_hub_intr_data, 0, sizeof(hc->root_hub_intr_data));
90219019Sgabor
91219019Sgabor    /* get the root hub status */
92219019Sgabor    //ohci_rh_status_t hstatus = ohci_rh_status_rd(hc->ohci_base);
93219019Sgabor
94219019Sgabor
95219019Sgabor    /* get the number of ports */
96219019Sgabor    uint16_t num_ports = hc->root_hub_num_ports + 1;
97219019Sgabor    if (num_ports > (8 * sizeof(hc->root_hub_intr_data))) {
98219019Sgabor        num_ports = (8 * sizeof(hc->root_hub_intr_data));
99219019Sgabor    }
100219019Sgabor
101260003Sdim    //char buf[4048];
102219019Sgabor        //     ohci_rh_portstat_pr(buf, 4047, hc->ohci_base);
103219019Sgabor          //  printf(buf);
104219019Sgabor    ohci_rh_portstat_t ps;
105219019Sgabor    /* set the bits in the interrupt data field */
106219019Sgabor    for (uint16_t i = 0; i < num_ports; i++) {
107219019Sgabor
108219019Sgabor        ps = ohci_rh_portstat_rd(hc->ohci_base, i);
109219019Sgabor        if (ps >> 16) {
110219019Sgabor            /* port i has changed */
111219019Sgabor            USB_DEBUG("port %u, has changed..\n", i);
112219019Sgabor            hc->root_hub_intr_data[i / 8] |= (1 << (i % 8));
113219019Sgabor        }
114219019Sgabor    }
115219019Sgabor
116219019Sgabor    /* TODO: Handle the hub interrupts */
117219019Sgabor   // assert(!"NYI: Root hub interrupt handling");
118219019Sgabor    //uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, sizeof(sc->sc_hub_idata));
119219019Sgabor}
120219019Sgabor
121219019Sgabor/*
122219019Sgabor * \brief   this function enables the status change interrupt
123219019Sgabor *          of the root hub and updates the enabled_intrs field
124219019Sgabor *          of the host controller.
125219019Sgabor *
126219019Sgabor * \param   hc  the host controller
127219019Sgabor */
128219019Sgaborstatic void usb_ohci_root_hub_sc_intr_enable(usb_ohci_hc_t *hc)
129219019Sgabor{
130219019Sgabor    /* update the enabled interrupt field in our hc */
131219019Sgabor    ohci_interrupt_t ie = ohci_intenable_rd(hc->ohci_base);
132219019Sgabor    ohci_interrupt_rhsc_insert(ie, 1);
133219019Sgabor    hc->enabled_intrs = ie;
134219019Sgabor
135219019Sgabor    /* enable the interrupt */
136219019Sgabor    ohci_intenable_rhsc_wrf(hc->ohci_base, 1);
137219019Sgabor
138219019Sgabor    /* acknowledge any RHSC interrupts */
139219019Sgabor    ohci_intstatus_rhsc_wrf(hc->ohci_base, 1);
140219019Sgabor
141219019Sgabor    usb_ohci_root_hub_interrupt(hc);
142219019Sgabor}
143219019Sgabor
144219019Sgabor/**
145219019Sgabor *  \brief  this function emulates the USB root hub device by software
146219019Sgabor *
147219019Sgabor *  \param  device      the USB device we want to issue the request for
148281550Stijl *  \param  req         the USB request to execute
149219019Sgabor *  \param  ret_data    pointer to the returned data
150219019Sgabor *  \param  ret_length  the returned length
151281550Stijl */
152219019Sgaborusb_error_t usb_ohci_roothub_exec(struct usb_device *device,
153219019Sgabor        struct usb_device_request *req, const void **ret_data,
154219019Sgabor        uint16_t *ret_length)
155219019Sgabor{
156219019Sgabor    usb_ohci_hc_t *hc = (usb_ohci_hc_t *) device->controller->hc_control;
157219019Sgabor
158219019Sgabor    const void *data = (const void *) hc->root_hub_desc.temp;
159219019Sgabor    uint16_t length = 0;
160219019Sgabor
161219019Sgabor    uint16_t req_value = req->wValue;
162219019Sgabor    uint16_t req_index = req->wIndex;
163219019Sgabor
164219019Sgabor    const char *str_ptr;
165219019Sgabor
166219019Sgabor    /*
167219019Sgabor     * execute the request for the USB root hub
168219019Sgabor     */
169219019Sgabor    switch (req->bRequest) {
170219019Sgabor
171219019Sgabor        case USB_REQUEST_CLEAR_FEATURE:
172219019Sgabor            /*
173219019Sgabor             * ClearFeature() Request
174219019Sgabor             *
175219019Sgabor             * The only clear feature request is the clear port feature
176219019Sgabor             * for an existing port 1..num_ports
177219019Sgabor             */
178219019Sgabor            if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) {
179219019Sgabor                if ((req_index < 1) || (req_index > hc->root_hub_num_ports)) {
180219019Sgabor                    *ret_length = length;
181219019Sgabor                    *ret_data = data;
182219019Sgabor                    return USB_ERR_IOERROR;
183219019Sgabor                }
184219019Sgabor                // get the current value of the register
185219019Sgabor                ohci_rh_portstat_t ps = ohci_rh_portstat_rd(hc->ohci_base,
186219019Sgabor                        req_index);
187219019Sgabor
188219019Sgabor                switch (req_value) {
189219019Sgabor                    case USB_HUB_FEATURE_PORT_ENABLE:
190219019Sgabor                        ohci_rh_portstat_ccs_insert(ps, 1);
191219019Sgabor                        break;
192219019Sgabor                    case USB_HUB_FEATURE_PORT_SUSPEND:
193219019Sgabor                        ohci_rh_portstat_poci_insert(ps, 1);
194219019Sgabor                        break;
195219019Sgabor                    case USB_HUB_FEATURE_PORT_POWER:
196219019Sgabor                        ohci_rh_portstat_lsda_insert(ps, 1);
197219019Sgabor                        break;
198219019Sgabor                    case USB_HUB_FEATURE_C_PORT_CONNECTION:
199219019Sgabor                        ohci_rh_portstat_csc_insert(ps, 1);
200219019Sgabor                        break;
201219019Sgabor                    case USB_HUB_FEATURE_C_PORT_ENABLE:
202219019Sgabor                        ohci_rh_portstat_pesc_insert(ps, 1);
203219019Sgabor                        break;
204219019Sgabor                    case USB_HUB_FEATURE_C_PORT_SUSPEND:
205219019Sgabor                        ohci_rh_portstat_pssc_insert(ps, 1);
206219019Sgabor                        break;
207219019Sgabor                    case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
208219019Sgabor                        ohci_rh_portstat_ocic_insert(ps, 1);
209219019Sgabor                        break;
210219019Sgabor                    case USB_HUB_FEATURE_C_PORT_RESET:
211219019Sgabor                        ohci_rh_portstat_prsc_insert(ps, 1);
212219019Sgabor                        break;
213219019Sgabor                    default:
214219019Sgabor                        *ret_length = length;
215219019Sgabor                        *ret_data = data;
216219019Sgabor                        return USB_ERR_IOERROR;
217219019Sgabor                }
218219019Sgabor                // write the value to the register
219219019Sgabor                ohci_rh_portctrl_rawwr(hc->ohci_base, req_index, ps);
220219019Sgabor
221219019Sgabor                switch (req_value) {
222219019Sgabor                    case USB_HUB_FEATURE_C_PORT_CONNECTION:
223219019Sgabor                    case USB_HUB_FEATURE_C_PORT_ENABLE:
224219019Sgabor                    case USB_HUB_FEATURE_C_PORT_SUSPEND:
225219019Sgabor                    case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
226219019Sgabor                    case USB_HUB_FEATURE_C_PORT_RESET:
227219019Sgabor                        ps = ohci_rh_portstat_rd(hc->ohci_base, req_index);
228219019Sgabor                        if ((ps >> 16) == 0) {
229219019Sgabor                            usb_ohci_root_hub_sc_intr_enable(hc);
230219019Sgabor                        }
231219019Sgabor                        break;
232219019Sgabor                    default:
233219019Sgabor                        break;
234219019Sgabor                }
235219019Sgabor            }
236219019Sgabor            break;
237219019Sgabor
238219019Sgabor        case USB_REQUEST_GET_CONFIG:
239219019Sgabor            /*
240219019Sgabor             * GetConfiguration() Request
241219019Sgabor             */
242219019Sgabor            if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE)
243219019Sgabor                    && req->bType.direction == USB_REQUEST_READ) {
244219019Sgabor                length = 1;
245219019Sgabor                hc->root_hub_desc.temp[0] = hc->root_hub_config;
246219019Sgabor            }
247219019Sgabor            break;
248219019Sgabor
249219019Sgabor        case USB_REQUEST_GET_DESCRIPTOR:
250219019Sgabor            /*
251219019Sgabor             * GetDescriptor() Request
252219019Sgabor             *
253219019Sgabor             * There are 3 different kind of standard descriptors we can
254219019Sgabor             * return: Device, Interface and String
255219019Sgabor             *
256219019Sgabor             * and also a class specific request
257219019Sgabor             */
258219019Sgabor            if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE)
259219019Sgabor                    && req->bType.direction == USB_REQUEST_READ) {
260219019Sgabor
261219019Sgabor                /* hub class specific request */
262219019Sgabor                if (req->bType.type == USB_REQUEST_TYPE_CLASS) {
263219019Sgabor                    if ((req_value & 0xFF) != 0) {
264219019Sgabor                        *ret_length = length;
265219019Sgabor                        *ret_data = data;
266219019Sgabor                        return USB_ERR_IOERROR;
267219019Sgabor                    }
268219019Sgabor                    ohci_rh_descra_t cda;
269219019Sgabor                    cda = ohci_rh_descra_rd(hc->ohci_base);
270219019Sgabor
271219019Sgabor                    // get the standard hub descriptor to fill in data
272219019Sgabor                    hc->root_hub_desc.hub_descriptor = usb_ohci_root_hub_desc;
273219019Sgabor
274219019Sgabor                    struct usb_hub_descriptor *hub = &(hc->root_hub_desc
275219019Sgabor                            .hub_descriptor);
276219019Sgabor                    hub->bNbrPorts = hc->root_hub_num_ports;
277219019Sgabor
278219019Sgabor                    hub->wHubCharacteristics.power_mode =
279219019Sgabor                            ohci_rh_descra_nps_extract(cda);
280219019Sgabor                    hub->bPwrOn2PwrGood = ohci_rh_descra_potpgt_extract(cda);
281219019Sgabor
282219019Sgabor                    /* update device removable stats */
283219019Sgabor                    ohci_rh_descra_t cdb;
284219019Sgabor                    cdb = ohci_rh_descrb_rd(hc->ohci_base);
285219019Sgabor                    for (uint16_t i = 0; i < hc->root_hub_num_ports; i++) {
286219019Sgabor                        if (cdb & 1) {
287219019Sgabor                            hub->bDeviceRemovable[i / 8] |= (1 << (i % 8));
288219019Sgabor                        }
289219019Sgabor                        i >>= 1;
290219019Sgabor                    }
291219019Sgabor                    hub->bDescLength = 8 + ((hc->root_hub_num_ports + 7 / 8));
292219019Sgabor                    length = hub->bDescLength;
293219019Sgabor                    break;
294219019Sgabor                }
295219019Sgabor                /* standard usb request */
296219019Sgabor                switch (req_value >> 8) {
297219019Sgabor                    case USB_DESCRIPTOR_TYPE_DEVICE:
298219019Sgabor                        if ((req_value & 0xFF) != 0) {
299219019Sgabor                            *ret_length = length;
300219019Sgabor                            *ret_data = data;
301219019Sgabor                            return USB_ERR_IOERROR;
302219019Sgabor                        }
303219019Sgabor                        length = sizeof(usb_ohci_root_hub_device_desc);
304219019Sgabor                        data = (const void *) &usb_ohci_root_hub_device_desc;
305219019Sgabor                        break;
306219019Sgabor                    case USB_DESCRIPTOR_TYPE_CONFIG:
307219019Sgabor                        if ((req_value & 0xFF) != 0) {
308219019Sgabor                            *ret_length = length;
309219019Sgabor                            *ret_data = data;
310219019Sgabor                            return USB_ERR_IOERROR;
311219019Sgabor                        }
312219019Sgabor                        length = sizeof(usb_ohci_root_hub_config_desc);
313219019Sgabor                        data = (const void *) &usb_ohci_root_hub_config_desc;
314219019Sgabor                        break;
315219019Sgabor                    case USB_DESCRIPTOR_TYPE_STRING:
316219019Sgabor                        switch (req_value & 0xFF) {
317219019Sgabor                            case 0:
318219019Sgabor                                str_ptr = "\001";
319219019Sgabor                                break;
320219019Sgabor                            case 1:
321219019Sgabor                                break;
322219019Sgabor                                str_ptr = hc->vendor;
323219019Sgabor                            case 2:
324219019Sgabor                                break;
325219019Sgabor                                str_ptr = "OHCI root HUB";
326219019Sgabor                            default:
327219019Sgabor                                str_ptr = "";
328219019Sgabor                                break;
329219019Sgabor                        }
330219019Sgabor                        /* TODO: Make string descriptor */
331219019Sgabor                        assert(!"NYI: Make string descriptor");
332219019Sgabor                        break;
333219019Sgabor                    default:
334219019Sgabor                        *ret_length = length;
335219019Sgabor                        *ret_data = data;
336                        return USB_ERR_IOERROR;
337                        break;
338                }
339            }
340            break;
341
342        case USB_REQUEST_GET_INTERFACE:
343            /*
344             * GetInterface() Request
345             *
346             * Root hub has just one interface and no alternative one
347             */
348            if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE)
349                    && req->bType.direction == USB_REQUEST_READ) {
350                length = 1;
351                hc->root_hub_desc.temp[0] = 0;
352            }
353            break;
354
355        case USB_REQUEST_GET_STATUS:
356            /*
357             * GetStatus() Request
358             */
359            if (req->bType.direction == USB_REQUEST_WRITE) {
360                *ret_data = data;
361                *ret_length = length;
362                return USB_ERR_IOERROR;
363            }
364
365            if (req->bType.type == USB_REQUEST_TYPE_CLASS) {
366                if (req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) {
367                    length = 16;
368                    memset(hc->root_hub_desc.temp, 0, 16);
369                    break;
370                } else if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) {
371                    /* get port status */
372                    if ((req_index < 1) || req_index > hc->root_hub_num_ports) {
373                        // invalid port number;
374                        *ret_length = length;
375                        *ret_data = data;
376                        return USB_ERR_IOERROR;
377                    }
378                    ohci_rh_portstat_t ps = ohci_rh_portstat_rawrd(
379                            hc->ohci_base, req_index);
380                    memcpy(&hc->root_hub_desc.port_status.wPortChange, &ps, 2);
381                    ps <<= 16;
382                    memcpy(&hc->root_hub_desc.port_status.wPortStatus, &ps, 2);
383                    //hc->root_hub_desc.port_status.wPortChange = (ps >> 16);
384                    //hc->root_hub_desc.port_status.wPortStatus = (ps & 0xFFFF);
385                    length = sizeof(hc->root_hub_desc.port_status);
386                    break;
387                }
388            }
389
390            if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE)) {
391                length = 2;
392                hc->root_hub_desc.status.wStatus = USB_STATUS_SELF_POWERED;
393            } else {
394                length = 2;
395                hc->root_hub_desc.status.wStatus = 0;
396            }
397
398            break;
399
400        case USB_REQUEST_SET_ADDRESS:
401            /*
402             * SetAddress() Request
403             *
404             * we can set the address of the root hub if it is
405             * withint the maximum devices range
406             */
407            if (req_value > USB_OHCI_MAX_DEVICES) {
408                *ret_length = length;
409                *ret_data = data;
410                return USB_ERR_IOERROR;
411            }
412            hc->root_hub_address = req_value;
413            break;
414
415        case USB_REQUEST_SET_CONFIG:
416            /*
417             * SetConfiguration() Request
418             *
419             * We have only two two options (0, 1) that we can set
420             */
421            if (req_value > 1) {
422                *ret_length = length;
423                *ret_data = data;
424                return USB_ERR_IOERROR;
425            }
426            hc->root_hub_config = req_value;
427            break;
428
429        case USB_REQUEST_SET_DESCRIPTOR:
430            /*
431             * SetDescriptor() Request
432             *
433             * We do not allow to change the USB root hub descriptor
434             * so this is a no-op for standard requests
435             *
436             * but is is an error for hub class requests
437             */
438            if (req->bType.type == USB_REQUEST_TYPE_CLASS) {
439                *ret_length = length;
440                *ret_data = data;
441                return USB_ERR_IOERROR;
442            }
443            break;
444
445        case USB_REQUEST_SET_FEATURE:
446            /*
447             * SetFeature() Request
448             *
449             * Setting a feature on the root hub is an error,
450             * so we reply with USB_ERR_IOERROR
451             */
452            if (req->bType.type != USB_REQUEST_TYPE_CLASS) {
453                *ret_length = length;
454                *ret_data = data;
455                return USB_ERR_IOERROR;
456                break;
457            }
458            /* handling of hub cpass specific port request */
459
460            if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) {
461                if ((req_index < 1) || (req_index > hc->root_hub_num_ports)) {
462                    *ret_length = length;
463                    *ret_data = data;
464                    return USB_ERR_IOERROR;
465                    break;
466                }
467                ohci_rh_portstat_t ps = ohci_rh_portstat_rawrd(hc->ohci_base,
468                        req_index);
469                switch (req_value) {
470                    case USB_HUB_FEATURE_PORT_ENABLE:
471                        ohci_rh_portstat_pes_insert(ps, 1);
472                        break;
473                    case USB_HUB_FEATURE_PORT_SUSPEND:
474                        ohci_rh_portstat_pss_insert(ps, 1);
475                        break;
476                    case USB_HUB_FEATURE_PORT_RESET:
477                        ohci_rh_portstat_prs_insert(ps, 1);
478                        break;
479                    case USB_HUB_FEATURE_PORT_POWER:
480                        ohci_rh_portstat_pps_insert(ps, 1);
481                        break;
482                    default:
483                        *ret_length = length;
484                        *ret_data = data;
485                        return USB_ERR_IOERROR;
486                        break;
487                }
488                ohci_rh_portctrl_rawwr(hc->ohci_base, req_index, ps);
489                /*
490                 * handle the reset of the port
491                 */
492                if (req_value == USB_HUB_FEATURE_PORT_RESET) {
493                    for (uint32_t i = 0;; i++) {
494                        if (ohci_rh_portstat_prs_rdf(hc->ohci_base,
495                                req_index)) {
496                            /*
497                             * bit has not been cleared, that means the
498                             * reset is not completed yet
499                             */
500                            /* TODO: WAIT SOME TIME */
501                            if (i > 12) {
502                                *ret_data = data;
503                                *ret_length = length;
504                                return USB_ERR_TIMEOUT;
505                            }
506                        } else {
507                            // reset complete
508                            break;
509                        }
510                    }
511                }
512            }
513            break;
514
515        case USB_REQUEST_SET_INTERFACE:
516            /*
517             * SetInterface() Request
518             *
519             * we have just one interface, so this is a no-op
520             */
521            break;
522
523        case USB_REQUEST_SYNCH_FRAME:
524            /*
525             * SetSynchFrame() Request
526             *
527             * No-op
528             */
529            break;
530        default:
531            *ret_length = length;
532            *ret_data = data;
533            return USB_ERR_IOERROR;
534            break;
535    }
536    *ret_length = length;
537    *ret_data = data;
538    return USB_ERR_OK;
539}
540
541