USB: backport fixes from develop branch

This commit is contained in:
Gauvain 'GovanifY' Roussel-Tarbouriech 2020-11-03 16:45:39 +01:00 committed by refractionpcsx2
parent 53b818ac3b
commit f1d1acd487
43 changed files with 1799 additions and 788 deletions

View File

@ -346,6 +346,7 @@ set(pcsx2USBSources
USB/usb-pad/usb-pad.cpp
USB/usb-pad/usb-pad-ff.cpp
USB/usb-pad/lg/lg_ff.cpp
USB/usb-pad/usb-seamic.cpp
USB/usb-mic/usb-mic-singstar.cpp
USB/usb-mic/usb-mic-logitech.cpp
USB/usb-mic/usb-headset.cpp

View File

@ -300,13 +300,13 @@ void USBclose()
u8 USBread8(u32 addr)
{
USB_LOG("* Invalid 8bit read at address %lx\n", addr);
USB_LOG("* Invalid 8bit read at address %08x\n", addr);
return 0;
}
u16 USBread16(u32 addr)
{
USB_LOG("* Invalid 16bit read at address %lx\n", addr);
USB_LOG("* Invalid 16bit read at address %08x\n", addr);
return 0;
}
@ -316,24 +316,24 @@ u32 USBread32(u32 addr)
hard = ohci_mem_read(qemu_ohci, addr);
USB_LOG("* Known 32bit read at address %lx: %lx\n", addr, hard);
USB_LOG("* Known 32bit read at address %08x: %08x\n", addr, hard);
return hard;
}
void USBwrite8(u32 addr, u8 value)
{
USB_LOG("* Invalid 8bit write at address %lx value %x\n", addr, value);
USB_LOG("* Invalid 8bit write at address %08x value %x\n", addr, value);
}
void USBwrite16(u32 addr, u16 value)
{
USB_LOG("* Invalid 16bit write at address %lx value %x\n", addr, value);
USB_LOG("* Invalid 16bit write at address %08x value %x\n", addr, value);
}
void USBwrite32(u32 addr, u32 value)
{
USB_LOG("* Known 32bit write at address %lx value %lx\n", addr, value);
USB_LOG("* Known 32bit write at address %08x value %08x\n", addr, value);
ohci_mem_write(qemu_ohci, addr, value);
}
@ -354,7 +354,7 @@ s32 USBfreeze(int mode, freezeData* data)
{
if ((long unsigned int)data->size < sizeof(USBfreezeData))
{
Console.WriteLn(Color_Red, "USB: Unable to load freeze data! Got %d bytes, expected >= %d.\n", data->size, sizeof(USBfreezeData));
Console.WriteLn(Color_Red, "USB: Unable to load freeze data! Got %d bytes, expected >= %zu.\n", data->size, sizeof(USBfreezeData));
return -1;
}
@ -367,6 +367,11 @@ s32 USBfreeze(int mode, freezeData* data)
return -1;
}
s8* ptr = data->data + sizeof(USBfreezeData);
// Load the state of the attached devices
if (data->size != sizeof(USBfreezeData) + usbd.device[0].size + usbd.device[1].size + 8192)
return -1;
//TODO Subsequent save state loadings make USB "stall" for n seconds since previous load
//clocks = usbd.cycles;
//remaining = usbd.remaining;
@ -377,12 +382,11 @@ s32 USBfreeze(int mode, freezeData* data)
usbd.t.rhport[i].port.ops = qemu_ohci->rhport[i].port.ops;
usbd.t.rhport[i].port.dev = qemu_ohci->rhport[i].port.dev;
}
//if (qemu_ohci->usb_packet.iov.iov)
usb_packet_cleanup(&qemu_ohci->usb_packet);
*qemu_ohci = usbd.t;
s8* ptr = data->data + sizeof(USBfreezeData);
// Load the state of the attached devices
if ((long unsigned int)data->size != sizeof(USBfreezeData) + usbd.device[0].size + usbd.device[1].size + 8192)
return -1;
// restore USBPacket for OHCIState
usb_packet_init(&qemu_ohci->usb_packet);
RegisterDevice& regInst = RegisterDevice::instance();
for (int i = 0; i < 2; i++)
@ -431,6 +435,21 @@ s32 USBfreeze(int mode, freezeData* data)
usb_device[i]->setup_len = tmp.setup_len;
usb_device[i]->setup_index = tmp.setup_index;
#ifndef NDEBUG
std::cerr << "Loading save state:\nport: " << i
<< "\naddr: " << (int)usb_device[i]->addr
<< "\nattached: " << usb_device[i]->attached
<< "\nauto_attach: " << usb_device[i]->auto_attach
<< "\nconfig: " << usb_device[i]->configuration
<< "\nninterf: " << usb_device[i]->ninterfaces
<< "\nflags: " << usb_device[i]->flags
<< "\nstate: " << usb_device[i]->state
<< "\nremote_wakeup: " << usb_device[i]->remote_wakeup
<< "\nsetup_state: " << usb_device[i]->setup_state
<< "\nsetup_len: " << usb_device[i]->setup_len
<< "\nsetup_index: " << usb_device[i]->setup_index
<< std::endl;
#endif
memcpy(usb_device[i]->data_buf, tmp.data_buf, sizeof(tmp.data_buf));
memcpy(usb_device[i]->setup_buf, tmp.setup_buf, sizeof(tmp.setup_buf));
@ -442,9 +461,14 @@ s32 USBfreeze(int mode, freezeData* data)
}
proxy->Freeze(FREEZE_LOAD, usb_device[i], ptr);
//TODO reset port if save state's and configured wheel types are different
usb_detach(&qemu_ohci->rhport[i].port);
usb_attach(&qemu_ohci->rhport[i].port);
if (!usb_device[i]->attached)
{ // FIXME FREEZE_SAVE fcked up
usb_device[i]->attached = true;
usb_device_reset(usb_device[i]);
//TODO reset port if save state's and configured wheel types are different
usb_detach(&qemu_ohci->rhport[i].port);
usb_attach(&qemu_ohci->rhport[i].port);
}
}
else if (!proxy && index != DEVTYPE_NONE)
{
@ -455,10 +479,6 @@ s32 USBfreeze(int mode, freezeData* data)
}
int dev_index = usbd.usb_packet.dev_index;
// restore USBPacket for OHCIState
//if (qemu_ohci->usb_packet.iov.iov)
usb_packet_cleanup(&qemu_ohci->usb_packet);
usb_packet_init(&qemu_ohci->usb_packet);
if (usb_device[dev_index])
{
@ -511,7 +531,7 @@ s32 USBfreeze(int mode, freezeData* data)
auto proxy = regInst.Device(index);
usbd.device[i].index = index;
if (proxy)
if (proxy && usb_device[i])
usbd.device[i].size = proxy->Freeze(FREEZE_SIZE, usb_device[i], nullptr);
else
usbd.device[i].size = 0;
@ -522,9 +542,10 @@ s32 USBfreeze(int mode, freezeData* data)
strncpy(usbd.freezeID, USBfreezeID, strlen(USBfreezeID));
usbd.t = *qemu_ohci;
usbd.usb_packet.ep = qemu_ohci->usb_packet.ep ? *qemu_ohci->usb_packet.ep : USBEndpoint{0};
usbd.t.usb_packet.iov = {};
usbd.t.usb_packet.ep = nullptr;
if (qemu_ohci->usb_packet.ep)
usbd.usb_packet.ep = *qemu_ohci->usb_packet.ep;
for (uint32_t i = 0; i < qemu_ohci->num_ports; i++)
{
@ -542,14 +563,13 @@ s32 USBfreeze(int mode, freezeData* data)
for (int i = 0; i < 2; i++)
{
auto proxy = regInst.Device(conf.Port[i]);
if (proxy && usbd.device[i].size)
if (usb_device[i])
{
proxy->Freeze(FREEZE_SAVE, usb_device[i], ptr);
if (usb_device[i])
usbd.device[i].dev = *usb_device[i];
memset(&usbd.device[i].dev.klass, 0, sizeof(USBDeviceClass));
usbd.device[i].dev = *usb_device[i];
if (proxy && usbd.device[i].size)
proxy->Freeze(FREEZE_SAVE, usb_device[i], ptr);
}
memset(&usbd.device[i].dev.klass, 0, sizeof(USBDeviceClass));
ptr += usbd.device[i].size;
}

View File

@ -161,3 +161,17 @@ void ClearSection(const TCHAR* section)
s->RemoveAllKeys();
}
}
void RemoveSection(const char* dev_type, int port, const std::string& key)
{
TSTDSTRING tkey;
tkey.assign(key.begin(), key.end());
TSTDSTRINGSTREAM section;
if (dev_type)
section << dev_type << _T(" ");
section << tkey << _T(" ") << port;
TSTDSTRING str = section.str();
ciniFile.RemoveSection(str_to_wstr(section.str()));
}

View File

@ -67,6 +67,7 @@ extern Config conf;
void SaveConfig();
void LoadConfig();
void ClearSection(const TCHAR* section);
void RemoveSection(const char* dev_type, int port, const std::string& key);
extern TSTDSTRING IniPath;
extern TSTDSTRING LogDir;

View File

@ -24,6 +24,8 @@
void RegisterDevice::Register()
{
auto& inst = RegisterDevice::instance();
if (inst.Map().size()) // FIXME Don't clear proxies, singstar keeps a copy to uninit audio
return;
inst.Add(DEVTYPE_PAD, new DeviceProxy<usb_pad::PadDevice>());
inst.Add(DEVTYPE_MSD, new DeviceProxy<usb_msd::MsdDevice>());
inst.Add(DEVTYPE_SINGSTAR, new DeviceProxy<usb_mic::SingstarDevice>());
@ -34,6 +36,8 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_RBKIT, new DeviceProxy<usb_pad::RBDrumKitDevice>());
inst.Add(DEVTYPE_BUZZ, new DeviceProxy<usb_pad::BuzzDevice>());
inst.Add(DEVTYPE_EYETOY, new DeviceProxy<usb_eyetoy::EyeToyWebCamDevice>());
inst.Add(DEVTYPE_BEATMANIA_DADADA, new DeviceProxy<usb_hid::BeatManiaDevice>());
inst.Add(DEVTYPE_SEGA_SEAMIC, new DeviceProxy<usb_pad::SeamicDevice>());
RegisterAPIs();
}

View File

@ -44,6 +44,8 @@ enum DeviceType
DEVTYPE_RBKIT,
DEVTYPE_BUZZ,
DEVTYPE_EYETOY,
DEVTYPE_BEATMANIA_DADADA,
DEVTYPE_SEGA_SEAMIC,
};
struct SelectDeviceName

View File

@ -173,7 +173,7 @@ static void configureApi(GtkWidget* widget, gpointer data)
GtkWidget* new_combobox(const char* label, GtkWidget* vbox)
{
GtkWidget *ro_label, *rs_hbox, *rs_label, *rs_cb;
GtkWidget *rs_hbox, *rs_label, *rs_cb;
rs_hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), rs_hbox, FALSE, TRUE, 0);
@ -218,7 +218,7 @@ void USBconfigure()
const char* players[] = {"Player 1:", "Player 2:"};
GtkWidget *rs_cb, *vbox;
uint32_t idx = 0, sel_idx = 0;
uint32_t sel_idx = 0;
// Create the dialog window
GtkWidget* dlg = gtk_dialog_new_with_buttons(
@ -246,10 +246,15 @@ void USBconfigure()
gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), 0);
auto devices = RegisterDevice::instance().Names();
int idx = 0, selected = 0;
int idx = 0;
for (auto& device : devices)
{
auto deviceProxy = RegisterDevice::instance().Device(device);
if (!deviceProxy)
{
OSDebugOut(_T("Device '%" SFMTs "' is registered, but failed to get proxy!\n"), device.c_str());
continue;
}
auto name = deviceProxy->Name();
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), name);
idx++;

View File

