~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/drivers/usb.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Driver for USB ported from CoreBoot
 
3
 *
 
4
 * Copyright (C) 2014 BALATON Zoltan
 
5
 *
 
6
 * This file was part of the libpayload project.
 
7
 *
 
8
 * Copyright (C) 2008-2010 coresystems GmbH
 
9
 *
 
10
 * Redistribution and use in source and binary forms, with or without
 
11
 * modification, are permitted provided that the following conditions
 
12
 * are met:
 
13
 * 1. Redistributions of source code must retain the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer.
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in the
 
17
 *    documentation and/or other materials provided with the distribution.
 
18
 * 3. The name of the author may not be used to endorse or promote products
 
19
 *    derived from this software without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include "config.h"
 
35
#include "drivers/usb.h"
 
36
#include "usb.h"
 
37
#include "timer.h"
 
38
#include "libc/byteorder.h"
 
39
 
 
40
hci_t *usb_hcs = 0;
 
41
 
 
42
static void usb_nop_init (usbdev_t *dev);
 
43
 
 
44
static void
 
45
usb_nop_destroy (usbdev_t *dev)
 
46
{
 
47
        if (dev->descriptor != 0)
 
48
                free (dev->descriptor);
 
49
        usb_nop_init (dev);
 
50
        dev->address = -1;
 
51
        dev->hub = -1;
 
52
        dev->port = -1;
 
53
}
 
54
 
 
55
static void
 
56
usb_nop_poll (usbdev_t *dev)
 
57
{
 
58
        return;
 
59
}
 
60
 
 
61
static void
 
62
usb_nop_init (usbdev_t *dev)
 
63
{
 
64
        dev->descriptor = 0;
 
65
        dev->destroy = usb_nop_destroy;
 
66
        dev->poll = usb_nop_poll;
 
67
}
 
68
 
 
69
hci_t *
 
70
new_controller (void)
 
71
{
 
72
        hci_t *controller = malloc (sizeof (hci_t));
 
73
 
 
74
        if (controller) {
 
75
                /* atomic */
 
76
                controller->next = usb_hcs;
 
77
                usb_hcs = controller;
 
78
                /* atomic end */
 
79
        }
 
80
 
 
81
        return controller;
 
82
}
 
83
 
 
84
void
 
85
detach_controller (hci_t *controller)
 
86
{
 
87
        if (controller == NULL)
 
88
                return;
 
89
        if (usb_hcs == controller) {
 
90
                usb_hcs = controller->next;
 
91
        } else {
 
92
                hci_t *it = usb_hcs;
 
93
                while (it != NULL) {
 
94
                        if (it->next == controller) {
 
95
                                it->next = controller->next;
 
96
                                return;
 
97
                        }
 
98
                        it = it->next;
 
99
                }
 
100
        }
 
101
}
 
102
 
 
103
/**
 
104
 * Shut down all controllers
 
105
 */
 
106
int
 
107
usb_exit (void)
 
108
{
 
109
        while (usb_hcs != NULL) {
 
110
                usb_hcs->shutdown(usb_hcs);
 
111
        }
 
112
        return 0;
 
113
}
 
114
 
 
115
/**
 
116
 * Polls all hubs on all USB controllers, to find out about device changes
 
117
 */
 
118
void
 
119
usb_poll (void)
 
120
{
 
121
        if (usb_hcs == 0)
 
122
                return;
 
123
        hci_t *controller = usb_hcs;
 
124
        while (controller != NULL) {
 
125
                int i;
 
126
                for (i = 0; i < 128; i++) {
 
127
                        if (controller->devices[i] != 0) {
 
128
                                controller->devices[i]->poll (controller->devices[i]);
 
129
                        }
 
130
                }
 
131
                controller = controller->next;
 
132
        }
 
133
}
 
134
 
 
135
void
 
136
init_device_entry (hci_t *controller, int i)
 
137
{
 
138
        if (controller->devices[i] != 0)
 
139
                usb_debug("warning: device %d reassigned?\n", i);
 
140
        controller->devices[i] = malloc(sizeof(usbdev_t));
 
141
        controller->devices[i]->controller = controller;
 
142
        controller->devices[i]->address = -1;
 
143
        controller->devices[i]->hub = -1;
 
144
        controller->devices[i]->port = -1;
 
145
        controller->devices[i]->init = usb_nop_init;
 
146
        controller->devices[i]->init (controller->devices[i]);
 
147
}
 
148
 
 
149
void
 
