|
|
1.1 ! root 1: /* ! 2: * QEMU USB audio device ! 3: * ! 4: * written by: ! 5: * H. Peter Anvin <[email protected]> ! 6: * Gerd Hoffmann <[email protected]> ! 7: * ! 8: * lousely based on usb net device code which is: ! 9: * ! 10: * Copyright (c) 2006 Thomas Sailer ! 11: * Copyright (c) 2008 Andrzej Zaborowski ! 12: * ! 13: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 14: * of this software and associated documentation files (the "Software"), to deal ! 15: * in the Software without restriction, including without limitation the rights ! 16: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 17: * copies of the Software, and to permit persons to whom the Software is ! 18: * furnished to do so, subject to the following conditions: ! 19: * ! 20: * The above copyright notice and this permission notice shall be included in ! 21: * all copies or substantial portions of the Software. ! 22: * ! 23: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 24: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 25: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 26: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 27: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 28: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 29: * THE SOFTWARE. ! 30: */ ! 31: ! 32: #include "qemu-common.h" ! 33: #include "hw/usb.h" ! 34: #include "hw/usb/desc.h" ! 35: #include "hw/hw.h" ! 36: #include "hw/audiodev.h" ! 37: #include "audio/audio.h" ! 38: ! 39: #define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */ ! 40: #define USBAUDIO_PRODUCT_NUM 0x0002 ! 41: ! 42: #define DEV_CONFIG_VALUE 1 /* The one and only */ ! 43: ! 44: /* Descriptor subtypes for AC interfaces */ ! 45: #define DST_AC_HEADER 1 ! 46: #define DST_AC_INPUT_TERMINAL 2 ! 47: #define DST_AC_OUTPUT_TERMINAL 3 ! 48: #define DST_AC_FEATURE_UNIT 6 ! 49: /* Descriptor subtypes for AS interfaces */ ! 50: #define DST_AS_GENERAL 1 ! 51: #define DST_AS_FORMAT_TYPE 2 ! 52: /* Descriptor subtypes for endpoints */ ! 53: #define DST_EP_GENERAL 1 ! 54: ! 55: enum usb_audio_strings { ! 56: STRING_NULL, ! 57: STRING_MANUFACTURER, ! 58: STRING_PRODUCT, ! 59: STRING_SERIALNUMBER, ! 60: STRING_CONFIG, ! 61: STRING_USBAUDIO_CONTROL, ! 62: STRING_INPUT_TERMINAL, ! 63: STRING_FEATURE_UNIT, ! 64: STRING_OUTPUT_TERMINAL, ! 65: STRING_NULL_STREAM, ! 66: STRING_REAL_STREAM, ! 67: }; ! 68: ! 69: static const USBDescStrings usb_audio_stringtable = { ! 70: [STRING_MANUFACTURER] = "QEMU", ! 71: [STRING_PRODUCT] = "QEMU USB Audio", ! 72: [STRING_SERIALNUMBER] = "1", ! 73: [STRING_CONFIG] = "Audio Configuration", ! 74: [STRING_USBAUDIO_CONTROL] = "Audio Device", ! 75: [STRING_INPUT_TERMINAL] = "Audio Output Pipe", ! 76: [STRING_FEATURE_UNIT] = "Audio Output Volume Control", ! 77: [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal", ! 78: [STRING_NULL_STREAM] = "Audio Output - Disabled", ! 79: [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo", ! 80: }; ! 81: ! 82: #define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff) ! 83: #define U24(x) U16(x), (((x) >> 16) & 0xff) ! 84: #define U32(x) U24(x), (((x) >> 24) & 0xff) ! 85: ! 86: /* ! 87: * A Basic Audio Device uses these specific values ! 88: */ ! 89: #define USBAUDIO_PACKET_SIZE 192 ! 90: #define USBAUDIO_SAMPLE_RATE 48000 ! 91: #define USBAUDIO_PACKET_INTERVAL 1 ! 92: ! 93: static const USBDescIface desc_iface[] = { ! 94: { ! 95: .bInterfaceNumber = 0, ! 96: .bNumEndpoints = 0, ! 97: .bInterfaceClass = USB_CLASS_AUDIO, ! 98: .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, ! 99: .bInterfaceProtocol = 0x04, ! 100: .iInterface = STRING_USBAUDIO_CONTROL, ! 101: .ndesc = 4, ! 102: .descs = (USBDescOther[]) { ! 103: { ! 104: /* Headphone Class-Specific AC Interface Header Descriptor */ ! 105: .data = (uint8_t[]) { ! 106: 0x09, /* u8 bLength */ ! 107: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 108: DST_AC_HEADER, /* u8 bDescriptorSubtype */ ! 109: U16(0x0100), /* u16 bcdADC */ ! 110: U16(0x2b), /* u16 wTotalLength */ ! 111: 0x01, /* u8 bInCollection */ ! 112: 0x01, /* u8 baInterfaceNr */ ! 113: } ! 114: },{ ! 115: /* Generic Stereo Input Terminal ID1 Descriptor */ ! 116: .data = (uint8_t[]) { ! 117: 0x0c, /* u8 bLength */ ! 118: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 119: DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */ ! 120: 0x01, /* u8 bTerminalID */ ! 121: U16(0x0101), /* u16 wTerminalType */ ! 122: 0x00, /* u8 bAssocTerminal */ ! 123: 0x02, /* u16 bNrChannels */ ! 124: U16(0x0003), /* u16 wChannelConfig */ ! 125: 0x00, /* u8 iChannelNames */ ! 126: STRING_INPUT_TERMINAL, /* u8 iTerminal */ ! 127: } ! 128: },{ ! 129: /* Generic Stereo Feature Unit ID2 Descriptor */ ! 130: .data = (uint8_t[]) { ! 131: 0x0d, /* u8 bLength */ ! 132: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 133: DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */ ! 134: 0x02, /* u8 bUnitID */ ! 135: 0x01, /* u8 bSourceID */ ! 136: 0x02, /* u8 bControlSize */ ! 137: U16(0x0001), /* u16 bmaControls(0) */ ! 138: U16(0x0002), /* u16 bmaControls(1) */ ! 139: U16(0x0002), /* u16 bmaControls(2) */ ! 140: STRING_FEATURE_UNIT, /* u8 iFeature */ ! 141: } ! 142: },{ ! 143: /* Headphone Ouptut Terminal ID3 Descriptor */ ! 144: .data = (uint8_t[]) { ! 145: 0x09, /* u8 bLength */ ! 146: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 147: DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */ ! 148: 0x03, /* u8 bUnitID */ ! 149: U16(0x0301), /* u16 wTerminalType (SPK) */ ! 150: 0x00, /* u8 bAssocTerminal */ ! 151: 0x02, /* u8 bSourceID */ ! 152: STRING_OUTPUT_TERMINAL, /* u8 iTerminal */ ! 153: } ! 154: } ! 155: }, ! 156: },{ ! 157: .bInterfaceNumber = 1, ! 158: .bAlternateSetting = 0, ! 159: .bNumEndpoints = 0, ! 160: .bInterfaceClass = USB_CLASS_AUDIO, ! 161: .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, ! 162: .iInterface = STRING_NULL_STREAM, ! 163: },{ ! 164: .bInterfaceNumber = 1, ! 165: .bAlternateSetting = 1, ! 166: .bNumEndpoints = 1, ! 167: .bInterfaceClass = USB_CLASS_AUDIO, ! 168: .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, ! 169: .iInterface = STRING_REAL_STREAM, ! 170: .ndesc = 2, ! 171: .descs = (USBDescOther[]) { ! 172: { ! 173: /* Headphone Class-specific AS General Interface Descriptor */ ! 174: .data = (uint8_t[]) { ! 175: 0x07, /* u8 bLength */ ! 176: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 177: DST_AS_GENERAL, /* u8 bDescriptorSubtype */ ! 178: 0x01, /* u8 bTerminalLink */ ! 179: 0x00, /* u8 bDelay */ ! 180: 0x01, 0x00, /* u16 wFormatTag */ ! 181: } ! 182: },{ ! 183: /* Headphone Type I Format Type Descriptor */ ! 184: .data = (uint8_t[]) { ! 185: 0x0b, /* u8 bLength */ ! 186: USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ ! 187: DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */ ! 188: 0x01, /* u8 bFormatType */ ! 189: 0x02, /* u8 bNrChannels */ ! 190: 0x02, /* u8 bSubFrameSize */ ! 191: 0x10, /* u8 bBitResolution */ ! 192: 0x01, /* u8 bSamFreqType */ ! 193: U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */ ! 194: } ! 195: } ! 196: }, ! 197: .eps = (USBDescEndpoint[]) { ! 198: { ! 199: .bEndpointAddress = USB_DIR_OUT | 0x01, ! 200: .bmAttributes = 0x0d, ! 201: .wMaxPacketSize = USBAUDIO_PACKET_SIZE, ! 202: .bInterval = 1, ! 203: .is_audio = 1, ! 204: /* Stereo Headphone Class-specific ! 205: AS Audio Data Endpoint Descriptor */ ! 206: .extra = (uint8_t[]) { ! 207: 0x07, /* u8 bLength */ ! 208: USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */ ! 209: DST_EP_GENERAL, /* u8 bDescriptorSubtype */ ! 210: 0x00, /* u8 bmAttributes */ ! 211: 0x00, /* u8 bLockDelayUnits */ ! 212: U16(0x0000), /* u16 wLockDelay */ ! 213: }, ! 214: }, ! 215: } ! 216: } ! 217: }; ! 218: ! 219: static const USBDescDevice desc_device = { ! 220: .bcdUSB = 0x0200, ! 221: .bMaxPacketSize0 = 64, ! 222: .bNumConfigurations = 1, ! 223: .confs = (USBDescConfig[]) { ! 224: { ! 225: .bNumInterfaces = 2, ! 226: .bConfigurationValue = DEV_CONFIG_VALUE, ! 227: .iConfiguration = STRING_CONFIG, ! 228: .bmAttributes = 0xc0, ! 229: .bMaxPower = 0x32, ! 230: .nif = ARRAY_SIZE(desc_iface), ! 231: .ifs = desc_iface, ! 232: }, ! 233: }, ! 234: }; ! 235: ! 236: static const USBDesc desc_audio = { ! 237: .id = { ! 238: .idVendor = USBAUDIO_VENDOR_NUM, ! 239: .idProduct = USBAUDIO_PRODUCT_NUM, ! 240: .bcdDevice = 0, ! 241: .iManufacturer = STRING_MANUFACTURER, ! 242: .iProduct = STRING_PRODUCT, ! 243: .iSerialNumber = STRING_SERIALNUMBER, ! 244: }, ! 245: .full = &desc_device, ! 246: .str = usb_audio_stringtable, ! 247: }; ! 248: ! 249: /* ! 250: * A USB audio device supports an arbitrary number of alternate ! 251: * interface settings for each interface. Each corresponds to a block ! 252: * diagram of parameterized blocks. This can thus refer to things like ! 253: * number of channels, data rates, or in fact completely different ! 254: * block diagrams. Alternative setting 0 is always the null block diagram, ! 255: * which is used by a disabled device. ! 256: */ ! 257: enum usb_audio_altset { ! 258: ALTSET_OFF = 0x00, /* No endpoint */ ! 259: ALTSET_ON = 0x01, /* Single endpoint */ ! 260: }; ! 261: ! 262: /* ! 263: * Class-specific control requests ! 264: */ ! 265: #define CR_SET_CUR 0x01 ! 266: #define CR_GET_CUR 0x81 ! 267: #define CR_SET_MIN 0x02 ! 268: #define CR_GET_MIN 0x82 ! 269: #define CR_SET_MAX 0x03 ! 270: #define CR_GET_MAX 0x83 ! 271: #define CR_SET_RES 0x04 ! 272: #define CR_GET_RES 0x84 ! 273: #define CR_SET_MEM 0x05 ! 274: #define CR_GET_MEM 0x85 ! 275: #define CR_GET_STAT 0xff ! 276: ! 277: /* ! 278: * Feature Unit Control Selectors ! 279: */ ! 280: #define MUTE_CONTROL 0x01 ! 281: #define VOLUME_CONTROL 0x02 ! 282: #define BASS_CONTROL 0x03 ! 283: #define MID_CONTROL 0x04 ! 284: #define TREBLE_CONTROL 0x05 ! 285: #define GRAPHIC_EQUALIZER_CONTROL 0x06 ! 286: #define AUTOMATIC_GAIN_CONTROL 0x07 ! 287: #define DELAY_CONTROL 0x08 ! 288: #define BASS_BOOST_CONTROL 0x09 ! 289: #define LOUDNESS_CONTROL 0x0a ! 290: ! 291: /* ! 292: * buffering ! 293: */ ! 294: ! 295: struct streambuf { ! 296: uint8_t *data; ! 297: uint32_t size; ! 298: uint32_t prod; ! 299: uint32_t cons; ! 300: }; ! 301: ! 302: static void streambuf_init(struct streambuf *buf, uint32_t size) ! 303: { ! 304: g_free(buf->data); ! 305: buf->size = size - (size % USBAUDIO_PACKET_SIZE); ! 306: buf->data = g_malloc(buf->size); ! 307: buf->prod = 0; ! 308: buf->cons = 0; ! 309: } ! 310: ! 311: static void streambuf_fini(struct streambuf *buf) ! 312: { ! 313: g_free(buf->data); ! 314: buf->data = NULL; ! 315: } ! 316: ! 317: static int streambuf_put(struct streambuf *buf, USBPacket *p) ! 318: { ! 319: uint32_t free = buf->size - (buf->prod - buf->cons); ! 320: ! 321: if (!free) { ! 322: return 0; ! 323: } ! 324: assert(free >= USBAUDIO_PACKET_SIZE); ! 325: usb_packet_copy(p, buf->data + (buf->prod % buf->size), ! 326: USBAUDIO_PACKET_SIZE); ! 327: buf->prod += USBAUDIO_PACKET_SIZE; ! 328: return USBAUDIO_PACKET_SIZE; ! 329: } ! 330: ! 331: static uint8_t *streambuf_get(struct streambuf *buf) ! 332: { ! 333: uint32_t used = buf->prod - buf->cons; ! 334: uint8_t *data; ! 335: ! 336: if (!used) { ! 337: return NULL; ! 338: } ! 339: assert(used >= USBAUDIO_PACKET_SIZE); ! 340: data = buf->data + (buf->cons % buf->size); ! 341: buf->cons += USBAUDIO_PACKET_SIZE; ! 342: return data; ! 343: } ! 344: ! 345: typedef struct USBAudioState { ! 346: /* qemu interfaces */ ! 347: USBDevice dev; ! 348: QEMUSoundCard card; ! 349: ! 350: /* state */ ! 351: struct { ! 352: enum usb_audio_altset altset; ! 353: struct audsettings as; ! 354: SWVoiceOut *voice; ! 355: bool mute; ! 356: uint8_t vol[2]; ! 357: struct streambuf buf; ! 358: } out; ! 359: ! 360: /* properties */ ! 361: uint32_t debug; ! 362: uint32_t buffer; ! 363: } USBAudioState; ! 364: ! 365: static void output_callback(void *opaque, int avail) ! 366: { ! 367: USBAudioState *s = opaque; ! 368: uint8_t *data; ! 369: ! 370: for (;;) { ! 371: if (avail < USBAUDIO_PACKET_SIZE) { ! 372: return; ! 373: } ! 374: data = streambuf_get(&s->out.buf); ! 375: if (NULL == data) { ! 376: return; ! 377: } ! 378: AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE); ! 379: avail -= USBAUDIO_PACKET_SIZE; ! 380: } ! 381: } ! 382: ! 383: static int usb_audio_set_output_altset(USBAudioState *s, int altset) ! 384: { ! 385: switch (altset) { ! 386: case ALTSET_OFF: ! 387: streambuf_init(&s->out.buf, s->buffer); ! 388: AUD_set_active_out(s->out.voice, false); ! 389: break; ! 390: case ALTSET_ON: ! 391: AUD_set_active_out(s->out.voice, true); ! 392: break; ! 393: default: ! 394: return -1; ! 395: } ! 396: ! 397: if (s->debug) { ! 398: fprintf(stderr, "usb-audio: set interface %d\n", altset); ! 399: } ! 400: s->out.altset = altset; ! 401: return 0; ! 402: } ! 403: ! 404: /* ! 405: * Note: we arbitrarily map the volume control range onto -inf..+8 dB ! 406: */ ! 407: #define ATTRIB_ID(cs, attrib, idif) \ ! 408: (((cs) << 24) | ((attrib) << 16) | (idif)) ! 409: ! 410: static int usb_audio_get_control(USBAudioState *s, uint8_t attrib, ! 411: uint16_t cscn, uint16_t idif, ! 412: int length, uint8_t *data) ! 413: { ! 414: uint8_t cs = cscn >> 8; ! 415: uint8_t cn = cscn - 1; /* -1 for the non-present master control */ ! 416: uint32_t aid = ATTRIB_ID(cs, attrib, idif); ! 417: int ret = USB_RET_STALL; ! 418: ! 419: switch (aid) { ! 420: case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200): ! 421: data[0] = s->out.mute; ! 422: ret = 1; ! 423: break; ! 424: case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200): ! 425: if (cn < 2) { ! 426: uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000; ! 427: data[0] = vol; ! 428: data[1] = vol >> 8; ! 429: ret = 2; ! 430: } ! 431: break; ! 432: case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200): ! 433: if (cn < 2) { ! 434: data[0] = 0x01; ! 435: data[1] = 0x80; ! 436: ret = 2; ! 437: } ! 438: break; ! 439: case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200): ! 440: if (cn < 2) { ! 441: data[0] = 0x00; ! 442: data[1] = 0x08; ! 443: ret = 2; ! 444: } ! 445: break; ! 446: case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200): ! 447: if (cn < 2) { ! 448: data[0] = 0x88; ! 449: data[1] = 0x00; ! 450: ret = 2; ! 451: } ! 452: break; ! 453: } ! 454: ! 455: return ret; ! 456: } ! 457: static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, ! 458: uint16_t cscn, uint16_t idif, ! 459: int length, uint8_t *data) ! 460: { ! 461: uint8_t cs = cscn >> 8; ! 462: uint8_t cn = cscn - 1; /* -1 for the non-present master control */ ! 463: uint32_t aid = ATTRIB_ID(cs, attrib, idif); ! 464: int ret = USB_RET_STALL; ! 465: bool set_vol = false; ! 466: ! 467: switch (aid) { ! 468: case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200): ! 469: s->out.mute = data[0] & 1; ! 470: set_vol = true; ! 471: ret = 0; ! 472: break; ! 473: case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200): ! 474: if (cn < 2) { ! 475: uint16_t vol = data[0] + (data[1] << 8); ! 476: ! 477: if (s->debug) { ! 478: fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol); ! 479: } ! 480: ! 481: vol -= 0x8000; ! 482: vol = (vol * 255 + 0x4400) / 0x8800; ! 483: if (vol > 255) { ! 484: vol = 255; ! 485: } ! 486: ! 487: s->out.vol[cn] = vol; ! 488: set_vol = true; ! 489: ret = 0; ! 490: } ! 491: break; ! 492: } ! 493: ! 494: if (set_vol) { ! 495: if (s->debug) { ! 496: fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n", ! 497: s->out.mute, s->out.vol[0], s->out.vol[1]); ! 498: } ! 499: AUD_set_volume_out(s->out.voice, s->out.mute, ! 500: s->out.vol[0], s->out.vol[1]); ! 501: } ! 502: ! 503: return ret; ! 504: } ! 505: ! 506: static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, ! 507: int request, int value, int index, ! 508: int length, uint8_t *data) ! 509: { ! 510: USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); ! 511: int ret = 0; ! 512: ! 513: if (s->debug) { ! 514: fprintf(stderr, "usb-audio: control transaction: " ! 515: "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", ! 516: request, value, index, length); ! 517: } ! 518: ! 519: ret = usb_desc_handle_control(dev, p, request, value, index, length, data); ! 520: if (ret >= 0) { ! 521: return ret; ! 522: } ! 523: ! 524: switch (request) { ! 525: case ClassInterfaceRequest | CR_GET_CUR: ! 526: case ClassInterfaceRequest | CR_GET_MIN: ! 527: case ClassInterfaceRequest | CR_GET_MAX: ! 528: case ClassInterfaceRequest | CR_GET_RES: ! 529: ret = usb_audio_get_control(s, request & 0xff, value, index, ! 530: length, data); ! 531: if (ret < 0) { ! 532: if (s->debug) { ! 533: fprintf(stderr, "usb-audio: fail: get control\n"); ! 534: } ! 535: goto fail; ! 536: } ! 537: break; ! 538: ! 539: case ClassInterfaceOutRequest | CR_SET_CUR: ! 540: case ClassInterfaceOutRequest | CR_SET_MIN: ! 541: case ClassInterfaceOutRequest | CR_SET_MAX: ! 542: case ClassInterfaceOutRequest | CR_SET_RES: ! 543: ret = usb_audio_set_control(s, request & 0xff, value, index, ! 544: length, data); ! 545: if (ret < 0) { ! 546: if (s->debug) { ! 547: fprintf(stderr, "usb-audio: fail: set control\n"); ! 548: } ! 549: goto fail; ! 550: } ! 551: break; ! 552: ! 553: default: ! 554: fail: ! 555: if (s->debug) { ! 556: fprintf(stderr, "usb-audio: failed control transaction: " ! 557: "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", ! 558: request, value, index, length); ! 559: } ! 560: ret = USB_RET_STALL; ! 561: break; ! 562: } ! 563: return ret; ! 564: } ! 565: ! 566: static void usb_audio_set_interface(USBDevice *dev, int iface, ! 567: int old, int value) ! 568: { ! 569: USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); ! 570: ! 571: if (iface == 1) { ! 572: usb_audio_set_output_altset(s, value); ! 573: } ! 574: } ! 575: ! 576: static void usb_audio_handle_reset(USBDevice *dev) ! 577: { ! 578: USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); ! 579: ! 580: if (s->debug) { ! 581: fprintf(stderr, "usb-audio: reset\n"); ! 582: } ! 583: usb_audio_set_output_altset(s, ALTSET_OFF); ! 584: } ! 585: ! 586: static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) ! 587: { ! 588: int rc; ! 589: ! 590: if (s->out.altset == ALTSET_OFF) { ! 591: return USB_RET_STALL; ! 592: } ! 593: ! 594: rc = streambuf_put(&s->out.buf, p); ! 595: if (rc < p->iov.size && s->debug > 1) { ! 596: fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n", ! 597: p->iov.size - rc); ! 598: } ! 599: ! 600: return 0; ! 601: } ! 602: ! 603: static int usb_audio_handle_data(USBDevice *dev, USBPacket *p) ! 604: { ! 605: USBAudioState *s = (USBAudioState *) dev; ! 606: int ret = 0; ! 607: ! 608: switch (p->pid) { ! 609: case USB_TOKEN_OUT: ! 610: switch (p->ep->nr) { ! 611: case 1: ! 612: ret = usb_audio_handle_dataout(s, p); ! 613: break; ! 614: default: ! 615: goto fail; ! 616: } ! 617: break; ! 618: ! 619: default: ! 620: fail: ! 621: ret = USB_RET_STALL; ! 622: break; ! 623: } ! 624: if (ret == USB_RET_STALL && s->debug) { ! 625: fprintf(stderr, "usb-audio: failed data transaction: " ! 626: "pid 0x%x ep 0x%x len 0x%zx\n", ! 627: p->pid, p->ep->nr, p->iov.size); ! 628: } ! 629: return ret; ! 630: } ! 631: ! 632: static void usb_audio_handle_destroy(USBDevice *dev) ! 633: { ! 634: USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); ! 635: ! 636: if (s->debug) { ! 637: fprintf(stderr, "usb-audio: destroy\n"); ! 638: } ! 639: ! 640: usb_audio_set_output_altset(s, ALTSET_OFF); ! 641: AUD_close_out(&s->card, s->out.voice); ! 642: AUD_remove_card(&s->card); ! 643: ! 644: streambuf_fini(&s->out.buf); ! 645: } ! 646: ! 647: static int usb_audio_initfn(USBDevice *dev) ! 648: { ! 649: USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); ! 650: ! 651: usb_desc_create_serial(dev); ! 652: usb_desc_init(dev); ! 653: s->dev.opaque = s; ! 654: AUD_register_card("usb-audio", &s->card); ! 655: ! 656: s->out.altset = ALTSET_OFF; ! 657: s->out.mute = false; ! 658: s->out.vol[0] = 240; /* 0 dB */ ! 659: s->out.vol[1] = 240; /* 0 dB */ ! 660: s->out.as.freq = USBAUDIO_SAMPLE_RATE; ! 661: s->out.as.nchannels = 2; ! 662: s->out.as.fmt = AUD_FMT_S16; ! 663: s->out.as.endianness = 0; ! 664: streambuf_init(&s->out.buf, s->buffer); ! 665: ! 666: s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio", ! 667: s, output_callback, &s->out.as); ! 668: AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]); ! 669: AUD_set_active_out(s->out.voice, 0); ! 670: return 0; ! 671: } ! 672: ! 673: static const VMStateDescription vmstate_usb_audio = { ! 674: .name = "usb-audio", ! 675: .unmigratable = 1, ! 676: }; ! 677: ! 678: static Property usb_audio_properties[] = { ! 679: DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0), ! 680: DEFINE_PROP_UINT32("buffer", USBAudioState, buffer, ! 681: 8 * USBAUDIO_PACKET_SIZE), ! 682: DEFINE_PROP_END_OF_LIST(), ! 683: }; ! 684: ! 685: static void usb_audio_class_init(ObjectClass *klass, void *data) ! 686: { ! 687: DeviceClass *dc = DEVICE_CLASS(klass); ! 688: USBDeviceClass *k = USB_DEVICE_CLASS(klass); ! 689: ! 690: dc->vmsd = &vmstate_usb_audio; ! 691: dc->props = usb_audio_properties; ! 692: k->product_desc = "QEMU USB Audio Interface"; ! 693: k->usb_desc = &desc_audio; ! 694: k->init = usb_audio_initfn; ! 695: k->handle_reset = usb_audio_handle_reset; ! 696: k->handle_control = usb_audio_handle_control; ! 697: k->handle_data = usb_audio_handle_data; ! 698: k->handle_destroy = usb_audio_handle_destroy; ! 699: k->set_interface = usb_audio_set_interface; ! 700: } ! 701: ! 702: static TypeInfo usb_audio_info = { ! 703: .name = "usb-audio", ! 704: .parent = TYPE_USB_DEVICE, ! 705: .instance_size = sizeof(USBAudioState), ! 706: .class_init = usb_audio_class_init, ! 707: }; ! 708: ! 709: static void usb_audio_register_types(void) ! 710: { ! 711: type_register_static(&usb_audio_info); ! 712: usb_legacy_register("usb-audio", "audio", NULL); ! 713: } ! 714: ! 715: type_init(usb_audio_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.