@ -27,15 +27,19 @@
#ifdef _WIN32
#define CALLBACK __stdcall
#else
#elif defined(__i386__)
#define CALLBACK __attribute__((stdcall))
#else
#define CALLBACK
#endif
#ifndef EXPORT_C_
#ifdef _MSC_VER
#define EXPORT_C_(type) extern "C" type CALLBACK
#elif defined(__i386__)
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, visibility("default"))) type
#else
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type
#define EXPORT_C_(type) extern "C" __attribute__((visibility("default"))) type
//#define EXPORT_C_(type) extern "C" __attribute__((stdcall,visibility("default"))) type
#endif
#endif

View File

@ -31,6 +31,8 @@
#define HID_MOUSE 1
#define HID_TABLET 2
#define HID_KEYBOARD 3
// idk
#define HID_SUBKIND_BEATMANIA 1
/* scancode without modifiers */
#define SCANCODE_KEYMASK 0xff
@ -323,6 +325,7 @@ struct HIDState
uint32_t head; /* index into circular queue */
uint32_t n;
int kind;
int sub_kind;
int32_t protocol;
uint8_t idle;
bool idle_pending;

View File

@ -461,7 +461,7 @@ struct USBPort
USBPortOps* ops;
void* opaque;
int index; /* internal port index, may be used with the opaque */
//QTAILQ_ENTRY(USBPort) next; /* Used internally by qemu. */
//QTAILQ_ENTRY(USBPort) next; /* Used internally by qemu. */
};
typedef void USBCallback(USBPacket* packet, void* opaque);

View File

@ -560,6 +560,11 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed,
the next ISO TD of the same ED */
//trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number,
// frame_count);
if (OHCI_CC_DATAOVERRUN == OHCI_BM(iso_td.flags, TD_CC))
{
/* avoid infinite loop */
return 1;
}
OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
ed->head &= ~OHCI_DPTR_MASK;
ed->head |= (iso_td.next & OHCI_DPTR_MASK);
@ -603,7 +608,14 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed,
}
start_offset = iso_td.offset[relative_frame_number];
next_offset = iso_td.offset[relative_frame_number + 1];
if (relative_frame_number < frame_count)
{
next_offset = iso_td.offset[relative_frame_number + 1];
}
else
{
next_offset = iso_td.be;
}
if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
((relative_frame_number < frame_count) &&
@ -647,7 +659,13 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed,
else
{
/* Last packet in the ISO TD */
end_addr = iso_td.be;
end_addr = next_offset;
}
if (start_addr > end_addr)
{
//trace_usb_ohci_iso_td_bad_cc_overrun(start_addr, end_addr);
return 1;
}
if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK))
@ -658,6 +676,10 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed,
{
len = end_addr - start_addr + 1;
}
if (len > sizeof(ohci->usb_buf))
{
len = sizeof(ohci->usb_buf);
}
if (len && dir != OHCI_TD_DIR_IN)
{
@ -674,6 +696,11 @@ static int ohci_service_iso_td(OHCIState* ohci, struct ohci_ed* ed,
bool int_req = relative_frame_number == frame_count &&
OHCI_BM(iso_td.flags, TD_DI) == 0;
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
if (dev == NULL)
{
//trace_usb_ohci_td_dev_error();
return 1;
}
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
@ -851,8 +878,18 @@ static int ohci_service_td(OHCIState* ohci, struct ohci_ed* ed)
}
else
{
if (td.cbp > td.be)
{
//trace_usb_ohci_iso_td_bad_cc_overrun(td.cbp, td.be);
ohci_die(ohci);
return 1;
}
len = (td.be - td.cbp) + 1;
}
if (len > sizeof(ohci->usb_buf))
{
len = sizeof(ohci->usb_buf);
}
pktlen = len;
if (len && dir != OHCI_TD_DIR_IN)
@ -897,6 +934,11 @@ static int ohci_service_td(OHCIState* ohci, struct ohci_ed* ed)
return 1;
}
dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
if (dev == NULL)
{
//trace_usb_ohci_td_dev_error();
return 1;
}
ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0);
@ -1042,7 +1084,7 @@ static int ohci_service_ed_list(OHCIState* ohci, uint32_t head, int completion)
if (head == 0)
return 0;
for (cur = head; cur; cur = next_ed)
for (cur = head; cur && link_cnt++ < ED_LINK_LIMIT; cur = next_ed)
{
if (!ohci_read_ed(ohci, cur, &ed))
{
@ -1053,12 +1095,6 @@ static int ohci_service_ed_list(OHCIState* ohci, uint32_t head, int completion)
next_ed = ed.next & OHCI_DPTR_MASK;
if (++link_cnt > ED_LINK_LIMIT)
{
ohci_die(ohci);
return 0;
}
if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K))
{
uint32_t addr;
@ -1445,7 +1481,47 @@ static void ohci_port_set_status(OHCIState* ohci, int portnum, uint32_t val)
ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
}
#ifdef DEBUG_OHCI
static const char* reg_names[] = {
"HcRevision",
"HcControl",
"HcCommandStatus",
"HcInterruptStatus",
"HcInterruptEnable",
"HcInterruptDisable",
"HcHCCA",
"HcPeriodCurrentED",
"HcControlHeadED",
"HcControlCurrentED",
"HcBulkHeadED",
"HcBulkCurrentED",
"HcDoneHead",
"HcFmInterval",
"HcFmRemaining",
"HcFmNumber",
"HcPeriodicStart",
"HcLSThreshold",
"HcRhDescriptorA",
"HcRhDescriptorB",
"HcRhStatus",
};
uint32_t ohci_mem_read_impl(OHCIState* ptr, uint32_t addr);
uint32_t ohci_mem_read(OHCIState* ptr, uint32_t addr)
{
auto val = ohci_mem_read_impl(ptr, addr);
int idx = (addr - ptr->mem_base) >> 2;
if (idx < countof(reg_names))
{
fprintf(stderr, "ohci_mem_read %s(%d): %08x\n", reg_names[idx], idx, val);
}
return val;
}
uint32_t ohci_mem_read_impl(OHCIState* ptr, uint32_t addr)
#else
uint32_t ohci_mem_read(OHCIState* ptr, uint32_t addr)
#endif
{
OHCIState* ohci = ptr;
@ -1463,9 +1539,6 @@ uint32_t ohci_mem_read(OHCIState* ptr, uint32_t addr)
/* HcRhPortStatus */
return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
}
#ifdef DEBUG_OHCI
OSDebugOut(TEXT("ohci_mem_read: addr %d\n"), addr >> 2);
#endif
switch (addr >> 2)
{
case 0: /* HcRevision */
@ -1535,7 +1608,22 @@ uint32_t ohci_mem_read(OHCIState* ptr, uint32_t addr)
}
}
#ifdef DEBUG_OHCI
void ohci_mem_write_impl(OHCIState* ptr, uint32_t addr, uint32_t val);
void ohci_mem_write(OHCIState* ptr, uint32_t addr, uint32_t val)
{
int idx = (addr - ptr->mem_base) >> 2;
if (idx < countof(reg_names))
{
fprintf(stderr, "ohci_mem_write %s(%d): %08x\n", reg_names[idx], idx, val);
}
ohci_mem_write_impl(ptr, addr, val);
}
void ohci_mem_write_impl(OHCIState* ptr, uint32_t addr, uint32_t val)
#else
void ohci_mem_write(OHCIState* ptr, uint32_t addr, uint32_t val)
#endif
{
OHCIState* ohci = ptr;
@ -1555,9 +1643,6 @@ void ohci_mem_write(OHCIState* ptr, uint32_t addr, uint32_t val)
ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
return;
}
#ifdef DEBUG_OHCI
OSDebugOut(TEXT("ohci_mem_write: addr %d = 0x%08x\n"), addr >> 2, val);
#endif
switch (addr >> 2)
{
case 1: /* HcControl */
@ -1658,7 +1743,7 @@ static USBPortOps ohci_port_ops = {
/*.detach =*/ohci_detach,
//.child_detach = ohci_child_detach,
/*.wakeup =*/ohci_wakeup,
//.complete = ohci_async_complete_packet,
/*.complete =*/ohci_async_complete_packet,
};
static USBBusOps ohci_bus_ops = {};

View File

@ -44,14 +44,12 @@ namespace usb_eyetoy
namespace linux_api
{
static pthread_t _eyetoy_thread;
static pthread_t* eyetoy_thread = &_eyetoy_thread;
static pthread_t eyetoy_thread = 0;
static unsigned char eyetoy_running = 0;
static int fd = -1;
buffer_t* buffers;
static unsigned int n_buffers;
static int out_buf;
static unsigned int pixelformat;
buffer_t mpeg_buffer;
@ -384,6 +382,8 @@ namespace usb_eyetoy
break;
}
}
eyetoy_running = 0;
fprintf(stderr, "V4L2 thread quit\n");
return NULL;
}
@ -448,15 +448,15 @@ namespace usb_eyetoy
if (eyetoy_running)
{
eyetoy_running = 0;
pthread_join(*eyetoy_thread, NULL);
pthread_join(eyetoy_thread, NULL);
v4l_close();
}
eyetoy_running = 1;
std::string selectedDevice;
LoadSetting(EyeToyWebCamDevice::TypeName(), mPort, APINAME, N_DEVICE, selectedDevice);
if (v4l_open(selectedDevice) != 0)
return -1;
pthread_create(eyetoy_thread, NULL, &v4l_thread, NULL);
pthread_create(&eyetoy_thread, NULL, &v4l_thread, NULL);
eyetoy_running = 1;
return 0;
};
@ -465,7 +465,9 @@ namespace usb_eyetoy
if (eyetoy_running)
{
eyetoy_running = 0;
pthread_join(*eyetoy_thread, NULL);
if (eyetoy_thread)
pthread_join(eyetoy_thread, NULL);
eyetoy_thread = 0;
v4l_close();
}
return 0;
@ -489,8 +491,6 @@ namespace usb_eyetoy
int GtkConfigure(int port, const char* dev_type, void* data)
{
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label;
std::string selectedDevice;
LoadSetting(dev_type, port, APINAME, N_DEVICE, selectedDevice);
@ -532,7 +532,7 @@ namespace usb_eyetoy
int ret = RESULT_OK;
if (result == GTK_RESPONSE_OK)
{
if (sel_new != sel_idx)
if (devList.size() && sel_new != sel_idx)
{
if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, devList.at(sel_new)))
{

File diff suppressed because it is too large Load Diff

View File

@ -28,14 +28,14 @@ extern GUID CLSID_NullRenderer;
}
#pragma region qedit.h
struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
struct //__declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
ISampleGrabberCB : IUnknown
{
virtual HRESULT __stdcall SampleCB(double SampleTime, struct IMediaSample* pSample) = 0;
virtual HRESULT __stdcall BufferCB(double SampleTime, unsigned char* pBuffer, long BufferLen) = 0;
};
struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
struct //__declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
ISampleGrabber : IUnknown
{
virtual HRESULT __stdcall SetOneShot(long OneShot) = 0;
@ -47,8 +47,8 @@ struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
virtual HRESULT __stdcall SetCallback(struct ISampleGrabberCB* pCallback, long WhichMethodToCallback) = 0;
};
struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37"))
SampleGrabber;
//struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37"))
// SampleGrabber;
#pragma endregion
@ -72,12 +72,6 @@ namespace usb_eyetoy
typedef void (*DShowVideoCaptureCallback)(unsigned char* data, int len, int bitsperpixel);
typedef struct
{
void* start = NULL;
size_t length = 0;
} buffer_t;
static const char* APINAME = "DirectShow";
class DirectShow : public VideoDevice
@ -100,10 +94,12 @@ namespace usb_eyetoy
void Port(int port) { mPort = port; }
protected:
void SetCallback(DShowVideoCaptureCallback cb) { callbackhandler->SetCallback(cb); }
void Start();
void Stop();
int InitializeDevice(std::wstring selectedDevice);
void store_mpeg_frame(const std::vector<unsigned char>& data);
void create_dummy_frame();
void dshow_callback(unsigned char* data, int len, int bitsperpixel);
private:
int mPort;
@ -118,10 +114,16 @@ namespace usb_eyetoy
ISampleGrabber* samplegrabber;
IBaseFilter* nullrenderer;
std::vector<unsigned char> mpeg_buffer{};
std::mutex mpeg_mutex;
class CallbackHandler : public ISampleGrabberCB
{
public:
CallbackHandler() { callback = 0; }
CallbackHandler(DirectShow* parent_)
: parent(parent_)
{
}
~CallbackHandler() {}
void SetCallback(DShowVideoCaptureCallback cb) { callback = cb; }
@ -133,7 +135,7 @@ namespace usb_eyetoy
virtual ULONG __stdcall Release() { return 2; }
private:
DShowVideoCaptureCallback callback;
DirectShow* parent;
} * callbackhandler;
};