150
set_feature (usbdev_t *dev, int endp, int feature, int rtype)
 
151
{
 
152
        dev_req_t dr;
 
153
 
 
154
        dr.bmRequestType = rtype;
 
155
        dr.data_dir = host_to_device;
 
156
        dr.bRequest = SET_FEATURE;
 
157
        dr.wValue = __cpu_to_le16(feature);
 
158
        dr.wIndex = __cpu_to_le16(endp);
 
159
        dr.wLength = 0;
 
160
        dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 
161
}
 
162
 
 
163
void
 
164
get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
 
165
{
 
166
        dev_req_t dr;
 
167
 
 
168
        dr.bmRequestType = rtype;
 
169
        dr.data_dir = device_to_host;
 
170
        dr.bRequest = GET_STATUS;
 
171
        dr.wValue = 0;
 
172
        dr.wIndex = __cpu_to_le16(intf);
 
173
        dr.wLength = __cpu_to_le16(len);
 
174
        dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
 
175
}
 
176
 
 
177
u8 *
 
178
get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
 
179
                int descIdx, int langID)
 
180
{
 
181
        u8 buf[8];
 
182
        u8 *result;
 
183
        dev_req_t dr;
 
184
        int size;
 
185
 
 
186
        dr.bmRequestType = bmRequestType;
 
187
        dr.data_dir = device_to_host;   // always like this for descriptors
 
188
        dr.bRequest = GET_DESCRIPTOR;
 
189
        dr.wValue = __cpu_to_le16((descType << 8) | descIdx);
 
190
        dr.wIndex = __cpu_to_le16(langID);
 
191
        dr.wLength = __cpu_to_le16(8);
 
192
        if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
 
193
                usb_debug ("getting descriptor size (type %x) failed\n",
 
194
                        descType);
 
195
        }
 
196
 
 
197
        if (descType == 1) {
 
198
                device_descriptor_t *dd = (device_descriptor_t *) buf;
 
199
                usb_debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
 
200
                if (dd->bMaxPacketSize0 != 0)
 
201
                        dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 
202
        }
 
203
 
 
204
        /* special case for configuration descriptors: they carry all their
 
205
           subsequent descriptors with them, and keep the entire size at a
 
206
           different location */
 
207
        size = buf[0];
 
208
        if (buf[1] == 2) {
 
209
                int realsize = __le16_to_cpu(((unsigned short *) (buf + 2))[0]);
 
210
                size = realsize;
 
211
        }
 
212
        result = malloc (size);
 
213
        memset (result, 0, size);
 
214
        dr.wLength = __cpu_to_le16(size);
 
215
        if (dev->controller->
 
216
            control (dev, IN, sizeof (dr), &dr, size, result)) {
 
217
                usb_debug ("getting descriptor (type %x, size %x) failed\n",
 
218
                        descType, size);
 
219
        }
 
220
 
 
221
        return result;
 
222
}
 
223
 
 
224
void
 
225
set_configuration (usbdev_t *dev)
 
226
{
 
227
        dev_req_t dr;
 
228
 
 
229
        dr.bmRequestType = 0;
 
230
        dr.bRequest = SET_CONFIGURATION;
 
231
        dr.wValue = __cpu_to_le16(dev->configuration[5]);
 
232
        dr.wIndex = 0;
 
233
        dr.wLength = 0;
 
234
        dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 
235
}
 
236
 
 
237
int
 
238
clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
 
239
{
 
240
        dev_req_t dr;
 
241
 
 
242
        dr.bmRequestType = rtype;
 
243
        dr.data_dir = host_to_device;
 
244
        dr.bRequest = CLEAR_FEATURE;
 
245
        dr.wValue = __cpu_to_le16(feature);
 
246
        dr.wIndex = __cpu_to_le16(endp);
 
247
        dr.wLength = 0;
 
248
        return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 
249
}
 
250
 
 
251
int
 
252
clear_stall (endpoint_t *ep)
 
253
{
 
254
        usbdev_t *dev = ep->dev;
 
255
        int endp = ep->endpoint;
 
256
        int rtype = gen_bmRequestType (host_to_device, standard_type,
 
257
                                        endp ? endp_recp : dev_recp);
 
258
 
 
259
        int ret = clear_feature (dev, endp, ENDPOINT_HALT, rtype);
 
260
        ep->toggle = 0;
 
261
        return ret;
 
262
}
 
263
 
 
264
/* returns free address or -1 */
 
