Annotation of qemu/hw/usb/bus.c, revision 1.1

1.1     ! root        1: #include "hw/hw.h"
        !             2: #include "hw/usb.h"
        !             3: #include "hw/qdev.h"
        !             4: #include "sysemu.h"
        !             5: #include "monitor.h"
        !             6: #include "trace.h"
        !             7: 
        !             8: static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
        !             9: 
        !            10: static char *usb_get_dev_path(DeviceState *dev);
        !            11: static char *usb_get_fw_dev_path(DeviceState *qdev);
        !            12: static int usb_qdev_exit(DeviceState *qdev);
        !            13: 
        !            14: static struct BusInfo usb_bus_info = {
        !            15:     .name      = "USB",
        !            16:     .size      = sizeof(USBBus),
        !            17:     .print_dev = usb_bus_dev_print,
        !            18:     .get_dev_path = usb_get_dev_path,
        !            19:     .get_fw_dev_path = usb_get_fw_dev_path,
        !            20:     .props      = (Property[]) {
        !            21:         DEFINE_PROP_STRING("port", USBDevice, port_path),
        !            22:         DEFINE_PROP_BIT("full-path", USBDevice, flags,
        !            23:                         USB_DEV_FLAG_FULL_PATH, true),
        !            24:         DEFINE_PROP_END_OF_LIST()
        !            25:     },
        !            26: };
        !            27: static int next_usb_bus = 0;
        !            28: static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
        !            29: 
        !            30: const VMStateDescription vmstate_usb_device = {
        !            31:     .name = "USBDevice",
        !            32:     .version_id = 1,
        !            33:     .minimum_version_id = 1,
        !            34:     .fields = (VMStateField []) {
        !            35:         VMSTATE_UINT8(addr, USBDevice),
        !            36:         VMSTATE_INT32(state, USBDevice),
        !            37:         VMSTATE_INT32(remote_wakeup, USBDevice),
        !            38:         VMSTATE_INT32(setup_state, USBDevice),
        !            39:         VMSTATE_INT32(setup_len, USBDevice),
        !            40:         VMSTATE_INT32(setup_index, USBDevice),
        !            41:         VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
        !            42:         VMSTATE_END_OF_LIST(),
        !            43:     }
        !            44: };
        !            45: 
        !            46: void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
        !            47: {
        !            48:     qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
        !            49:     bus->ops = ops;
        !            50:     bus->busnr = next_usb_bus++;
        !            51:     bus->qbus.allow_hotplug = 1; /* Yes, we can */
        !            52:     QTAILQ_INIT(&bus->free);
        !            53:     QTAILQ_INIT(&bus->used);
        !            54:     QTAILQ_INSERT_TAIL(&busses, bus, next);
        !            55: }
        !            56: 
        !            57: USBBus *usb_bus_find(int busnr)
        !            58: {
        !            59:     USBBus *bus;
        !            60: 
        !            61:     if (-1 == busnr)
        !            62:         return QTAILQ_FIRST(&busses);
        !            63:     QTAILQ_FOREACH(bus, &busses, next) {
        !            64:         if (bus->busnr == busnr)
        !            65:             return bus;
        !            66:     }
        !            67:     return NULL;
        !            68: }
        !            69: 
        !            70: static int usb_device_init(USBDevice *dev)
        !            71: {
        !            72:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !            73:     if (klass->init) {
        !            74:         return klass->init(dev);
        !            75:     }
        !            76:     return 0;
        !            77: }
        !            78: 
        !            79: USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr)
        !            80: {
        !            81:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !            82:     if (klass->find_device) {
        !            83:         return klass->find_device(dev, addr);
        !            84:     }
        !            85:     return NULL;
        !            86: }
        !            87: 
        !            88: static void usb_device_handle_destroy(USBDevice *dev)
        !            89: {
        !            90:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !            91:     if (klass->handle_destroy) {
        !            92:         klass->handle_destroy(dev);
        !            93:     }
        !            94: }
        !            95: 
        !            96: void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
        !            97: {
        !            98:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !            99:     if (klass->cancel_packet) {
        !           100:         klass->cancel_packet(dev, p);
        !           101:     }
        !           102: }
        !           103: 
        !           104: void usb_device_handle_attach(USBDevice *dev)
        !           105: {
        !           106:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           107:     if (klass->handle_attach) {
        !           108:         klass->handle_attach(dev);
        !           109:     }
        !           110: }
        !           111: 
        !           112: void usb_device_handle_reset(USBDevice *dev)
        !           113: {
        !           114:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           115:     if (klass->handle_reset) {
        !           116:         klass->handle_reset(dev);
        !           117:     }
        !           118: }
        !           119: 
        !           120: int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
        !           121:                               int value, int index, int length, uint8_t *data)
        !           122: {
        !           123:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           124:     if (klass->handle_control) {
        !           125:         return klass->handle_control(dev, p, request, value, index, length,
        !           126:                                          data);
        !           127:     }
        !           128:     return -ENOSYS;
        !           129: }
        !           130: 
        !           131: int usb_device_handle_data(USBDevice *dev, USBPacket *p)
        !           132: {
        !           133:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           134:     if (klass->handle_data) {
        !           135:         return klass->handle_data(dev, p);
        !           136:     }
        !           137:     return -ENOSYS;
        !           138: }
        !           139: 
        !           140: const char *usb_device_get_product_desc(USBDevice *dev)
        !           141: {
        !           142:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           143:     return klass->product_desc;
        !           144: }
        !           145: 
        !           146: const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
        !           147: {
        !           148:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           149:     return klass->usb_desc;
        !           150: }
        !           151: 
        !           152: void usb_device_set_interface(USBDevice *dev, int interface,
        !           153:                               int alt_old, int alt_new)
        !           154: {
        !           155:     USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
        !           156:     if (klass->set_interface) {
        !           157:         klass->set_interface(dev, interface, alt_old, alt_new);
        !           158:     }
        !           159: }
        !           160: 
        !           161: static int usb_qdev_init(DeviceState *qdev)
        !           162: {
        !           163:     USBDevice *dev = USB_DEVICE(qdev);
        !           164:     int rc;
        !           165: 
        !           166:     pstrcpy(dev->product_desc, sizeof(dev->product_desc),
        !           167:             usb_device_get_product_desc(dev));
        !           168:     dev->auto_attach = 1;
        !           169:     QLIST_INIT(&dev->strings);
        !           170:     usb_ep_init(dev);
        !           171:     rc = usb_claim_port(dev);
        !           172:     if (rc != 0) {
        !           173:         return rc;
        !           174:     }
        !           175:     rc = usb_device_init(dev);
        !           176:     if (rc != 0) {
        !           177:         usb_release_port(dev);
        !           178:         return rc;
        !           179:     }
        !           180:     if (dev->auto_attach) {
        !           181:         rc = usb_device_attach(dev);
        !           182:         if (rc != 0) {
        !           183:             usb_qdev_exit(qdev);
        !           184:             return rc;
        !           185:         }
        !           186:     }
        !           187:     return 0;
        !           188: }
        !           189: 
        !           190: static int usb_qdev_exit(DeviceState *qdev)
        !           191: {
        !           192:     USBDevice *dev = USB_DEVICE(qdev);
        !           193: 
        !           194:     if (dev->attached) {
        !           195:         usb_device_detach(dev);
        !           196:     }
        !           197:     usb_device_handle_destroy(dev);
        !           198:     if (dev->port) {
        !           199:         usb_release_port(dev);
        !           200:     }
        !           201:     return 0;
        !           202: }
        !           203: 
        !           204: typedef struct LegacyUSBFactory
        !           205: {
        !           206:     const char *name;
        !           207:     const char *usbdevice_name;
        !           208:     USBDevice *(*usbdevice_init)(USBBus *bus, const char *params);
        !           209: } LegacyUSBFactory;
        !           210: 
        !           211: static GSList *legacy_usb_factory;
        !           212: 
        !           213: void usb_legacy_register(const char *typename, const char *usbdevice_name,
        !           214:                          USBDevice *(*usbdevice_init)(USBBus *bus,
        !           215:                                                       const char *params))
        !           216: {
        !           217:     if (usbdevice_name) {
        !           218:         LegacyUSBFactory *f = g_malloc0(sizeof(*f));
        !           219:         f->name = typename;
        !           220:         f->usbdevice_name = usbdevice_name;
        !           221:         f->usbdevice_init = usbdevice_init;
        !           222:         legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
        !           223:     }
        !           224: }
        !           225: 
        !           226: USBDevice *usb_create(USBBus *bus, const char *name)
        !           227: {
        !           228:     DeviceState *dev;
        !           229: 
        !           230:     dev = qdev_create(&bus->qbus, name);
        !           231:     return USB_DEVICE(dev);
        !           232: }
        !           233: 
        !           234: USBDevice *usb_create_simple(USBBus *bus, const char *name)
        !           235: {
        !           236:     USBDevice *dev = usb_create(bus, name);
        !           237:     int rc;
        !           238: 
        !           239:     if (!dev) {
        !           240:         error_report("Failed to create USB device '%s'", name);
        !           241:         return NULL;
        !           242:     }
        !           243:     rc = qdev_init(&dev->qdev);
        !           244:     if (rc < 0) {
        !           245:         error_report("Failed to initialize USB device '%s'", name);
        !           246:         return NULL;
        !           247:     }
        !           248:     return dev;
        !           249: }
        !           250: 
        !           251: static void usb_fill_port(USBPort *port, void *opaque, int index,
        !           252:                           USBPortOps *ops, int speedmask)
        !           253: {
        !           254:     port->opaque = opaque;
        !           255:     port->index = index;
        !           256:     port->ops = ops;
        !           257:     port->speedmask = speedmask;
        !           258:     usb_port_location(port, NULL, index + 1);
        !           259: }
        !           260: 
        !           261: void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
        !           262:                        USBPortOps *ops, int speedmask)
        !           263: {
        !           264:     usb_fill_port(port, opaque, index, ops, speedmask);
        !           265:     QTAILQ_INSERT_TAIL(&bus->free, port, next);
        !           266:     bus->nfree++;
        !           267: }
        !           268: 
        !           269: int usb_register_companion(const char *masterbus, USBPort *ports[],
        !           270:                            uint32_t portcount, uint32_t firstport,
        !           271:                            void *opaque, USBPortOps *ops, int speedmask)
        !           272: {
        !           273:     USBBus *bus;
        !           274:     int i;
        !           275: 
        !           276:     QTAILQ_FOREACH(bus, &busses, next) {
        !           277:         if (strcmp(bus->qbus.name, masterbus) == 0) {
        !           278:             break;
        !           279:         }
        !           280:     }
        !           281: 
        !           282:     if (!bus || !bus->ops->register_companion) {
        !           283:         qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
        !           284:                       "an USB masterbus");
        !           285:         if (bus) {
        !           286:             error_printf_unless_qmp(
        !           287:                 "USB bus '%s' does not allow companion controllers\n",
        !           288:                 masterbus);
        !           289:         }
        !           290:         return -1;
        !           291:     }
        !           292: 
        !           293:     for (i = 0; i < portcount; i++) {
        !           294:         usb_fill_port(ports[i], opaque, i, ops, speedmask);
        !           295:     }
        !           296: 
        !           297:     return bus->ops->register_companion(bus, ports, portcount, firstport);
        !           298: }
        !           299: 
        !           300: void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
        !           301: {
        !           302:     if (upstream) {
        !           303:         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
        !           304:                  upstream->path, portnr);
        !           305:     } else {
        !           306:         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
        !           307:     }
        !           308: }
        !           309: 
        !           310: void usb_unregister_port(USBBus *bus, USBPort *port)
        !           311: {
        !           312:     if (port->dev)
        !           313:         qdev_free(&port->dev->qdev);
        !           314:     QTAILQ_REMOVE(&bus->free, port, next);
        !           315:     bus->nfree--;
        !           316: }
        !           317: 
        !           318: int usb_claim_port(USBDevice *dev)
        !           319: {
        !           320:     USBBus *bus = usb_bus_from_device(dev);
        !           321:     USBPort *port;
        !           322: 
        !           323:     assert(dev->port == NULL);
        !           324: 
        !           325:     if (dev->port_path) {
        !           326:         QTAILQ_FOREACH(port, &bus->free, next) {
        !           327:             if (strcmp(port->path, dev->port_path) == 0) {
        !           328:                 break;
        !           329:             }
        !           330:         }
        !           331:         if (port == NULL) {
        !           332:             error_report("Error: usb port %s (bus %s) not found (in use?)",
        !           333:                          dev->port_path, bus->qbus.name);
        !           334:             return -1;
        !           335:         }
        !           336:     } else {
        !           337:         if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
        !           338:             /* Create a new hub and chain it on */
        !           339:             usb_create_simple(bus, "usb-hub");
        !           340:         }
        !           341:         if (bus->nfree == 0) {
        !           342:             error_report("Error: tried to attach usb device %s to a bus "
        !           343:                          "with no free ports", dev->product_desc);
        !           344:             return -1;
        !           345:         }
        !           346:         port = QTAILQ_FIRST(&bus->free);
        !           347:     }
        !           348:     trace_usb_port_claim(bus->busnr, port->path);
        !           349: 
        !           350:     QTAILQ_REMOVE(&bus->free, port, next);
        !           351:     bus->nfree--;
        !           352: 
        !           353:     dev->port = port;
        !           354:     port->dev = dev;
        !           355: 
        !           356:     QTAILQ_INSERT_TAIL(&bus->used, port, next);
        !           357:     bus->nused++;
        !           358:     return 0;
        !           359: }
        !           360: 
        !           361: void usb_release_port(USBDevice *dev)
        !           362: {
        !           363:     USBBus *bus = usb_bus_from_device(dev);
        !           364:     USBPort *port = dev->port;
        !           365: 
        !           366:     assert(port != NULL);
        !           367:     trace_usb_port_release(bus->busnr, port->path);
        !           368: 
        !           369:     QTAILQ_REMOVE(&bus->used, port, next);
        !           370:     bus->nused--;
        !           371: 
        !           372:     dev->port = NULL;
        !           373:     port->dev = NULL;
        !           374: 
        !           375:     QTAILQ_INSERT_TAIL(&bus->free, port, next);
        !           376:     bus->nfree++;
        !           377: }
        !           378: 
        !           379: int usb_device_attach(USBDevice *dev)
        !           380: {
        !           381:     USBBus *bus = usb_bus_from_device(dev);
        !           382:     USBPort *port = dev->port;
        !           383: 
        !           384:     assert(port != NULL);
        !           385:     assert(!dev->attached);
        !           386:     trace_usb_port_attach(bus->busnr, port->path);
        !           387: 
        !           388:     if (!(port->speedmask & dev->speedmask)) {
        !           389:         error_report("Warning: speed mismatch trying to attach "
        !           390:                      "usb device %s to bus %s",
        !           391:                      dev->product_desc, bus->qbus.name);
        !           392:         return -1;
        !           393:     }
        !           394: 
        !           395:     dev->attached++;
        !           396:     usb_attach(port);
        !           397: 
        !           398:     return 0;
        !           399: }
        !           400: 
        !           401: int usb_device_detach(USBDevice *dev)
        !           402: {
        !           403:     USBBus *bus = usb_bus_from_device(dev);
        !           404:     USBPort *port = dev->port;
        !           405: 
        !           406:     assert(port != NULL);
        !           407:     assert(dev->attached);
        !           408:     trace_usb_port_detach(bus->busnr, port->path);
        !           409: 
        !           410:     usb_detach(port);
        !           411:     dev->attached--;
        !           412:     return 0;
        !           413: }
        !           414: 
        !           415: int usb_device_delete_addr(int busnr, int addr)
        !           416: {
        !           417:     USBBus *bus;
        !           418:     USBPort *port;
        !           419:     USBDevice *dev;
        !           420: 
        !           421:     bus = usb_bus_find(busnr);
        !           422:     if (!bus)
        !           423:         return -1;
        !           424: 
        !           425:     QTAILQ_FOREACH(port, &bus->used, next) {
        !           426:         if (port->dev->addr == addr)
        !           427:             break;
        !           428:     }
        !           429:     if (!port)
        !           430:         return -1;
        !           431:     dev = port->dev;
        !           432: 
        !           433:     qdev_free(&dev->qdev);
        !           434:     return 0;
        !           435: }
        !           436: 
        !           437: static const char *usb_speed(unsigned int speed)
        !           438: {
        !           439:     static const char *txt[] = {
        !           440:         [ USB_SPEED_LOW  ] = "1.5",
        !           441:         [ USB_SPEED_FULL ] = "12",
        !           442:         [ USB_SPEED_HIGH ] = "480",
        !           443:         [ USB_SPEED_SUPER ] = "5000",
        !           444:     };
        !           445:     if (speed >= ARRAY_SIZE(txt))
        !           446:         return "?";
        !           447:     return txt[speed];
        !           448: }
        !           449: 
        !           450: static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
        !           451: {
        !           452:     USBDevice *dev = USB_DEVICE(qdev);
        !           453:     USBBus *bus = usb_bus_from_device(dev);
        !           454: 
        !           455:     monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
        !           456:                    indent, "", bus->busnr, dev->addr,
        !           457:                    dev->port ? dev->port->path : "-",
        !           458:                    usb_speed(dev->speed), dev->product_desc,
        !           459:                    dev->attached ? ", attached" : "");
        !           460: }
        !           461: 
        !           462: static char *usb_get_dev_path(DeviceState *qdev)
        !           463: {
        !           464:     USBDevice *dev = USB_DEVICE(qdev);
        !           465:     DeviceState *hcd = qdev->parent_bus->parent;
        !           466:     char *id = NULL;
        !           467: 
        !           468:     if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
        !           469:         hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
        !           470:         id = hcd->parent_bus->info->get_dev_path(hcd);
        !           471:     }
        !           472:     if (id) {
        !           473:         char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
        !           474:         g_free(id);
        !           475:         return ret;
        !           476:     } else {
        !           477:         return g_strdup(dev->port->path);
        !           478:     }
        !           479: }
        !           480: 
        !           481: static char *usb_get_fw_dev_path(DeviceState *qdev)
        !           482: {
        !           483:     USBDevice *dev = USB_DEVICE(qdev);
        !           484:     char *fw_path, *in;
        !           485:     ssize_t pos = 0, fw_len;
        !           486:     long nr;
        !           487: 
        !           488:     fw_len = 32 + strlen(dev->port->path) * 6;
        !           489:     fw_path = g_malloc(fw_len);
        !           490:     in = dev->port->path;
        !           491:     while (fw_len - pos > 0) {
        !           492:         nr = strtol(in, &in, 10);
        !           493:         if (in[0] == '.') {
        !           494:             /* some hub between root port and device */
        !           495:             pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
        !           496:             in++;
        !           497:         } else {
        !           498:             /* the device itself */
        !           499:             pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
        !           500:                             qdev_fw_name(qdev), nr);
        !           501:             break;
        !           502:         }
        !           503:     }
        !           504:     return fw_path;
        !           505: }
        !           506: 
        !           507: void usb_info(Monitor *mon)
        !           508: {
        !           509:     USBBus *bus;
        !           510:     USBDevice *dev;
        !           511:     USBPort *port;
        !           512: 
        !           513:     if (QTAILQ_EMPTY(&busses)) {
        !           514:         monitor_printf(mon, "USB support not enabled\n");
        !           515:         return;
        !           516:     }
        !           517: 
        !           518:     QTAILQ_FOREACH(bus, &busses, next) {
        !           519:         QTAILQ_FOREACH(port, &bus->used, next) {
        !           520:             dev = port->dev;
        !           521:             if (!dev)
        !           522:                 continue;
        !           523:             monitor_printf(mon, "  Device %d.%d, Port %s, Speed %s Mb/s, Product %s\n",
        !           524:                            bus->busnr, dev->addr, port->path, usb_speed(dev->speed),
        !           525:                            dev->product_desc);
        !           526:         }
        !           527:     }
        !           528: }
        !           529: 
        !           530: /* handle legacy -usbdevice cmd line option */
        !           531: USBDevice *usbdevice_create(const char *cmdline)
        !           532: {
        !           533:     USBBus *bus = usb_bus_find(-1 /* any */);
        !           534:     LegacyUSBFactory *f = NULL;
        !           535:     GSList *i;
        !           536:     char driver[32];
        !           537:     const char *params;
        !           538:     int len;
        !           539: 
        !           540:     params = strchr(cmdline,':');
        !           541:     if (params) {
        !           542:         params++;
        !           543:         len = params - cmdline;
        !           544:         if (len > sizeof(driver))
        !           545:             len = sizeof(driver);
        !           546:         pstrcpy(driver, len, cmdline);
        !           547:     } else {
        !           548:         params = "";
        !           549:         pstrcpy(driver, sizeof(driver), cmdline);
        !           550:     }
        !           551: 
        !           552:     for (i = legacy_usb_factory; i; i = i->next) {
        !           553:         f = i->data;
        !           554:         if (strcmp(f->usbdevice_name, driver) == 0) {
        !           555:             break;
        !           556:         }
        !           557:     }
        !           558:     if (i == NULL) {
        !           559: #if 0
        !           560:         /* no error because some drivers are not converted (yet) */
        !           561:         error_report("usbdevice %s not found", driver);
        !           562: #endif
        !           563:         return NULL;
        !           564:     }
        !           565: 
        !           566:     if (!f->usbdevice_init) {
        !           567:         if (*params) {
        !           568:             error_report("usbdevice %s accepts no params", driver);
        !           569:             return NULL;
        !           570:         }
        !           571:         return usb_create_simple(bus, f->name);
        !           572:     }
        !           573:     return f->usbdevice_init(bus, params);
        !           574: }
        !           575: 
        !           576: static void usb_device_class_init(ObjectClass *klass, void *data)
        !           577: {
        !           578:     DeviceClass *k = DEVICE_CLASS(klass);
        !           579:     k->bus_info = &usb_bus_info;
        !           580:     k->init     = usb_qdev_init;
        !           581:     k->unplug   = qdev_simple_unplug_cb;
        !           582:     k->exit     = usb_qdev_exit;
        !           583: }
        !           584: 
        !           585: static TypeInfo usb_device_type_info = {
        !           586:     .name = TYPE_USB_DEVICE,
        !           587:     .parent = TYPE_DEVICE,
        !           588:     .instance_size = sizeof(USBDevice),
        !           589:     .abstract = true,
        !           590:     .class_size = sizeof(USBDeviceClass),
        !           591:     .class_init = usb_device_class_init,
        !           592: };
        !           593: 
        !           594: static void usb_register_types(void)
        !           595: {
        !           596:     type_register_static(&usb_device_type_info);
        !           597: }
        !           598: 
        !           599: type_init(usb_register_types)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.