View File

@ -454,7 +454,7 @@ namespace usb_eyetoy
s->frame_step++;
}
else if (s->frame_step < 10)
else if (s->mpeg_frame_offset < s->mpeg_frame_size)
{
int data_pk = s->mpeg_frame_size - s->mpeg_frame_offset;
if (data_pk > max_ep_size)
@ -464,7 +464,7 @@ namespace usb_eyetoy
s->frame_step++;
}
else if (s->frame_step == 10)
else
{
uint8_t footer[] = {
0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
@ -518,7 +518,7 @@ namespace usb_eyetoy
VideoDeviceProxyBase* proxy = RegisterVideoDevice::instance().Proxy(varApi);
if (!proxy)
{
SysMessage(TEXT("Invalid video device API: " SFMTs "\n"), varApi.c_str());
SysMessage(TEXT("Invalid video device API: %" SFMTs "\n"), varApi.c_str());
return NULL;
}
@ -597,7 +597,7 @@ namespace usb_eyetoy
default:
break;
}*/
return -1;
return 0;
}
} // namespace usb_eyetoy

View File

@ -109,8 +109,7 @@ namespace usb_hid
int GtkHidConfigure(int port, const char* dev_type, HIDType hid_type, GtkWindow* parent)
{
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label, *rs_cb;
GtkWidget *main_hbox, *right_vbox, *left_vbox;
GtkWidget *main_hbox, *right_vbox, *rs_cb;
assert((int)HIDTYPE_MOUSE == 1); //make sure there is atleast two types so we won't go beyond array length

View File

@ -39,7 +39,6 @@ namespace usb_hid
bool FindHid(const std::string& evphys, std::string& hid_dev)
{
int fd;
int res;
char buf[256];
std::stringstream str;
@ -100,18 +99,8 @@ namespace usb_hid
{
// Make sure there is atleast two types so we won't go beyond array length
assert((int)HIDTYPE_MOUSE == 1);
int t;
std::stringstream name;
char buf[1024];
unsigned long keybit[NBITS(KEY_MAX)] = {0};
unsigned long absbit[NBITS(ABS_MAX)] = {0};
memset(mAxisMap, -1, sizeof(mAxisMap));
memset(mBtnMap, -1, sizeof(mBtnMap));
mAxisCount = 0;
mButtonCount = 0;
mHandle = -1;
std::string path;
@ -124,39 +113,12 @@ namespace usb_hid
if (path.empty() || !file_exists(path))
goto quit;
/*if (GetEvdevName(joypath, buf)) {
name << buf;
name << " (evdev)";
}*/
if ((mHandle = open(path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
{
OSDebugOut("Cannot open device: %s\n", path.c_str());
goto quit;
}
/* if ((ioctl(mHandle, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) &&
(ioctl(mHandle, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0)) {
// Probably isn't a evdev joystick
SysMessage(APINAME ": Getting atleast some of the bits failed: %s\n", strerror(errno));
goto quit;
}*/
/*unsigned int version;
if (ioctl(mHandle, EVIOCGVERSION, &version) < 0)
{
SysMessage(APINAME ": Get version failed: %s\n", strerror(errno));
return false;
}*/
/* for (int i = 0; i < KEY_MAX; ++i) {
if (test_bit(i, keybit)) {
OSDebugOut("Joystick has button: 0x%x\n", i);
mBtnMap[i] = mButtonCount;
++mButtonCount;
}
}*/
if (!mReaderThreadIsRunning)
{
if (mReaderThread.joinable())
@ -186,9 +148,6 @@ namespace usb_hid
EvDev* dev = static_cast<EvDev*>(ptr);
HIDState* hs = dev->mHIDState;
int32_t lastX = 0, lastY = 0;
bool shift = false;
bool grabbed = false;
dev->mReaderThreadIsRunning = true;

View File

@ -57,10 +57,6 @@ namespace usb_hid
static void ReaderThread(void* ptr);
int mHandle;
uint16_t mAxisMap[ABS_MAX + 1];
uint16_t mBtnMap[KEY_MAX + 1];
int mAxisCount;
int mButtonCount;
std::thread mReaderThread;
std::atomic<bool> mReaderThreadIsRunning;

View File

@ -46,6 +46,7 @@ namespace usb_hid
UsbHIDProxyBase(const std::string& name);
virtual UsbHID* CreateObject(int port, const char* dev_type) const = 0;
// ProxyBase::Configure is ignored
virtual int Configure(int port, const char* dev_type, void* data) { return RESULT_CANCELED; }
virtual int Configure(int port, const char* dev_type, HIDType hid_type, void* data) = 0;
};
@ -76,10 +77,6 @@ namespace usb_hid
{
return T::Name();
}
virtual int Configure(int port, const char* dev_type, void* data)
{
return RESULT_CANCELED;
}
virtual int Configure(int port, const char* dev_type, HIDType hid_type, void* data)
{
return T::Configure(port, dev_type, hid_type, data);

View File

@ -64,6 +64,18 @@ namespace usb_hid
return nullptr;
}
std::list<std::string> BeatManiaDevice::ListAPIs()
{
return RegisterUsbHID::instance().Names();
}
const TCHAR* BeatManiaDevice::LongAPIName(const std::string& name)
{
auto proxy = RegisterUsbHID::instance().Proxy(name);
if (proxy)
return proxy->Name();
return nullptr;
}
std::list<std::string> HIDMouseDevice::ListAPIs()
{
return RegisterUsbHID::instance().Names();
@ -100,6 +112,14 @@ namespace usb_hid
"HID Keyboard",
};
static const USBDescStrings beatmania_dadada_desc_strings = {
"",
"KONAMI CPJ1",
"USB JIS Mini Keyboard",
};
/* mostly the same values as the Bochs USB Keyboard device */
static const uint8_t kbd_dev_desc[] = {
0x12, /* u8 bLength; */
@ -414,6 +434,105 @@ namespace usb_hid
0xc0, /* End Collection */
};
static const uint8_t beatmania_dev_desc[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
WBVAL(0x110), /* u16 bcdUSB; v1.10 */
0x00, /* u8 bDeviceClass; */
0x00, /* u8 bDeviceSubClass; */
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
0x08, /* u8 bMaxPacketSize0; 8 Bytes */
// 0x27, 0x06, /* u16 idVendor; */
WBVAL(0x0510),
// 0x01, 0x00, /* u16 idProduct; */
WBVAL(0x0002),
WBVAL(0x0020), /* u16 bcdDevice */
1, /* u8 iManufacturer; */
2, /* u8 iProduct; */
0, /* u8 iSerialNumber; */
0x01 /* u8 bNumConfigurations; */
};
static const uint8_t beatmania_config_desc[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x02, // iConfiguration (String Index)
0xA0, // bmAttributes Remote Wakeup
0x14, // bMaxPower 40mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x03, // bInterfaceClass
0x01, // bInterfaceSubClass
0x01, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x10, 0x01, // bcdHID 1.10
0x0F, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x44, 0x00, // wDescriptorLength[0] 68
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize 8
0x0A, // bInterval 10 (unit depends on device speed)
// 34 bytes
};
static const uint8_t beatmania_dadada_hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0xFF, // Usage Maximum (0xFF)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x06, // Report Count (6)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x05, // Report Count (5)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x75, 0x03, // Report Size (3)
0x95, 0x01, // Report Count (1)
0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
// 68 bytes
};
static void usb_hid_changed(HIDState* hs)
{
UsbHIDState* us = CONTAINER_OF(hs, UsbHIDState, f.hid);
@ -463,9 +582,16 @@ namespace usb_hid
}
else if (hs->kind == HID_KEYBOARD)
{
memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
if (hs->sub_kind == HID_SUBKIND_BEATMANIA)
{
p->actual_length = sizeof(beatmania_dadada_hid_report_descriptor);
memcpy(data, beatmania_dadada_hid_report_descriptor, p->actual_length);
}
else
{
p->actual_length = sizeof(qemu_keyboard_hid_report_descriptor);
memcpy(data, qemu_keyboard_hid_report_descriptor, p->actual_length);
}
}
break;
default:
@ -665,6 +791,8 @@ namespace usb_hid
auto s = reinterpret_cast<UsbHIDState*>(dev);
auto freezed = reinterpret_cast<UsbHIDState::freeze*>(data);
if (!s)
return 0;
switch (mode)
{
case FREEZE_LOAD:
@ -682,7 +810,7 @@ namespace usb_hid
default:
break;
}
return -1;
return 0;
}
USBDevice* HIDMouseDevice::CreateDevice(int port)
@ -754,4 +882,77 @@ namespace usb_hid
return HIDKbdDevice::Freeze(mode, dev, data);
}
// ---- BeatMania Da Da Da!! ----
USBDevice* BeatManiaDevice::CreateDevice(int port)
{
OSDebugOut(_T("%s\n"), __func__);
UsbHIDState* s;
std::string varApi;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
UsbHIDProxyBase* proxy = RegisterUsbHID::instance().Proxy(varApi);
if (!proxy)
{
SysMessage(TEXT("Invalid HID API: %" SFMTs "\n"), varApi.c_str());
return nullptr;
}
UsbHID* usbhid = proxy->CreateObject(port, TypeName());
if (!usbhid)
return nullptr;
s = new UsbHIDState();
s->desc.full = &s->desc_dev;
s->desc.str = beatmania_dadada_desc_strings;
if (usb_desc_parse_dev(beatmania_dev_desc, sizeof(beatmania_dev_desc), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(beatmania_config_desc, sizeof(beatmania_config_desc), s->desc_dev) < 0)
goto fail;
s->usbhid = usbhid;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = usb_hid_handle_reset;
s->dev.klass.handle_control = usb_hid_handle_control;
s->dev.klass.handle_data = usb_hid_handle_data;
s->dev.klass.unrealize = usb_hid_unrealize;
s->dev.klass.open = usb_hid_open;
s->dev.klass.close = usb_hid_close;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = s->desc.str[2];
s->port = port;
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
s->intr = usb_ep_get(&s->dev, USB_TOKEN_IN, 1);
hid_init(&s->f.hid, HID_KEYBOARD, usb_hid_changed);
s->f.hid.sub_kind = HID_SUBKIND_BEATMANIA;
s->usbhid->SetHIDState(&s->f.hid);
s->usbhid->SetHIDType(HIDTYPE_KBD);
usb_hid_handle_reset((USBDevice*)s);
return (USBDevice*)s;
fail:
usb_hid_unrealize((USBDevice*)s);
return nullptr;
}
int BeatManiaDevice::Configure(int port, const std::string& api, void* data)
{
auto proxy = RegisterUsbHID::instance().Proxy(api);
if (proxy)
return proxy->Configure(port, TypeName(), HIDTYPE_KBD, data);
return RESULT_CANCELED;
}
int BeatManiaDevice::Freeze(int mode, USBDevice* dev, void* data)
{
return HIDKbdDevice::Freeze(mode, dev, data);
}
} // namespace usb_hid

View File

@ -93,4 +93,23 @@ namespace usb_hid
static int Freeze(int mode, USBDevice* dev, void* data);
};
class BeatManiaDevice
{
public:
virtual ~BeatManiaDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
return TEXT("BeatMania Da Da Da!! Keyboard");
}
static const char* TypeName()
{
return "beatmania";
}
static std::list<std::string> ListAPIs();
static const TCHAR* LongAPIName(const std::string& name);
static int Configure(int port, const std::string& api, void* data);
static int Freeze(int mode, USBDevice* dev, void* data);
};
} // namespace usb_hid