265
static int
 
266
get_free_address (hci_t *controller)
 
267
{
 
268
        int i;
 
269
        for (i = 1; i < 128; i++) {
 
270
                if (controller->devices[i] == 0)
 
271
                        return i;
 
272
        }
 
273
        usb_debug ("no free address found\n");
 
274
        return -1;              // no free address
 
275
}
 
276
 
 
277
int
 
278
generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr)
 
279
{
 
280
        int adr = get_free_address (controller);        // address to set
 
281
        dev_req_t dr;
 
282
 
 
283
        memset (&dr, 0, sizeof (dr));
 
284
        dr.data_dir = host_to_device;
 
285
        dr.req_type = standard_type;
 
286
        dr.req_recp = dev_recp;
 
287
        dr.bRequest = SET_ADDRESS;
 
288
        dr.wValue = __cpu_to_le16(adr);
 
289
        dr.wIndex = 0;
 
290
        dr.wLength = 0;
 
291
 
 
292
        init_device_entry(controller, adr);
 
293
        usbdev_t *dev = controller->devices[adr];
 
294
        // dummy values for registering the address
 
295
        dev->address = 0;
 
296
        dev->hub = hubaddr;
 
297
        dev->port = hubport;
 
298
        dev->speed = speed;
 
299
        dev->endpoints[0].dev = dev;
 
300
        dev->endpoints[0].endpoint = 0;
 
301
        dev->endpoints[0].maxpacketsize = 8;
 
302
        dev->endpoints[0].toggle = 0;
 
303
        dev->endpoints[0].direction = SETUP;
 
304
        mdelay (50);
 
305
        if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
 
306
                return -1;
 
307
        }
 
308
        mdelay (50);
 
309
 
 
310
        return adr;
 
311
}
 
312
 
 
313
/* Normalize bInterval to log2 of microframes */
 
314
static int
 
315
usb_decode_interval(const int speed, const endpoint_type type, const unsigned char bInterval)
 
316
{
 
317
#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
 
318
        switch (speed) {
 
319
        case LOW_SPEED:
 
320
                switch (type) {
 
321
                case ISOCHRONOUS: case INTERRUPT:
 
322
                        return LOG2(bInterval) + 3;
 
323
                default:
 
324
                        return 0;
 
325
                }
 
326
        case FULL_SPEED:
 
327
                switch (type) {
 
328
                case ISOCHRONOUS:
 
329
                        return (bInterval - 1) + 3;
 
330
                case INTERRUPT:
 
331
                        return LOG2(bInterval) + 3;
 
332
                default:
 
333
                        return 0;
 
334
                }
 
335
        case HIGH_SPEED:
 
336
                switch (type) {
 
337
                case ISOCHRONOUS: case INTERRUPT:
 
338
                        return bInterval - 1;
 
339
                default:
 
340
                        return LOG2(bInterval);
 
341
                }
 
342
        case SUPER_SPEED:
 
343
                switch (type) {
 
344
                case ISOCHRONOUS: case INTERRUPT:
 
345
                        return bInterval - 1;
 
346
                default:
 
347
                        return 0;
 
348
                }
 
349
        default:
 
350
                return 0;
 
351
        }
 
352
#undef LOG2
 
353
}
 
354
 
 
355
static int
 
356
set_address (hci_t *controller, int speed, int hubport, int hubaddr)
 
357
{
 
358
        int adr = controller->set_address(controller, speed, hubport, hubaddr);
 
359
        if (adr < 0 || !controller->devices[adr]) {
 
360
                usb_debug ("set_address failed\n");
 
361
                return -1;
 
362
        }
 
363
        configuration_descriptor_t *cd;
 
364
        device_descriptor_t *dd;
 
365
 
 
366
        usbdev_t *dev = controller->devices[adr];
 
367
        dev->address = adr;
 
368
        dev->hub = hubaddr;
 
369
        dev->port = hubport;
 
370
        dev->speed = speed;
 
371
        dev->descriptor = get_descriptor (dev, gen_bmRequestType
 
372
                (device_to_host, standard_type, dev_recp), 1, 0, 0);
 
373
        dd = (device_descriptor_t *) dev->descriptor;
 
374
 
 
375
        usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x)",
 
376
                 __le16_to_cpu(dd->idVendor), __le16_to_cpu(dd->idProduct),
 
377
                 __le16_to_cpu(dd->bcdUSB) >> 8, __le16_to_cpu(dd->bcdUSB) & 0xff);
 
