|
|
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)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.