View File

@ -177,7 +177,7 @@ namespace usb_mic
static int GtkConfigure(int port, const char* dev_type, void* data)
{
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label, *rs_cb, *vbox;
GtkWidget* ro_frame;
int dev_idxs[] = {0, 0, 0, 0};
@ -763,7 +763,7 @@ namespace usb_mic
if (ret != PA_OK)
return;
auto dur = std::chrono::duration_cast<ms>(hrc::now() - padev->mLastGetBuffer).count();
//auto dur = std::chrono::duration_cast<ms>(hrc::now() - padev->mLastGetBuffer).count();
if (padev->mPaused /*|| dur > 5000*/ || (!padata && nbytes /* hole */))
{
ret = pa_stream_drop(p);
@ -836,7 +836,7 @@ namespace usb_mic
void PulseAudioDevice::stream_write_cb(pa_stream* p, size_t nbytes, void* userdata)
{
void* pa_buffer = NULL;
size_t pa_bytes, old_size;
size_t pa_bytes;
// The length of the data to write in bytes, must be in multiples of the stream's sample spec frame size
ssize_t remaining_bytes = nbytes;
int ret = PA_OK;

View File

@ -926,12 +926,12 @@ namespace usb_mic
switch (uMsg)
{
case WM_CREATE:
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
SetWindowLongPtr(hW, GWLP_USERDATA, lParam);
break;
case WM_INITDIALOG:
{
s = (WASAPISettings*)lParam;
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
SetWindowLongPtr(hW, GWLP_USERDATA, lParam);
int buffering = 50;
LoadSetting(s->dev_type, s->port, APINAME, N_BUFFER_LEN_SRC, buffering);

View File

@ -1062,11 +1062,11 @@ namespace usb_mic
int HeadsetDevice::Freeze(int mode, USBDevice* dev, void* data)
{
HeadsetState* s = (HeadsetState*)dev;
if (!s)
return 0;
switch (mode)
{
case FREEZE_LOAD:
if (!s)
return -1;
s->f = *(HeadsetState::freeze*)data;
if (s->audsrc)
s->audsrc->SetResampling(s->f.in.srate);
@ -1074,8 +1074,6 @@ namespace usb_mic
s->audsink->SetResampling(s->f.out.srate);
return sizeof(HeadsetState::freeze);
case FREEZE_SAVE:
if (!s)
return -1;
*(HeadsetState::freeze*)data = s->f;
return sizeof(HeadsetState::freeze);
case FREEZE_SIZE:
@ -1083,7 +1081,7 @@ namespace usb_mic
default:
break;
}
return -1;
return 0;
}
} // namespace usb_mic

View File

@ -624,7 +624,7 @@ namespace usb_mic
return;
}
OSDebugOut(TEXT("data len: %d bytes, src[0]: %d frames, src[1]: %d frames\n"), len, out_frames[0], out_frames[1]);
OSDebugOut(TEXT("data len: %zu bytes, src[0]: %d frames, src[1]: %d frames\n"), len, out_frames[0], out_frames[1]);
//TODO well, it is 16bit interleaved, right?
//Merge with MIC_MODE_SHARED case?
@ -718,7 +718,7 @@ namespace usb_mic
case USB_TOKEN_OUT:
printf("token out ep: %d\n", devep);
OSDebugOut(TEXT("token out ep: %d len: %d\n"), devep, p->actual_length);
[[fallthrough]];
break;
default:
p->status = USB_RET_STALL;
break;
@ -866,11 +866,11 @@ namespace usb_mic
int SingstarDevice::Freeze(int mode, USBDevice* dev, void* data)
{
SINGSTARMICState* s = (SINGSTARMICState*)dev;
if (!s)
return 0;
switch (mode)
{
case FREEZE_LOAD:
if (!s)
return -1;
s->f = *(SINGSTARMICState::freeze*)data;
if (s->audsrc[0])
s->audsrc[0]->SetResampling(s->f.srate[0]);
@ -878,8 +878,6 @@ namespace usb_mic
s->audsrc[1]->SetResampling(s->f.srate[1]);
return sizeof(SINGSTARMICState::freeze);
case FREEZE_SAVE:
if (!s)
return -1;
*(SINGSTARMICState::freeze*)data = s->f;
return sizeof(SINGSTARMICState::freeze);
case FREEZE_SIZE:
@ -887,7 +885,7 @@ namespace usb_mic
default:
break;
}
return -1;
return 0;
}
} // namespace usb_mic

View File

@ -23,8 +23,10 @@ namespace usb_msd
static void entryChanged(GtkWidget* widget, gpointer data)
{
#ifndef NDEBUG
const gchar* text = gtk_entry_get_text(GTK_ENTRY(widget));
//fprintf(stderr, "Entry text:%s\n", text);
fprintf(stderr, "Entry text:%s\n", text);
#endif
}
static void fileChooser(GtkWidget* widget, gpointer data)
@ -59,7 +61,7 @@ namespace usb_msd
int MsdDevice::Configure(int port, const std::string& api, void* data)
{
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label, *rs_cb, *vbox;
GtkWidget *ro_frame, *ro_label, *rs_hbox, *vbox;
GtkWidget* dlg = gtk_dialog_new_with_buttons(
"Mass Storage Settings", GTK_WINDOW(data), GTK_DIALOG_MODAL,

View File

@ -618,7 +618,7 @@ namespace usb_msd
MSDState* s = (MSDState*)opaque;
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x\n", cbw->lun, cbw->tag, cbw->data_len, cbw->cmd[0]);
uint32_t lba;
int64_t lba;
uint32_t xfer_len;
s->f.last_cmd = cbw->cmd[0];
@ -701,7 +701,7 @@ namespace usb_msd
s->f.data_len = xfer_len * LBA_BLOCK_SIZE;
s->f.file_op_tag = s->f.tag;
DPRINTF("read lba=0x%x, len=0x%x\n", lba, xfer_len * LBA_BLOCK_SIZE);
DPRINTF("read lba=0x%llx, len=0x%x\n", lba, xfer_len * LBA_BLOCK_SIZE);
if (xfer_len == 0) // nothing to do
break;
@ -1088,11 +1088,11 @@ namespace usb_msd
MSDState* s = (MSDState*)dev;
MSDState::freeze* tmp;
if (!s)
return 0;
switch (mode)
{
case FREEZE_LOAD:
if (!s)
return -1;
//if (s->f.req) free (s->f.req);
tmp = (MSDState::freeze*)data;
@ -1107,8 +1107,6 @@ namespace usb_msd
return sizeof(MSDState::freeze); // + sizeof(ReqState);
case FREEZE_SAVE:
if (!s)
return -1;
tmp = (MSDState::freeze*)data;
*tmp = s->f;
return sizeof(MSDState::freeze);
@ -1118,7 +1116,7 @@ namespace usb_msd
default:
break;
}
return -1;
return 0;
}
#undef DPRINTF

View File

@ -46,14 +46,6 @@ namespace usb_pad
std::vector<DIJOYSTATE2> jso; // DInput joystick old state, only for config
std::vector<DIJOYSTATE2> jsi; // DInput joystick initial state, only for config
int32_t AXISID[2][CID_COUNT];
int32_t BUTTON[2][CID_COUNT];
int32_t INVERT[2][CID_COUNT];
int32_t HALF[2][CID_COUNT];
int32_t LINEAR[2][CID_COUNT];
int32_t OFFSET[2][CID_COUNT];
int32_t DEADZONE[2][CID_COUNT];
int32_t BYPASSCAL = 0;
int32_t GAINZ[2][1];
int32_t FFMULTI[2][1];
@ -64,7 +56,7 @@ namespace usb_pad
HWND hKey;
HWND hWnd;
TCHAR text[1024];
ControlID CID = CID_COUNT;
ControlID CID = CID_COUNT; //keep track of last assigned control
HFONT hFont;
HDC hDC;
@ -305,17 +297,18 @@ namespace usb_pad
if (filtercontrol == -1)
return;
//slider
LINEAR[port][filtercontrol] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
OFFSET[port][filtercontrol] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
DEADZONE[port][filtercontrol] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
auto& im = g_Controls[port][filtercontrol];
im.LINEAR = SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
im.OFFSET = SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
im.DEADZONE = SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_GETPOS, 0, 0) - 50 * PRECMULTI;
GAINZ[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_GETPOS, 0, 0);
FFMULTI[port][0] = SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_GETPOS, 0, 0);
swprintf_s(text, TEXT("LINEARITY: %0.02f"), float(LINEAR[port][filtercontrol]) / PRECMULTI);
swprintf_s(text, TEXT("LINEARITY: %0.02f"), float(im.LINEAR) / PRECMULTI);
SetWindowText(GetDlgItem(hWnd, IDC_LINEAR), text);
swprintf_s(text, TEXT("OFFSET: %0.02f"), float(OFFSET[port][filtercontrol]) / PRECMULTI);
swprintf_s(text, TEXT("OFFSET: %0.02f"), float(im.OFFSET) / PRECMULTI);
SetWindowText(GetDlgItem(hWnd, IDC_OFFSET), text);
swprintf_s(text, TEXT("DEAD-ZONE: %0.02f"), float(DEADZONE[port][filtercontrol]) / PRECMULTI);
swprintf_s(text, TEXT("DEAD-ZONE: %0.02f"), float(im.DEADZONE) / PRECMULTI);
SetWindowText(GetDlgItem(hWnd, IDC_DEADZONE), text);
GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect);
@ -328,12 +321,11 @@ namespace usb_pad
filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0);
if (filtercontrol == -1)
return;
//InputMapped im = {};
//GetInputMap(port, (ControlID)filtercontrol, im);
auto& im = g_Controls[port][filtercontrol];
//slider
SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETPOS, 1, LINEAR[port][filtercontrol] + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETPOS, 1, OFFSET[port][filtercontrol] + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETPOS, 1, DEADZONE[port][filtercontrol] + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER1), TBM_SETPOS, 1, im.LINEAR + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER2), TBM_SETPOS, 1, im.OFFSET + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER3), TBM_SETPOS, 1, im.DEADZONE + 50 * PRECMULTI);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER4), TBM_SETPOS, 1, GAINZ[port][0]);
SendMessage(GetDlgItem(hWnd, IDC_SLIDER5), TBM_SETPOS, 1, FFMULTI[port][0]);
@ -342,44 +334,47 @@ namespace usb_pad
void DefaultFilters(int port, LONG id)
{
auto& im_l = g_Controls[port][CID_STEERING];
auto& im_r = g_Controls[port][CID_STEERING_R];
for (int i = 0; i < 6; i++)
{
LINEAR[port][i] = 0;
OFFSET[port][i] = 0;
DEADZONE[port][i] = 0;
auto& c = g_Controls[port][i];
c.LINEAR = 0;
c.OFFSET = 0;
c.DEADZONE = 0;
}
switch (id)
{
case 0:
LINEAR[port][0] = 0;
OFFSET[port][0] = 0;
LINEAR[port][1] = 0;
OFFSET[port][1] = 0;
im_l.LINEAR = 0;
im_l.OFFSET = 0;
im_r.LINEAR = 0;
im_r.OFFSET = 0;
break;
case 1:
LINEAR[port][0] = 6 * PRECMULTI;
OFFSET[port][0] = 0;
LINEAR[port][1] = 6 * PRECMULTI;
OFFSET[port][1] = 0;
im_l.LINEAR = 6 * PRECMULTI;
im_l.OFFSET = 0;
im_r.LINEAR = 6 * PRECMULTI;
im_r.OFFSET = 0;
break;
case 2:
LINEAR[port][0] = 12 * PRECMULTI;
OFFSET[port][0] = 0;
LINEAR[port][1] = 12 * PRECMULTI;
OFFSET[port][1] = 0;
im_l.LINEAR = 12 * PRECMULTI;
im_l.OFFSET = 0;
im_r.LINEAR = 12 * PRECMULTI;
im_r.OFFSET = 0;
break;
case 3:
LINEAR[port][0] = 18 * PRECMULTI;
OFFSET[port][0] = 0;
LINEAR[port][1] = 18 * PRECMULTI;
OFFSET[port][1] = 0;
im_l.LINEAR = 18 * PRECMULTI;
im_l.OFFSET = 0;
im_r.LINEAR = 18 * PRECMULTI;
im_r.OFFSET = 0;
break;
case 4:
LINEAR[port][0] = 25 * PRECMULTI;
OFFSET[port][0] = 0;
LINEAR[port][1] = 25 * PRECMULTI;
OFFSET[port][1] = 0;
im_l.LINEAR = 25 * PRECMULTI;
im_l.OFFSET = 0;
im_r.LINEAR = 25 * PRECMULTI;
im_r.OFFSET = 0;
break;
}
@ -398,7 +393,7 @@ namespace usb_pad
if (GetInputMap(port, (ControlID)filtercontrol, im))
{
TESTV = ReadAxis(im);
TESTVF = FilterControl(ReadAxis(im), LINEAR[port][filtercontrol], OFFSET[port][filtercontrol], DEADZONE[port][filtercontrol]);
TESTVF = FilterControl(ReadAxis(im), im.LINEAR, im.OFFSET, im.DEADZONE);
GetClientRect(GetDlgItem(hWnd, IDC_PICTURE), &rect);
MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2);
InvalidateRect(hWnd, &rect, TRUE);
@ -418,13 +413,6 @@ namespace usb_pad
if (FindControl(port, CID, im))
{
if (CID <= CID_BRAKE)
{
LINEAR[port][CID] = im.LINEAR;
OFFSET[port][CID] = im.OFFSET;
DEADZONE[port][CID] = im.DEADZONE;
}
AddInputMap(port, CID, im);
SetControlLabel(CID, im);
}
@ -501,13 +489,14 @@ namespace usb_pad
filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0);
if (filtercontrol >= 0)
{
auto& im = g_Controls[port][filtercontrol];
//draw nonlinear line
SelectObject(hDrawingDC, bluepen);
MoveToEx(hDrawingDC, (px + 8) * scale, (pheight + py - 8) * scale, 0);
for (float x = 0; x < 1.0f; x += 0.001f)
{
float y1 = FilterControl(x, LINEAR[port][filtercontrol], OFFSET[port][filtercontrol], DEADZONE[port][filtercontrol]);
float y1 = FilterControl(x, im.LINEAR, im.OFFSET, im.DEADZONE);
LineTo(hDrawingDC, (x * (pwidth - 16) + px + 8) * scale, (-y1 * (pheight - 16) + (pheight - 8) + py) * scale);
}
LineTo(hDrawingDC, (1.0f * (pwidth - 16) + px + 8) * scale, (-1.0f * (pheight - 16) + (pheight - 8) + py) * scale);
@ -1340,13 +1329,6 @@ namespace usb_pad
im.DEADZONE = std::stoi(value);
}
//if (cid <= CID_BRAKE)
{
LINEAR[port][cid] = im.LINEAR;
OFFSET[port][cid] = im.OFFSET;
DEADZONE[port][cid] = im.DEADZONE;
}
AddInputMap(port, (ControlID)cid, im);
}
}