378
        dev->quirks = USB_QUIRK_NONE;
 
379
 
 
380
        usb_debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
 
381
        if (dd->bNumConfigurations == 0) {
 
382
                /* device isn't usable */
 
383
                usb_debug ("... no usable configuration!\n");
 
384
                dev->address = 0;
 
385
                return -1;
 
386
        }
 
387
 
 
388
        dev->configuration = get_descriptor (dev, gen_bmRequestType
 
389
                (device_to_host, standard_type, dev_recp), 2, 0, 0);
 
390
        cd = (configuration_descriptor_t *) dev->configuration;
 
391
        interface_descriptor_t *interface =
 
392
                (interface_descriptor_t *) (((char *) cd) + cd->bLength);
 
393
        {
 
394
                int i;
 
395
                int num = cd->bNumInterfaces;
 
396
                interface_descriptor_t *current = interface;
 
397
                usb_debug ("device has %x interfaces\n", num);
 
398
                if (num > 1) {
 
399
                        usb_debug ("\nNOTICE: This driver defaults to using the first interface.\n"
 
400
                                   "This might be the wrong choice and lead to limited functionality\n"
 
401
                                   "of the device.\n");
 
402
                         /* we limit to the first interface, as there was no need to
 
403
                         * implement something else for the time being. If you need
 
404
                         * it, see the SetInterface and GetInterface functions in
 
405
                         * the USB specification, and adapt appropriately.
 
406
                         */
 
407
                        num = (num > 1) ? 1 : num;
 
408
                }
 
409
                for (i = 0; i < num; i++) {
 
410
                        int j;
 
411
                        usb_debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
 
412
                                        current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
 
413
                        endpoint_descriptor_t *endp =
 
414
                                (endpoint_descriptor_t *) (((char *) current)
 
415
                                                           + current->bLength);
 
416
                        /* Skip any non-endpoint descriptor */
 
417
                        if (endp->bDescriptorType != 0x05)
 
418
                                endp = (endpoint_descriptor_t *)(((char *)endp) + ((char *)endp)[0]);
 
419
 
 
420
                        memset (dev->endpoints, 0, sizeof (dev->endpoints));
 
421
                        dev->num_endp = 1;      // 0 always exists
 
422
                        dev->endpoints[0].dev = dev;
 
423
                        dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 
424
                        dev->endpoints[0].direction = SETUP;
 
425
                        dev->endpoints[0].type = CONTROL;
 
426
                        dev->endpoints[0].interval = usb_decode_interval(dev->speed, CONTROL, endp->bInterval);
 
427
                        for (j = 1; j <= current->bNumEndpoints; j++) {
 
428
#ifdef CONFIG_DEBUG_USB
 
429
                                static const char *transfertypes[4] = {
 
430
                                        "control", "isochronous", "bulk", "interrupt"
 
431
                                };
 
432
                                usb_debug ("   #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", __le16_to_cpu(endp->wMaxPacketSize), transfertypes[endp->bmAttributes]);
 
433
#endif
 
434
                                endpoint_t *ep =
 
435
                                        &dev->endpoints[dev->num_endp++];
 
436
                                ep->dev = dev;
 
437
                                ep->endpoint = endp->bEndpointAddress;
 
438
                                ep->toggle = 0;
 
439
                                ep->maxpacketsize = __le16_to_cpu(endp->wMaxPacketSize);
 
440
                                ep->direction =
 
441
                                        ((endp->bEndpointAddress & 0x80) ==
 
442
                                         0) ? OUT : IN;
 
443
                                ep->type = endp->bmAttributes;
 
444
                                ep->interval = usb_decode_interval(dev->speed, ep->type, endp->bInterval);
 
445
                                endp = (endpoint_descriptor_t
 
446
                                        *) (((char *) endp) + endp->bLength);
 
447
                        }
 
448
                        current = (interface_descriptor_t *) endp;
 
449
                }
 
450
        }
 
451
 
 
452
        if (controller->finish_device_config &&
 
453
                        controller->finish_device_config(dev))
 
454
                return adr; /* Device isn't configured correctly,
 
455
                               only control transfers may work. */
 
456
 
 
457
        set_configuration(dev);
 
458
 
 
459
        int class = dd->bDeviceClass;
 
460
        if (class == 0)
 
461
                class = interface->bInterfaceClass;
 
462
 
 
463
        usb_debug(", class: ");
 
