mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-01-18 14:40:22 +01:00
USB: Usbd support for microphones
This commit is contained in:
parent
cf6aaaa74f
commit
d9edf98d55
|
|
@ -423,6 +423,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||
Io/TopShotFearmaster.cpp
|
||||
Io/Turntable.cpp
|
||||
Io/usb_device.cpp
|
||||
Io/usb_microphone.cpp
|
||||
Io/usb_vfs.cpp
|
||||
Io/usio.cpp
|
||||
Io/LogitechG27.cpp
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "Emu/Cell/timers.hpp"
|
||||
|
||||
#include "Emu/Io/usb_device.h"
|
||||
#include "Emu/Io/usb_microphone.h"
|
||||
#include "Emu/Io/usb_vfs.h"
|
||||
#include "Emu/Io/Skylander.h"
|
||||
#include "Emu/Io/Infinity.h"
|
||||
|
|
@ -185,6 +186,9 @@ private:
|
|||
// Music devices
|
||||
{0x1415, 0x0000, 0x0000, "Singstar Microphone", nullptr, nullptr},
|
||||
// {0x1415, 0x0020, 0x0020, "SingStar Microphone Wireless", nullptr, nullptr}, // TODO: verifiy
|
||||
// {0x12ba, 0x00f0, 0x00f0, "Bandfuse USB Guitar Adapter", nullptr, nullptr},
|
||||
// {0x28aa, 0x0001, 0x0001, "Bandfuse USB Microphone", nullptr, nullptr},
|
||||
// {0x046d, 0x0a03, 0x0a03, "Logitech Microphone", nullptr, nullptr},
|
||||
|
||||
{0x12BA, 0x00FF, 0x00FF, "Rocksmith Guitar Adapter", nullptr, nullptr},
|
||||
{0x12BA, 0x0100, 0x0100, "Guitar Hero Guitar", nullptr, nullptr},
|
||||
|
|
@ -549,6 +553,20 @@ usb_handler_thread::usb_handler_thread()
|
|||
}
|
||||
}
|
||||
|
||||
switch (g_cfg.audio.microphone_type)
|
||||
{
|
||||
case microphone_handler::standard:
|
||||
usb_devices.push_back(std::make_shared<usb_device_mic>(0, get_new_location(), MicType::Logitech));
|
||||
break;
|
||||
case microphone_handler::real_singstar:
|
||||
case microphone_handler::singstar:
|
||||
usb_devices.push_back(std::make_shared<usb_device_mic>(0, get_new_location(), MicType::SingStar));
|
||||
break;
|
||||
case microphone_handler::rocksmith:
|
||||
usb_devices.push_back(std::make_shared<usb_device_mic>(0, get_new_location(), MicType::Rocksmith));
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) // Add VFS USB mass storage devices (/dev_usbXXX) to the USB device list
|
||||
{
|
||||
const auto usb_info = g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/dev_usb%03d", i));
|
||||
|
|
@ -1128,7 +1146,7 @@ error_code sys_usbd_finalize(ppu_thread& ppu, u32 handle)
|
|||
// Forcefully awake all waiters
|
||||
while (auto cpu = lv2_obj::schedule<ppu_thread>(usbh.sq, SYS_SYNC_FIFO))
|
||||
{
|
||||
// Special ternimation signal value
|
||||
// Special termination signal value
|
||||
cpu->gpr[4] = 4;
|
||||
cpu->gpr[5] = 0;
|
||||
cpu->gpr[6] = 0;
|
||||
|
|
@ -1480,7 +1498,7 @@ error_code sys_usbd_transfer_data(ppu_thread& ppu, u32 handle, u32 id_pipe, vm::
|
|||
case LIBUSB_REQUEST_SET_CONFIGURATION:
|
||||
{
|
||||
pipe.device->set_configuration(static_cast<u8>(+request->wValue));
|
||||
pipe.device->set_interface(0);
|
||||
pipe.device->set_interface(0, 0);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
|
@ -1523,7 +1541,7 @@ error_code sys_usbd_isochronous_transfer_data(ppu_thread& ppu, u32 handle, u32 i
|
|||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_usbd.todo("sys_usbd_isochronous_transfer_data(handle=0x%x, id_pipe=0x%x, iso_request=*0x%x)", handle, id_pipe, iso_request);
|
||||
sys_usbd.trace("sys_usbd_isochronous_transfer_data(handle=0x%x, id_pipe=0x%x, iso_request=*0x%x)", handle, id_pipe, iso_request);
|
||||
|
||||
auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
||||
|
||||
|
|
@ -1537,8 +1555,21 @@ error_code sys_usbd_isochronous_transfer_data(ppu_thread& ppu, u32 handle, u32 i
|
|||
const auto& pipe = usbh.get_pipe(id_pipe);
|
||||
auto&& [transfer_id, transfer] = usbh.get_free_transfer();
|
||||
|
||||
transfer.iso_request.buf = iso_request->buf;
|
||||
transfer.iso_request.start_frame = iso_request->start_frame;
|
||||
transfer.iso_request.num_packets = iso_request->num_packets;
|
||||
for (u32 index = 0; index < iso_request->num_packets; index++)
|
||||
{
|
||||
transfer.iso_request.packets[index] = iso_request->packets[index];
|
||||
}
|
||||
|
||||
pipe.device->isochronous_transfer(&transfer);
|
||||
|
||||
if (transfer.fake)
|
||||
{
|
||||
usbh.push_fake_transfer(&transfer);
|
||||
}
|
||||
|
||||
// returns an identifier specific to the transfer
|
||||
return not_an_error(transfer_id);
|
||||
}
|
||||
|
|
@ -1567,7 +1598,7 @@ error_code sys_usbd_get_isochronous_transfer_status(ppu_thread& ppu, u32 handle,
|
|||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_usbd.todo("sys_usbd_get_isochronous_transfer_status(handle=0x%x, id_transfer=0x%x, unk1=0x%x, request=*0x%x, result=*0x%x)", handle, id_transfer, unk1, request, result);
|
||||
sys_usbd.trace("sys_usbd_get_isochronous_transfer_status(handle=0x%x, id_transfer=0x%x, unk1=0x%x, request=*0x%x, result=*0x%x)", handle, id_transfer, unk1, request, result);
|
||||
|
||||
auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ struct UsbDeviceRequest
|
|||
|
||||
struct UsbDeviceIsoRequest
|
||||
{
|
||||
vm::ptr<void> buf;
|
||||
vm::bptr<void> buf;
|
||||
be_t<u32> start_frame;
|
||||
be_t<u32> num_packets;
|
||||
be_t<u16> packets[8];
|
||||
|
|
|
|||
|
|
@ -40,9 +40,10 @@ bool usb_device::set_configuration(u8 cfg_num)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool usb_device::set_interface(u8 int_num)
|
||||
bool usb_device::set_interface(u8 int_num, u8 alt_num)
|
||||
{
|
||||
current_interface = int_num;
|
||||
current_altsetting = alt_num;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -141,9 +142,9 @@ bool usb_device_passthrough::set_configuration(u8 cfg_num)
|
|||
return (libusb_set_configuration(lusb_handle, cfg_num) == LIBUSB_SUCCESS);
|
||||
};
|
||||
|
||||
bool usb_device_passthrough::set_interface(u8 int_num)
|
||||
bool usb_device_passthrough::set_interface(u8 int_num, u8 alt_num)
|
||||
{
|
||||
usb_device::set_interface(int_num);
|
||||
usb_device::set_interface(int_num, alt_num);
|
||||
return (libusb_claim_interface(lusb_handle, int_num) == LIBUSB_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +291,7 @@ void usb_device_emulated::control_transfer(u8 bmRequestType, u8 bRequest, u16 wV
|
|||
case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_INTERFACE: // 0x01
|
||||
switch (bRequest)
|
||||
{
|
||||
case LIBUSB_REQUEST_SET_INTERFACE: usb_device::set_interface(::narrow<u8>(wIndex)); break;
|
||||
case LIBUSB_REQUEST_SET_INTERFACE: usb_device::set_interface(::narrow<u8>(wIndex), ::narrow<u8>(wValue)); break;
|
||||
default: sys_usbd.error("Unhandled control transfer(0x%02x): 0x%02x", bmRequestType, bRequest); break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,54 @@ struct UsbDeviceHID
|
|||
le_t<u16, 1> wDescriptorLength;
|
||||
};
|
||||
|
||||
struct UsbAudioInputTerminal
|
||||
{
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bTerminalID;
|
||||
le_t<u16, 1> wTerminalType;
|
||||
u8 bAssocTerminal;
|
||||
u8 bNrChannels;
|
||||
le_t<u16, 1> wChannelConfig;
|
||||
u8 iChannelNames;
|
||||
u8 iTerminal;
|
||||
};
|
||||
|
||||
struct UsbAudioOutputTerminal
|
||||
{
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bTerminalID;
|
||||
le_t<u16, 1> wTerminalType;
|
||||
u8 bAssocTerminal;
|
||||
u8 bSourceID;
|
||||
u8 iTerminal;
|
||||
};
|
||||
|
||||
struct UsbAudioInterface
|
||||
{
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bTerminalLink;
|
||||
u8 bDelay;
|
||||
le_t<u16, 1> wFormatTag;
|
||||
};
|
||||
|
||||
struct UsbAudioEndpoint
|
||||
{
|
||||
u8 bEndpointAddress;
|
||||
u8 bmAttributes;
|
||||
le_t<u16, 1> wMaxPacketSize;
|
||||
u8 bInterval;
|
||||
u8 bRefresh;
|
||||
u8 bSynchAddress;
|
||||
};
|
||||
|
||||
struct UsbAudioStreamingEndpoint
|
||||
{
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bmAttributes;
|
||||
u8 bLockDelayUnits;
|
||||
le_t<u16, 1> wLockDelay;
|
||||
};
|
||||
|
||||
struct UsbTransfer
|
||||
{
|
||||
u32 assigned_number = 0;
|
||||
|
|
@ -183,7 +231,7 @@ public:
|
|||
|
||||
virtual u32 get_configuration(u8* buf);
|
||||
virtual bool set_configuration(u8 cfg_num);
|
||||
virtual bool set_interface(u8 int_num);
|
||||
virtual bool set_interface(u8 int_num, u8 alt_num);
|
||||
|
||||
virtual void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) = 0;
|
||||
virtual void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) = 0;
|
||||
|
|
@ -198,6 +246,7 @@ public:
|
|||
protected:
|
||||
u8 current_config = 1;
|
||||
u8 current_interface = 0;
|
||||
u8 current_altsetting = 0;
|
||||
std::array<u8, 7> location{};
|
||||
|
||||
protected:
|
||||
|
|
@ -214,7 +263,7 @@ public:
|
|||
void read_descriptors() override;
|
||||
u32 get_configuration(u8* buf) override;
|
||||
bool set_configuration(u8 cfg_num) override;
|
||||
bool set_interface(u8 int_num) override;
|
||||
bool set_interface(u8 int_num, u8 alt_num) override;
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
|
||||
void isochronous_transfer(UsbTransfer* transfer) override;
|
||||
|
|
|
|||
690
rpcs3/Emu/Io/usb_microphone.cpp
Normal file
690
rpcs3/Emu/Io/usb_microphone.cpp
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Io/usb_microphone.h"
|
||||
#include "Emu/Cell/lv2/sys_usbd.h"
|
||||
#include "Emu/Cell/Modules/cellMic.h"
|
||||
#include "Input/pad_thread.h"
|
||||
|
||||
LOG_CHANNEL(usb_mic_log);
|
||||
|
||||
usb_device_mic::usb_device_mic(u32 controller_index, const std::array<u8, 7>& location, MicType mic_type)
|
||||
: usb_device_emulated(location)
|
||||
, m_controller_index(controller_index)
|
||||
, m_mic_type(mic_type)
|
||||
, m_sample_rate(8000)
|
||||
, m_volume(0, 0)
|
||||
{
|
||||
switch (mic_type)
|
||||
{
|
||||
case MicType::SingStar:
|
||||
{
|
||||
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE,
|
||||
UsbDeviceDescriptor {
|
||||
.bcdUSB = 0x0110,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 0x08,
|
||||
.idVendor = 0x1415,
|
||||
.idProduct = 0x0000,
|
||||
.bcdDevice = 0x0001,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x00,
|
||||
.bNumConfigurations = 0x01});
|
||||
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG,
|
||||
UsbDeviceConfiguration {
|
||||
.wTotalLength = 0x00b1,
|
||||
.bNumInterfaces = 0x02,
|
||||
.bConfigurationValue = 0x01,
|
||||
.iConfiguration = 0x00,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 0x2d}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x00,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
|
||||
static constexpr u8 audio_if0_header[] = {
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
|
||||
0x00, 0x01, // bcdADC 1.00
|
||||
0x28, 0x00, // wTotalLength 36
|
||||
0x01, // binCollection 0x01
|
||||
0x01, // baInterfaceNr 1
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_header[0], audio_if0_header[1], &audio_if0_header[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInputTerminal {
|
||||
.bDescriptorSubtype = 0x02, // INPUT_TERMINAL
|
||||
.bTerminalID = 0x01,
|
||||
.wTerminalType = 0x0201, // Microphone
|
||||
.bAssocTerminal = 0x02,
|
||||
.bNrChannels = 0x02,
|
||||
.wChannelConfig = 0x0003,
|
||||
.iChannelNames = 0x00,
|
||||
.iTerminal = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioOutputTerminal {
|
||||
.bDescriptorSubtype = 0x03, // OUTPUT_TERMINAL
|
||||
.bTerminalID = 0x02,
|
||||
.wTerminalType = 0x0101, // USB Streaming
|
||||
.bAssocTerminal = 0x01,
|
||||
.bSourceID = 0x03,
|
||||
.iTerminal = 0x00}));
|
||||
|
||||
static constexpr u8 audio_if0_feature[] = {
|
||||
0x0A, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
|
||||
0x03, // bUnitID
|
||||
0x01, // bSourceID
|
||||
0x01, // bControlSize 1
|
||||
0x01, 0x02, // bmaControls[0] (Mute,Volume)
|
||||
0x02, 0x00, // bmaControls[1] (Volume,None)
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_feature[0], audio_if0_feature[1], &audio_if0_feature[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x01,
|
||||
.bNumEndpoints = 0x01,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInterface {
|
||||
.bDescriptorSubtype = 0x01, // AS_GENERAL
|
||||
.bTerminalLink = 0x02,
|
||||
.bDelay = 0x01,
|
||||
.wFormatTag = 0x0001}));
|
||||
|
||||
static constexpr u8 audio_if1_alt1_type[] = {
|
||||
0x17, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
|
||||
0x01, // bFormatType 1
|
||||
0x01, // bNrChannels (Mono)
|
||||
0x02, // bSubFrameSize 2
|
||||
0x10, // bBitResolution 16
|
||||
0x05, // bSamFreqType 5
|
||||
0x40, 0x1F, 0x00, // tSamFreq[1] 8000 Hz
|
||||
0x11, 0x2B, 0x00, // tSamFreq[2] 11025 Hz
|
||||
0x22, 0x56, 0x00, // tSamFreq[3] 22050 Hz
|
||||
0x44, 0xAC, 0x00, // tSamFreq[4] 44100 Hz
|
||||
0x80, 0xBB, 0x00, // tSamFreq[5] 48000 Hz
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if1_alt1_type[0], audio_if1_alt1_type[1], &audio_if1_alt1_type[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
|
||||
UsbAudioEndpoint {
|
||||
.bEndpointAddress = 0x81,
|
||||
.bmAttributes = 0x05,
|
||||
.wMaxPacketSize = 0x0064,
|
||||
.bInterval = 0x01,
|
||||
.bRefresh = 0x00,
|
||||
.bSynchAddress = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT_ASI,
|
||||
UsbAudioStreamingEndpoint {
|
||||
.bDescriptorSubtype = 0x01, // EP_GENERAL
|
||||
.bmAttributes = 0x01, // Sampling Freq Control
|
||||
.bLockDelayUnits = 0x00,
|
||||
.wLockDelay = 0x0000}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x02,
|
||||
.bNumEndpoints = 0x01,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInterface {
|
||||
.bDescriptorSubtype = 0x01, // AS_GENERAL
|
||||
.bTerminalLink = 0x02,
|
||||
.bDelay = 0x01,
|
||||
.wFormatTag = 0x0001}));
|
||||
|
||||
static constexpr u8 audio_if1_alt2_type[] = {
|
||||
0x17, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
|
||||
0x01, // bFormatType 1
|
||||
0x02, // bNrChannels (Stereo)
|
||||
0x02, // bSubFrameSize 2
|
||||
0x10, // bBitResolution 16
|
||||
0x05, // bSamFreqType 5
|
||||
0x40, 0x1F, 0x00, // tSamFreq[1] 8000 Hz
|
||||
0x11, 0x2B, 0x00, // tSamFreq[2] 11025 Hz
|
||||
0x22, 0x56, 0x00, // tSamFreq[3] 22050 Hz
|
||||
0x44, 0xAC, 0x00, // tSamFreq[4] 44100 Hz
|
||||
0x80, 0xBB, 0x00, // tSamFreq[5] 48000 Hz
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if1_alt2_type[0], audio_if1_alt2_type[1], &audio_if1_alt2_type[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
|
||||
UsbAudioEndpoint {
|
||||
.bEndpointAddress = 0x81,
|
||||
.bmAttributes = 0x05,
|
||||
.wMaxPacketSize = 0x00c8,
|
||||
.bInterval = 0x01,
|
||||
.bRefresh = 0x00,
|
||||
.bSynchAddress = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT_ASI,
|
||||
UsbAudioStreamingEndpoint {
|
||||
.bDescriptorSubtype = 0x01, // EP_GENERAL
|
||||
.bmAttributes = 0x01, // Sampling Freq Control
|
||||
.bLockDelayUnits = 0x00,
|
||||
.wLockDelay = 0x0000}));
|
||||
|
||||
add_string("Nam Tai E&E Products Ltd.");
|
||||
add_string("USBMIC Serial# 012345678");
|
||||
break;
|
||||
}
|
||||
case MicType::Logitech:
|
||||
{
|
||||
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE,
|
||||
UsbDeviceDescriptor {
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 0x08,
|
||||
.idVendor = 0x046d,
|
||||
.idProduct = 0x0a03,
|
||||
.bcdDevice = 0x0102,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x00,
|
||||
.bNumConfigurations = 0x01});
|
||||
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG,
|
||||
UsbDeviceConfiguration {
|
||||
.wTotalLength = 0x0079,
|
||||
.bNumInterfaces = 0x02,
|
||||
.bConfigurationValue = 0x01,
|
||||
.iConfiguration = 0x03,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 0x1e}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x00,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
|
||||
static constexpr u8 audio_if0_header[] = {
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
|
||||
0x00, 0x01, // bcdADC 1.00
|
||||
0x27, 0x00, // wTotalLength 39
|
||||
0x01, // binCollection 0x01
|
||||
0x01, // baInterfaceNr 1
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_header[0], audio_if0_header[1], &audio_if0_header[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInputTerminal {
|
||||
.bDescriptorSubtype = 0x02, // INPUT_TERMINAL
|
||||
.bTerminalID = 0x0d,
|
||||
.wTerminalType = 0x0201, // Microphone
|
||||
.bAssocTerminal = 0x00,
|
||||
.bNrChannels = 0x01,
|
||||
.wChannelConfig = 0x0000,
|
||||
.iChannelNames = 0x00,
|
||||
.iTerminal = 0x00}));
|
||||
static constexpr u8 audio_if0_feature[] = {
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
|
||||
0x02, // bUnitID
|
||||
0x0d, // bSourceID
|
||||
0x01, // bControlSize 1
|
||||
0x03, // bmaControls[0] (Mute,Volume)
|
||||
0x00, // bmaControls[1] (None)
|
||||
0x00, // iFeature
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_feature[0], audio_if0_feature[1], &audio_if0_feature[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioOutputTerminal {
|
||||
.bDescriptorSubtype = 0x03, // OUTPUT_TERMINAL
|
||||
.bTerminalID = 0x0a,
|
||||
.wTerminalType = 0x0101, // USB Streaming
|
||||
.bAssocTerminal = 0x00,
|
||||
.bSourceID = 0x02,
|
||||
.iTerminal = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x01,
|
||||
.bNumEndpoints = 0x01,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInterface {
|
||||
.bDescriptorSubtype = 0x01, // AS_GENERAL
|
||||
.bTerminalLink = 0x0a,
|
||||
.bDelay = 0x00,
|
||||
.wFormatTag = 0x0001}));
|
||||
|
||||
static constexpr u8 audio_if1_alt1_type[] = {
|
||||
0x17, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
|
||||
0x01, // bFormatType 1
|
||||
0x01, // bNrChannels (Mono)
|
||||
0x02, // bSubFrameSize 2
|
||||
0x10, // bBitResolution 16
|
||||
0x05, // bSamFreqType 5
|
||||
0x40, 0x1F, 0x00, // tSamFreq[1] 8000 Hz
|
||||
0x11, 0x2B, 0x00, // tSamFreq[2] 11025 Hz
|
||||
0x22, 0x56, 0x00, // tSamFreq[4] 22050 Hz
|
||||
0x44, 0xAC, 0x00, // tSamFreq[6] 44100 Hz
|
||||
0x80, 0xBB, 0x00, // tSamFreq[7] 48000 Hz
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if1_alt1_type[0], audio_if1_alt1_type[1], &audio_if1_alt1_type[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
|
||||
UsbAudioEndpoint {
|
||||
.bEndpointAddress = 0x84,
|
||||
.bmAttributes = 0x0d,
|
||||
.wMaxPacketSize = 0x0060,
|
||||
.bInterval = 0x01,
|
||||
.bRefresh = 0x00,
|
||||
.bSynchAddress = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT_ASI,
|
||||
UsbAudioStreamingEndpoint {
|
||||
.bDescriptorSubtype = 0x01, // EP_GENERAL
|
||||
.bmAttributes = 0x01, // Sampling Freq Control
|
||||
.bLockDelayUnits = 0x02,
|
||||
.wLockDelay = 0x0001}));
|
||||
|
||||
add_string("Logitech");
|
||||
add_string("Logitech USB Microphone");
|
||||
break;
|
||||
}
|
||||
case MicType::Rocksmith:
|
||||
{
|
||||
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE,
|
||||
UsbDeviceDescriptor {
|
||||
.bcdUSB = 0x0110,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 0x10,
|
||||
.idVendor = 0x12ba,
|
||||
.idProduct = 0x00ff,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x00,
|
||||
.bNumConfigurations = 0x01});
|
||||
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG,
|
||||
UsbDeviceConfiguration {
|
||||
.wTotalLength = 0x0098,
|
||||
.bNumInterfaces = 0x03,
|
||||
.bConfigurationValue = 0x01,
|
||||
.iConfiguration = 0x00,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 0x32}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x00,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
|
||||
static constexpr u8 audio_if0_header[] = {
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
|
||||
0x00, 0x01, // bcdADC 1.00
|
||||
0x27, 0x00, // wTotalLength 39
|
||||
0x01, // binCollection 0x01
|
||||
0x01, // baInterfaceNr 1
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_header[0], audio_if0_header[1], &audio_if0_header[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInputTerminal {
|
||||
.bDescriptorSubtype = 0x02, // INPUT_TERMINAL
|
||||
.bTerminalID = 0x02,
|
||||
.wTerminalType = 0x0201, // Microphone
|
||||
.bAssocTerminal = 0x00,
|
||||
.bNrChannels = 0x01,
|
||||
.wChannelConfig = 0x0001,
|
||||
.iChannelNames = 0x00,
|
||||
.iTerminal = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioOutputTerminal {
|
||||
.bDescriptorSubtype = 0x03, // OUTPUT_TERMINAL
|
||||
.bTerminalID = 0x07,
|
||||
.wTerminalType = 0x0101, // USB Streaming
|
||||
.bAssocTerminal = 0x00,
|
||||
.bSourceID = 0x0a,
|
||||
.iTerminal = 0x00}));
|
||||
|
||||
static constexpr u8 audio_if0_feature[] = {
|
||||
0x09, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
|
||||
0x0a, // bUnitID
|
||||
0x02, // bSourceID
|
||||
0x01, // bControlSize 1
|
||||
0x03, // bmaControls[0] (Mute,Volume)
|
||||
0x00, // bmaControls[1] (None)
|
||||
0x00, // iFeature
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if0_feature[0], audio_if0_feature[1], &audio_if0_feature[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x00,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x01,
|
||||
.bAlternateSetting = 0x01,
|
||||
.bNumEndpoints = 0x01,
|
||||
.bInterfaceClass = 0x01,
|
||||
.bInterfaceSubClass = 0x02,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ACI,
|
||||
UsbAudioInterface {
|
||||
.bDescriptorSubtype = 0x01, // AS_GENERAL
|
||||
.bTerminalLink = 0x07,
|
||||
.bDelay = 0x01,
|
||||
.wFormatTag = 0x0001}));
|
||||
|
||||
static constexpr u8 audio_if1_alt1_type[] = {
|
||||
0x1d, // bLength
|
||||
0x24, // bDescriptorType (See Next Line)
|
||||
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
|
||||
0x01, // bFormatType 1
|
||||
0x01, // bNrChannels (Mono)
|
||||
0x02, // bSubFrameSize 2
|
||||
0x10, // bBitResolution 16
|
||||
0x07, // bSamFreqType 5
|
||||
0x40, 0x1F, 0x00, // tSamFreq[1] 8000 Hz
|
||||
0x11, 0x2B, 0x00, // tSamFreq[2] 11025 Hz
|
||||
0x80, 0x3e, 0x00, // tSamFreq[3] 16000 Hz
|
||||
0x22, 0x56, 0x00, // tSamFreq[4] 22050 Hz
|
||||
0x00, 0x7d, 0x00, // tSamFreq[5] 32000 Hz
|
||||
0x44, 0xAC, 0x00, // tSamFreq[6] 44100 Hz
|
||||
0x80, 0xBB, 0x00, // tSamFreq[7] 48000 Hz
|
||||
};
|
||||
config0.add_node(UsbDescriptorNode(audio_if1_alt1_type[0], audio_if1_alt1_type[1], &audio_if1_alt1_type[2]));
|
||||
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
|
||||
UsbAudioEndpoint {
|
||||
.bEndpointAddress = 0x82,
|
||||
.bmAttributes = 0x0d,
|
||||
.wMaxPacketSize = 0x0064,
|
||||
.bInterval = 0x01,
|
||||
.bRefresh = 0x00,
|
||||
.bSynchAddress = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT_ASI,
|
||||
UsbAudioStreamingEndpoint {
|
||||
.bDescriptorSubtype = 0x01, // EP_GENERAL
|
||||
.bmAttributes = 0x01, // Sampling Freq Control
|
||||
.bLockDelayUnits = 0x00,
|
||||
.wLockDelay = 0x0000}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE,
|
||||
UsbDeviceInterface {
|
||||
.bInterfaceNumber = 0x02,
|
||||
.bAlternateSetting = 0x00,
|
||||
.bNumEndpoints = 0x01,
|
||||
.bInterfaceClass = 0x03,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0x00}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID,
|
||||
UsbDeviceHID {
|
||||
.bcdHID = 0x0111,
|
||||
.bCountryCode = 0x00,
|
||||
.bNumDescriptors = 0x01,
|
||||
.bDescriptorType = 0x22,
|
||||
.wDescriptorLength = 0x001a}));
|
||||
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT,
|
||||
UsbDeviceEndpoint {
|
||||
.bEndpointAddress = 0x87,
|
||||
.bmAttributes = 0x03,
|
||||
.wMaxPacketSize = 0x0010,
|
||||
.bInterval = 0x01}));
|
||||
|
||||
add_string("Hercules.");
|
||||
add_string("Rocksmith USB Guitar Adapter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<usb_device> usb_device_mic::make_singstar(u32 controller_index, const std::array<u8, 7>& location)
|
||||
{
|
||||
return std::make_shared<usb_device_mic>(controller_index, location, MicType::SingStar);
|
||||
}
|
||||
|
||||
std::shared_ptr<usb_device> usb_device_mic::make_logitech(u32 controller_index, const std::array<u8, 7>& location)
|
||||
{
|
||||
return std::make_shared<usb_device_mic>(controller_index, location, MicType::Logitech);
|
||||
}
|
||||
|
||||
std::shared_ptr<usb_device> usb_device_mic::make_rocksmith(u32 controller_index, const std::array<u8, 7>& location)
|
||||
{
|
||||
return std::make_shared<usb_device_mic>(controller_index, location, MicType::Rocksmith);
|
||||
}
|
||||
|
||||
u16 usb_device_mic::get_num_emu_devices()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void usb_device_mic::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer)
|
||||
{
|
||||
transfer->fake = true;
|
||||
transfer->expected_count = buf_size;
|
||||
transfer->expected_result = HC_CC_NOERR;
|
||||
transfer->expected_time = get_timestamp() + 1000;
|
||||
|
||||
switch (bmRequestType)
|
||||
{
|
||||
case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0x21
|
||||
switch (bRequest)
|
||||
{
|
||||
case SET_CUR:
|
||||
{
|
||||
ensure(buf_size >= 2);
|
||||
const u8 ch = wValue & 0xff;
|
||||
if (ch == 0)
|
||||
{
|
||||
m_volume[0] = (buf[1] << 8) | buf[0];
|
||||
m_volume[1] = (buf[1] << 8) | buf[0];
|
||||
usb_mic_log.notice("Set Cur Volume[%d]: 0x%04x (%d dB)", ch, m_volume[0], m_volume[0] / 256);
|
||||
}
|
||||
else if (ch == 1)
|
||||
{
|
||||
m_volume[0] = (buf[1] << 8) | buf[0];
|
||||
usb_mic_log.notice("Set Cur Volume[%d]: 0x%04x (%d dB)", ch, m_volume[0], m_volume[0] / 256);
|
||||
}
|
||||
else if (ch == 2)
|
||||
{
|
||||
m_volume[1] = (buf[1] << 8) | buf[0];
|
||||
usb_mic_log.notice("Set Cur Volume[%d]: 0x%04x (%d dB)", ch, m_volume[1], m_volume[1] / 256);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
usb_mic_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0U /*silences warning*/ | LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_ENDPOINT: // 0x22
|
||||
switch (bRequest)
|
||||
{
|
||||
case SET_CUR:
|
||||
ensure(buf_size >= 3);
|
||||
m_sample_rate = (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
usb_mic_log.notice("Set Sample Rate: %d", m_sample_rate);
|
||||
break;
|
||||
default:
|
||||
usb_mic_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0U /*silences warning*/ | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE: // 0xa1
|
||||
switch (bRequest)
|
||||
{
|
||||
case GET_CUR:
|
||||
{
|
||||
ensure(buf_size >= 2);
|
||||
const u8 ch = wValue & 0xff;
|
||||
if (ch == 2)
|
||||
{
|
||||
buf[0] = (m_volume[1] ) & 0xff;
|
||||
buf[1] = (m_volume[1] >> 8) & 0xff;
|
||||
usb_mic_log.notice("Get Cur Volume[%d]: 0x%04x (%d dB)", ch, m_volume[1], m_volume[1] / 256);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = (m_volume[0] ) & 0xff;
|
||||
buf[1] = (m_volume[0] >> 8) & 0xff;
|
||||
usb_mic_log.notice("Get Cur Volume[%d]: 0x%04x (%d dB)", ch, m_volume[0], m_volume[0] / 256);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GET_MIN:
|
||||
{
|
||||
ensure(buf_size >= 2);
|
||||
constexpr s16 minVol = 0xff00;
|
||||
buf[0] = (minVol ) & 0xff;
|
||||
buf[1] = (minVol >> 8) & 0xff;
|
||||
usb_mic_log.notice("Get Min Volume: 0x%04x (%d dB)", minVol, minVol / 256);
|
||||
break;
|
||||
}
|
||||
case GET_MAX:
|
||||
{
|
||||
ensure(buf_size >= 2);
|
||||
constexpr s16 maxVol = 0x0100;
|
||||
buf[0] = (maxVol ) & 0xff;
|
||||
buf[1] = (maxVol >> 8) & 0xff;
|
||||
usb_mic_log.notice("Get Max Volume: 0x%04x (%d dB)", maxVol, maxVol / 256);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
usb_mic_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0U /*silences warning*/ | LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_ENDPOINT: // 0xa2
|
||||
switch (bRequest)
|
||||
{
|
||||
case GET_CUR:
|
||||
ensure(buf_size >= 3);
|
||||
buf[0] = (m_sample_rate ) & 0xff;
|
||||
buf[1] = (m_sample_rate >> 8) & 0xff;
|
||||
buf[2] = (m_sample_rate >> 16) & 0xff;
|
||||
usb_mic_log.notice("Get Sample Rate: %d", m_sample_rate);
|
||||
break;
|
||||
default:
|
||||
usb_mic_log.error("Unhandled Request: 0x%02X/0x%02X", bmRequestType, bRequest);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
|
||||
break;
|
||||
}
|
||||
|
||||
usb_mic_log.trace("control_transfer: req=0x%02X/0x%02X, val=0x%02x, idx=0x%02x, len=0x%02x, [%s]",
|
||||
bmRequestType, bRequest, wValue, wIndex, wLength, fmt::buf_to_hexstring(buf, buf_size));
|
||||
}
|
||||
|
||||
void usb_device_mic::isochronous_transfer(UsbTransfer* transfer)
|
||||
{
|
||||
transfer->fake = true;
|
||||
transfer->expected_count = 0;
|
||||
transfer->expected_result = HC_CC_NOERR;
|
||||
transfer->expected_time = get_timestamp() + 1000;
|
||||
|
||||
const bool stereo = (m_mic_type == MicType::SingStar && current_altsetting == 2);
|
||||
|
||||
auto& mic_thr = g_fxo->get<mic_thread>();
|
||||
const std::lock_guard lock(mic_thr.mutex);
|
||||
if (!mic_thr.init)
|
||||
{
|
||||
usb_mic_log.notice("mic init");
|
||||
mic_thr.load_config_and_init();
|
||||
mic_thr.init = 1;
|
||||
}
|
||||
if (!mic_thr.check_device(0))
|
||||
{
|
||||
usb_mic_log.notice("mic check");
|
||||
}
|
||||
microphone_device& device = ::at32(mic_thr.mic_list, 0);
|
||||
if (!device.is_opened())
|
||||
{
|
||||
usb_mic_log.notice("mic open");
|
||||
device.open_microphone(CELLMIC_SIGTYPE_RAW, m_sample_rate, m_sample_rate, stereo ? 2 : 1);
|
||||
}
|
||||
if (!device.is_started())
|
||||
{
|
||||
usb_mic_log.notice("mic start");
|
||||
device.start_microphone();
|
||||
}
|
||||
|
||||
u8* buf = static_cast<u8*>(transfer->iso_request.buf.get_ptr());
|
||||
for (u32 index = 0; index < transfer->iso_request.num_packets; index++)
|
||||
{
|
||||
const u16 inlen = transfer->iso_request.packets[index] >> 4;
|
||||
ensure(inlen >= (stereo ? 192 : 96));
|
||||
const u32 outlen = device.read_raw(buf, stereo ? 192 : 96);
|
||||
buf += outlen;
|
||||
transfer->iso_request.packets[index] = (outlen & 0xFFF) << 4;
|
||||
usb_mic_log.trace(" isochronous_transfer: dev=%d, buf=0x%x, start=0x%x, pks=0x%x idx=0x%x, inlen=0x%x, outlen=0x%x",
|
||||
static_cast<u8>(m_mic_type), transfer->iso_request.buf, transfer->iso_request.start_frame, transfer->iso_request.num_packets, index, inlen, outlen);
|
||||
}
|
||||
}
|
||||
40
rpcs3/Emu/Io/usb_microphone.h
Normal file
40
rpcs3/Emu/Io/usb_microphone.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Io/usb_device.h"
|
||||
|
||||
enum class MicType
|
||||
{
|
||||
SingStar,
|
||||
Logitech,
|
||||
Rocksmith,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SET_CUR = 0x01,
|
||||
GET_CUR = 0x81,
|
||||
SET_MIN = 0x02,
|
||||
GET_MIN = 0x82,
|
||||
SET_MAX = 0x03,
|
||||
GET_MAX = 0x83,
|
||||
};
|
||||
|
||||
class usb_device_mic : public usb_device_emulated
|
||||
{
|
||||
public:
|
||||
usb_device_mic(u32 controller_index, const std::array<u8, 7>& location, MicType mic_type);
|
||||
|
||||
static std::shared_ptr<usb_device> make_singstar(u32 controller_index, const std::array<u8, 7>& location);
|
||||
static std::shared_ptr<usb_device> make_logitech(u32 controller_index, const std::array<u8, 7>& location);
|
||||
static std::shared_ptr<usb_device> make_rocksmith(u32 controller_index, const std::array<u8, 7>& location);
|
||||
static u16 get_num_emu_devices();
|
||||
|
||||
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
|
||||
void isochronous_transfer(UsbTransfer* transfer) override;
|
||||
|
||||
private:
|
||||
u32 m_controller_index;
|
||||
MicType m_mic_type;
|
||||
u32 m_sample_rate;
|
||||
s16 m_volume[2];
|
||||
};
|
||||
|
|
@ -459,6 +459,7 @@
|
|||
<ClCompile Include="Emu\Io\Skylander.cpp" />
|
||||
<ClCompile Include="Emu\Io\KamenRider.cpp" />
|
||||
<ClCompile Include="Emu\Io\usb_device.cpp" />
|
||||
<ClCompile Include="Emu\Io\usb_microphone.cpp" />
|
||||
<ClCompile Include="Emu\Io\usb_vfs.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Capture\rsx_capture.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Capture\rsx_replay.cpp" />
|
||||
|
|
@ -831,6 +832,7 @@
|
|||
<ClInclude Include="Emu\Io\Skylander.h" />
|
||||
<ClInclude Include="Emu\Io\KamenRider.h" />
|
||||
<ClInclude Include="Emu\Io\usb_device.h" />
|
||||
<ClInclude Include="Emu\Io\usb_microphone.h" />
|
||||
<ClInclude Include="Emu\Io\usb_vfs.h" />
|
||||
<ClInclude Include="Emu\IPC.h" />
|
||||
<ClInclude Include="Emu\Audio\AudioDumper.h" />
|
||||
|
|
|
|||
|
|
@ -924,6 +924,9 @@
|
|||
<ClCompile Include="Emu\Io\usb_device.cpp">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Io\usb_microphone.cpp">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Io\usb_vfs.cpp">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -2121,6 +2124,9 @@
|
|||
<ClInclude Include="Emu\Io\usb_device.h">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Io\usb_microphone.h">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Io\usb_vfs.h">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
|||
Loading…
Reference in a new issue