View File

@ -29,9 +29,15 @@ namespace usb_pad
(((x) + 8 * sizeof(unsigned char) - 1) / (8 * sizeof(unsigned char)))
#define testBit(bit, array) ((((uint8_t*)(array))[(bit) / 8] >> ((bit) % 8)) & 1)
EvdevFF::EvdevFF(int fd)
EvdevFF::EvdevFF(int fd, bool gain_enabled, int gain, bool ac_managed, int ac_strength)
: mHandle(fd)
, mUseRumble(false)
, mLastValue(0)
, m_gain_enabled(gain_enabled)
, m_gain(gain)
//, m_ac_managed(ac_enabled)
, m_ac_managed(true)
, m_ac_strength(ac_strength)
{
unsigned char features[BITS_TO_UCHAR(FF_MAX)];
if (ioctl(mHandle, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0)
@ -80,17 +86,21 @@ namespace usb_pad
// Logitech wheels' force vs turn direction: 255 - left, 127/128 - neutral, 0 - right
// left direction
mEffect.direction = 0x4000;
mEffect.u.constant.envelope.attack_length = 0; //0x100;
mEffect.u.constant.envelope.attack_level = 0;
mEffect.u.constant.envelope.fade_length = 0; //0x100;
mEffect.u.constant.envelope.fade_level = 0;
mEffect.trigger.button = 0;
mEffect.trigger.interval = 0;
mEffect.replay.length = 0x7FFFUL; /* mseconds */
mEffect.replay.delay = 0;
SetGain(100);
SetAutoCenter(0);
if (m_gain_enabled)
SetGain(m_gain);
m_ac_strength = std::min(100, std::max(0, m_ac_strength));
if (ac_managed)
SetAutoCenter(0); // default to off
else
SetAutoCenter(m_ac_strength);
m_ac_managed = ac_managed;
}
EvdevFF::~EvdevFF()
@ -128,6 +138,10 @@ namespace usb_pad
mEffect.type = FF_CONSTANT;
mEffect.id = mEffIds[EFF_CONSTANT];
mEffect.u.constant.level = /*ff.u.constant.*/ level;
// mEffect.u.constant.envelope.attack_length = 0;//0x100;
// mEffect.u.constant.envelope.attack_level = 0;
// mEffect.u.constant.envelope.fade_length = 0;//0x100;
// mEffect.u.constant.envelope.fade_level = 0;
OSDebugOut("Constant force: %d\n", level);
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
@ -277,7 +291,10 @@ namespace usb_pad
void EvdevFF::SetAutoCenter(int value)
{
if (!m_ac_managed)
return;
struct input_event ie;
value = value * m_ac_strength / 100;
ie.type = EV_FF;
ie.code = FF_AUTOCENTER;

View File

@ -27,7 +27,7 @@ namespace usb_pad
class EvdevFF : public FFDevice
{
public:
EvdevFF(int fd);
EvdevFF(int fd, bool gain_enabled, int gain, bool ac_managed, int ac_strength);
~EvdevFF();
void SetConstantForce(int level);
@ -45,6 +45,10 @@ namespace usb_pad
bool mUseRumble;
int mLastValue;
bool m_gain_enabled;
int m_gain;
bool m_ac_managed;
int m_ac_strength;
};
} // namespace evdev

View File

@ -584,7 +584,7 @@ namespace usb_pad
static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping>>& fds, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial)
{
int event_fd = -1, t;
int event_fd = -1;
ssize_t len;
input_event event;
struct AxisValue
@ -749,9 +749,9 @@ namespace usb_pad
ApiCallbacks apicbs{GetEventName, EnumerateDevices, PollInput};
int ret = 0;
if (!strcmp(dev_type, BuzzDevice::TypeName()))
ret = GtkBuzzConfigure(port, dev_type, "Evdev Settings", "evdev", GTK_WINDOW(data), apicbs);
ret = GtkBuzzConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs);
else
ret = GtkPadConfigure(port, dev_type, "Evdev Settings", "evdev", GTK_WINDOW(data), apicbs);
ret = GtkPadConfigure(port, dev_type, "Evdev Settings", evdev::APINAME, GTK_WINDOW(data), apicbs);
return ret;
}

View File

