|
|
1.1 ! root 1: /* ! 2: * QEMU Bluetooth HCI USB Transport Layer v1.0 ! 3: * ! 4: * Copyright (C) 2007 OpenMoko, Inc. ! 5: * Copyright (C) 2008 Andrzej Zaborowski <[email protected]> ! 6: * ! 7: * This program is free software; you can redistribute it and/or ! 8: * modify it under the terms of the GNU General Public License as ! 9: * published by the Free Software Foundation; either version 2 or ! 10: * (at your option) version 3 of the License. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: * GNU General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License along ! 18: * with this program; if not, see <http://www.gnu.org/licenses/>. ! 19: */ ! 20: ! 21: #include "qemu-common.h" ! 22: #include "hw/usb.h" ! 23: #include "hw/usb/desc.h" ! 24: #include "net.h" ! 25: #include "hw/bt.h" ! 26: ! 27: struct USBBtState { ! 28: USBDevice dev; ! 29: struct HCIInfo *hci; ! 30: ! 31: int config; ! 32: ! 33: #define CFIFO_LEN_MASK 255 ! 34: #define DFIFO_LEN_MASK 4095 ! 35: struct usb_hci_in_fifo_s { ! 36: uint8_t data[(DFIFO_LEN_MASK + 1) * 2]; ! 37: struct { ! 38: uint8_t *data; ! 39: int len; ! 40: } fifo[CFIFO_LEN_MASK + 1]; ! 41: int dstart, dlen, dsize, start, len; ! 42: } evt, acl, sco; ! 43: ! 44: struct usb_hci_out_fifo_s { ! 45: uint8_t data[4096]; ! 46: int len; ! 47: } outcmd, outacl, outsco; ! 48: }; ! 49: ! 50: #define USB_EVT_EP 1 ! 51: #define USB_ACL_EP 2 ! 52: #define USB_SCO_EP 3 ! 53: ! 54: enum { ! 55: STR_MANUFACTURER = 1, ! 56: STR_SERIALNUMBER, ! 57: }; ! 58: ! 59: static const USBDescStrings desc_strings = { ! 60: [STR_MANUFACTURER] = "QEMU " QEMU_VERSION, ! 61: [STR_SERIALNUMBER] = "1", ! 62: }; ! 63: ! 64: static const USBDescIface desc_iface_bluetooth[] = { ! 65: { ! 66: .bInterfaceNumber = 0, ! 67: .bNumEndpoints = 3, ! 68: .bInterfaceClass = 0xe0, /* Wireless */ ! 69: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 70: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 71: .eps = (USBDescEndpoint[]) { ! 72: { ! 73: .bEndpointAddress = USB_DIR_IN | USB_EVT_EP, ! 74: .bmAttributes = USB_ENDPOINT_XFER_INT, ! 75: .wMaxPacketSize = 0x10, ! 76: .bInterval = 0x02, ! 77: }, ! 78: { ! 79: .bEndpointAddress = USB_DIR_OUT | USB_ACL_EP, ! 80: .bmAttributes = USB_ENDPOINT_XFER_BULK, ! 81: .wMaxPacketSize = 0x40, ! 82: .bInterval = 0x0a, ! 83: }, ! 84: { ! 85: .bEndpointAddress = USB_DIR_IN | USB_ACL_EP, ! 86: .bmAttributes = USB_ENDPOINT_XFER_BULK, ! 87: .wMaxPacketSize = 0x40, ! 88: .bInterval = 0x0a, ! 89: }, ! 90: }, ! 91: },{ ! 92: .bInterfaceNumber = 1, ! 93: .bAlternateSetting = 0, ! 94: .bNumEndpoints = 2, ! 95: .bInterfaceClass = 0xe0, /* Wireless */ ! 96: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 97: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 98: .eps = (USBDescEndpoint[]) { ! 99: { ! 100: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 101: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 102: .wMaxPacketSize = 0, ! 103: .bInterval = 0x01, ! 104: }, ! 105: { ! 106: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 107: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 108: .wMaxPacketSize = 0, ! 109: .bInterval = 0x01, ! 110: }, ! 111: }, ! 112: },{ ! 113: .bInterfaceNumber = 1, ! 114: .bAlternateSetting = 1, ! 115: .bNumEndpoints = 2, ! 116: .bInterfaceClass = 0xe0, /* Wireless */ ! 117: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 118: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 119: .eps = (USBDescEndpoint[]) { ! 120: { ! 121: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 122: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 123: .wMaxPacketSize = 0x09, ! 124: .bInterval = 0x01, ! 125: }, ! 126: { ! 127: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 128: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 129: .wMaxPacketSize = 0x09, ! 130: .bInterval = 0x01, ! 131: }, ! 132: }, ! 133: },{ ! 134: .bInterfaceNumber = 1, ! 135: .bAlternateSetting = 2, ! 136: .bNumEndpoints = 2, ! 137: .bInterfaceClass = 0xe0, /* Wireless */ ! 138: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 139: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 140: .eps = (USBDescEndpoint[]) { ! 141: { ! 142: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 143: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 144: .wMaxPacketSize = 0x11, ! 145: .bInterval = 0x01, ! 146: }, ! 147: { ! 148: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 149: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 150: .wMaxPacketSize = 0x11, ! 151: .bInterval = 0x01, ! 152: }, ! 153: }, ! 154: },{ ! 155: .bInterfaceNumber = 1, ! 156: .bAlternateSetting = 3, ! 157: .bNumEndpoints = 2, ! 158: .bInterfaceClass = 0xe0, /* Wireless */ ! 159: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 160: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 161: .eps = (USBDescEndpoint[]) { ! 162: { ! 163: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 164: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 165: .wMaxPacketSize = 0x19, ! 166: .bInterval = 0x01, ! 167: }, ! 168: { ! 169: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 170: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 171: .wMaxPacketSize = 0x19, ! 172: .bInterval = 0x01, ! 173: }, ! 174: }, ! 175: },{ ! 176: .bInterfaceNumber = 1, ! 177: .bAlternateSetting = 4, ! 178: .bNumEndpoints = 2, ! 179: .bInterfaceClass = 0xe0, /* Wireless */ ! 180: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 181: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 182: .eps = (USBDescEndpoint[]) { ! 183: { ! 184: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 185: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 186: .wMaxPacketSize = 0x21, ! 187: .bInterval = 0x01, ! 188: }, ! 189: { ! 190: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 191: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 192: .wMaxPacketSize = 0x21, ! 193: .bInterval = 0x01, ! 194: }, ! 195: }, ! 196: },{ ! 197: .bInterfaceNumber = 1, ! 198: .bAlternateSetting = 5, ! 199: .bNumEndpoints = 2, ! 200: .bInterfaceClass = 0xe0, /* Wireless */ ! 201: .bInterfaceSubClass = 0x01, /* Radio Frequency */ ! 202: .bInterfaceProtocol = 0x01, /* Bluetooth */ ! 203: .eps = (USBDescEndpoint[]) { ! 204: { ! 205: .bEndpointAddress = USB_DIR_OUT | USB_SCO_EP, ! 206: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 207: .wMaxPacketSize = 0x31, ! 208: .bInterval = 0x01, ! 209: }, ! 210: { ! 211: .bEndpointAddress = USB_DIR_IN | USB_SCO_EP, ! 212: .bmAttributes = USB_ENDPOINT_XFER_ISOC, ! 213: .wMaxPacketSize = 0x31, ! 214: .bInterval = 0x01, ! 215: }, ! 216: }, ! 217: } ! 218: }; ! 219: ! 220: static const USBDescDevice desc_device_bluetooth = { ! 221: .bcdUSB = 0x0110, ! 222: .bDeviceClass = 0xe0, /* Wireless */ ! 223: .bDeviceSubClass = 0x01, /* Radio Frequency */ ! 224: .bDeviceProtocol = 0x01, /* Bluetooth */ ! 225: .bMaxPacketSize0 = 64, ! 226: .bNumConfigurations = 1, ! 227: .confs = (USBDescConfig[]) { ! 228: { ! 229: .bNumInterfaces = 2, ! 230: .bConfigurationValue = 1, ! 231: .bmAttributes = 0xc0, ! 232: .bMaxPower = 0, ! 233: .nif = ARRAY_SIZE(desc_iface_bluetooth), ! 234: .ifs = desc_iface_bluetooth, ! 235: }, ! 236: }, ! 237: }; ! 238: ! 239: static const USBDesc desc_bluetooth = { ! 240: .id = { ! 241: .idVendor = 0x0a12, ! 242: .idProduct = 0x0001, ! 243: .bcdDevice = 0x1958, ! 244: .iManufacturer = STR_MANUFACTURER, ! 245: .iProduct = 0, ! 246: .iSerialNumber = STR_SERIALNUMBER, ! 247: }, ! 248: .full = &desc_device_bluetooth, ! 249: .str = desc_strings, ! 250: }; ! 251: ! 252: static void usb_bt_fifo_reset(struct usb_hci_in_fifo_s *fifo) ! 253: { ! 254: fifo->dstart = 0; ! 255: fifo->dlen = 0; ! 256: fifo->dsize = DFIFO_LEN_MASK + 1; ! 257: fifo->start = 0; ! 258: fifo->len = 0; ! 259: } ! 260: ! 261: static void usb_bt_fifo_enqueue(struct usb_hci_in_fifo_s *fifo, ! 262: const uint8_t *data, int len) ! 263: { ! 264: int off = fifo->dstart + fifo->dlen; ! 265: uint8_t *buf; ! 266: ! 267: fifo->dlen += len; ! 268: if (off <= DFIFO_LEN_MASK) { ! 269: if (off + len > DFIFO_LEN_MASK + 1 && ! 270: (fifo->dsize = off + len) > (DFIFO_LEN_MASK + 1) * 2) { ! 271: fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); ! 272: exit(-1); ! 273: } ! 274: buf = fifo->data + off; ! 275: } else { ! 276: if (fifo->dlen > fifo->dsize) { ! 277: fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len); ! 278: exit(-1); ! 279: } ! 280: buf = fifo->data + off - fifo->dsize; ! 281: } ! 282: ! 283: off = (fifo->start + fifo->len ++) & CFIFO_LEN_MASK; ! 284: fifo->fifo[off].data = memcpy(buf, data, len); ! 285: fifo->fifo[off].len = len; ! 286: } ! 287: ! 288: static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo, ! 289: USBPacket *p) ! 290: { ! 291: int len; ! 292: ! 293: if (likely(!fifo->len)) ! 294: return USB_RET_STALL; ! 295: ! 296: len = MIN(p->iov.size, fifo->fifo[fifo->start].len); ! 297: usb_packet_copy(p, fifo->fifo[fifo->start].data, len); ! 298: if (len == p->iov.size) { ! 299: fifo->fifo[fifo->start].len -= len; ! 300: fifo->fifo[fifo->start].data += len; ! 301: } else { ! 302: fifo->start ++; ! 303: fifo->start &= CFIFO_LEN_MASK; ! 304: fifo->len --; ! 305: } ! 306: ! 307: fifo->dstart += len; ! 308: fifo->dlen -= len; ! 309: if (fifo->dstart >= fifo->dsize) { ! 310: fifo->dstart = 0; ! 311: fifo->dsize = DFIFO_LEN_MASK + 1; ! 312: } ! 313: ! 314: return len; ! 315: } ! 316: ! 317: static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s, ! 318: struct usb_hci_out_fifo_s *fifo, ! 319: void (*send)(struct HCIInfo *, const uint8_t *, int), ! 320: int (*complete)(const uint8_t *, int), ! 321: USBPacket *p) ! 322: { ! 323: usb_packet_copy(p, fifo->data + fifo->len, p->iov.size); ! 324: fifo->len += p->iov.size; ! 325: if (complete(fifo->data, fifo->len)) { ! 326: send(s->hci, fifo->data, fifo->len); ! 327: fifo->len = 0; ! 328: } ! 329: ! 330: /* TODO: do we need to loop? */ ! 331: } ! 332: ! 333: static int usb_bt_hci_cmd_complete(const uint8_t *data, int len) ! 334: { ! 335: len -= HCI_COMMAND_HDR_SIZE; ! 336: return len >= 0 && ! 337: len >= ((struct hci_command_hdr *) data)->plen; ! 338: } ! 339: ! 340: static int usb_bt_hci_acl_complete(const uint8_t *data, int len) ! 341: { ! 342: len -= HCI_ACL_HDR_SIZE; ! 343: return len >= 0 && ! 344: len >= le16_to_cpu(((struct hci_acl_hdr *) data)->dlen); ! 345: } ! 346: ! 347: static int usb_bt_hci_sco_complete(const uint8_t *data, int len) ! 348: { ! 349: len -= HCI_SCO_HDR_SIZE; ! 350: return len >= 0 && ! 351: len >= ((struct hci_sco_hdr *) data)->dlen; ! 352: } ! 353: ! 354: static void usb_bt_handle_reset(USBDevice *dev) ! 355: { ! 356: struct USBBtState *s = (struct USBBtState *) dev->opaque; ! 357: ! 358: usb_bt_fifo_reset(&s->evt); ! 359: usb_bt_fifo_reset(&s->acl); ! 360: usb_bt_fifo_reset(&s->sco); ! 361: s->outcmd.len = 0; ! 362: s->outacl.len = 0; ! 363: s->outsco.len = 0; ! 364: } ! 365: ! 366: static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, ! 367: int request, int value, int index, int length, uint8_t *data) ! 368: { ! 369: struct USBBtState *s = (struct USBBtState *) dev->opaque; ! 370: int ret; ! 371: ! 372: ret = usb_desc_handle_control(dev, p, request, value, index, length, data); ! 373: if (ret >= 0) { ! 374: switch (request) { ! 375: case DeviceRequest | USB_REQ_GET_CONFIGURATION: ! 376: s->config = 0; ! 377: break; ! 378: case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: ! 379: s->config = 1; ! 380: usb_bt_fifo_reset(&s->evt); ! 381: usb_bt_fifo_reset(&s->acl); ! 382: usb_bt_fifo_reset(&s->sco); ! 383: break; ! 384: } ! 385: return ret; ! 386: } ! 387: ! 388: ret = 0; ! 389: switch (request) { ! 390: case InterfaceRequest | USB_REQ_GET_STATUS: ! 391: case EndpointRequest | USB_REQ_GET_STATUS: ! 392: data[0] = 0x00; ! 393: data[1] = 0x00; ! 394: ret = 2; ! 395: break; ! 396: case InterfaceOutRequest | USB_REQ_CLEAR_FEATURE: ! 397: case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ! 398: goto fail; ! 399: case InterfaceOutRequest | USB_REQ_SET_FEATURE: ! 400: case EndpointOutRequest | USB_REQ_SET_FEATURE: ! 401: goto fail; ! 402: break; ! 403: case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8): ! 404: if (s->config) ! 405: usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send, ! 406: usb_bt_hci_cmd_complete, p); ! 407: break; ! 408: default: ! 409: fail: ! 410: ret = USB_RET_STALL; ! 411: break; ! 412: } ! 413: return ret; ! 414: } ! 415: ! 416: static int usb_bt_handle_data(USBDevice *dev, USBPacket *p) ! 417: { ! 418: struct USBBtState *s = (struct USBBtState *) dev->opaque; ! 419: int ret = 0; ! 420: ! 421: if (!s->config) ! 422: goto fail; ! 423: ! 424: switch (p->pid) { ! 425: case USB_TOKEN_IN: ! 426: switch (p->ep->nr) { ! 427: case USB_EVT_EP: ! 428: ret = usb_bt_fifo_dequeue(&s->evt, p); ! 429: break; ! 430: ! 431: case USB_ACL_EP: ! 432: ret = usb_bt_fifo_dequeue(&s->acl, p); ! 433: break; ! 434: ! 435: case USB_SCO_EP: ! 436: ret = usb_bt_fifo_dequeue(&s->sco, p); ! 437: break; ! 438: ! 439: default: ! 440: goto fail; ! 441: } ! 442: break; ! 443: ! 444: case USB_TOKEN_OUT: ! 445: switch (p->ep->nr) { ! 446: case USB_ACL_EP: ! 447: usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send, ! 448: usb_bt_hci_acl_complete, p); ! 449: break; ! 450: ! 451: case USB_SCO_EP: ! 452: usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send, ! 453: usb_bt_hci_sco_complete, p); ! 454: break; ! 455: ! 456: default: ! 457: goto fail; ! 458: } ! 459: break; ! 460: ! 461: default: ! 462: fail: ! 463: ret = USB_RET_STALL; ! 464: break; ! 465: } ! 466: ! 467: return ret; ! 468: } ! 469: ! 470: static void usb_bt_out_hci_packet_event(void *opaque, ! 471: const uint8_t *data, int len) ! 472: { ! 473: struct USBBtState *s = (struct USBBtState *) opaque; ! 474: ! 475: usb_bt_fifo_enqueue(&s->evt, data, len); ! 476: } ! 477: ! 478: static void usb_bt_out_hci_packet_acl(void *opaque, ! 479: const uint8_t *data, int len) ! 480: { ! 481: struct USBBtState *s = (struct USBBtState *) opaque; ! 482: ! 483: usb_bt_fifo_enqueue(&s->acl, data, len); ! 484: } ! 485: ! 486: static void usb_bt_handle_destroy(USBDevice *dev) ! 487: { ! 488: struct USBBtState *s = (struct USBBtState *) dev->opaque; ! 489: ! 490: s->hci->opaque = NULL; ! 491: s->hci->evt_recv = NULL; ! 492: s->hci->acl_recv = NULL; ! 493: } ! 494: ! 495: static int usb_bt_initfn(USBDevice *dev) ! 496: { ! 497: usb_desc_create_serial(dev); ! 498: usb_desc_init(dev); ! 499: return 0; ! 500: } ! 501: ! 502: USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci) ! 503: { ! 504: USBDevice *dev; ! 505: struct USBBtState *s; ! 506: ! 507: if (!hci) ! 508: return NULL; ! 509: dev = usb_create_simple(bus, "usb-bt-dongle"); ! 510: if (!dev) { ! 511: return NULL; ! 512: } ! 513: s = DO_UPCAST(struct USBBtState, dev, dev); ! 514: s->dev.opaque = s; ! 515: ! 516: s->hci = hci; ! 517: s->hci->opaque = s; ! 518: s->hci->evt_recv = usb_bt_out_hci_packet_event; ! 519: s->hci->acl_recv = usb_bt_out_hci_packet_acl; ! 520: ! 521: usb_bt_handle_reset(&s->dev); ! 522: ! 523: return dev; ! 524: } ! 525: ! 526: static const VMStateDescription vmstate_usb_bt = { ! 527: .name = "usb-bt", ! 528: .unmigratable = 1, ! 529: }; ! 530: ! 531: static void usb_bt_class_initfn(ObjectClass *klass, void *data) ! 532: { ! 533: DeviceClass *dc = DEVICE_CLASS(klass); ! 534: USBDeviceClass *uc = USB_DEVICE_CLASS(klass); ! 535: ! 536: uc->init = usb_bt_initfn; ! 537: uc->product_desc = "QEMU BT dongle"; ! 538: uc->usb_desc = &desc_bluetooth; ! 539: uc->handle_reset = usb_bt_handle_reset; ! 540: uc->handle_control = usb_bt_handle_control; ! 541: uc->handle_data = usb_bt_handle_data; ! 542: uc->handle_destroy = usb_bt_handle_destroy; ! 543: dc->vmsd = &vmstate_usb_bt; ! 544: } ! 545: ! 546: static TypeInfo bt_info = { ! 547: .name = "usb-bt-dongle", ! 548: .parent = TYPE_USB_DEVICE, ! 549: .instance_size = sizeof(struct USBBtState), ! 550: .class_init = usb_bt_class_initfn, ! 551: }; ! 552: ! 553: static void usb_bt_register_types(void) ! 554: { ! 555: type_register_static(&bt_info); ! 556: } ! 557: ! 558: type_init(usb_bt_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.