464
        switch (class) {
 
465
        case audio_device:
 
466
                usb_debug("audio\n");
 
467
                break;
 
468
        case comm_device:
 
469
                usb_debug("communication\n");
 
470
                break;
 
471
        case hid_device:
 
472
                usb_debug ("HID\n");
 
473
#ifdef CONFIG_USB_HID
 
474
                controller->devices[adr]->init = usb_hid_init;
 
475
                return adr;
 
476
#else
 
477
                usb_debug ("NOTICE: USB HID support not compiled in\n");
 
478
#endif
 
479
                break;
 
480
        case physical_device:
 
481
                usb_debug("physical\n");
 
482
                break;
 
483
        case imaging_device:
 
484
                usb_debug("camera\n");
 
485
                break;
 
486
        case printer_device:
 
487
                usb_debug("printer\n");
 
488
                break;
 
489
        case msc_device:
 
490
                usb_debug ("MSC\n");
 
491
#ifdef CONFIG_USB_MSC
 
492
                controller->devices[adr]->init = usb_msc_init;
 
493
                return adr;
 
494
#else
 
495
                usb_debug ("NOTICE: USB MSC support not compiled in\n");
 
496
#endif
 
497
                break;
 
498
        case hub_device:
 
499
                usb_debug ("hub\n");
 
500
#ifdef CONFIG_USB_HUB
 
501
                controller->devices[adr]->init = usb_hub_init;
 
502
                return adr;
 
503
#else
 
504
                usb_debug ("NOTICE: USB hub support not compiled in.\n");
 
505
#endif
 
506
                break;
 
507
        case cdc_device:
 
508
                usb_debug("CDC\n");
 
509
                break;
 
510
        case ccid_device:
 
511
                usb_debug("smartcard / CCID\n");
 
512
                break;
 
513
        case security_device:
 
514
                usb_debug("content security\n");
 
515
                break;
 
516
        case video_device:
 
517
                usb_debug("video\n");
 
518
                break;
 
519
        case healthcare_device:
 
520
                usb_debug("healthcare\n");
 
521
                break;
 
522
        case diagnostic_device:
 
523
                usb_debug("diagnostic\n");
 
524
                break;
 
525
        case wireless_device:
 
526
                usb_debug("wireless\n");
 
527
                break;
 
528
        default:
 
529
                usb_debug("unsupported class %x\n", class);
 
530
                break;
 
531
        }
 
532
        controller->devices[adr]->init = usb_generic_init;
 
533
        return adr;
 
534
}
 
535
 
 
536
/*
 
537
 * Should be called by the hub drivers whenever a physical detach occurs
 
538
 * and can be called by usb class drivers if they are unsatisfied with a
 
539
 * malfunctioning device.
 
540
 */
 
541
void
 
542
usb_detach_device(hci_t *controller, int devno)
 
543
{
 
544
        /* check if device exists, as we may have
 
545
           been called yet by the usb class driver */
 
546
        if (controller->devices[devno]) {
 
547
                controller->devices[devno]->destroy (controller->devices[devno]);
 
548
                free(controller->devices[devno]);
 
549
                controller->devices[devno] = NULL;
 
550
                if (controller->destroy_device)
 
551
                        controller->destroy_device(controller, devno);
 
552
        }
 
553
}
 
554
 
 
555
int
 
556
usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
 
557
{
 
558
#ifdef CONFIG_DEBUG_USB
 
559
        static const char* speeds[] = { "full", "low", "high" };
 
560
        usb_debug ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
 
561
#endif
 
562
        int newdev = set_address (controller, speed, port, hubaddress);
 
563
        if (newdev == -1)
 
564
                return -1;
 
565
        usbdev_t *newdev_t = controller->devices[newdev];
 
566
        // determine responsible driver - current done in set_address
 
567
        newdev_t->init (newdev_t);
 
568
        /* init() may have called usb_detach_device() yet, so check */
 
569
        return controller->devices[newdev] ? newdev : -1;
 
570
}
 
571
 
 
572
static void
 
573
usb_generic_destroy (usbdev_t *dev)
 
574
{
 
575
        if (usb_generic_remove)
 
576
                usb_generic_remove(dev);
 
577
}
 
578
 
 
579
void
 
580
usb_generic_init (usbdev_t *dev)
 
581
{
 
582
        dev->data = NULL;
 
583
        dev->destroy = usb_generic_destroy;
 
584
 
 
585
        if (usb_generic_create)
 
586
                usb_generic_create(dev);
 
587
}