@ -118,7 +118,7 @@ namespace usb_pad
}
#define EVDEV_DIR "/dev/input/by-id/"
void EnumerateDevices(vstring& list)
void EnumerateDevices(device_list& list)
{
int fd;
int res;
@ -128,7 +128,7 @@ namespace usb_pad
struct dirent* dp;
//TODO do some caching? ioctl is "very" slow
static vstring list_cache;
static device_list list_cache;
DIR* dirp = opendir(EVDEV_DIR);
if (!dirp)
@ -140,7 +140,7 @@ namespace usb_pad
// get rid of unplugged devices
for (int i = 0; i < list_cache.size();)
{
if (!file_exists(list_cache[i].second))
if (!file_exists(list_cache[i].path))
list_cache.erase(list_cache.begin() + i);
else
i++;
@ -159,8 +159,8 @@ namespace usb_pad
std::string path = str.str();
auto it = std::find_if(list_cache.begin(), list_cache.end(),
[&path](auto& pair) {
return pair.second == path;
[&path](evdev_device& dev) {
return dev.path == path;
});
if (it != list_cache.end())
continue;
@ -173,16 +173,16 @@ namespace usb_pad
continue;
}
list_cache.push_back(std::make_pair(std::string(dp->d_name), path));
//list_cache.push_back(std::make_pair(std::string(dp->d_name), path));
/*res = ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
if (res < 0)
perror("EVIOCGNAME");
else
{
OSDebugOut("Evdev device name: %s\n", buf);
list_cache.push_back(std::make_pair(std::string(buf) + " (evdev)", path));
}*/
res = ioctl(fd, EVIOCGNAME(sizeof(buf)), buf);
if (res < 0)
perror("EVIOCGNAME");
else
{
OSDebugOut("Evdev device name: %s\n", buf);
list_cache.push_back({buf, dp->d_name, path});
}
close(fd);
}
@ -368,6 +368,7 @@ namespace usb_pad
}
else
{
#if 0
// Map to xbox360ish controller
switch (code)
{
@ -408,16 +409,17 @@ namespace usb_pad
case BTN_TL:
button = PAD_L1;
break;
case BTN_THUMBR:
case BTN_TR2:
button = PAD_R2;
break;
case BTN_THUMBL:
case BTN_TL2:
button = PAD_L2;
break;
default:
OSDebugOut("Unmapped Button: %d, %d\n", code, event.value);
break;
}
#endif
}
//if (button != PAD_BUTTON_COUNT)
@ -530,9 +532,10 @@ namespace usb_pad
int EvDevPad::Open()
{
std::stringstream name;
vstring device_list;
device_list device_list;
char buf[1024];
mWheelData = {};
int32_t b_gain, gain, b_ac, ac;
unsigned long keybit[NBITS(KEY_MAX)];
unsigned long absbit[NBITS(ABS_MAX)];
@ -563,7 +566,8 @@ namespace usb_pad
case WT_DRIVING_FORCE_PRO:
case WT_DRIVING_FORCE_PRO_1102:
{
LoadSetting(mDevType, mPort, APINAME, N_HIDRAW_FF_PT, mUseRawFF);
if (!LoadSetting(mDevType, mPort, APINAME, N_HIDRAW_FF_PT, mUseRawFF))
mUseRawFF = 0;
}
break;
default:
@ -614,7 +618,7 @@ namespace usb_pad
{
if (mWriterThread.joinable())
mWriterThread.join();
mWriterThread = std::thread(EvDevPad::WriterThread, this);
mWriterThread = std::thread(&EvDevPad::WriterThread, this);
}
}
}
@ -633,11 +637,11 @@ namespace usb_pad
mDevices.push_back({});
struct device_data& device = mDevices.back();
device.name = it.first;
device.name = it.name;
if ((device.cfg.fd = open(it.second.c_str(), O_RDWR | O_NONBLOCK)) < 0)
if ((device.cfg.fd = open(it.path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
{
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
OSDebugOut("Cannot open device: %s\n", it.path.c_str());
continue;
}
@ -664,11 +668,19 @@ namespace usb_pad
switch (mType)
{
case WT_BUZZ_CONTROLLER:
LoadBuzzMappings(mDevType, mPort, device.name, device.cfg);
LoadBuzzMappings(mDevType, mPort, it.id, device.cfg);
max_buttons = 20;
break;
default:
LoadMappings(mDevType, mPort, device.name, device.cfg);
LoadMappings(mDevType, mPort, it.id, device.cfg);
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN_ENABLED, b_gain))
b_gain = 1;
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN, gain))
gain = 100;
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER_MANAGED, b_ac))
b_ac = 1;
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER, ac))
ac = 100;
break;
}
@ -716,7 +728,9 @@ namespace usb_pad
// TODO Instead of single FF instance, create for every device with X-axis???
// and then switch between them according to which device was used recently
if (k == JOY_STEERING && !mFFdev && !mUseRawFF)
mFFdev = new EvdevFF(device.cfg.fd);
{
mFFdev = new EvdevFF(device.cfg.fd, b_gain, gain, b_ac, ac);
}
}
}
}
@ -805,20 +819,19 @@ namespace usb_pad
return 0;
}
void EvDevPad::WriterThread(void* ptr)
void EvDevPad::WriterThread()
{
std::array<uint8_t, 8> buf;
int res;
EvDevPad* pad = static_cast<EvDevPad*>(ptr);
pad->mWriterThreadIsRunning = true;
mWriterThreadIsRunning = true;
while (pad->mHidHandle != -1)
while (mHidHandle != -1)
{
//if (pad->mFFData.wait_dequeue_timed(buf, std::chrono::milliseconds(1000))) //FIXME SIGABORT :S
if (pad->mFFData.try_dequeue(buf))
//if (mFFData.wait_dequeue_timed(buf, std::chrono::milliseconds(1000))) //FIXME SIGABORT :S
if (mFFData.try_dequeue(buf))
{
res = write(pad->mHidHandle, buf.data(), buf.size());
res = write(mHidHandle, buf.data(), buf.size());
if (res < 0)
{
printf("Error: %d\n", errno);
@ -832,7 +845,7 @@ namespace usb_pad
}
OSDebugOut(TEXT("WriterThread exited.\n"));
pad->mWriterThreadIsRunning = false;
mWriterThreadIsRunning = false;
}
} // namespace evdev

View File

@ -32,17 +32,15 @@ namespace usb_pad
(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
#define NBITS(x) ((((x)-1) / (sizeof(long) * 8)) + 1)
void EnumerateDevices(vstring& list);
void EnumerateDevices(device_list& list);
static const char* APINAME = "evdev";
static constexpr const char* APINAME = "evdev";
class EvDevPad : public Pad
{
public:
EvDevPad(int port, const char* dev_type)
: Pad(port, dev_type)
, mUseRawFF(0)
, mHidHandle(-1)
, mWriterThreadIsRunning(false)
{
}
@ -64,13 +62,15 @@ namespace usb_pad
protected:
void PollAxesValues(const device_data& device);
void SetAxis(const device_data& device, int code, int value);
static void WriterThread(void* ptr);
void WriterThread();
int mHidHandle;
EvdevFF* mEvdevFF;
struct wheel_data_t mWheelData;
int mHidHandle = -1;
EvdevFF* mEvdevFF = nullptr;
struct wheel_data_t mWheelData
{
};
std::vector<device_data> mDevices;
int32_t mUseRawFF;
int32_t mUseRawFF = 0;
std::thread mWriterThread;
std::atomic<bool> mWriterThreadIsRunning;
moodycamel::BlockingReaderWriterQueue<std::array<uint8_t, 8>, 32> mFFData;

View File

@ -85,6 +85,7 @@ namespace usb_pad
if (joyname.empty() || cfg.controls.size() != JOY_MAPS_COUNT)
return false;
RemoveSection(dev_type, port, joyname);
std::stringstream str;
for (int i = 0; i < JOY_MAPS_COUNT; i++)
{
@ -92,7 +93,7 @@ namespace usb_pad
str.str("");
str << "map_" << JoystickMapNames[i];
const std::string& name = str.str();
if (!SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
if (cfg.controls[i] >= 0 && !SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
return false;
}
@ -150,6 +151,7 @@ namespace usb_pad
if (joyname.empty())
return false;
RemoveSection(dev_type, port, joyname);
std::stringstream str;
const size_t c = countof(buzz_map_names);
@ -159,7 +161,7 @@ namespace usb_pad
str.clear();
str << "map_" << buzz_map_names[i % c] << "_" << (i / c);
const std::string& name = str.str();
if (!SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
if (cfg.controls[i] >= 0 && !SaveSetting(dev_type, port, joyname, name.c_str(), static_cast<int32_t>(cfg.controls[i])))
return false;
}
return true;
@ -174,7 +176,7 @@ namespace usb_pad
{
for (int i = 0; /*i < JOY_MAPS_COUNT && */ i < it.second.controls.size(); i++)
{
if (it.second.controls[i] == (uint16_t)-1)
if (it.second.controls[i] < 0)
continue;
const char* pc_name = "Unknown";
@ -225,7 +227,7 @@ namespace usb_pad
if (idx > -1)
{
std::string name = (cfg->joysticks.begin() + idx)->first;
std::string name = (cfg->joysticks.begin() + idx)->name;
cfg->js_iter = (cfg->joysticks.begin() + idx);
OSDebugOut("Selected player %d idx: %d dev: '%s'\n", 2 - port, idx, name.c_str());
}
@ -233,7 +235,6 @@ namespace usb_pad
static void button_clicked(GtkComboBox* widget, gpointer data)
{
int port = reinterpret_cast<uintptr_t>(data);
int type = reinterpret_cast<uintptr_t>(g_object_get_data(G_OBJECT(widget), JOYTYPE));
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
@ -254,7 +255,7 @@ namespace usb_pad
if (cfg->cb->poll(cfg->jsconf, dev_name, is_axis, value, inverted, initial))
{
auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(),
[&dev_name](auto& i) -> bool {
[&dev_name](MappingPair& i) -> bool {
return i.first == dev_name;
});
@ -275,7 +276,6 @@ namespace usb_pad
static void button_clicked_buzz(GtkComboBox* widget, gpointer data)
{
int port = reinterpret_cast<uintptr_t>(data);
int type = reinterpret_cast<uintptr_t>(g_object_get_data(G_OBJECT(widget), JOYTYPE));
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
@ -295,7 +295,7 @@ namespace usb_pad
if (cfg->cb->poll(cfg->jsconf, dev_name, false, value, inverted, initial))
{
auto it = std::find_if(cfg->jsconf.begin(), cfg->jsconf.end(),
[&dev_name](auto& i) -> bool {
[&dev_name](MappingPair& i) -> bool {
return i.first == dev_name;
});
@ -333,7 +333,7 @@ namespace usb_pad
auto& js = cfg->jsconf;
auto it = std::find_if(js.begin(), js.end(),
[&dev_name](auto i) {
[&dev_name](MappingPair i) {
return i.first == dev_name;
});
if (it != js.end())
@ -394,19 +394,18 @@ namespace usb_pad
refresh_store(cfg);
}
static void hidraw_toggled(GtkToggleButton* widget, gpointer data)
static void checkbox_toggled(GtkToggleButton* widget, gpointer data)
{
int port = reinterpret_cast<uintptr_t>(data);
ConfigData* cfg = (ConfigData*)g_object_get_data(G_OBJECT(widget), CFG);
if (cfg)
gboolean* val = reinterpret_cast<gboolean*>(data);
if (val)
{
cfg->use_hidraw_ff_pt = (bool)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
*val = (bool)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
}
int GtkPadConfigure(int port, const char* dev_type, const char* apititle, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs)
{
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label, *rs_cb;
GtkWidget *ro_frame, *rs_cb;
GtkWidget *main_hbox, *right_vbox, *left_vbox, *treeview;
GtkWidget* button;
@ -424,17 +423,16 @@ namespace usb_pad
for (const auto& it : cfg.joysticks)
{
if ((fd = open(it.second.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
{
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
OSDebugOut("Cannot open device: %s\n", it.path.c_str());
continue;
}
ConfigMapping c;
c.fd = fd;
LoadMappings(cfg.dev_type, port, it.first, c);
cfg.jsconf.push_back(std::make_pair(it.first, c));
OSDebugOut("mappings for '%s': %zu\n", it.first.c_str(), c.controls.size());
ConfigMapping c(fd);
LoadMappings(cfg.dev_type, port, it.id, c);
cfg.jsconf.push_back(std::make_pair(it.id, c));
OSDebugOut("mappings for '%s': %zu\n", it.name.c_str(), c.controls.size());
}
refresh_store(&cfg);
@ -596,6 +594,62 @@ namespace usb_pad
gtk_box_pack_start(GTK_BOX(right_vbox), cfg.label, TRUE, TRUE, 5);
}
ro_frame = gtk_frame_new("Force feedback");
gtk_box_pack_start(GTK_BOX(right_vbox), ro_frame, TRUE, FALSE, 5);
//GtkWidget *frame_vbox = gtk_vbox_new (FALSE, 5);
//gtk_container_add (GTK_CONTAINER (ro_frame), frame_vbox);
const char* labels_buff[][2] = {{"Set gain", "Gain"}, {"Managed by game", "Autocenter strength"}};
const char* ff_var_name[][2] = {{N_GAIN_ENABLED, N_GAIN}, {N_AUTOCENTER_MANAGED, N_AUTOCENTER}};
GtkWidget* ff_scales[2];
int32_t ff_enabled[2];
GtkWidget* table = gtk_table_new(3, 2, true);
gtk_container_add(GTK_CONTAINER(ro_frame), table);
gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
GtkAttachOptions opt = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL); // default
for (int i = 0; i < 2; i++)
{
if (LoadSetting(dev_type, port, apiname, ff_var_name[i][0], ff_enabled[i]))
ff_enabled[i] = !!ff_enabled[i];
else
ff_enabled[i] = 1;
GtkWidget* chk_btn = gtk_check_button_new_with_label(labels_buff[i][0]);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_btn), (gboolean)ff_enabled[i]);
g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(checkbox_toggled), reinterpret_cast<gboolean*>(&ff_enabled[i]));
gtk_table_attach(GTK_TABLE(table), chk_btn,
2, 3,
0 + i, 1 + i,
GTK_FILL, GTK_SHRINK, 5, 1);
GtkWidget* label = gtk_label_new(labels_buff[i][1]);
gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
gtk_table_attach(GTK_TABLE(table), label,
0, 1,
0 + i, 1 + i,
GTK_FILL, GTK_SHRINK, 5, 1);
//ff_scales[i] = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 1, 100, 1);
ff_scales[i] = gtk_hscale_new_with_range(0, 100, 1);
for (int v = 0; v <= 100; v += 10)
gtk_scale_add_mark(GTK_SCALE(ff_scales[i]), v, GTK_POS_BOTTOM, nullptr);
gtk_table_attach(GTK_TABLE(table), ff_scales[i],
1, 2,
0 + i, 1 + i,
opt, opt, 5, 1);
int32_t var;
if (LoadSetting(dev_type, port, apiname, ff_var_name[i][1], var))
{
var = std::min(100, std::max(0, var));
gtk_range_set_value(GTK_RANGE(ff_scales[i]), var);
}
else
gtk_range_set_value(GTK_RANGE(ff_scales[i]), 100);
}
if (is_evdev)
{
@ -607,8 +661,8 @@ namespace usb_pad
GtkWidget* chk_btn = gtk_check_button_new_with_label("Enable");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_btn), (gboolean)cfg.use_hidraw_ff_pt);
g_object_set_data(G_OBJECT(chk_btn), CFG, &cfg);
g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(hidraw_toggled), reinterpret_cast<gpointer>(port));
//g_object_set_data(G_OBJECT(chk_btn), CFG, &cfg);
g_signal_connect(G_OBJECT(chk_btn), "toggled", G_CALLBACK(checkbox_toggled), reinterpret_cast<gboolean*>(&cfg.use_hidraw_ff_pt));
gtk_box_pack_start(GTK_BOX(frame_vbox), chk_btn, FALSE, FALSE, 5);
rs_cb = new_combobox("Device:", frame_vbox);
@ -617,12 +671,12 @@ namespace usb_pad
for (auto& it : cfg.joysticks)
{
std::stringstream str;
str << it.first;
if (strcmp(apiname, "evdev") && !it.second.empty())
str << " [" << it.second << "]";
str << it.name;
if (!strcmp(apiname, "evdev") && !it.id.empty())
str << " [" << it.id << "]";
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), str.str().c_str());
if (path == it.second)
if (path == it.path)
sel_idx = idx;
idx++;
}
@ -640,7 +694,7 @@ namespace usb_pad
{
if (cfg.js_iter != cfg.joysticks.end())
{
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->second))
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path))
ret = RESULT_FAILED;
}
@ -651,6 +705,12 @@ namespace usb_pad
{
SaveSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
}
for (int i = 0; i < 2; i++)
{
SaveSetting(dev_type, port, apiname, ff_var_name[i][0], ff_enabled[i]);
int val = gtk_range_get_value(GTK_RANGE(ff_scales[i]));
SaveSetting(dev_type, port, apiname, ff_var_name[i][1], val);
}
}
else
ret = RESULT_CANCELED;
@ -699,17 +759,17 @@ namespace usb_pad
for (const auto& it : cfg.joysticks)
{
if ((fd = open(it.second.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
if ((fd = open(it.path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
{
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
OSDebugOut("Cannot open device: %s\n", it.path.c_str());
continue;
}
ConfigMapping c;
c.fd = fd;
LoadBuzzMappings(cfg.dev_type, port, it.first, c);
cfg.jsconf.push_back(std::make_pair(it.first, c));
OSDebugOut("mappings for '%s': %lu\n", it.first.c_str(), c.controls.size());
LoadBuzzMappings(cfg.dev_type, port, it.id, c);
cfg.jsconf.push_back(std::make_pair(it.id, c));
OSDebugOut("mappings for '%s': %lu\n", it.name.c_str(), c.controls.size());
}
refresh_store(&cfg);
@ -867,7 +927,7 @@ namespace usb_pad
{
if (cfg.js_iter != cfg.joysticks.end())
{
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->second))
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->path))
ret = RESULT_FAILED;
}

View File

@ -21,8 +21,19 @@
#include "../../configuration.h"
#define N_HIDRAW_FF_PT "hidraw_ff_pt"
#define N_GAIN_ENABLED "gain_enabled"
#define N_GAIN "gain"
#define N_AUTOCENTER "autocenter"
#define N_AUTOCENTER_MANAGED "ac_managed"
typedef std::vector<std::pair<std::string, std::string>> vstring;
struct evdev_device
{
std::string name;
std::string id;
std::string path;
};
typedef std::vector<evdev_device> device_list;
GtkWidget* new_combobox(const char* label, GtkWidget* vbox);
namespace usb_pad
@ -65,7 +76,7 @@ namespace usb_pad
JOY_MAPS_COUNT
};
static const char* JoystickMapNames[] = {
static constexpr const char* JoystickMapNames[] = {
"cross",
"square",
"circle",
@ -86,7 +97,7 @@ namespace usb_pad
"throttle",
"brake"};
static const char* buzz_map_names[] = {
static constexpr const char* buzz_map_names[] = {
"red",
"yellow",
"green",
@ -103,24 +114,31 @@ namespace usb_pad
struct ConfigMapping
{
std::vector<uint16_t> controls;
std::vector<int16_t> controls;
int inverted[3];
int initial[3];
int fd = -1;
ConfigMapping() = default;
ConfigMapping(int fd_)
: fd(fd_)
{
}
};
struct ApiCallbacks
{
bool (*get_event_name)(const char* dev_type, int map, int event, const char** name);
void (*populate)(vstring& jsdata);
void (*populate)(device_list& jsdata);
bool (*poll)(const std::vector<std::pair<std::string, ConfigMapping>>& jsconf, std::string& dev_name, bool isaxis, int& value, bool& inverted, int& initial);
};
typedef std::pair<std::string, ConfigMapping> MappingPair;
struct ConfigData
{
std::vector<std::pair<std::string, ConfigMapping>> jsconf;
vstring joysticks;
vstring::const_iterator js_iter;
std::vector<MappingPair> jsconf;
device_list joysticks;
device_list::const_iterator js_iter;
GtkWidget* label;
GtkListStore* store;
GtkTreeView* treeview;

View File

@ -173,7 +173,7 @@ namespace usb_pad
return RESULT_CANCELED;
evdev::ApiCallbacks apicbs{GetEventName, EnumerateDevices, PollInput};
int ret = evdev::GtkPadConfigure(port, dev_type, "Joydev Settings", "joydev", GTK_WINDOW(data), apicbs);
int ret = evdev::GtkPadConfigure(port, dev_type, "Joydev Settings", joydev::APINAME, GTK_WINDOW(data), apicbs);
return ret;
}

View File

@ -29,7 +29,7 @@ namespace usb_pad
#define NORM(x, n) (((uint32_t)(32768 + x) * n) / 0xFFFF)
#define NORM2(x, n) (((uint32_t)(32768 + x) * n) / 0x7FFF)
void EnumerateDevices(vstring& list)
void EnumerateDevices(device_list& list)
{
int fd;
int res;
@ -69,7 +69,7 @@ namespace usb_pad
else
{
OSDebugOut("Joydev device name: %s\n", buf);
list.push_back(std::make_pair(std::string(buf), path));
list.push_back({buf, buf, path});
}
close(fd);
@ -114,7 +114,6 @@ namespace usb_pad
continue;
}
const auto& mappings = device.cfg.controls;
//Non-blocking read sets len to -1 and errno to EAGAIN if no new data
while ((len = read(device.cfg.fd, &events, sizeof(events))) > -1)
{
@ -325,9 +324,10 @@ namespace usb_pad
int JoyDevPad::Open()
{
vstring device_list;
device_list device_list;
bool has_steering;
int count;
int32_t b_gain, gain, b_ac, ac;
memset(&mWheelData, 0, sizeof(wheel_data_t));
// Setting to unpressed
@ -350,17 +350,26 @@ namespace usb_pad
EnumerateDevices(device_list);
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN_ENABLED, b_gain))
b_gain = 1;
if (!LoadSetting(mDevType, mPort, APINAME, N_GAIN, gain))
gain = 100;
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER_MANAGED, b_ac))
b_ac = 1;
if (!LoadSetting(mDevType, mPort, APINAME, N_AUTOCENTER, ac))
ac = 100;
for (const auto& it : device_list)
{
has_steering = false;
mDevices.push_back({});
struct device_data& device = mDevices.back();
device.name = it.first;
device.name = it.name;
if ((device.cfg.fd = open(it.second.c_str(), O_RDWR | O_NONBLOCK)) < 0)
if ((device.cfg.fd = open(it.path.c_str(), O_RDWR | O_NONBLOCK)) < 0)
{
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
OSDebugOut("Cannot open device: %s\n", it.path.c_str());
continue;
}
@ -441,12 +450,12 @@ namespace usb_pad
std::stringstream event;
int index = 0;
const char* tmp = it.second.c_str();
const char* tmp = it.path.c_str();
while (*tmp && !isdigit(*tmp))
tmp++;
sscanf(tmp, "%d", &index);
OSDebugOut("input index: %d of '%s'\n", index, it.second.c_str());
OSDebugOut("input index: %d of '%s'\n", index, it.path.c_str());
//TODO kernel limit is 32?
for (int j = 0; j <= 99; j++)
@ -472,15 +481,11 @@ namespace usb_pad
OSDebugOut("%s: Cannot open '%s'\n", APINAME, event.str().c_str());
}
else
mFFdev = new evdev::EvdevFF(mHandleFF);
mFFdev = new evdev::EvdevFF(mHandleFF, b_gain, gain, b_ac, ac);
}
}
return 0;
quit:
Close();
return 1;
}
int JoyDevPad::Close()

View File

@ -23,9 +23,9 @@ namespace usb_pad
namespace joydev
{
void EnumerateDevices(vstring& list);
void EnumerateDevices(device_list& list);
static const char* APINAME = "joydev";
static constexpr const char* APINAME = "joydev";
class JoyDevPad : public Pad
{
@ -50,8 +50,10 @@ namespace usb_pad
static int Configure(int port, const char* dev_type, void* data);
protected:
int mHandleFF;
struct wheel_data_t mWheelData;
int mHandleFF = -1;
struct wheel_data_t mWheelData
{
};
std::vector<evdev::device_data> mDevices;
};

View File

@ -695,7 +695,7 @@ namespace usb_pad
if (!InitHid())
return FALSE;
dgHwnd = hW;
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
SetWindowLongPtr(hW, GWLP_USERDATA, lParam);
//SendDlgItemMessage(hW, IDC_BUILD_DATE, WM_SETTEXT, 0, (LPARAM)__DATE__ " " __TIME__);
ListView_SetExtendedListViewStyle(GetDlgItem(hW, IDC_LIST1), LVS_EX_FULLROWSELECT);

View File

@ -88,6 +88,12 @@ namespace usb_pad
ffdev->SetFrictionForce(ff);
}
void SetAutoCenter(FFDevice* ffdev, const autocenter& effect)
{
OSDebugOut(_T("%s: k1 %d k2 %d clip %d\n"), __func__, effect.k1, effect.k2, effect.clip);
ffdev->SetAutoCenter((effect.k1 * effect.clip / 255) * 100 / 255); // FIXME
}
// Unless passing ff packets straight to a device, parse it here
void Pad::ParseFFData(const ff_data* ffdata, bool isDFP)
{
@ -205,6 +211,9 @@ namespace usb_pad
caps |= FF_LG_CAPS_DAMPER_CLIP;
SetDamperForce(mFFdev, ffdata->u.damper, caps);
break;
case FTYPE_AUTO_CENTER_SPRING:
SetAutoCenter(mFFdev, ffdata->u.autocenter);
break;
default:
OSDebugOut(TEXT("CMD_DOWNLOAD_AND_PLAY: unhandled force type 0x%02X in slots 0x%02X\n"), ffdata->type, slots);
break;
@ -230,9 +239,9 @@ namespace usb_pad
case FTYPE_HIGH_RESOLUTION_SPRING:
mFFdev->DisableForce(EFF_SPRING);
break;
//case FTYPE_AUTO_CENTER_SPRING:
//mFFdev->DisableSpring();
//break;
case FTYPE_AUTO_CENTER_SPRING:
mFFdev->SetAutoCenter(0);
break;
case FTYPE_FRICTION:
mFFdev->DisableForce(EFF_FRICTION);
break;

View File

@ -420,6 +420,14 @@ namespace usb_pad
buf[3] = (data.buttons >> 8) & 0xff;
buf[4] = 0xf0 | ((data.buttons >> 16) & 0xf);
break;
case WT_SEGA_SEAMIC:
buf[0] = data.steering & 0xFF;
buf[1] = data.throttle & 0xFF;
buf[2] = data.brake & 0xFF;
buf[3] = data.hatswitch & 0x0F; // 4bits?
buf[3] |= (data.buttons & 0x0F) << 4; // 4 bits // TODO Or does it start at buf[4]?
buf[4] = (data.buttons >> 4) & 0x3F; // 10 - 4 = 6 bits
break;
default:
break;
@ -629,17 +637,15 @@ namespace usb_pad
{
PADState* s = (PADState*)dev;
if (!s)
return 0;
switch (mode)
{
case FREEZE_LOAD:
if (!s)
return -1;
s->f = *(PADState::freeze*)data;
s->pad->Type((PS2WheelTypes)s->f.wheel_type);
return sizeof(PADState::freeze);
case FREEZE_SAVE:
if (!s)
return -1;
*(PADState::freeze*)data = s->f;
return sizeof(PADState::freeze);
case FREEZE_SIZE:
@ -647,7 +653,7 @@ namespace usb_pad
default:
break;
}
return -1;
return 0;
}
// ---- Rock Band drum kit ----

View File

@ -100,6 +100,25 @@ namespace usb_pad
static void Initialize();
};
class SeamicDevice
{
public:
virtual ~SeamicDevice() {}
static USBDevice* CreateDevice(int port);
static const TCHAR* Name()
{
return TEXT("Sega Seamic");
}
static const char* TypeName()
{
return "seamic";
}
static std::list<std::string> ListAPIs();
static const TCHAR* LongAPIName(const std::string& name);
static int Configure(int port, const std::string& api, void* data);
static int Freeze(int mode, USBDevice* dev, void* data);
};
// Most likely as seen on https://github.com/matlo/GIMX
#define CMD_DOWNLOAD 0x00
#define CMD_DOWNLOAD_AND_PLAY 0x01
@ -148,12 +167,15 @@ namespace usb_pad
WT_GT_FORCE, //formula gp
WT_ROCKBAND1_DRUMKIT,
WT_BUZZ_CONTROLLER,
WT_SEGA_SEAMIC,
};
inline int range_max(PS2WheelTypes type)
{
if (type == WT_DRIVING_FORCE_PRO || type == WT_DRIVING_FORCE_PRO_1102)
return 0x3FFF;
if (type == WT_SEGA_SEAMIC)
return 255;
return 0x3FF;
}
@ -296,7 +318,7 @@ namespace usb_pad
virtual void SetSpringForce(const parsed_ff_data& ff) = 0;
virtual void SetDamperForce(const parsed_ff_data& ff) = 0;
virtual void SetFrictionForce(const parsed_ff_data& ff) = 0;
//virtual void SetAutoCenter(int value) = 0;
virtual void SetAutoCenter(int value) = 0;
//virtual void SetGain(int gain) = 0;
virtual void DisableForce(EffectID force) = 0;
};
@ -1083,7 +1105,7 @@ namespace usb_pad
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
// 41 bytes
// 41 bytes
};
//Wii Rock Band drum kit

View File

@ -0,0 +1,467 @@
#include "padproxy.h"
#include "usb-pad.h"
#include "../qemu-usb/desc.h"
#include "../usb-mic/usb-mic-singstar.h"
namespace usb_pad
{
static const USBDescStrings desc_strings = {
"",
"ASCII CORPORATION",
"ASCII Mic/Joy-stick",
};
static const uint8_t dev_descriptor[] = {
/* bLength */ 0x12, //(18)
/* bDescriptorType */ 0x01, //(1)
/* bcdUSB */ WBVAL(0x0110),
/* bDeviceClass */ 0x00, //(0)
/* bDeviceSubClass */ 0x00, //(0)
/* bDeviceProtocol */ 0x00, //(0)
/* bMaxPacketSize0 */ 0x08, //(8)
/* idVendor */ WBVAL(0x0B49),
/* idProduct */ WBVAL(0x0644),
/* bcdDevice */ WBVAL(0x0100),
/* iManufacturer */ 0x01,
/* iProduct */ 0x02,
/* iSerialNumber */ 0x00,
/* bNumConfigurations */ 0x01,
};
static const uint8_t hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x95, 0x03, // Report Count (3)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x66, 0x00, 0x00, // Unit (None)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x04, // Report Size (4)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x66, 0x14, 0x00, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x95, 0x0A, // Report Count (10)
0x75, 0x01, // Report Size (1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x66, 0x00, 0x00, // Unit (None)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0A, // Usage Maximum (0x0A)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x08, // Report Count (8)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x08, // Usage Maximum (Do Not Disturb)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
0xC0, // End Collection
// 98 bytes
};
static const uint8_t config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x86, 0x00, // wTotalLength 134
0x03, // bNumInterfaces 3
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x31, // bMaxPower 98mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x01, // bInterfaceSubClass (Audio Control)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> HEADER)
0x00, 0x01, // bcdADC 1.00
WBVAL(38), // wTotalLength 38
0x01, // binCollection 0x01
0x01, // baInterfaceNr 1
0x0C, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> INPUT_TERMINAL)
0x01, // bTerminalID
0x01, 0x02, // wTerminalType (Microphone)
0x02, // bAssocTerminal
0x01, // bNrChannels 1
0x00, 0x00, // wChannelConfig
0x00, // iChannelNames
0x00, // iTerminal
0x09, // bLength
0x24, // bDescriptorType (See Next Line)
0x03, // bDescriptorSubtype (CS_INTERFACE -> OUTPUT_TERMINAL)
0x02, // bTerminalID
0x01, 0x01, // wTerminalType (USB Streaming)
0x01, // bAssocTerminal
0x03, // bSourceID
0x00, // iTerminal
0x08, // bLength
0x24, // bDescriptorType (See Next Line)
0x06, // bDescriptorSubtype (CS_INTERFACE -> FEATURE_UNIT)
0x03, // bUnitID
0x01, // bSourceID
0x01, // bControlSize 1
0x03, 0x00, // bmaControls[0] (Mute,Volume)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x00, // bNumEndpoints 0
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x01, // bAlternateSetting
0x01, // bNumEndpoints 1
0x01, // bInterfaceClass (Audio)
0x02, // bInterfaceSubClass (Audio Streaming)
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x24, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_INTERFACE -> AS_GENERAL)
0x02, // bTerminalLink
0x01, // bDelay 1
0x01, 0x00, // wFormatTag (PCM)
0x0E, // bLength
0x24, // bDescriptorType (See Next Line)
0x02, // bDescriptorSubtype (CS_INTERFACE -> FORMAT_TYPE)
0x01, // bFormatType 1
0x01, // bNrChannels (Mono)
0x02, // bSubFrameSize 2
0x10, // bBitResolution 16
0x02, // bSamFreqType 2
B3VAL(8000), // tSamFreq[1] 8000 Hz
B3VAL(11025), // tSamFreq[2] 11025 Hz
0x07, // bLength
USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType (See Next Line)
USB_ENDPOINT_IN(1), // bEndpointAddress (IN/D2H)
0x01, // bmAttributes (Isochronous, No Sync, Data EP)
WBVAL(100), // wMaxPacketSize 100
0x01, // bInterval 1 (unit depends on device speed)
0x07, // bLength
0x25, // bDescriptorType (See Next Line)
0x01, // bDescriptorSubtype (CS_ENDPOINT -> EP_GENERAL)
0x01, // bmAttributes (Sampling Freq Control)
0x00, // bLockDelayUnits
0x00, 0x00, // wLockDelay 0
USB_INTERFACE_DESC_SIZE, // bLength
USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType (Interface)
0x02, // bInterfaceNumber 2
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
USB_CLASS_HID, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
USB_DT_HID, // bDescriptorType (HID)
WBVAL(0x0100), // bcdHID 1.00
0x00, // bCountryCode
0x01, // bNumDescriptors
USB_DT_REPORT, // bDescriptorType[0] (HID)
WBVAL(98), // wDescriptorLength[0] 98
0x07, // bLength
USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType (Endpoint)
USB_ENDPOINT_IN(2), // bEndpointAddress (IN/D2H)
USB_ENDPOINT_TYPE_INTERRUPT, // bmAttributes (Interrupt)
WBVAL(8), // wMaxPacketSize 8
0x0A, // bInterval 10 (unit depends on device speed)
// 134 bytes
};
std::list<std::string> SeamicDevice::ListAPIs()
{
return RegisterPad::instance().Names();
}
const TCHAR* SeamicDevice::LongAPIName(const std::string& name)
{
auto proxy = RegisterPad::instance().Proxy(name);
if (proxy)
return proxy->Name();
return nullptr;
}
typedef struct SeamicState
{
USBDevice dev;
USBDesc desc;
USBDescDevice desc_dev;
USBDevice* mic;
Pad* pad;
uint8_t port;
struct freeze
{
int nothing;
} f;
} SeamicState;
static void pad_handle_data(USBDevice* dev, USBPacket* p)
{
SeamicState* s = (SeamicState*)dev;
uint8_t data[64];
int ret = 0;
uint8_t devep = p->ep->nr;
switch (p->pid)
{
case USB_TOKEN_IN:
if (devep == 1 && s->mic)
{
s->mic->klass.handle_data(s->mic, p);
}
else if (devep == 2 && s->pad)
{
ret = s->pad->TokenIn(data, p->iov.size);
if (ret > 0)
usb_packet_copy(p, data, MIN(ret, sizeof(data)));
else
p->status = ret;
}
else
{
goto fail;
}
break;
case USB_TOKEN_OUT:
usb_packet_copy(p, data, MIN(p->iov.size, sizeof(data)));
ret = s->pad->TokenOut(data, p->iov.size);
break;
default:
fail:
p->status = USB_RET_STALL;
break;
}
}
static void pad_handle_reset(USBDevice* dev)
{
/* XXX: do it */
SeamicState* s = (SeamicState*)dev;
s->pad->Reset();
s->mic->klass.handle_reset(s->mic);
return;
}
static void pad_handle_control(USBDevice* dev, USBPacket* p, int request, int value,
int index, int length, uint8_t* data)
{
int ret = 0;
switch (request)
{
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret < 0)
goto fail;
break;
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
OSDebugOut(TEXT("InterfaceRequest | USB_REQ_GET_DESCRIPTOR 0x%04X\n"), value);
switch (value >> 8)
{
case USB_DT_REPORT:
OSDebugOut(TEXT("Sending hid report desc.\n"));
ret = sizeof(hid_report_descriptor);
memcpy(data, hid_report_descriptor, ret);
p->actual_length = ret;
break;
default:
goto fail;
}
break;
/* hid specific requests */
case SET_REPORT:
if (length > 0)
{
OSDebugOut(TEXT("SET_REPORT: 0x%02X \n"), data[0]);
p->actual_length = 0;
//p->status = USB_RET_SUCCESS;
}
break;
case SET_IDLE:
OSDebugOut(TEXT("SET_IDLE\n"));
break;
default:
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0)
{
return;
}
fail:
p->status = USB_RET_STALL;
break;
}
}
static void pad_handle_destroy(USBDevice* dev)
{
SeamicState* s = (SeamicState*)dev;
s->mic->klass.unrealize(s->mic);
s->mic = nullptr;
delete s;
}
static int pad_open(USBDevice* dev)
{
SeamicState* s = (SeamicState*)dev;
if (s)
{
s->mic->klass.open(s->mic);
return s->pad->Open();
}
return 1;
}
static void pad_close(USBDevice* dev)
{
SeamicState* s = (SeamicState*)dev;
if (s)
{
s->mic->klass.close(s->mic);
s->pad->Close();
}
}
USBDevice* SeamicDevice::CreateDevice(int port)
{
std::string varApi;
LoadSetting(nullptr, port, TypeName(), N_DEVICE_API, varApi);
PadProxyBase* proxy = RegisterPad::instance().Proxy(varApi);
if (!proxy)
{
SysMessage(TEXT("PAD: Invalid input API.\n"));
USB_LOG("usb-pad: %s: Invalid input API.\n", TypeName());
return NULL;
}
USB_LOG("usb-pad: creating device '%s' on port %d with %s\n", TypeName(), port, varApi.c_str());
std::string api;
if (!LoadSetting(nullptr, port, usb_mic::SingstarDevice::TypeName(), N_DEVICE_API, api))
return nullptr;
USBDevice* mic = usb_mic::SingstarDevice::CreateDevice(port, api);
if (!mic)
return nullptr;
Pad* pad = proxy->CreateObject(port, TypeName());
if (!pad)
return NULL;
pad->Type(WT_SEGA_SEAMIC);
SeamicState* s = new SeamicState();
s->mic = mic;
s->desc.full = &s->desc_dev;
s->desc.str = desc_strings;
if (usb_desc_parse_dev(dev_descriptor, sizeof(dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0)
goto fail;
s->pad = pad;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = pad_handle_reset;
s->dev.klass.handle_control = pad_handle_control;
s->dev.klass.handle_data = pad_handle_data;
s->dev.klass.unrealize = pad_handle_destroy;
s->dev.klass.open = pad_open;
s->dev.klass.close = pad_close;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = s->desc.str[2]; //not really used
s->port = port;
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
pad_handle_reset((USBDevice*)s);
return (USBDevice*)s;
fail:
pad_handle_destroy((USBDevice*)s);
return nullptr;
}
int SeamicDevice::Configure(int port, const std::string& api, void* data)
{
auto proxy = RegisterPad::instance().Proxy(api);
if (proxy)
return proxy->Configure(port, TypeName(), data);
return RESULT_CANCELED;
}
int SeamicDevice::Freeze(int mode, USBDevice* dev, void* data)
{
return 0;
// SeamicState *s = (SeamicState *)dev;
// switch (mode)
// {
// case FREEZE_LOAD:
// if (!s) return -1;
// s->f = *(SeamicState::freeze *)data;
// return sizeof(SeamicState::freeze);
// case FREEZE_SAVE:
// if (!s) return -1;
// return sizeof(SeamicState::freeze);
// case FREEZE_SIZE:
// return sizeof(SeamicState::freeze);
// default:
// break;
// }
// return -1;
}
} // namespace usb_pad