mirror of https://github.com/PCSX2/pcsx2.git
432 lines
16 KiB
C++
432 lines
16 KiB
C++
/*
|
|
* QEMU USB HID devices
|
|
*
|
|
* Copyright (c) 2005 Fabrice Bellard
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
#include "../qemu-usb/vl.h"
|
|
|
|
/* HID interface requests */
|
|
#define GET_REPORT 0xa101
|
|
#define GET_IDLE 0xa102
|
|
#define GET_PROTOCOL 0xa103
|
|
#define SET_IDLE 0x210a
|
|
#define SET_PROTOCOL 0x210b
|
|
|
|
#define USB_MOUSE 1
|
|
#define USB_TABLET 2
|
|
|
|
#include "type.h"
|
|
|
|
#include "usb.h"
|
|
#include "audio.h"
|
|
#include "usbcfg.h"
|
|
#include "usbdesc.h"
|
|
|
|
typedef struct SINGSTARMICState {
|
|
USBDevice dev;
|
|
//nothing yet
|
|
} SINGSTARMICState;
|
|
|
|
/* descriptor dumped from a real singstar MIC adapter */
|
|
static const uint8_t singstar_mic_dev_descriptor[] = {
|
|
/* bLength */ 0x12, //(18)
|
|
/* bDescriptorType */ 0x01, //(1)
|
|
/* bcdUSB */ WBVAL(0x0110), //(272)
|
|
/* bDeviceClass */ 0x00, //(0)
|
|
/* bDeviceSubClass */ 0x00, //(0)
|
|
/* bDeviceProtocol */ 0x00, //(0)
|
|
/* bMaxPacketSize0 */ 0x08, //(8)
|
|
/* idVendor */ WBVAL(0x1415), //(5141)
|
|
/* idProduct */ WBVAL(0x0000), //(0)
|
|
/* bcdDevice */ WBVAL(0x0001), //(1)
|
|
/* iManufacturer */ 0x01, //(1)
|
|
/* iProduct */ 0x02, //(2)
|
|
/* iSerialNumber */ 0x00, //(0)
|
|
/* bNumConfigurations */ 0x01, //(1)
|
|
|
|
};
|
|
|
|
static const uint8_t singstar_mic_config_descriptor[] = {
|
|
|
|
/* Configuration 1 */
|
|
0x09, /* bLength */
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
WBVAL(0x00b1), /* wTotalLength */
|
|
0x02, /* bNumInterfaces */
|
|
0x01, /* bConfigurationValue */
|
|
0x00, /* iConfiguration */
|
|
USB_CONFIG_BUS_POWERED, /* bmAttributes */
|
|
USB_CONFIG_POWER_MA(90), /* bMaxPower */
|
|
|
|
/* Interface 0, Alternate Setting 0, Audio Control */
|
|
USB_INTERFACE_DESC_SIZE, /* bLength */
|
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
0x00, /* bInterfaceNumber */
|
|
0x00, /* bAlternateSetting */
|
|
0x00, /* bNumEndpoints */
|
|
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
|
|
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
|
|
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
|
0x00, /* iInterface */
|
|
|
|
/* Audio Control Interface */
|
|
AUDIO_CONTROL_INTERFACE_DESC_SZ(1), /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
|
|
WBVAL(0x0100), /* 1.00 */ /* bcdADC */
|
|
WBVAL(0x0028), /* wTotalLength */
|
|
0x01, /* bInCollection */
|
|
0x01, /* baInterfaceNr */
|
|
|
|
/* Audio Input Terminal */
|
|
AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
|
|
0x01, /* bTerminalID */
|
|
WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */
|
|
0x02, /* bAssocTerminal */
|
|
0x02, /* bNrChannels */
|
|
WBVAL(AUDIO_CHANNEL_L
|
|
|AUDIO_CHANNEL_R), /* wChannelConfig */
|
|
0x00, /* iChannelNames */
|
|
0x00, /* iTerminal */
|
|
|
|
/* Audio Output Terminal */
|
|
AUDIO_OUTPUT_TERMINAL_DESC_SIZE, /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
|
|
0x02, /* bTerminalID */
|
|
WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */
|
|
0x01, /* bAssocTerminal */
|
|
0x03, /* bSourceID */
|
|
0x00, /* iTerminal */
|
|
|
|
/* Audio Feature Unit */
|
|
AUDIO_FEATURE_UNIT_DESC_SZ(2,1), /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
|
|
0x03, /* bUnitID */
|
|
0x01, /* bSourceID */
|
|
0x01, /* bControlSize */
|
|
0x01, /* bmaControls(0) */
|
|
0x02, /* bmaControls(1) */
|
|
0x02, /* bmaControls(2) */
|
|
0x00, /* iTerminal */
|
|
|
|
/* Interface 1, Alternate Setting 0, Audio Streaming - Zero Bandwith */
|
|
USB_INTERFACE_DESC_SIZE, /* bLength */
|
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
0x01, /* bInterfaceNumber */
|
|
0x00, /* bAlternateSetting */
|
|
0x00, /* bNumEndpoints */
|
|
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
|
|
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
|
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
|
0x00, /* iInterface */
|
|
|
|
/* Interface 1, Alternate Setting 1, Audio Streaming - Operational */
|
|
USB_INTERFACE_DESC_SIZE, /* bLength */
|
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
0x01, /* bInterfaceNumber */
|
|
0x01, /* bAlternateSetting */
|
|
0x01, /* bNumEndpoints */
|
|
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
|
|
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
|
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
|
0x00, /* iInterface */
|
|
|
|
/* Audio Streaming Interface */
|
|
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
|
0x02, /* bTerminalLink */
|
|
0x01, /* bDelay */
|
|
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
|
|
|
/* Audio Type I Format */
|
|
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
|
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
|
0x01, /* bNrChannels */
|
|
0x02, /* bSubFrameSize */
|
|
0x10, /* bBitResolution */
|
|
0x05, /* bSamFreqType */
|
|
B3VAL(8000), /* tSamFreq 1 */
|
|
B3VAL(11025), /* tSamFreq 2 */
|
|
B3VAL(22050), /* tSamFreq 3 */
|
|
B3VAL(44100), /* tSamFreq 4 */
|
|
B3VAL(48000), /* tSamFreq 5 */
|
|
|
|
/* Endpoint - Standard Descriptor */
|
|
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
USB_ENDPOINT_OUT(0x81), /* bEndpointAddress */
|
|
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
|
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
|
WBVAL(0x0064), /* wMaxPacketSize */
|
|
0x01, /* bInterval */
|
|
0x00, /* bRefresh */
|
|
0x00, /* bSynchAddress */
|
|
|
|
/* Endpoint - Audio Streaming */
|
|
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
|
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
|
0x01, /* bmAttributes */
|
|
0x00, /* bLockDelayUnits */
|
|
WBVAL(0x0000), /* wLockDelay */
|
|
|
|
/* Interface 1, Alternate Setting 2, Audio Streaming - ? */
|
|
USB_INTERFACE_DESC_SIZE, /* bLength */
|
|
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
0x01, /* bInterfaceNumber */
|
|
0x02, /* bAlternateSetting */
|
|
0x01, /* bNumEndpoints */
|
|
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
|
|
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
|
|
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
|
|
0x00, /* iInterface */
|
|
|
|
/* Audio Streaming Interface */
|
|
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
|
|
0x02, /* bTerminalLink */
|
|
0x01, /* bDelay */
|
|
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag */
|
|
|
|
/* Audio Type I Format */
|
|
AUDIO_FORMAT_TYPE_I_DESC_SZ(5), /* bLength */
|
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
|
|
AUDIO_FORMAT_TYPE_I, /* bFormatType */
|
|
0x02, /* bNrChannels */
|
|
0x02, /* bSubFrameSize */
|
|
0x10, /* bBitResolution */
|
|
0x05, /* bSamFreqType */
|
|
B3VAL(8000), /* tSamFreq 1 */
|
|
B3VAL(11025), /* tSamFreq 2 */
|
|
B3VAL(22050), /* tSamFreq 3 */
|
|
B3VAL(44100), /* tSamFreq 4 */
|
|
B3VAL(48000), /* tSamFreq 5 */
|
|
|
|
/* Endpoint - Standard Descriptor */
|
|
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
USB_ENDPOINT_OUT(0x81), /* bEndpointAddress */
|
|
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
|
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
|
WBVAL(0x00c8), /* wMaxPacketSize */
|
|
0x01, /* bInterval */
|
|
0x00, /* bRefresh */
|
|
0x00, /* bSynchAddress */
|
|
|
|
/* Endpoint - Audio Streaming */
|
|
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
|
|
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
|
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
|
|
0x01, /* bmAttributes */
|
|
0x00, /* bLockDelayUnits */
|
|
WBVAL(0x0000), /* wLockDelay */
|
|
|
|
/* Terminator */
|
|
0 /* bLength */
|
|
};
|
|
|
|
|
|
static void singstar_mic_handle_reset(USBDevice *dev)
|
|
{
|
|
/* XXX: do it */
|
|
return;
|
|
}
|
|
|
|
static int singstar_mic_handle_control(USBDevice *dev, int request, int value,
|
|
int index, int length, uint8_t *data)
|
|
{
|
|
SINGSTARMICState *s = (SINGSTARMICState *)dev;
|
|
int ret = 0;
|
|
|
|
switch(request) {
|
|
case DeviceRequest | USB_REQ_GET_STATUS:
|
|
data[0] = (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
|
|
data[1] = 0x00;
|
|
ret = 2;
|
|
break;
|
|
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
|
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
|
dev->remote_wakeup = 0;
|
|
} else {
|
|
goto fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
|
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
|
dev->remote_wakeup = 1;
|
|
} else {
|
|
goto fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
|
dev->addr = value;
|
|
ret = 0;
|
|
break;
|
|
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
|
switch(value >> 8) {
|
|
case USB_DT_DEVICE:
|
|
memcpy(data, singstar_mic_dev_descriptor,
|
|
sizeof(singstar_mic_dev_descriptor));
|
|
ret = sizeof(singstar_mic_dev_descriptor);
|
|
break;
|
|
case USB_DT_CONFIG:
|
|
memcpy(data, singstar_mic_config_descriptor,
|
|
sizeof(singstar_mic_config_descriptor));
|
|
ret = sizeof(singstar_mic_config_descriptor);
|
|
break;
|
|
case USB_DT_STRING:
|
|
switch(value & 0xff) {
|
|
case 0:
|
|
/* language ids */
|
|
data[0] = 4;
|
|
data[1] = 3;
|
|
data[2] = 0x09;
|
|
data[3] = 0x04;
|
|
ret = 4;
|
|
break;
|
|
case 1:
|
|
/* serial number */
|
|
ret = set_usb_string(data, "3X0420811");
|
|
break;
|
|
case 2:
|
|
/* product description */
|
|
ret = set_usb_string(data, "EyeToy USB camera Namtai");
|
|
break;
|
|
case 3:
|
|
/* vendor description */
|
|
ret = set_usb_string(data, "PCSX2/QEMU");
|
|
break;
|
|
default:
|
|
goto fail;
|
|
}
|
|
break;
|
|
default:
|
|
goto fail;
|
|
}
|
|
break;
|
|
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
|
data[0] = 1;
|
|
ret = 1;
|
|
break;
|
|
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
|
ret = 0;
|
|
break;
|
|
case DeviceRequest | USB_REQ_GET_INTERFACE:
|
|
data[0] = 0;
|
|
ret = 1;
|
|
break;
|
|
case DeviceOutRequest | USB_REQ_SET_INTERFACE:
|
|
ret = 0;
|
|
break;
|
|
/* hid specific requests */
|
|
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
|
//switch(value >> 8) {
|
|
//((case 0x22:
|
|
// memcpy(data, qemu_mouse_hid_report_descriptor,
|
|
// sizeof(qemu_mouse_hid_report_descriptor));
|
|
// ret = sizeof(qemu_mouse_hid_report_descriptor);
|
|
// break;
|
|
//default:
|
|
goto fail;
|
|
//}
|
|
break;
|
|
case GET_REPORT:
|
|
ret = 0;
|
|
break;
|
|
case SET_IDLE:
|
|
ret = 0;
|
|
break;
|
|
default:
|
|
fail:
|
|
ret = USB_RET_STALL;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int singstar_mic_handle_data(USBDevice *dev, int pid,
|
|
uint8_t devep, uint8_t *data, int len)
|
|
{
|
|
SINGSTARMICState *s = (SINGSTARMICState *)dev;
|
|
int ret = 0;
|
|
|
|
switch(pid) {
|
|
case USB_TOKEN_IN:
|
|
if (devep == 1) {
|
|
goto fail;
|
|
}
|
|
break;
|
|
case USB_TOKEN_OUT:
|
|
default:
|
|
fail:
|
|
ret = USB_RET_STALL;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void singstar_mic_handle_destroy(USBDevice *dev)
|
|
{
|
|
SINGSTARMICState *s = (SINGSTARMICState *)dev;
|
|
|
|
free(s);
|
|
}
|
|
|
|
int singstar_mic_handle_packet(USBDevice *s, int pid,
|
|
uint8_t devaddr, uint8_t devep,
|
|
uint8_t *data, int len)
|
|
{
|
|
fprintf(stderr,"usb-singstar_mic: packet received with pid=%x, devaddr=%x, devep=%x and len=%x\n",pid,devaddr,devep,len);
|
|
return usb_generic_handle_packet(s,pid,devaddr,devep,data,len);
|
|
}
|
|
|
|
USBDevice *singstar_mic_init()
|
|
{
|
|
SINGSTARMICState *s;
|
|
|
|
s = (SINGSTARMICState *)qemu_mallocz(sizeof(SINGSTARMICState));
|
|
if (!s)
|
|
return NULL;
|
|
s->dev.speed = USB_SPEED_FULL;
|
|
s->dev.handle_packet = singstar_mic_handle_packet;
|
|
s->dev.handle_reset = singstar_mic_handle_reset;
|
|
s->dev.handle_control = singstar_mic_handle_control;
|
|
s->dev.handle_data = singstar_mic_handle_data;
|
|
s->dev.handle_destroy = singstar_mic_handle_destroy;
|
|
|
|
strncpy(s->dev.devname, "EyeToy USB camera Namtai", sizeof(s->dev.devname));
|
|
|
|
return (USBDevice *)s;
|
|
|
|
}
|