mirror of https://github.com/PCSX2/pcsx2.git
USB: clang-format
This commit is contained in:
parent
56e96a8ff9
commit
0c43fa92e5
|
@ -34,18 +34,21 @@ bool configChanged = false;
|
|||
|
||||
Config conf;
|
||||
char USBfreezeID[] = "USBqemuW01";
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
char freezeID[11];
|
||||
s64 cycles;
|
||||
s64 remaining;
|
||||
OHCIState t;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
DeviceType index;
|
||||
u32 size;
|
||||
USBDevice dev;
|
||||
} device[2];
|
||||
|
||||
struct usb_packet {
|
||||
struct usb_packet
|
||||
{
|
||||
USBEndpoint ep; //usb packet endpoint
|
||||
int dev_index;
|
||||
int data_size;
|
||||
|
@ -70,7 +73,8 @@ Display *g_GSdsp;
|
|||
Window g_GSwin;
|
||||
#endif
|
||||
|
||||
Config::Config(): Log(0)
|
||||
Config::Config()
|
||||
: Log(0)
|
||||
{
|
||||
memset(&WheelType, 0, sizeof(WheelType));
|
||||
}
|
||||
|
@ -86,7 +90,8 @@ void DestroyDevices()
|
|||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if(qemu_ohci && qemu_ohci->rhport[i].port.dev) {
|
||||
if (qemu_ohci && qemu_ohci->rhport[i].port.dev)
|
||||
{
|
||||
qemu_ohci->rhport[i].port.dev->klass.unrealize(qemu_ohci->rhport[i].port.dev);
|
||||
qemu_ohci->rhport[i].port.dev = nullptr;
|
||||
}
|
||||
|
@ -111,7 +116,8 @@ USBDevice* CreateDevice(DeviceType index, int port)
|
|||
else
|
||||
SysMessage(TEXT("Device %d: Unknown device type"), 1 - port);
|
||||
|
||||
if (!device) {
|
||||
if (!device)
|
||||
{
|
||||
USB_LOG("USBqemu: failed to create device type %d on port %d\n", index, port);
|
||||
}
|
||||
return device;
|
||||
|
@ -120,7 +126,8 @@ USBDevice* CreateDevice(DeviceType index, int port)
|
|||
//TODO re-do sneaky attach
|
||||
void USBAttach(int port, USBDevice* dev, bool sneaky = false)
|
||||
{
|
||||
if (!qemu_ohci) return;
|
||||
if (!qemu_ohci)
|
||||
return;
|
||||
|
||||
USBDevice* tmp = qemu_ohci->rhport[port].port.dev;
|
||||
if (tmp)
|
||||
|
@ -152,7 +159,8 @@ USBDevice* CreateDevice(const std::string& name, int port)
|
|||
SysMessage(TEXT("Port %d: Unknown device type"), port);
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
if (!device)
|
||||
{
|
||||
USB_LOG("USBqemu: failed to create device '%s' on port %d\n", name.c_str(), port);
|
||||
}
|
||||
return device;
|
||||
|
@ -160,7 +168,8 @@ USBDevice* CreateDevice(const std::string& name, int port)
|
|||
|
||||
void CreateDevices()
|
||||
{
|
||||
if(!qemu_ohci) return; //No USBinit yet ie. called from config. dialog
|
||||
if (!qemu_ohci)
|
||||
return; //No USBinit yet ie. called from config. dialog
|
||||
DestroyDevices();
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
@ -170,7 +179,8 @@ void CreateDevices()
|
|||
}
|
||||
}
|
||||
|
||||
s32 USBinit() {
|
||||
s32 USBinit()
|
||||
{
|
||||
OSDebugOut(TEXT("USBinit\n"));
|
||||
|
||||
RegisterDevice::Register();
|
||||
|
@ -184,7 +194,8 @@ s32 USBinit() {
|
|||
}
|
||||
|
||||
qemu_ohci = ohci_create(0x1f801600, 2);
|
||||
if(!qemu_ohci) return 1;
|
||||
if (!qemu_ohci)
|
||||
return 1;
|
||||
|
||||
clocks = 0;
|
||||
remaining = 0;
|
||||
|
@ -192,7 +203,8 @@ s32 USBinit() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void USBshutdown() {
|
||||
void USBshutdown()
|
||||
{
|
||||
|
||||
OSDebugOut(TEXT("USBshutdown\n"));
|
||||
DestroyDevices();
|
||||
|
@ -203,14 +215,16 @@ void USBshutdown() {
|
|||
ram = 0;
|
||||
|
||||
//#ifdef _DEBUG
|
||||
if (conf.Log && usbLog) {
|
||||
if (conf.Log && usbLog)
|
||||
{
|
||||
fclose(usbLog);
|
||||
usbLog = nullptr;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
s32 USBopen(void *pDsp) {
|
||||
s32 USBopen(void* pDsp)
|
||||
{
|
||||
|
||||
if (conf.Log && !usbLog)
|
||||
{
|
||||
|
@ -245,9 +259,12 @@ s32 USBopen(void *pDsp) {
|
|||
OSDebugOut("X11 display %p Xwindow %lu\n", g_GSdsp, g_GSwin);
|
||||
#endif
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
shared::Initialize(pDsp);
|
||||
} catch (std::runtime_error &e) {
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
SysMessage(TEXT("%" SFMTs "\n"), e.what());
|
||||
}
|
||||
|
||||
|
@ -267,7 +284,8 @@ s32 USBopen(void *pDsp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void USBclose() {
|
||||
void USBclose()
|
||||
{
|
||||
OSDebugOut(TEXT("USBclose\n"));
|
||||
|
||||
if (usb_device[0] && usb_device[0]->klass.close)
|
||||
|
@ -277,20 +295,22 @@ void USBclose() {
|
|||
usb_device[1]->klass.close(usb_device[1]);
|
||||
|
||||
shared::Uninitialize();
|
||||
|
||||
}
|
||||
|
||||
u8 USBread8(u32 addr) {
|
||||
u8 USBread8(u32 addr)
|
||||
{
|
||||
USB_LOG("* Invalid 8bit read at address %lx\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 USBread16(u32 addr) {
|
||||
u16 USBread16(u32 addr)
|
||||
{
|
||||
USB_LOG("* Invalid 16bit read at address %lx\n", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 USBread32(u32 addr) {
|
||||
u32 USBread32(u32 addr)
|
||||
{
|
||||
u32 hard;
|
||||
|
||||
hard = ohci_mem_read(qemu_ohci, addr);
|
||||
|
@ -300,27 +320,32 @@ u32 USBread32(u32 addr) {
|
|||
return hard;
|
||||
}
|
||||
|
||||
void USBwrite8(u32 addr, u8 value) {
|
||||
void USBwrite8(u32 addr, u8 value)
|
||||
{
|
||||
USB_LOG("* Invalid 8bit write at address %lx value %x\n", addr, value);
|
||||
}
|
||||
|
||||
void USBwrite16(u32 addr, u16 value) {
|
||||
void USBwrite16(u32 addr, u16 value)
|
||||
{
|
||||
USB_LOG("* Invalid 16bit write at address %lx value %x\n", addr, value);
|
||||
}
|
||||
|
||||
void USBwrite32(u32 addr, u32 value) {
|
||||
void USBwrite32(u32 addr, u32 value)
|
||||
{
|
||||
USB_LOG("* Known 32bit write at address %lx value %lx\n", addr, value);
|
||||
ohci_mem_write(qemu_ohci, addr, value);
|
||||
}
|
||||
|
||||
extern u32 bits;
|
||||
|
||||
void USBsetRAM(void *mem) {
|
||||
void USBsetRAM(void* mem)
|
||||
{
|
||||
ram = (u8*)mem;
|
||||
Reset();
|
||||
}
|
||||
|
||||
s32 USBfreeze(int mode, freezeData *data) {
|
||||
s32 USBfreeze(int mode, freezeData* data)
|
||||
{
|
||||
USBfreezeData usbd = {0};
|
||||
|
||||
//TODO FREEZE_SIZE mismatch causes loading to fail in PCSX2 beforehand
|
||||
|
@ -409,7 +434,8 @@ s32 USBfreeze(int mode, freezeData *data) {
|
|||
memcpy(usb_device[i]->setup_buf, tmp.setup_buf, sizeof(tmp.setup_buf));
|
||||
|
||||
usb_desc_set_config(usb_device[i], tmp.configuration);
|
||||
for (int k = 0; k < 16; k++) {
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
usb_device[i]->altsetting[k] = tmp.altsetting[k];
|
||||
usb_desc_set_interface(usb_device[i], k, tmp.altsetting[k]);
|
||||
}
|
||||
|
@ -454,12 +480,10 @@ s32 USBfreeze(int mode, freezeData *data) {
|
|||
else //if (usbd.ep.pid == USB_TOKEN_OUT)
|
||||
eps = usb_device[dev_index]->ep_out;
|
||||
|
||||
for (int k = 0; k < USB_MAX_ENDPOINTS; k++) {
|
||||
for (int k = 0; k < USB_MAX_ENDPOINTS; k++)
|
||||
{
|
||||
|
||||
if (usbd.usb_packet.ep.type == eps[k].type
|
||||
&& usbd.usb_packet.ep.nr == eps[k].nr
|
||||
&& usbd.usb_packet.ep.ifnum == eps[k].ifnum
|
||||
&& usbd.usb_packet.ep.pid == eps[k].pid)
|
||||
if (usbd.usb_packet.ep.type == eps[k].type && usbd.usb_packet.ep.nr == eps[k].nr && usbd.usb_packet.ep.ifnum == eps[k].ifnum && usbd.usb_packet.ep.pid == eps[k].pid)
|
||||
{
|
||||
qemu_ohci->usb_packet.ep = &eps[k];
|
||||
break;
|
||||
|
@ -552,7 +576,8 @@ s32 USBfreeze(int mode, freezeData *data) {
|
|||
|
||||
// PCSX2 queries size before load too, so can't use actual packet length which varies :(
|
||||
data->size += 8192; // qemu_ohci->usb_packet.actual_length;
|
||||
if (qemu_ohci->usb_packet.actual_length > 8192) {
|
||||
if (qemu_ohci->usb_packet.actual_length > 8192)
|
||||
{
|
||||
fprintf(stderr, "Saving failed! USB packet is larger than 8K, try again later.\n");
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -64,4 +64,3 @@ int InitWindow(HWND);
|
|||
void UninitWindow();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
HINSTANCE hInst;
|
||||
extern bool configChanged;
|
||||
|
||||
void SysMessageA(const char *fmt, ...) {
|
||||
void SysMessageA(const char* fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
char tmp[512];
|
||||
|
||||
|
@ -35,7 +36,8 @@ void SysMessageA(const char *fmt, ...) {
|
|||
MessageBoxA(0, tmp, "Qemu USB Msg", 0);
|
||||
}
|
||||
|
||||
void SysMessageW(const wchar_t *fmt, ...) {
|
||||
void SysMessageW(const wchar_t* fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
wchar_t tmp[512];
|
||||
|
||||
|
@ -101,10 +103,12 @@ void PopulateAPIs(HWND hW, int port)
|
|||
SendDlgItemMessage(hW, port ? IDC_COMBO_API1 : IDC_COMBO_API2, CB_SETCURSEL, sel, 0);
|
||||
}
|
||||
|
||||
BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
||||
int port;
|
||||
switch(uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
SendDlgItemMessageA(hW, IDC_BUILD_DATE, WM_SETTEXT, 0, (LPARAM)__DATE__ " " __TIME__);
|
||||
LoadConfig();
|
||||
|
@ -154,7 +158,8 @@ BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
switch (HIWORD(wParam))
|
||||
{
|
||||
case CBN_SELCHANGE:
|
||||
switch (LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_COMBO_API1:
|
||||
case IDC_COMBO_API2:
|
||||
port = (LOWORD(wParam) == IDC_COMBO_API1) ? 1 : 0;
|
||||
|
@ -168,7 +173,8 @@ BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
break;
|
||||
case BN_CLICKED:
|
||||
switch(LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_CONFIGURE1:
|
||||
case IDC_CONFIGURE2:
|
||||
{
|
||||
|
@ -227,13 +233,17 @@ BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
|
||||
|
||||
EXPORT_C_(BOOL) AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch(uMsg) {
|
||||
EXPORT_C_(BOOL)
|
||||
AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
EndDialog(hW, FALSE);
|
||||
return TRUE;
|
||||
|
@ -242,7 +252,8 @@ EXPORT_C_(BOOL) AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
void USBconfigure() {
|
||||
void USBconfigure()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
RegisterDevice::Register();
|
||||
DialogBox(hInst,
|
||||
|
@ -252,7 +263,9 @@ void USBconfigure() {
|
|||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
EXPORT_C_(void) USBabout() {
|
||||
EXPORT_C_(void)
|
||||
USBabout()
|
||||
{
|
||||
DialogBox(hInst,
|
||||
MAKEINTRESOURCE(IDD_ABOUT),
|
||||
GetActiveWindow(),
|
||||
|
@ -261,7 +274,8 @@ EXPORT_C_(void) USBabout() {
|
|||
|
||||
BOOL APIENTRY DllMain(HANDLE hModule,
|
||||
DWORD dwReason,
|
||||
LPVOID lpReserved) {
|
||||
LPVOID lpReserved)
|
||||
{
|
||||
hInst = (HINSTANCE)hModule;
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -21,15 +21,16 @@ typedef struct Win32Handles
|
|||
{
|
||||
HINSTANCE hInst;
|
||||
HWND hWnd;
|
||||
Win32Handles(HINSTANCE i, HWND w):
|
||||
hInst(i),
|
||||
hWnd(w)
|
||||
Win32Handles(HINSTANCE i, HWND w)
|
||||
: hInst(i)
|
||||
, hWnd(w)
|
||||
{
|
||||
}
|
||||
} Win32Handles;
|
||||
|
||||
#define CHECKED_SET_MAX_INT(var, hDlg, nIDDlgItem, bSigned, min, max) \
|
||||
do {\
|
||||
do \
|
||||
{ \
|
||||
/*CheckControlTextIsNumber(GetDlgItem(hDlg, nIDDlgItem), bSigned, 0);*/ \
|
||||
var = GetDlgItemInt(hDlg, nIDDlgItem, NULL, bSigned); \
|
||||
if (var < min) \
|
||||
|
|
|
@ -51,7 +51,8 @@ bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TC
|
|||
{
|
||||
CIniKey* key;
|
||||
auto sect = ciniFile.GetSection(str_to_wstr(section));
|
||||
if (sect && (key = sect->GetKey(str_to_wstr(param)))) {
|
||||
if (sect && (key = sect->GetKey(str_to_wstr(param))))
|
||||
{
|
||||
value = wstr_to_str(key->GetValue());
|
||||
return true;
|
||||
}
|
||||
|
@ -62,12 +63,15 @@ bool LoadSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TC
|
|||
{
|
||||
CIniKey* key;
|
||||
auto sect = ciniFile.GetSection(str_to_wstr(section));
|
||||
if (sect && (key = sect->GetKey(str_to_wstr(param)))) {
|
||||
try {
|
||||
if (sect && (key = sect->GetKey(str_to_wstr(param))))
|
||||
{
|
||||
try
|
||||
{
|
||||
value = std::stoi(key->GetValue());
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& err) {
|
||||
catch (std::exception& err)
|
||||
{
|
||||
OSDebugOut(TEXT("%" SFMTs "\n"), err.what());
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +90,8 @@ bool SaveSettingValue(const TSTDSTRING& ini, const TSTDSTRING& section, const TC
|
|||
return true;
|
||||
}
|
||||
|
||||
void SaveConfig() {
|
||||
void SaveConfig()
|
||||
{
|
||||
|
||||
SaveSetting("MAIN", "log", conf.Log);
|
||||
|
||||
|
@ -105,8 +110,10 @@ void SaveConfig() {
|
|||
OSDebugOut(_T("ciniFile.Save: %d [%s]\n"), ret, IniPath.c_str());
|
||||
}
|
||||
|
||||
void LoadConfig() {
|
||||
std::cerr << "USB load config\n" << std::endl;
|
||||
void LoadConfig()
|
||||
{
|
||||
std::cerr << "USB load config\n"
|
||||
<< std::endl;
|
||||
ciniFile.Load(str_to_wstr(IniPath));
|
||||
|
||||
LoadSetting("MAIN", "log", conf.Log);
|
||||
|
@ -149,7 +156,8 @@ void LoadConfig() {
|
|||
void ClearSection(const TCHAR* section)
|
||||
{
|
||||
auto s = ciniFile.GetSection(str_to_wstr(section));
|
||||
if (s) {
|
||||
if (s)
|
||||
{
|
||||
s->RemoveAllKeys();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
#define PLAYER_ONE_PORT 1
|
||||
#define USB_PORT PLAYER_ONE_PORT
|
||||
|
||||
struct Config {
|
||||
struct Config
|
||||
{
|
||||
int Log;
|
||||
std::string Port[2];
|
||||
int WheelType[2];
|
||||
|
|
|
@ -46,15 +46,22 @@ enum DeviceType
|
|||
DEVTYPE_EYETOY,
|
||||
};
|
||||
|
||||
struct SelectDeviceName {
|
||||
struct SelectDeviceName
|
||||
{
|
||||
template <typename S>
|
||||
std::string operator()(const std::pair<const DeviceType, S> &x) const { return x.second->TypeName(); }
|
||||
std::string operator()(const std::pair<const DeviceType, S>& x) const
|
||||
{
|
||||
return x.second->TypeName();
|
||||
}
|
||||
};
|
||||
|
||||
class DeviceError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
DeviceError(const char* msg) : std::runtime_error(msg) {}
|
||||
DeviceError(const char* msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~DeviceError() {}
|
||||
};
|
||||
|
||||
|
@ -128,12 +135,17 @@ class RegisterProxy
|
|||
|
||||
public:
|
||||
typedef std::map<std::string, std::unique_ptr<T>> RegisterProxyMap;
|
||||
static RegisterProxy& instance() {
|
||||
static RegisterProxy& instance()
|
||||
{
|
||||
static RegisterProxy registerProxy;
|
||||
return registerProxy;
|
||||
}
|
||||
|
||||
virtual ~RegisterProxy() { Clear(); OSDebugOut("%p\n", this); }
|
||||
virtual ~RegisterProxy()
|
||||
{
|
||||
Clear();
|
||||
OSDebugOut("%p\n", this);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
|
@ -186,7 +198,8 @@ class RegisterDevice
|
|||
|
||||
public:
|
||||
typedef std::map<DeviceType, std::unique_ptr<DeviceProxyBase>> RegisterDeviceMap;
|
||||
static RegisterDevice& instance() {
|
||||
static RegisterDevice& instance()
|
||||
{
|
||||
if (!registerDevice)
|
||||
registerDevice = new RegisterDevice();
|
||||
return *registerDevice;
|
||||
|
@ -211,8 +224,7 @@ class RegisterDevice
|
|||
return nullptr;*/
|
||||
auto proxy = std::find_if(registerDeviceMap.begin(),
|
||||
registerDeviceMap.end(),
|
||||
[&name](const RegisterDeviceMap::value_type& val) -> bool
|
||||
{
|
||||
[&name](const RegisterDeviceMap::value_type& val) -> bool {
|
||||
return val.second->TypeName() == name;
|
||||
});
|
||||
if (proxy != registerDeviceMap.end())
|
||||
|
@ -233,8 +245,7 @@ class RegisterDevice
|
|||
{
|
||||
auto proxy = std::find_if(registerDeviceMap.begin(),
|
||||
registerDeviceMap.end(),
|
||||
[&name](RegisterDeviceMap::value_type& val) -> bool
|
||||
{
|
||||
[&name](RegisterDeviceMap::value_type& val) -> bool {
|
||||
return val.second->TypeName() == name;
|
||||
});
|
||||
if (proxy != registerDeviceMap.end())
|
||||
|
|
|
@ -15,4 +15,3 @@
|
|||
|
||||
#define GLIB_DISABLE_DEPRECATION_WARNINGS
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
#ifndef HELPERS_H
|
||||
#define HELPERS_H
|
||||
|
||||
struct SelectKey {
|
||||
struct SelectKey
|
||||
{
|
||||
template <typename F, typename S>
|
||||
F operator()(const std::pair<const F, S> &x) const { return x.first; }
|
||||
F operator()(const std::pair<const F, S>& x) const
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,68 +15,580 @@
|
|||
|
||||
#include "icon_buzz_24.h"
|
||||
const unsigned char icon_buzz_24[]{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa6, 0xf5,
|
||||
0xfd, 0xff, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xfd,
|
||||
0xfd, 0xff, 0xfd, 0xf6, 0xa6, 0x39, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x50, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xd6, 0x50, 0x00, 0x00, 0x00, 0x1e, 0xce,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xce, 0x1e, 0x00, 0x00, 0x8b, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8b, 0x00,
|
||||
0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x5e, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x5e, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x5e, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11,
|
||||
0x00, 0x8b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x8b, 0x00, 0x00, 0x1e, 0xce,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xce, 0x1e, 0x00, 0x00, 0x00, 0x50, 0xd6, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xd6, 0x50, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x39, 0xa6, 0xf0, 0xfd, 0xff, 0xfe,
|
||||
0xfe, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xfd,
|
||||
0xf0, 0xa6, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x39,
|
||||
0xa6,
|
||||
0xf5,
|
||||
0xfd,
|
||||
0xff,
|
||||
0xfd,
|
||||
0xfe,
|
||||
0xfe,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xfd,
|
||||
0xfd,
|
||||
0xff,
|
||||
0xfd,
|
||||
0xf6,
|
||||
0xa6,
|
||||
0x39,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x50,
|
||||
0xd6,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xd6,
|
||||
0x50,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1e,
|
||||
0xce,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xce,
|
||||
0x1e,
|
||||
0x00,
|
||||
0x00,
|
||||
0x8b,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x8b,
|
||||
0x00,
|
||||
0x11,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x11,
|
||||
0x5e,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x5e,
|
||||
0xe4,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xe4,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xe4,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xe4,
|
||||
0x5e,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x5e,
|
||||
0x11,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x11,
|
||||
0x00,
|
||||
0x8b,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x8b,
|
||||
0x00,
|
||||
0x00,
|
||||
0x1e,
|
||||
0xce,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xce,
|
||||
0x1e,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x50,
|
||||
0xd6,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xd6,
|
||||
0x50,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x39,
|
||||
0xa6,
|
||||
0xf0,
|
||||
0xfd,
|
||||
0xff,
|
||||
0xfe,
|
||||
0xfe,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xfe,
|
||||
0xfe,
|
||||
0xff,
|
||||
0xfd,
|
||||
0xf0,
|
||||
0xa6,
|
||||
0x39,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
|
|
@ -203,7 +203,8 @@ static GtkWidget* new_frame(const char *label, GtkWidget *box)
|
|||
}
|
||||
|
||||
|
||||
void USBconfigure() {
|
||||
void USBconfigure()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
|
||||
RegisterDevice::Register();
|
||||
|
@ -319,5 +320,6 @@ void USBconfigure() {
|
|||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
void CALLBACK USBabout() {
|
||||
void CALLBACK USBabout()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
#include "osdebugout.h"
|
||||
|
||||
std::wostream& operator<<(std::wostream& os, const std::string& s) {
|
||||
std::wostream& operator<<(std::wostream& os, const std::string& s)
|
||||
{
|
||||
std::wstring ws;
|
||||
ws.assign(s.begin(), s.end());
|
||||
return os << ws;
|
||||
|
|
|
@ -31,23 +31,59 @@ std::wostream& operator<<(std::wostream& os, const std::string& s);
|
|||
#ifdef _DEBUG
|
||||
#define OSDebugOut(psz_fmt, ...) _OSDebugOut(TEXT("[USBqemu] [%" SFMTs "]:%d\t") psz_fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) _OSDebugOut(TEXT(psz_fmt), ##__VA_ARGS__)
|
||||
#define OSDebugOutStream_noprfx(psz_str) do{ TSTDSTRINGSTREAM ss; ss << psz_str; _OSDebugOut(_T("%s\n"), ss.str().c_str()); }while(0)
|
||||
#define OSDebugOutStream_noprfx(psz_str) \
|
||||
do \
|
||||
{ \
|
||||
TSTDSTRINGSTREAM ss; \
|
||||
ss << psz_str; \
|
||||
_OSDebugOut(_T("%s\n"), ss.str().c_str()); \
|
||||
} while (0)
|
||||
#else
|
||||
#define OSDebugOut(psz_fmt, ...) do{}while(0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) do{}while(0)
|
||||
#define OSDebugOutStream_noprfx(str) do{}while(0)
|
||||
#define OSDebugOut(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define OSDebugOutStream_noprfx(str) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#else //_WIN32
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define OSDebugOut(psz_fmt, ...) do{ fprintf(stderr, "[USBqemu] [%s]:%d\t" psz_fmt, __func__, __LINE__, ##__VA_ARGS__); }while(0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) do{ fprintf(stderr, psz_fmt, ##__VA_ARGS__); }while(0)
|
||||
#define OSDebugOutStream_noprfx(str) do{ std::cerr << str << std::endl; }while(0)
|
||||
#define OSDebugOut(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, "[USBqemu] [%s]:%d\t" psz_fmt, __func__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, psz_fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define OSDebugOutStream_noprfx(str) \
|
||||
do \
|
||||
{ \
|
||||
std::cerr << str << std::endl; \
|
||||
} while (0)
|
||||
#else
|
||||
#define OSDebugOut(psz_fmt, ...) do{}while(0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) do{}while(0)
|
||||
#define OSDebugOutStream_noprfx(str) do{}while(0)
|
||||
#define OSDebugOut(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define OSDebugOut_noprfx(psz_fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#define OSDebugOutStream_noprfx(str) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif //_WIN32
|
||||
|
|
|
@ -99,8 +99,7 @@ errno_t mbstowcs_s(
|
|||
size_t* pReturnValue,
|
||||
wchar_t (&wcstr)[size],
|
||||
const char* mbstr,
|
||||
size_t count
|
||||
)
|
||||
size_t count)
|
||||
{
|
||||
return mbstowcs_s(pReturnValue, wcstr, size, mbstr, count);
|
||||
}
|
||||
|
@ -110,8 +109,7 @@ errno_t wcstombs_s(
|
|||
size_t* pReturnValue,
|
||||
char (&mbstr)[size],
|
||||
const wchar_t* wcstr,
|
||||
size_t count
|
||||
)
|
||||
size_t count)
|
||||
{
|
||||
return wcstombs_s(pReturnValue, mbstr, size, wcstr, count);
|
||||
}
|
||||
|
|
|
@ -25,20 +25,22 @@
|
|||
|
||||
/* Number of Downstream Ports on the root hub. */
|
||||
|
||||
#define OHCI_MAX_PORTS 15 // status regs from 0x0c54 but usb snooping
|
||||
#define OHCI_MAX_PORTS 15 // status regs from 0x0c54 but usb snooping \
|
||||
// reg is at 0x0c80, so only 11 ports?
|
||||
|
||||
extern int64_t usb_frame_time;
|
||||
extern int64_t usb_bit_time;
|
||||
|
||||
typedef struct OHCIPort {
|
||||
typedef struct OHCIPort
|
||||
{
|
||||
USBPort port;
|
||||
uint32_t ctrl;
|
||||
} OHCIPort;
|
||||
|
||||
typedef uint32_t target_phys_addr_t;
|
||||
|
||||
typedef struct OHCIState {
|
||||
typedef struct OHCIState
|
||||
{
|
||||
target_phys_addr_t mem_base;
|
||||
int mem;
|
||||
uint32_t num_ports;
|
||||
|
@ -85,7 +87,8 @@ typedef struct OHCIState {
|
|||
} OHCIState;
|
||||
|
||||
/* Host Controller Communications Area */
|
||||
struct ohci_hcca {
|
||||
struct ohci_hcca
|
||||
{
|
||||
uint32_t intr[32];
|
||||
uint16_t frame, pad;
|
||||
uint32_t done;
|
||||
|
@ -165,13 +168,16 @@ struct ohci_hcca {
|
|||
#define OHCI_BM(val, field) \
|
||||
(((val)&OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
|
||||
|
||||
#define OHCI_SET_BM(val, field, newval) do { \
|
||||
#define OHCI_SET_BM(val, field, newval) \
|
||||
do \
|
||||
{ \
|
||||
val &= ~OHCI_##field##_MASK; \
|
||||
val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
|
||||
} while (0)
|
||||
|
||||
/* endpoint descriptor */
|
||||
struct ohci_ed {
|
||||
struct ohci_ed
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t tail;
|
||||
uint32_t head;
|
||||
|
@ -179,7 +185,8 @@ struct ohci_ed {
|
|||
};
|
||||
|
||||
/* General transfer descriptor */
|
||||
struct ohci_td {
|
||||
struct ohci_td
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t cbp;
|
||||
uint32_t next;
|
||||
|
@ -187,7 +194,8 @@ struct ohci_td {
|
|||
};
|
||||
|
||||
/* Isochronous transfer descriptor */
|
||||
struct ohci_iso_td {
|
||||
struct ohci_iso_td
|
||||
{
|
||||
uint32_t flags;
|
||||
uint32_t bp;
|
||||
uint32_t next;
|
||||
|
@ -268,8 +276,7 @@ struct ohci_iso_td {
|
|||
#define OHCI_PORT_PSSC (1 << 18)
|
||||
#define OHCI_PORT_OCIC (1 << 19)
|
||||
#define OHCI_PORT_PRSC (1 << 20)
|
||||
#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
|
||||
|OHCI_PORT_OCIC|OHCI_PORT_PRSC)
|
||||
#define OHCI_PORT_WTC (OHCI_PORT_CSC | OHCI_PORT_PESC | OHCI_PORT_PSSC | OHCI_PORT_OCIC | OHCI_PORT_PRSC)
|
||||
|
||||
#define OHCI_TD_DIR_SETUP 0x0
|
||||
#define OHCI_TD_DIR_OUT 0x1
|
||||
|
|
|
@ -22,7 +22,8 @@ static void usb_device_realize(USBDevice *dev/*, Error **errp*/)
|
|||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (klass->realize) {
|
||||
if (klass->realize)
|
||||
{
|
||||
klass->realize(dev /*, errp*/);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +31,8 @@ static void usb_device_realize(USBDevice *dev/*, Error **errp*/)
|
|||
USBDevice* usb_device_find_device(USBDevice* dev, uint8_t addr)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->find_device) {
|
||||
if (klass->find_device)
|
||||
{
|
||||
return klass->find_device(dev, addr);
|
||||
}
|
||||
return NULL;
|
||||
|
@ -40,7 +42,8 @@ static void usb_device_unrealize(USBDevice *dev/*, Error **errp*/)
|
|||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
|
||||
if (klass->unrealize) {
|
||||
if (klass->unrealize)
|
||||
{
|
||||
klass->unrealize(dev /*, errp*/);
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +51,8 @@ static void usb_device_unrealize(USBDevice *dev/*, Error **errp*/)
|
|||
void usb_device_cancel_packet(USBDevice* dev, USBPacket* p)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->cancel_packet) {
|
||||
if (klass->cancel_packet)
|
||||
{
|
||||
klass->cancel_packet(dev, p);
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +60,8 @@ void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
|
|||
void usb_device_handle_attach(USBDevice* dev)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_attach) {
|
||||
if (klass->handle_attach)
|
||||
{
|
||||
klass->handle_attach(dev);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +69,8 @@ void usb_device_handle_attach(USBDevice *dev)
|
|||
void usb_device_handle_reset(USBDevice* dev)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_reset) {
|
||||
if (klass->handle_reset)
|
||||
{
|
||||
klass->handle_reset(dev);
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +79,8 @@ void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
|
|||
int value, int index, int length, uint8_t* data)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_control) {
|
||||
if (klass->handle_control)
|
||||
{
|
||||
klass->handle_control(dev, p, request, value, index, length, data);
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +88,8 @@ void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
|
|||
void usb_device_handle_data(USBDevice* dev, USBPacket* p)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_data) {
|
||||
if (klass->handle_data)
|
||||
{
|
||||
klass->handle_data(dev, p);
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +103,8 @@ void usb_device_handle_data(USBDevice *dev, USBPacket *p)
|
|||
const USBDesc* usb_device_get_usb_desc(USBDevice* dev)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (dev->usb_desc) {
|
||||
if (dev->usb_desc)
|
||||
{
|
||||
return dev->usb_desc;
|
||||
}
|
||||
return klass->usb_desc;
|
||||
|
@ -105,7 +114,8 @@ void usb_device_set_interface(USBDevice *dev, int intf,
|
|||
int alt_old, int alt_new)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->set_interface) {
|
||||
if (klass->set_interface)
|
||||
{
|
||||
klass->set_interface(dev, intf, alt_old, alt_new);
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +123,8 @@ void usb_device_set_interface(USBDevice *dev, int intf,
|
|||
void usb_device_flush_ep_queue(USBDevice* dev, USBEndpoint* ep)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->flush_ep_queue) {
|
||||
if (klass->flush_ep_queue)
|
||||
{
|
||||
klass->flush_ep_queue(dev, ep);
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +132,8 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
|
|||
void usb_device_ep_stopped(USBDevice* dev, USBEndpoint* ep)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->ep_stopped) {
|
||||
if (klass->ep_stopped)
|
||||
{
|
||||
klass->ep_stopped(dev, ep);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +142,8 @@ int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
|
|||
int streams)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->alloc_streams) {
|
||||
if (klass->alloc_streams)
|
||||
{
|
||||
return klass->alloc_streams(dev, eps, nr_eps, streams);
|
||||
}
|
||||
return 0;
|
||||
|
@ -139,7 +152,8 @@ int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps,
|
|||
void usb_device_free_streams(USBDevice* dev, USBEndpoint** eps, int nr_eps)
|
||||
{
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->free_streams) {
|
||||
if (klass->free_streams)
|
||||
{
|
||||
klass->free_streams(dev, eps, nr_eps);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,9 +40,11 @@ void usb_pick_speed(USBPort *port)
|
|||
USBDevice* udev = port->dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)ARRAY_SIZE(speeds); i++) {
|
||||
for (i = 0; i < (int)ARRAY_SIZE(speeds); i++)
|
||||
{
|
||||
if ((udev->speedmask & (1 << speeds[i])) &&
|
||||
(port->speedmask & (1 << speeds[i]))) {
|
||||
(port->speedmask & (1 << speeds[i])))
|
||||
{
|
||||
udev->speed = speeds[i];
|
||||
return;
|
||||
}
|
||||
|
@ -91,7 +93,8 @@ void usb_port_reset(USBPort *port)
|
|||
|
||||
void usb_device_reset(USBDevice* dev)
|
||||
{
|
||||
if (dev == NULL || !dev->attached) {
|
||||
if (dev == NULL || !dev->attached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
dev->remote_wakeup = 0;
|
||||
|
@ -105,10 +108,12 @@ void usb_wakeup(USBEndpoint *ep, unsigned int stream)
|
|||
USBDevice* dev = ep->dev;
|
||||
USBBus* bus = dev->bus; //usb_bus_from_device(dev);
|
||||
|
||||
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
|
||||
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup)
|
||||
{
|
||||
dev->port->ops->wakeup(dev->port);
|
||||
}
|
||||
if (bus && bus->ops->wakeup_endpoint) {
|
||||
if (bus && bus->ops->wakeup_endpoint)
|
||||
{
|
||||
bus->ops->wakeup_endpoint(bus, ep, stream);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +135,8 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
|||
{
|
||||
int request, value, index;
|
||||
|
||||
if (p->iov.size != 8) {
|
||||
if (p->iov.size != 8)
|
||||
{
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
|
@ -139,7 +145,8 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
|||
s->setup_index = 0;
|
||||
p->actual_length = 0;
|
||||
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
if (s->setup_len > (int32_t)sizeof(s->data_buf)) {
|
||||
if (s->setup_len > (int32_t)sizeof(s->data_buf))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
|
@ -151,21 +158,27 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
|||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||
if (s->setup_buf[0] & USB_DIR_IN)
|
||||
{
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
if (p->status == USB_RET_ASYNC)
|
||||
{
|
||||
s->setup_state = SETUP_STATE_SETUP;
|
||||
}
|
||||
if (p->status != USB_RET_SUCCESS) {
|
||||
if (p->status != USB_RET_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->actual_length < s->setup_len) {
|
||||
if (p->actual_length < s->setup_len)
|
||||
{
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->setup_len == 0)
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
else
|
||||
|
@ -185,12 +198,15 @@ static void do_token_in(USBDevice *s, USBPacket *p)
|
|||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
switch(s->setup_state) {
|
||||
switch (s->setup_state)
|
||||
{
|
||||
case SETUP_STATE_ACK:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN))
|
||||
{
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
if (p->status == USB_RET_ASYNC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
|
@ -199,14 +215,17 @@ static void do_token_in(USBDevice *s, USBPacket *p)
|
|||
break;
|
||||
|
||||
case SETUP_STATE_DATA:
|
||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||
if (s->setup_buf[0] & USB_DIR_IN)
|
||||
{
|
||||
int len = s->setup_len - s->setup_index;
|
||||
if ((size_t)len > p->iov.size) {
|
||||
if ((size_t)len > p->iov.size)
|
||||
{
|
||||
len = p->iov.size;
|
||||
}
|
||||
usb_packet_copy(p, s->data_buf + s->setup_index, len);
|
||||
s->setup_index += len;
|
||||
if (s->setup_index >= s->setup_len) {
|
||||
if (s->setup_index >= s->setup_len)
|
||||
{
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
}
|
||||
return;
|
||||
|
@ -224,25 +243,32 @@ static void do_token_out(USBDevice *s, USBPacket *p)
|
|||
{
|
||||
assert(p->ep->nr == 0);
|
||||
|
||||
switch(s->setup_state) {
|
||||
switch (s->setup_state)
|
||||
{
|
||||
case SETUP_STATE_ACK:
|
||||
if (s->setup_buf[0] & USB_DIR_IN) {
|
||||
if (s->setup_buf[0] & USB_DIR_IN)
|
||||
{
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
/* transfer OK */
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ignore additional output */
|
||||
}
|
||||
break;
|
||||
|
||||
case SETUP_STATE_DATA:
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN)) {
|
||||
if (!(s->setup_buf[0] & USB_DIR_IN))
|
||||
{
|
||||
int len = s->setup_len - s->setup_index;
|
||||
if ((size_t)len > p->iov.size) {
|
||||
if ((size_t)len > p->iov.size)
|
||||
{
|
||||
len = p->iov.size;
|
||||
}
|
||||
usb_packet_copy(p, s->data_buf + s->setup_index, len);
|
||||
s->setup_index += len;
|
||||
if (s->setup_index >= s->setup_len) {
|
||||
if (s->setup_index >= s->setup_len)
|
||||
{
|
||||
s->setup_state = SETUP_STATE_ACK;
|
||||
}
|
||||
return;
|
||||
|
@ -260,7 +286,8 @@ static void do_parameter(USBDevice *s, USBPacket *p)
|
|||
{
|
||||
int i, request, value, index;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
s->setup_buf[i] = p->parameter >> (i * 8);
|
||||
}
|
||||
|
||||
|
@ -272,7 +299,8 @@ static void do_parameter(USBDevice *s, USBPacket *p)
|
|||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
if (s->setup_len > (int32_t)sizeof(s->data_buf)) {
|
||||
if (s->setup_len > (int32_t)sizeof(s->data_buf))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
s->setup_len, sizeof(s->data_buf));
|
||||
|
@ -280,20 +308,24 @@ static void do_parameter(USBDevice *s, USBPacket *p)
|
|||
return;
|
||||
}
|
||||
|
||||
if (p->pid == USB_TOKEN_OUT) {
|
||||
if (p->pid == USB_TOKEN_OUT)
|
||||
{
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
|
||||
usb_device_handle_control(s, p, request, value, index,
|
||||
s->setup_len, s->data_buf);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
if (p->status == USB_RET_ASYNC)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->actual_length < s->setup_len) {
|
||||
if (p->actual_length < s->setup_len)
|
||||
{
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
if (p->pid == USB_TOKEN_IN)
|
||||
{
|
||||
p->actual_length = 0;
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
|
@ -305,13 +337,16 @@ static void do_parameter(USBDevice *s, USBPacket *p)
|
|||
usb_packet_complete to complete their async control packets. */
|
||||
void usb_generic_async_ctrl_complete(USBDevice* s, USBPacket* p)
|
||||
{
|
||||
if (p->status < 0) {
|
||||
if (p->status < 0)
|
||||
{
|
||||
s->setup_state = SETUP_STATE_IDLE;
|
||||
}
|
||||
|
||||
switch (s->setup_state) {
|
||||
switch (s->setup_state)
|
||||
{
|
||||
case SETUP_STATE_SETUP:
|
||||
if (p->actual_length < s->setup_len) {
|
||||
if (p->actual_length < s->setup_len)
|
||||
{
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
s->setup_state = SETUP_STATE_DATA;
|
||||
|
@ -324,10 +359,12 @@ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
|
|||
break;
|
||||
|
||||
case SETUP_STATE_PARAM:
|
||||
if (p->actual_length < s->setup_len) {
|
||||
if (p->actual_length < s->setup_len)
|
||||
{
|
||||
s->setup_len = p->actual_length;
|
||||
}
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
if (p->pid == USB_TOKEN_IN)
|
||||
{
|
||||
p->actual_length = 0;
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
}
|
||||
|
@ -343,10 +380,12 @@ USBDevice *usb_find_device(USBPort *port, uint8_t addr)
|
|||
{
|
||||
USBDevice* dev = port->dev;
|
||||
|
||||
if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT) {
|
||||
if (dev == NULL || !dev->attached || dev->state != USB_STATE_DEFAULT)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (dev->addr == addr) {
|
||||
if (dev->addr == addr)
|
||||
{
|
||||
return dev;
|
||||
}
|
||||
return usb_device_find_device(dev, addr);
|
||||
|
@ -363,13 +402,16 @@ static void usb_process_one(USBPacket *p)
|
|||
*/
|
||||
p->status = USB_RET_SUCCESS;
|
||||
|
||||
if (p->ep->nr == 0) {
|
||||
if (p->ep->nr == 0)
|
||||
{
|
||||
/* control pipe */
|
||||
if (p->parameter) {
|
||||
if (p->parameter)
|
||||
{
|
||||
do_parameter(dev, p);
|
||||
return;
|
||||
}
|
||||
switch (p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_SETUP:
|
||||
do_token_setup(dev, p);
|
||||
break;
|
||||
|
@ -382,7 +424,9 @@ static void usb_process_one(USBPacket *p)
|
|||
default:
|
||||
p->status = USB_RET_STALL;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data pipe */
|
||||
usb_device_handle_data(dev, p);
|
||||
}
|
||||
|
@ -400,7 +444,8 @@ static void usb_queue_one(USBPacket *p)
|
|||
driver will call usb_packet_complete() when done processing it. */
|
||||
void usb_handle_packet(USBDevice* dev, USBPacket* p)
|
||||
{
|
||||
if (dev == NULL) {
|
||||
if (dev == NULL)
|
||||
{
|
||||
p->status = USB_RET_NODEV;
|
||||
return;
|
||||
}
|
||||
|
@ -410,14 +455,17 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p)
|
|||
assert(p->ep != NULL);
|
||||
|
||||
/* Submitting a new packet clears halt */
|
||||
if (p->ep->halted) {
|
||||
if (p->ep->halted)
|
||||
{
|
||||
assert(QTAILQ_EMPTY(&p->ep->queue));
|
||||
p->ep->halted = false;
|
||||
}
|
||||
|
||||
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline || p->stream) {
|
||||
if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline || p->stream)
|
||||
{
|
||||
usb_process_one(p);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
if (p->status == USB_RET_ASYNC)
|
||||
{
|
||||
/* hcd drivers cannot handle async for isoc */
|
||||
assert(p->ep->type != USB_ENDPOINT_XFER_ISOC);
|
||||
/* using async for interrupt packets breaks migration */
|
||||
|
@ -425,20 +473,27 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p)
|
|||
(dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
|
||||
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
||||
QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue);
|
||||
} else if (p->status == USB_RET_ADD_TO_QUEUE) {
|
||||
}
|
||||
else if (p->status == USB_RET_ADD_TO_QUEUE)
|
||||
{
|
||||
usb_queue_one(p);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* When pipelining is enabled usb-devices must always return async,
|
||||
* otherwise packets can complete out of order!
|
||||
*/
|
||||
assert(p->stream || !p->ep->pipeline ||
|
||||
QTAILQ_EMPTY(&p->ep->queue));
|
||||
if (p->status != USB_RET_NAK) {
|
||||
if (p->status != USB_RET_NAK)
|
||||
{
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_queue_one(p);
|
||||
}
|
||||
}
|
||||
|
@ -451,7 +506,8 @@ void usb_packet_complete_one(USBDevice *dev, USBPacket *p)
|
|||
assert(p->status != USB_RET_ASYNC && p->status != USB_RET_NAK);
|
||||
|
||||
if (p->status != USB_RET_SUCCESS ||
|
||||
(p->short_not_ok && ((size_t)p->actual_length < p->iov.size))) {
|
||||
(p->short_not_ok && ((size_t)p->actual_length < p->iov.size)))
|
||||
{
|
||||
ep->halted = true;
|
||||
}
|
||||
usb_packet_set_state(p, USB_PACKET_COMPLETE);
|
||||
|
@ -469,20 +525,24 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
|||
usb_packet_check_state(p, USB_PACKET_ASYNC);
|
||||
usb_packet_complete_one(dev, p);
|
||||
|
||||
while (!QTAILQ_EMPTY(&ep->queue)) {
|
||||
while (!QTAILQ_EMPTY(&ep->queue))
|
||||
{
|
||||
p = QTAILQ_FIRST(&ep->queue);
|
||||
if (ep->halted) {
|
||||
if (ep->halted)
|
||||
{
|
||||
/* Empty the queue on a halt */
|
||||
p->status = USB_RET_REMOVE_FROM_QUEUE;
|
||||
dev->port->ops->complete(dev->port, p);
|
||||
continue;
|
||||
}
|
||||
if (p->state == USB_PACKET_ASYNC) {
|
||||
if (p->state == USB_PACKET_ASYNC)
|
||||
{
|
||||
break;
|
||||
}
|
||||
usb_packet_check_state(p, USB_PACKET_QUEUED);
|
||||
usb_process_one(p);
|
||||
if (p->status == USB_RET_ASYNC) {
|
||||
if (p->status == USB_RET_ASYNC)
|
||||
{
|
||||
usb_packet_set_state(p, USB_PACKET_ASYNC);
|
||||
break;
|
||||
}
|
||||
|
@ -499,7 +559,8 @@ void usb_cancel_packet(USBPacket * p)
|
|||
assert(usb_packet_is_inflight(p));
|
||||
usb_packet_set_state(p, USB_PACKET_CANCELED);
|
||||
QTAILQ_REMOVE(&p->ep->queue, p, queue);
|
||||
if (callback) {
|
||||
if (callback)
|
||||
{
|
||||
usb_device_cancel_packet(p->ep->dev, p);
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +581,8 @@ static const char *usb_packet_state_name(USBPacketState state)
|
|||
/*[USB_PACKET_COMPLETE] =*/"complete",
|
||||
/*[USB_PACKET_CANCELED] =*/"canceled",
|
||||
};
|
||||
if (state < ARRAY_SIZE(name)) {
|
||||
if (state < ARRAY_SIZE(name))
|
||||
{
|
||||
return name[state];
|
||||
}
|
||||
return "INVALID";
|
||||
|
@ -528,7 +590,8 @@ static const char *usb_packet_state_name(USBPacketState state)
|
|||
|
||||
void usb_packet_check_state(USBPacket* p, USBPacketState expected)
|
||||
{
|
||||
if (p->state == expected) {
|
||||
if (p->state == expected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//trace_usb_packet_state_fault(bus->busnr, dev->port->path, p->ep->nr, p,
|
||||
|
@ -585,7 +648,8 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
|
|||
assert(bytes <= INT_MAX);
|
||||
assert(p->actual_length >= 0);
|
||||
assert(p->actual_length + bytes <= iov->size);
|
||||
switch (p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_SETUP:
|
||||
case USB_TOKEN_OUT:
|
||||
iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes);
|
||||
|
@ -607,7 +671,8 @@ void usb_packet_skip(USBPacket *p, size_t bytes)
|
|||
assert(bytes <= INT_MAX);
|
||||
assert(p->actual_length >= 0);
|
||||
assert(p->actual_length + bytes <= iov->size);
|
||||
if (p->pid == USB_TOKEN_IN) {
|
||||
if (p->pid == USB_TOKEN_IN)
|
||||
{
|
||||
iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes);
|
||||
}
|
||||
p->actual_length += bytes;
|
||||
|
@ -635,7 +700,8 @@ void usb_ep_reset(USBDevice *dev)
|
|||
dev->ep_ctl.max_streams = 0;
|
||||
dev->ep_ctl.dev = dev;
|
||||
dev->ep_ctl.pipeline = false;
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++)
|
||||
{
|
||||
dev->ep_in[ep].nr = ep + 1;
|
||||
dev->ep_out[ep].nr = ep + 1;
|
||||
dev->ep_in[ep].pid = USB_TOKEN_IN;
|
||||
|
@ -661,7 +727,8 @@ void usb_ep_init(USBDevice *dev)
|
|||
|
||||
usb_ep_reset(dev);
|
||||
QTAILQ_INIT(&dev->ep_ctl.queue);
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++)
|
||||
{
|
||||
QTAILQ_INIT(&dev->ep_in[ep].queue);
|
||||
QTAILQ_INIT(&dev->ep_out[ep].queue);
|
||||
}
|
||||
|
@ -679,12 +746,16 @@ void usb_ep_dump(USBDevice *dev)
|
|||
|
||||
fprintf(stderr, "Device \"%s\", config %d\n",
|
||||
dev->product_desc, dev->configuration);
|
||||
for (ifnum = 0; ifnum < 16; ifnum++) {
|
||||
for (ifnum = 0; ifnum < 16; ifnum++)
|
||||
{
|
||||
first = 1;
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++)
|
||||
{
|
||||
if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
|
||||
dev->ep_in[ep].ifnum == ifnum) {
|
||||
if (first) {
|
||||
dev->ep_in[ep].ifnum == ifnum)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = 0;
|
||||
fprintf(stderr, " Interface %d, alternative %d\n",
|
||||
ifnum, dev->altsetting[ifnum]);
|
||||
|
@ -694,8 +765,10 @@ void usb_ep_dump(USBDevice *dev)
|
|||
dev->ep_in[ep].max_packet_size);
|
||||
}
|
||||
if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
|
||||
dev->ep_out[ep].ifnum == ifnum) {
|
||||
if (first) {
|
||||
dev->ep_out[ep].ifnum == ifnum)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = 0;
|
||||
fprintf(stderr, " Interface %d, alternative %d\n",
|
||||
ifnum, dev->altsetting[ifnum]);
|
||||
|
@ -713,11 +786,13 @@ struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
|
|||
{
|
||||
struct USBEndpoint* eps;
|
||||
|
||||
if (dev == NULL) {
|
||||
if (dev == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
eps = (pid == USB_TOKEN_IN) ? dev->ep_in : dev->ep_out;
|
||||
if (ep == 0) {
|
||||
if (ep == 0)
|
||||
{
|
||||
return &dev->ep_ctl;
|
||||
}
|
||||
assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
|
||||
|
@ -750,7 +825,8 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
|
|||
int size, microframes;
|
||||
|
||||
size = raw & 0x7ff;
|
||||
switch ((raw >> 11) & 3) {
|
||||
switch ((raw >> 11) & 3)
|
||||
{
|
||||
case 1:
|
||||
microframes = 2;
|
||||
break;
|
||||
|
@ -770,9 +846,12 @@ void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw)
|
|||
int MaxStreams;
|
||||
|
||||
MaxStreams = raw & 0x1f;
|
||||
if (MaxStreams) {
|
||||
if (MaxStreams)
|
||||
{
|
||||
uep->max_streams = 1 << MaxStreams;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
uep->max_streams = 0;
|
||||
}
|
||||
}
|
||||
|
@ -789,8 +868,10 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
|||
struct USBEndpoint* uep = usb_ep_get(dev, pid, ep);
|
||||
USBPacket* p;
|
||||
|
||||
QTAILQ_FOREACH(p, &uep->queue, queue) {
|
||||
if (p->id == id) {
|
||||
QTAILQ_FOREACH(p, &uep->queue, queue)
|
||||
{
|
||||
if (p->id == id)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@ -800,7 +881,8 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
|||
|
||||
void usb_wakeup(USBDevice* dev)
|
||||
{
|
||||
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
|
||||
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup)
|
||||
{
|
||||
dev->port->ops->wakeup(dev->port);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,16 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
|||
uint8_t bLength = 0x12;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
d->bLength = bLength;
|
||||
d->bDescriptorType = USB_DT_DEVICE;
|
||||
|
||||
if (msos && dev->bcdUSB < 0x0200) {
|
||||
if (msos && dev->bcdUSB < 0x0200)
|
||||
{
|
||||
/*
|
||||
* Version 2.0+ required for microsoft os descriptors to work.
|
||||
* Done this way so msos-desc compat property will handle both
|
||||
|
@ -42,7 +44,9 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
|
|||
*/
|
||||
d->u.device.bcdUSB_lo = usb_lo(0x0200);
|
||||
d->u.device.bcdUSB_hi = usb_hi(0x0200);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB);
|
||||
d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB);
|
||||
}
|
||||
|
@ -72,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
|
|||
uint8_t bLength = 0x0a;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -99,7 +104,8 @@ int usb_desc_config(const USBDescConfig& conf, int flags,
|
|||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
int rc;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -114,21 +120,25 @@ int usb_desc_config(const USBDescConfig& conf, int flags,
|
|||
wTotalLength += bLength;
|
||||
|
||||
/* handle grouped interfaces if any */
|
||||
for (auto& i : conf.if_groups) {
|
||||
for (auto& i : conf.if_groups)
|
||||
{
|
||||
rc = usb_desc_iface_group(i, flags,
|
||||
dest + wTotalLength,
|
||||
len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
wTotalLength += rc;
|
||||
}
|
||||
|
||||
/* handle normal (ungrouped / no IAD) interfaces if any */
|
||||
for (auto& i : conf.ifs) {
|
||||
for (auto& i : conf.ifs)
|
||||
{
|
||||
rc = usb_desc_iface(i, flags,
|
||||
dest + wTotalLength, len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
wTotalLength += rc;
|
||||
|
@ -147,7 +157,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc& iad, int flags,
|
|||
/* handle interface association descriptor */
|
||||
uint8_t bLength = 0x08;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -162,9 +173,11 @@ int usb_desc_iface_group(const USBDescIfaceAssoc& iad, int flags,
|
|||
pos += bLength;
|
||||
|
||||
/* handle associated interfaces in this group */
|
||||
for (auto& i : iad.ifs) {
|
||||
for (auto& i : iad.ifs)
|
||||
{
|
||||
int rc = usb_desc_iface(i, flags, dest + pos, len - pos);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
pos += rc;
|
||||
|
@ -180,7 +193,8 @@ int usb_desc_iface(const USBDescIface& iface, int flags,
|
|||
int rc, pos = 0;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -196,17 +210,21 @@ int usb_desc_iface(const USBDescIface& iface, int flags,
|
|||
d->u.intf.iInterface = iface.iInterface;
|
||||
pos += bLength;
|
||||
|
||||
for (auto& i : iface.descs) {
|
||||
for (auto& i : iface.descs)
|
||||
{
|
||||
rc = usb_desc_other(i, dest + pos, len - pos);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
pos += rc;
|
||||
}
|
||||
|
||||
for (auto& i : iface.eps) {
|
||||
for (auto& i : iface.eps)
|
||||
{
|
||||
rc = usb_desc_endpoint(i, flags, dest + pos, len - pos);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
pos += rc;
|
||||
|
@ -223,7 +241,8 @@ int usb_desc_endpoint(const USBDescEndpoint& ep, int flags,
|
|||
uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < (size_t)(bLength + extralen + superlen)) {
|
||||
if (len < (size_t)(bLength + extralen + superlen))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -235,12 +254,14 @@ int usb_desc_endpoint(const USBDescEndpoint& ep, int flags,
|
|||
d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep.wMaxPacketSize);
|
||||
d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep.wMaxPacketSize);
|
||||
d->u.endpoint.bInterval = ep.bInterval;
|
||||
if (ep.is_audio) {
|
||||
if (ep.is_audio)
|
||||
{
|
||||
d->u.endpoint.bRefresh = ep.bRefresh;
|
||||
d->u.endpoint.bSynchAddress = ep.bSynchAddress;
|
||||
}
|
||||
|
||||
if (superlen) {
|
||||
if (superlen)
|
||||
{
|
||||
USBDescriptor* d = (USBDescriptor*)(dest + bLength);
|
||||
|
||||
d->bLength = 0x06;
|
||||
|
@ -254,7 +275,8 @@ int usb_desc_endpoint(const USBDescEndpoint& ep, int flags,
|
|||
usb_hi(ep.wBytesPerInterval);
|
||||
}
|
||||
|
||||
if (ep.extra) {
|
||||
if (ep.extra)
|
||||
{
|
||||
memcpy(dest + bLength + superlen, ep.extra, extralen);
|
||||
}
|
||||
|
||||
|
@ -265,7 +287,8 @@ int usb_desc_other(const USBDescOther& desc, uint8_t *dest, size_t len)
|
|||
{
|
||||
int bLength = desc.length ? desc.length : desc.data[0];
|
||||
|
||||
if (len < (size_t)bLength) {
|
||||
if (len < (size_t)bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -278,7 +301,8 @@ static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len)
|
|||
uint8_t bLength = 0x07;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -299,7 +323,8 @@ static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
|
|||
uint8_t bLength = 0x0a;
|
||||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -315,19 +340,24 @@ static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len)
|
|||
d->u.cap.u.super.wU2DevExitLat_lo = 0x20;
|
||||
d->u.cap.u.super.wU2DevExitLat_hi = 0;
|
||||
|
||||
if (desc->full) {
|
||||
if (desc->full)
|
||||
{
|
||||
d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1);
|
||||
d->u.cap.u.super.bFunctionalitySupport = 1;
|
||||
}
|
||||
if (desc->high) {
|
||||
if (desc->high)
|
||||
{
|
||||
d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2);
|
||||
if (!d->u.cap.u.super.bFunctionalitySupport) {
|
||||
if (!d->u.cap.u.super.bFunctionalitySupport)
|
||||
{
|
||||
d->u.cap.u.super.bFunctionalitySupport = 2;
|
||||
}
|
||||
}
|
||||
if (desc->super) {
|
||||
if (desc->super)
|
||||
{
|
||||
d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3);
|
||||
if (!d->u.cap.u.super.bFunctionalitySupport) {
|
||||
if (!d->u.cap.u.super.bFunctionalitySupport)
|
||||
{
|
||||
d->u.cap.u.super.bFunctionalitySupport = 3;
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +373,8 @@ static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
|
|||
USBDescriptor* d = (USBDescriptor*)dest;
|
||||
int rc;
|
||||
|
||||
if (len < bLength) {
|
||||
if (len < bLength)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -352,20 +383,24 @@ static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len)
|
|||
|
||||
wTotalLength += bLength;
|
||||
|
||||
if (desc->high != NULL) {
|
||||
if (desc->high != NULL)
|
||||
{
|
||||
rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength,
|
||||
len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
wTotalLength += rc;
|
||||
bNumDeviceCaps++;
|
||||
}
|
||||
|
||||
if (desc->super != NULL) {
|
||||
if (desc->super != NULL)
|
||||
{
|
||||
rc = usb_desc_cap_super(desc, dest + wTotalLength,
|
||||
len - wTotalLength);
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
wTotalLength += rc;
|
||||
|
@ -516,14 +551,18 @@ static void usb_desc_ep_init(USBDevice *dev)
|
|||
int i, e, pid, ep;
|
||||
|
||||
usb_ep_init(dev);
|
||||
for (i = 0; i < dev->ninterfaces; i++) {
|
||||
for (i = 0; i < dev->ninterfaces; i++)
|
||||
{
|
||||
iface = dev->ifaces[i];
|
||||
if (iface == NULL) {
|
||||
if (iface == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (e = 0; e < iface->bNumEndpoints; e++) {
|
||||
for (e = 0; e < iface->bNumEndpoints; e++)
|
||||
{
|
||||
pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
|
||||
USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
USB_TOKEN_IN :
|
||||
USB_TOKEN_OUT;
|
||||
ep = iface->eps[e].bEndpointAddress & 0x0f;
|
||||
usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
|
||||
usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
|
||||
|
@ -538,20 +577,26 @@ static void usb_desc_ep_init(USBDevice *dev)
|
|||
static const USBDescIface* usb_desc_find_interface(USBDevice* dev,
|
||||
int nif, int alt)
|
||||
{
|
||||
if (!dev->config) {
|
||||
if (!dev->config)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
for (auto& g : dev->config->if_groups) {
|
||||
for (auto& iface : g.ifs) {
|
||||
for (auto& g : dev->config->if_groups)
|
||||
{
|
||||
for (auto& iface : g.ifs)
|
||||
{
|
||||
if (iface.bInterfaceNumber == nif &&
|
||||
iface.bAlternateSetting == alt) {
|
||||
iface.bAlternateSetting == alt)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto& iface : dev->config->ifs) {
|
||||
for (auto& iface : dev->config->ifs)
|
||||
{
|
||||
if (iface.bInterfaceNumber == nif &&
|
||||
iface.bAlternateSetting == alt) {
|
||||
iface.bAlternateSetting == alt)
|
||||
{
|
||||
return &iface;
|
||||
}
|
||||
}
|
||||
|
@ -565,7 +610,8 @@ int usb_desc_set_interface(USBDevice *dev, int index, int value)
|
|||
int old;
|
||||
|
||||
iface = usb_desc_find_interface(dev, index, value);
|
||||
if (iface == NULL) {
|
||||
if (iface == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -574,7 +620,8 @@ int usb_desc_set_interface(USBDevice *dev, int index, int value)
|
|||
dev->ifaces[index] = iface;
|
||||
usb_desc_ep_init(dev);
|
||||
|
||||
if (old != value) {
|
||||
if (old != value)
|
||||
{
|
||||
usb_device_set_interface(dev, index, old, value);
|
||||
}
|
||||
return 0;
|
||||
|
@ -585,13 +632,18 @@ int usb_desc_set_config(USBDevice *dev, int value)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (value == 0) {
|
||||
if (value == 0)
|
||||
{
|
||||
dev->configuration = 0;
|
||||
dev->ninterfaces = 0;
|
||||
dev->config = NULL;
|
||||
} else {
|
||||
for (auto& i : dev->device->confs) {
|
||||
if (i.bConfigurationValue == value) {
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& i : dev->device->confs)
|
||||
{
|
||||
if (i.bConfigurationValue == value)
|
||||
{
|
||||
dev->configuration = value;
|
||||
dev->ninterfaces = i.bNumInterfaces;
|
||||
dev->config = &i;
|
||||
|
@ -603,10 +655,12 @@ int usb_desc_set_config(USBDevice *dev, int value)
|
|||
}*/
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->ninterfaces; i++) {
|
||||
for (i = 0; i < dev->ninterfaces; i++)
|
||||
{
|
||||
usb_desc_set_interface(dev, i, 0);
|
||||
}
|
||||
for (; i < USB_MAX_INTERFACES; i++) {
|
||||
for (; i < USB_MAX_INTERFACES; i++)
|
||||
{
|
||||
dev->altsetting[i] = 0;
|
||||
dev->ifaces[i] = NULL;
|
||||
}
|
||||
|
@ -619,7 +673,8 @@ static void usb_desc_setdefaults(USBDevice *dev)
|
|||
const USBDesc* desc = usb_device_get_usb_desc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
switch (dev->speed) {
|
||||
switch (dev->speed)
|
||||
{
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
dev->device = desc->full;
|
||||
|
@ -643,7 +698,8 @@ void usb_desc_init(USBDevice *dev)
|
|||
assert(desc != NULL);
|
||||
dev->speed = USB_SPEED_FULL;
|
||||
dev->speedmask = 0;
|
||||
if (desc->full) {
|
||||
if (desc->full)
|
||||
{
|
||||
dev->speedmask |= USB_SPEED_MASK_FULL;
|
||||
}
|
||||
usb_desc_setdefaults(dev);
|
||||
|
@ -659,11 +715,13 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
|
|||
uint8_t bLength, pos, i;
|
||||
const char* str;
|
||||
|
||||
if (len < 4) {
|
||||
if (len < 4)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
if (index == 0)
|
||||
{
|
||||
/* language ids */
|
||||
dest[0] = 4;
|
||||
dest[1] = USB_DT_STRING;
|
||||
|
@ -673,15 +731,18 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
|
|||
}
|
||||
|
||||
str = usb_device_get_usb_desc(dev)->str[index];
|
||||
if (str == NULL) {
|
||||
if (str == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bLength = strlen(str) * 2 + 2;
|
||||
dest[0] = bLength;
|
||||
dest[1] = USB_DT_STRING;
|
||||
i = 0; pos = 2;
|
||||
while (pos+1 < bLength && (size_t)(pos+1) < len) {
|
||||
i = 0;
|
||||
pos = 2;
|
||||
while (pos + 1 < bLength && (size_t)(pos + 1) < len)
|
||||
{
|
||||
dest[pos++] = str[i++];
|
||||
dest[pos++] = 0;
|
||||
}
|
||||
|
@ -699,24 +760,30 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
|||
uint8_t index = value & 0xff;
|
||||
int flags, ret = -1;
|
||||
|
||||
if (dev->speed == USB_SPEED_HIGH) {
|
||||
if (dev->speed == USB_SPEED_HIGH)
|
||||
{
|
||||
other_dev = usb_device_get_usb_desc(dev)->full;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
other_dev = usb_device_get_usb_desc(dev)->high;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
if (dev->device->bcdUSB >= 0x0300) {
|
||||
if (dev->device->bcdUSB >= 0x0300)
|
||||
{
|
||||
flags |= USB_DESC_FLAG_SUPER;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
switch (type)
|
||||
{
|
||||
case USB_DT_DEVICE:
|
||||
ret = usb_desc_device(&desc->id, dev->device, msos, buf, sizeof(buf));
|
||||
//trace_usb_desc_device(dev->addr, len, ret);
|
||||
break;
|
||||
case USB_DT_CONFIG:
|
||||
if (index < dev->device->bNumConfigurations) {
|
||||
if (index < dev->device->bNumConfigurations)
|
||||
{
|
||||
ret = usb_desc_config(dev->device->confs[index], flags,
|
||||
buf, sizeof(buf));
|
||||
}
|
||||
|
@ -728,13 +795,15 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
|||
//trace_usb_desc_string(dev->addr, index, len, ret);
|
||||
break;
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
if (other_dev != NULL) {
|
||||
if (other_dev != NULL)
|
||||
{
|
||||
ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf));
|
||||
}
|
||||
//trace_usb_desc_device_qualifier(dev->addr, len, ret);
|
||||
break;
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
if (other_dev != NULL && index < other_dev->bNumConfigurations) {
|
||||
if (other_dev != NULL && index < other_dev->bNumConfigurations)
|
||||
{
|
||||
ret = usb_desc_config(other_dev->confs[index], flags,
|
||||
buf, sizeof(buf));
|
||||
buf[0x01] = USB_DT_OTHER_SPEED_CONFIG;
|
||||
|
@ -756,8 +825,10 @@ int usb_desc_get_descriptor(USBDevice *dev, USBPacket *p,
|
|||
break;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
if ((size_t)ret > len) {
|
||||
if (ret > 0)
|
||||
{
|
||||
if ((size_t)ret > len)
|
||||
{
|
||||
ret = len;
|
||||
}
|
||||
memcpy(dest, buf, ret);
|
||||
|
@ -773,7 +844,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|||
assert(usb_device_get_usb_desc(dev) != NULL);
|
||||
int ret = -1;
|
||||
|
||||
switch(request) {
|
||||
switch (request)
|
||||
{
|
||||
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||
dev->addr = value;
|
||||
//trace_usb_set_addr(dev->addr);
|
||||
|
@ -798,9 +870,11 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|||
//trace_usb_set_config(dev->addr, value, ret);
|
||||
break;
|
||||
|
||||
case DeviceRequest | USB_REQ_GET_STATUS: {
|
||||
case DeviceRequest | USB_REQ_GET_STATUS:
|
||||
{
|
||||
const USBDescConfig* config = dev->config ?
|
||||
dev->config : &dev->device->confs[0];
|
||||
dev->config :
|
||||
&dev->device->confs[0];
|
||||
|
||||
data[0] = 0;
|
||||
/*
|
||||
|
@ -809,10 +883,12 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|||
* We return the same value that a configured device would return if
|
||||
* it used the first configuration.
|
||||
*/
|
||||
if (config->bmAttributes & USB_CFG_ATT_SELFPOWER) {
|
||||
if (config->bmAttributes & USB_CFG_ATT_SELFPOWER)
|
||||
{
|
||||
data[0] |= 1 << USB_DEVICE_SELF_POWERED;
|
||||
}
|
||||
if (dev->remote_wakeup) {
|
||||
if (dev->remote_wakeup)
|
||||
{
|
||||
data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
|
||||
}
|
||||
data[1] = 0x00;
|
||||
|
@ -821,14 +897,16 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|||
break;
|
||||
}
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->remote_wakeup = 0;
|
||||
ret = 0;
|
||||
}
|
||||
//trace_usb_clear_device_feature(dev->addr, value, ret);
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->remote_wakeup = 1;
|
||||
ret = 0;
|
||||
}
|
||||
|
@ -843,7 +921,8 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
|
|||
break;
|
||||
*/
|
||||
case InterfaceRequest | USB_REQ_GET_INTERFACE:
|
||||
if (index < 0 || index >= dev->ninterfaces) {
|
||||
if (index < 0 || index >= dev->ninterfaces)
|
||||
{
|
||||
break;
|
||||
}
|
||||
data[0] = dev->altsetting[index];
|
||||
|
|
|
@ -20,11 +20,14 @@
|
|||
#include "../platcompat.h"
|
||||
|
||||
/* binary representation */
|
||||
PACK(typedef struct USBDescriptor {
|
||||
PACK(
|
||||
typedef struct USBDescriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t bcdUSB_lo;
|
||||
uint8_t bcdUSB_hi;
|
||||
uint8_t bDeviceClass;
|
||||
|
@ -42,7 +45,8 @@ PACK(typedef struct USBDescriptor {
|
|||
uint8_t iSerialNumber;
|
||||
uint8_t bNumConfigurations;
|
||||
} device;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bcdUSB_lo;
|
||||
uint8_t bcdUSB_hi;
|
||||
uint8_t bDeviceClass;
|
||||
|
@ -52,7 +56,8 @@ PACK(typedef struct USBDescriptor {
|
|||
uint8_t bNumConfigurations;
|
||||
uint8_t bReserved;
|
||||
} device_qualifier;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t wTotalLength_lo;
|
||||
uint8_t wTotalLength_hi;
|
||||
uint8_t bNumInterfaces;
|
||||
|
@ -61,7 +66,8 @@ PACK(typedef struct USBDescriptor {
|
|||
uint8_t bmAttributes;
|
||||
uint8_t bMaxPower;
|
||||
} config;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t bNumEndpoints;
|
||||
|
@ -70,7 +76,8 @@ PACK(typedef struct USBDescriptor {
|
|||
uint8_t bInterfaceProtocol;
|
||||
uint8_t iInterface;
|
||||
} intf;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t wMaxPacketSize_lo;
|
||||
|
@ -79,27 +86,33 @@ PACK(typedef struct USBDescriptor {
|
|||
uint8_t bRefresh; /* only audio ep */
|
||||
uint8_t bSynchAddress; /* only audio ep */
|
||||
} endpoint;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bMaxBurst;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t wBytesPerInterval_lo;
|
||||
uint8_t wBytesPerInterval_hi;
|
||||
} super_endpoint;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t wTotalLength_lo;
|
||||
uint8_t wTotalLength_hi;
|
||||
uint8_t bNumDeviceCaps;
|
||||
} bos;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bDevCapabilityType;
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t bmAttributes_1;
|
||||
uint8_t bmAttributes_2;
|
||||
uint8_t bmAttributes_3;
|
||||
uint8_t bmAttributes_4;
|
||||
} usb2_ext;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t bmAttributes;
|
||||
uint8_t wSpeedsSupported_lo;
|
||||
uint8_t wSpeedsSupported_hi;
|
||||
|
@ -111,9 +124,11 @@ PACK(typedef struct USBDescriptor {
|
|||
} u;
|
||||
} cap;
|
||||
} u;
|
||||
}, USBDescriptor);
|
||||
},
|
||||
USBDescriptor);
|
||||
|
||||
struct USBDescID {
|
||||
struct USBDescID
|
||||
{
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
uint16_t bcdDevice;
|
||||
|
@ -122,7 +137,8 @@ struct USBDescID {
|
|||
uint8_t iSerialNumber;
|
||||
};
|
||||
|
||||
struct USBDescDevice {
|
||||
struct USBDescDevice
|
||||
{
|
||||
uint16_t bcdUSB;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
|
@ -133,7 +149,8 @@ struct USBDescDevice {
|
|||
std::vector<USBDescConfig> confs;
|
||||
};
|
||||
|
||||
struct USBDescConfig {
|
||||
struct USBDescConfig
|
||||
{
|
||||
uint8_t bNumInterfaces;
|
||||
uint8_t bConfigurationValue;
|
||||
uint8_t iConfiguration;
|
||||
|
@ -150,7 +167,8 @@ struct USBDescConfig {
|
|||
};
|
||||
|
||||
/* conceptually an Interface Association Descriptor, and releated interfaces */
|
||||
struct USBDescIfaceAssoc {
|
||||
struct USBDescIfaceAssoc
|
||||
{
|
||||
uint8_t bFirstInterface;
|
||||
uint8_t bInterfaceCount;
|
||||
uint8_t bFunctionClass;
|
||||
|
@ -162,7 +180,8 @@ struct USBDescIfaceAssoc {
|
|||
std::vector<USBDescIface> ifs;
|
||||
};
|
||||
|
||||
struct USBDescIface {
|
||||
struct USBDescIface
|
||||
{
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t bNumEndpoints;
|
||||
|
@ -176,7 +195,8 @@ struct USBDescIface {
|
|||
std::vector<USBDescEndpoint> eps;
|
||||
};
|
||||
|
||||
struct USBDescEndpoint {
|
||||
struct USBDescEndpoint
|
||||
{
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint16_t wMaxPacketSize;
|
||||
|
@ -193,12 +213,14 @@ struct USBDescEndpoint {
|
|||
uint16_t wBytesPerInterval;
|
||||
};
|
||||
|
||||
struct USBDescOther {
|
||||
struct USBDescOther
|
||||
{
|
||||
uint8_t length;
|
||||
const uint8_t* data;
|
||||
};
|
||||
|
||||
struct USBDescMSOS {
|
||||
struct USBDescMSOS
|
||||
{
|
||||
const char* CompatibleID;
|
||||
const wchar_t* Label;
|
||||
bool SelectiveSuspendEnabled;
|
||||
|
@ -206,7 +228,8 @@ struct USBDescMSOS {
|
|||
|
||||
typedef const char* USBDescStrings[256];
|
||||
|
||||
struct USBDesc {
|
||||
struct USBDesc
|
||||
{
|
||||
USBDescID id;
|
||||
const USBDescDevice* full;
|
||||
const USBDescDevice* high;
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
*
|
||||
* Returns: a pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
my_g_malloc (size_t n_bytes)
|
||||
void* my_g_malloc(size_t n_bytes)
|
||||
{
|
||||
if (G_LIKELY(n_bytes))
|
||||
{
|
||||
|
@ -57,8 +56,7 @@ my_g_malloc (size_t n_bytes)
|
|||
*
|
||||
* Returns: a pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
my_g_malloc0 (size_t n_bytes)
|
||||
void* my_g_malloc0(size_t n_bytes)
|
||||
{
|
||||
if (G_LIKELY(n_bytes))
|
||||
{
|
||||
|
@ -88,8 +86,7 @@ my_g_malloc0 (size_t n_bytes)
|
|||
* Since: 2.24
|
||||
* Returns: a pointer to the allocated memory
|
||||
*/
|
||||
void*
|
||||
my_g_malloc_n (size_t n_blocks,
|
||||
void* my_g_malloc_n(size_t n_blocks,
|
||||
size_t n_block_bytes)
|
||||
{
|
||||
if (SIZE_OVERFLOWS(n_blocks, n_block_bytes))
|
||||
|
@ -114,8 +111,7 @@ my_g_malloc_n (size_t n_blocks,
|
|||
*
|
||||
* Returns: the new address of the allocated memory
|
||||
*/
|
||||
void*
|
||||
my_g_realloc (void* mem,
|
||||
void* my_g_realloc(void* mem,
|
||||
size_t n_bytes)
|
||||
{
|
||||
void* newmem;
|
||||
|
@ -151,8 +147,7 @@ my_g_realloc (void* mem,
|
|||
* Since: 2.24
|
||||
* Returns: the new address of the allocated memory
|
||||
*/
|
||||
void*
|
||||
my_g_realloc_n (void* mem,
|
||||
void* my_g_realloc_n(void* mem,
|
||||
size_t n_blocks,
|
||||
size_t n_block_bytes)
|
||||
{
|
||||
|
|
|
@ -33,39 +33,263 @@
|
|||
/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
|
||||
* above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
|
||||
static const uint8_t hid_usage_keys[0x100] = {
|
||||
0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
||||
0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
|
||||
0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
|
||||
0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
|
||||
0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
|
||||
0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
|
||||
0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
|
||||
0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
|
||||
0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
|
||||
0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
|
||||
0x5a, 0x5b, 0x62, 0x63, 0x46, 0x00, 0x64, 0x44,
|
||||
0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
|
||||
0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
|
||||
0x00,
|
||||
0x29,
|
||||
0x1e,
|
||||
0x1f,
|
||||
0x20,
|
||||
0x21,
|
||||
0x22,
|
||||
0x23,
|
||||
0x24,
|
||||
0x25,
|
||||
0x26,
|
||||
0x27,
|
||||
0x2d,
|
||||
0x2e,
|
||||
0x2a,
|
||||
0x2b,
|
||||
0x14,
|
||||
0x1a,
|
||||
0x08,
|
||||
0x15,
|
||||
0x17,
|
||||
0x1c,
|
||||
0x18,
|
||||
0x0c,
|
||||
0x12,
|
||||
0x13,
|
||||
0x2f,
|
||||
0x30,
|
||||
0x28,
|
||||
0xe0,
|
||||
0x04,
|
||||
0x16,
|
||||
0x07,
|
||||
0x09,
|
||||
0x0a,
|
||||
0x0b,
|
||||
0x0d,
|
||||
0x0e,
|
||||
0x0f,
|
||||
0x33,
|
||||
0x34,
|
||||
0x35,
|
||||
0xe1,
|
||||
0x31,
|
||||
0x1d,
|
||||
0x1b,
|
||||
0x06,
|
||||
0x19,
|
||||
0x05,
|
||||
0x11,
|
||||
0x10,
|
||||
0x36,
|
||||
0x37,
|
||||
0x38,
|
||||
0xe5,
|
||||
0x55,
|
||||
0xe2,
|
||||
0x2c,
|
||||
0x39,
|
||||
0x3a,
|
||||
0x3b,
|
||||
0x3c,
|
||||
0x3d,
|
||||
0x3e,
|
||||
0x3f,
|
||||
0x40,
|
||||
0x41,
|
||||
0x42,
|
||||
0x43,
|
||||
0x53,
|
||||
0x47,
|
||||
0x5f,
|
||||
0x60,
|
||||
0x61,
|
||||
0x56,
|
||||
0x5c,
|
||||
0x5d,
|
||||
0x5e,
|
||||
0x57,
|
||||
0x59,
|
||||
0x5a,
|
||||
0x5b,
|
||||
0x62,
|
||||
0x63,
|
||||
0x46,
|
||||
0x00,
|
||||
0x64,
|
||||
0x44,
|
||||
0x45,
|
||||
0x68,
|
||||
0x69,
|
||||
0x6a,
|
||||
0x6b,
|
||||
0x6c,
|
||||
0x6d,
|
||||
0x6e,
|
||||
0xe8,
|
||||
0xe9,
|
||||
0x71,
|
||||
0x72,
|
||||
0x73,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x85,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xe3,
|
||||
0xe7,
|
||||
0x65,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
|
||||
0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a,
|
||||
0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
|
||||
0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x58,
|
||||
0xe4,
|
||||
0x00,
|
||||
0x00,
|
||||
0x7f,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x81,
|
||||
0x00,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x54,
|
||||
0x00,
|
||||
0x46,
|
||||
0xe6,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x48,
|
||||
0x48,
|
||||
0x4a,
|
||||
0x52,
|
||||
0x4b,
|
||||
0x00,
|
||||
0x50,
|
||||
0x00,
|
||||
0x4f,
|
||||
0x00,
|
||||
0x4d,
|
||||
0x51,
|
||||
0x4e,
|
||||
0x49,
|
||||
0x4c,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xe3,
|
||||
0xe7,
|
||||
0x65,
|
||||
0x66,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
bool hid_has_events(HIDState* hs)
|
||||
|
@ -111,8 +335,7 @@ static void hid_pointer_event(HIDState *hs, InputEvent *evt)
|
|||
/*[INPUT_BUTTON_LEFT] =*/0x01,
|
||||
/*[INPUT_BUTTON_MIDDLE] =*/0x04,
|
||||
/*[INPUT_BUTTON_RIGHT] =*/0x02,
|
||||
0,0,0,0
|
||||
};
|
||||
0, 0, 0, 0};
|
||||
HIDPointerEvent* e;
|
||||
InputMoveEvent* move;
|
||||
InputBtnEvent* btn;
|
||||
|
@ -120,39 +343,48 @@ static void hid_pointer_event(HIDState *hs, InputEvent *evt)
|
|||
assert(hs->n < QUEUE_LENGTH);
|
||||
e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
|
||||
switch (evt->type) {
|
||||
switch (evt->type)
|
||||
{
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
move = &evt->u.rel;
|
||||
if (move->axis == INPUT_AXIS_X) {
|
||||
if (move->axis == INPUT_AXIS_X)
|
||||
{
|
||||
e->xdx += move->value;
|
||||
}
|
||||
else if (move->axis == INPUT_AXIS_Y) {
|
||||
else if (move->axis == INPUT_AXIS_Y)
|
||||
{
|
||||
e->ydy += move->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
move = &evt->u.abs;
|
||||
if (move->axis == INPUT_AXIS_X) {
|
||||
if (move->axis == INPUT_AXIS_X)
|
||||
{
|
||||
e->xdx = move->value;
|
||||
}
|
||||
else if (move->axis == INPUT_AXIS_Y) {
|
||||
else if (move->axis == INPUT_AXIS_Y)
|
||||
{
|
||||
e->ydy = move->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
btn = &evt->u.btn;
|
||||
if (btn->down) {
|
||||
if (btn->down)
|
||||
{
|
||||
e->buttons_state |= bmap[btn->button];
|
||||
if (btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
if (btn->button == INPUT_BUTTON_WHEEL_UP)
|
||||
{
|
||||
e->dz--;
|
||||
}
|
||||
else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
|
||||
else if (btn->button == INPUT_BUTTON_WHEEL_DOWN)
|
||||
{
|
||||
e->dz++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
e->buttons_state &= ~bmap[btn->button];
|
||||
}
|
||||
break;
|
||||
|
@ -161,7 +393,6 @@ static void hid_pointer_event(HIDState *hs, InputEvent *evt)
|
|||
/* keep gcc happy */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hid_pointer_sync(HIDState* hs)
|
||||
|
@ -169,7 +400,8 @@ static void hid_pointer_sync(HIDState *hs)
|
|||
HIDPointerEvent *prev, *curr, *next;
|
||||
bool event_compression = false;
|
||||
|
||||
if (hs->n == QUEUE_LENGTH - 1) {
|
||||
if (hs->n == QUEUE_LENGTH - 1)
|
||||
{
|
||||
/*
|
||||
* Queue full. We are losing information, but we at least
|
||||
* keep track of most recent button state.
|
||||
|
@ -181,40 +413,48 @@ static void hid_pointer_sync(HIDState *hs)
|
|||
curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
|
||||
|
||||
if (hs->n > 0) {
|
||||
if (hs->n > 0)
|
||||
{
|
||||
/*
|
||||
* No button state change between previous and current event
|
||||
* (and previous wasn't seen by the guest yet), so there is
|
||||
* motion information only and we can combine the two event
|
||||
* into one.
|
||||
*/
|
||||
if (curr->buttons_state == prev->buttons_state) {
|
||||
if (curr->buttons_state == prev->buttons_state)
|
||||
{
|
||||
event_compression = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event_compression) {
|
||||
if (event_compression)
|
||||
{
|
||||
/* add current motion to previous, clear current */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
if (hs->kind == HID_MOUSE)
|
||||
{
|
||||
prev->xdx += curr->xdx;
|
||||
curr->xdx = 0;
|
||||
prev->ydy += curr->ydy;
|
||||
curr->ydy = 0;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
prev->xdx = curr->xdx;
|
||||
prev->ydy = curr->ydy;
|
||||
}
|
||||
prev->dz += curr->dz;
|
||||
curr->dz = 0;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* prepate next (clear rel, copy abs + btns) */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
if (hs->kind == HID_MOUSE)
|
||||
{
|
||||
next->xdx = 0;
|
||||
next->ydy = 0;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
next->xdx = curr->xdx;
|
||||
next->ydy = curr->ydy;
|
||||
}
|
||||
|
@ -235,12 +475,15 @@ static void hid_keyboard_event(HIDState *hs, InputEvent *evt)
|
|||
count = qemu_input_key_value_to_scancode(&key->key,
|
||||
key->down,
|
||||
scancodes);
|
||||
if (hs->n + count > QUEUE_LENGTH) {
|
||||
if (hs->n + count > QUEUE_LENGTH)
|
||||
{
|
||||
//trace_hid_kbd_queue_full();
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK;
|
||||
hs->n++;
|
||||
hs->kbd.keycodes[slot] = scancodes[i];
|
||||
}
|
||||
hs->event(hs);
|
||||
|
@ -251,13 +494,17 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||
uint8_t hid_code, index, key;
|
||||
int i, keycode, slot;
|
||||
|
||||
if (hs->n == 0) {
|
||||
if (hs->n == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
|
||||
slot = hs->head & QUEUE_MASK;
|
||||
QUEUE_INCR(hs->head);
|
||||
hs->n--;
|
||||
keycode = hs->kbd.keycodes[slot];
|
||||
|
||||
if (!hs->n) {
|
||||
if (!hs->n)
|
||||
{
|
||||
//trace_hid_kbd_queue_empty();
|
||||
}
|
||||
|
||||
|
@ -266,13 +513,15 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||
hid_code = hid_usage_keys[index];
|
||||
hs->kbd.modifiers &= ~(1 << 8);
|
||||
|
||||
switch (hid_code) {
|
||||
switch (hid_code)
|
||||
{
|
||||
case 0x00:
|
||||
return;
|
||||
|
||||
case 0xe0:
|
||||
assert(key == 0x1d);
|
||||
if (hs->kbd.modifiers & (1 << 9)) {
|
||||
if (hs->kbd.modifiers & (1 << 9))
|
||||
{
|
||||
/* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
|
||||
* Here we're processing the second hid_code. By dropping bit 9
|
||||
* and setting bit 8, the scancode after 0x1d will access the
|
||||
|
@ -294,7 +543,8 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||
/* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
|
||||
* Handle releases here, or fall through to process presses.
|
||||
*/
|
||||
if (keycode & (1 << 7)) {
|
||||
if (keycode & (1 << 7))
|
||||
{
|
||||
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
|
||||
return;
|
||||
}
|
||||
|
@ -323,30 +573,40 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||
break;
|
||||
}
|
||||
|
||||
if (keycode & (1 << 7)) {
|
||||
for (i = hs->kbd.keys - 1; i >= 0; i--) {
|
||||
if (hs->kbd.key[i] == hid_code) {
|
||||
if (keycode & (1 << 7))
|
||||
{
|
||||
for (i = hs->kbd.keys - 1; i >= 0; i--)
|
||||
{
|
||||
if (hs->kbd.key[i] == hid_code)
|
||||
{
|
||||
hs->kbd.key[i] = hs->kbd.key[--hs->kbd.keys];
|
||||
hs->kbd.key[hs->kbd.keys] = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
if (i < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = hs->kbd.keys - 1; i >= 0; i--) {
|
||||
if (hs->kbd.key[i] == hid_code) {
|
||||
else
|
||||
{
|
||||
for (i = hs->kbd.keys - 1; i >= 0; i--)
|
||||
{
|
||||
if (hs->kbd.key[i] == hid_code)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
if (hs->kbd.keys < (int32_t)sizeof(hs->kbd.key)) {
|
||||
if (i < 0)
|
||||
{
|
||||
if (hs->kbd.keys < (int32_t)sizeof(hs->kbd.key))
|
||||
{
|
||||
hs->kbd.key[hs->kbd.keys++] = hid_code;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -354,20 +614,24 @@ static void hid_keyboard_process_keycode(HIDState *hs)
|
|||
|
||||
static inline int int_clamp(int val, int vmin, int vmax)
|
||||
{
|
||||
if (val < vmin) {
|
||||
if (val < vmin)
|
||||
{
|
||||
return vmin;
|
||||
}
|
||||
else if (val > vmax) {
|
||||
else if (val > vmax)
|
||||
{
|
||||
return vmax;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
void hid_pointer_activate(HIDState* hs)
|
||||
{
|
||||
if (!hs->ptr.mouse_grabbed) {
|
||||
if (!hs->ptr.mouse_grabbed)
|
||||
{
|
||||
//qemu_input_handler_activate(hs->s);
|
||||
hs->ptr.mouse_grabbed = 1;
|
||||
}
|
||||
|
@ -388,13 +652,15 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
index = (hs->n ? hs->head : hs->head - 1);
|
||||
e = &hs->ptr.queue[index & QUEUE_MASK];
|
||||
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
if (hs->kind == HID_MOUSE)
|
||||
{
|
||||
dx = int_clamp(e->xdx, -127, 127);
|
||||
dy = int_clamp(e->ydy, -127, 127);
|
||||
e->xdx -= dx;
|
||||
e->ydy -= dy;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
dx = e->xdx;
|
||||
dy = e->ydy;
|
||||
}
|
||||
|
@ -403,7 +669,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
|
||||
if (hs->n &&
|
||||
!e->dz &&
|
||||
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
|
||||
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy)))
|
||||
{
|
||||
/* that deals with this event */
|
||||
QUEUE_INCR(hs->head);
|
||||
hs->n--;
|
||||
|
@ -412,39 +679,50 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
/* Appears we have to invert the wheel direction */
|
||||
dz = 0 - dz;
|
||||
l = 0;
|
||||
switch (hs->kind) {
|
||||
switch (hs->kind)
|
||||
{
|
||||
case HID_MOUSE:
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dx;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dy;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dz;
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_TABLET:
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dx & 0xff;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dx >> 8;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dy & 0xff;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dy >> 8;
|
||||
}
|
||||
if (len > l) {
|
||||
if (len > l)
|
||||
{
|
||||
buf[l++] = dz;
|
||||
}
|
||||
break;
|
||||
|
@ -460,7 +738,8 @@ int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
{
|
||||
hs->idle_pending = false;
|
||||
|
||||
if (len < 2) {
|
||||
if (len < 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -468,10 +747,12 @@ int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
|
||||
buf[0] = hs->kbd.modifiers & 0xff;
|
||||
buf[1] = 0;
|
||||
if (hs->kbd.keys > 6) {
|
||||
if (hs->kbd.keys > 6)
|
||||
{
|
||||
memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
|
||||
}
|
||||
|
||||
|
@ -480,7 +761,8 @@ int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
|
|||
|
||||
int hid_keyboard_write(HIDState* hs, uint8_t* buf, int len)
|
||||
{
|
||||
if (len > 0) {
|
||||
if (len > 0)
|
||||
{
|
||||
int ledstate = 0;
|
||||
/* 0x01: Num Lock LED
|
||||
* 0x02: Caps Lock LED
|
||||
|
@ -488,13 +770,16 @@ int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
|
|||
* 0x08: Compose LED
|
||||
* 0x10: Kana LED */
|
||||
hs->kbd.leds = buf[0];
|
||||
if (hs->kbd.leds & 0x04) {
|
||||
if (hs->kbd.leds & 0x04)
|
||||
{
|
||||
ledstate |= QEMU_SCROLL_LOCK_LED;
|
||||
}
|
||||
if (hs->kbd.leds & 0x01) {
|
||||
if (hs->kbd.leds & 0x01)
|
||||
{
|
||||
ledstate |= QEMU_NUM_LOCK_LED;
|
||||
}
|
||||
if (hs->kbd.leds & 0x02) {
|
||||
if (hs->kbd.leds & 0x02)
|
||||
{
|
||||
ledstate |= QEMU_CAPS_LOCK_LED;
|
||||
}
|
||||
//kbd_put_ledstate(ledstate);
|
||||
|
@ -504,7 +789,8 @@ int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
|
|||
|
||||
void hid_reset(HIDState* hs)
|
||||
{
|
||||
switch (hs->kind) {
|
||||
switch (hs->kind)
|
||||
{
|
||||
case HID_KEYBOARD:
|
||||
memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
|
||||
memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
|
||||
|
@ -535,11 +821,13 @@ void hid_init(HIDState *hs, int kind, HIDEventFunc event)
|
|||
hs->kind = kind;
|
||||
hs->event = event;
|
||||
|
||||
if (hs->kind == HID_KEYBOARD) {
|
||||
if (hs->kind == HID_KEYBOARD)
|
||||
{
|
||||
hs->kbd.eh_entry = hid_keyboard_event;
|
||||
} else if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
}
|
||||
else if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET)
|
||||
{
|
||||
hs->ptr.eh_entry = hid_pointer_event;
|
||||
hs->ptr.eh_sync = hid_pointer_sync;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@
|
|||
#define SCANCODE_ALT 0x400
|
||||
#define SCANCODE_ALTGR 0x800
|
||||
|
||||
typedef enum QKeyCode {
|
||||
typedef enum QKeyCode
|
||||
{
|
||||
Q_KEY_CODE_UNMAPPED = 0,
|
||||
Q_KEY_CODE_SHIFT = 1,
|
||||
Q_KEY_CODE_SHIFT_R = 2,
|
||||
|
@ -202,7 +203,8 @@ typedef enum QKeyCode {
|
|||
Q_KEY_CODE__MAX = 148,
|
||||
} QKeyCode;
|
||||
|
||||
typedef enum InputEventKind {
|
||||
typedef enum InputEventKind
|
||||
{
|
||||
INPUT_EVENT_KIND_KEY = 0,
|
||||
INPUT_EVENT_KIND_BTN = 1,
|
||||
INPUT_EVENT_KIND_REL = 2,
|
||||
|
@ -210,19 +212,22 @@ typedef enum InputEventKind {
|
|||
INPUT_EVENT_KIND__MAX = 4,
|
||||
} InputEventKind;
|
||||
|
||||
typedef enum KeyValueKind {
|
||||
typedef enum KeyValueKind
|
||||
{
|
||||
KEY_VALUE_KIND_NUMBER = 0,
|
||||
KEY_VALUE_KIND_QCODE = 1,
|
||||
KEY_VALUE_KIND__MAX = 2,
|
||||
} KeyValueKind;
|
||||
|
||||
typedef enum InputAxis {
|
||||
typedef enum InputAxis
|
||||
{
|
||||
INPUT_AXIS_X = 0,
|
||||
INPUT_AXIS_Y = 1,
|
||||
INPUT_AXIS__MAX = 2,
|
||||
} InputAxis;
|
||||
|
||||
typedef enum InputButton {
|
||||
typedef enum InputButton
|
||||
{
|
||||
INPUT_BUTTON_LEFT = 0,
|
||||
INPUT_BUTTON_MIDDLE = 1,
|
||||
INPUT_BUTTON_RIGHT = 2,
|
||||
|
@ -233,32 +238,39 @@ typedef enum InputButton {
|
|||
INPUT_BUTTON__MAX = 7,
|
||||
} InputButton;
|
||||
|
||||
struct KeyValue {
|
||||
struct KeyValue
|
||||
{
|
||||
KeyValueKind type;
|
||||
union {
|
||||
union
|
||||
{
|
||||
int number;
|
||||
QKeyCode qcode;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct InputKeyEvent {
|
||||
struct InputKeyEvent
|
||||
{
|
||||
KeyValue key;
|
||||
bool down;
|
||||
};
|
||||
|
||||
struct InputBtnEvent {
|
||||
struct InputBtnEvent
|
||||
{
|
||||
InputButton button;
|
||||
bool down;
|
||||
};
|
||||
|
||||
struct InputMoveEvent {
|
||||
struct InputMoveEvent
|
||||
{
|
||||
InputAxis axis;
|
||||
int64_t value;
|
||||
};
|
||||
|
||||
struct InputEvent {
|
||||
struct InputEvent
|
||||
{
|
||||
InputEventKind type;
|
||||
union {
|
||||
union
|
||||
{
|
||||
InputKeyEvent key;
|
||||
InputBtnEvent btn;
|
||||
InputMoveEvent rel;
|
||||
|
@ -273,7 +285,8 @@ typedef void QEMUPutKBDEvent(HIDState *hs, InputEvent *evt);
|
|||
typedef void QEMUPutLEDEvent(void* opaque, int ledstate);
|
||||
typedef void QEMUPutMouseEvent(HIDState* hs, InputEvent* evt);
|
||||
|
||||
typedef struct HIDPointerEvent {
|
||||
typedef struct HIDPointerEvent
|
||||
{
|
||||
int32_t xdx, ydy; /* relative if it's a mouse, otherwise absolute */
|
||||
int32_t dz, buttons_state;
|
||||
} HIDPointerEvent;
|
||||
|
@ -282,14 +295,16 @@ typedef struct HIDPointerEvent {
|
|||
#define QUEUE_MASK (QUEUE_LENGTH - 1u)
|
||||
#define QUEUE_INCR(v) ((v)++, (v) &= QUEUE_MASK)
|
||||
|
||||
typedef struct HIDMouseState {
|
||||
typedef struct HIDMouseState
|
||||
{
|
||||
HIDPointerEvent queue[QUEUE_LENGTH];
|
||||
int mouse_grabbed;
|
||||
QEMUPutMouseEvent* eh_entry;
|
||||
HIDEventFunc eh_sync;
|
||||
} HIDMouseState;
|
||||
|
||||
typedef struct HIDKeyboardState {
|
||||
typedef struct HIDKeyboardState
|
||||
{
|
||||
uint32_t keycodes[QUEUE_LENGTH];
|
||||
uint16_t modifiers;
|
||||
uint8_t leds;
|
||||
|
@ -298,8 +313,10 @@ typedef struct HIDKeyboardState {
|
|||
QEMUPutKBDEvent* eh_entry;
|
||||
} HIDKeyboardState;
|
||||
|
||||
struct HIDState {
|
||||
union {
|
||||
struct HIDState
|
||||
{
|
||||
union
|
||||
{
|
||||
HIDMouseState ptr;
|
||||
HIDKeyboardState kbd;
|
||||
};
|
||||
|
|
|
@ -176,10 +176,12 @@ int qemu_input_qcode_to_number(const QKeyCode value)
|
|||
|
||||
int qemu_input_key_value_to_number(const KeyValue* value)
|
||||
{
|
||||
if (value->type == KEY_VALUE_KIND_QCODE) {
|
||||
if (value->type == KEY_VALUE_KIND_QCODE)
|
||||
{
|
||||
return qemu_input_qcode_to_number(value->u.qcode);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
assert(value->type == KEY_VALUE_KIND_NUMBER);
|
||||
return value->u.number;
|
||||
}
|
||||
|
@ -192,7 +194,8 @@ int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
|
|||
int count = 0;
|
||||
|
||||
if (value->type == KEY_VALUE_KIND_QCODE &&
|
||||
value->u.qcode == Q_KEY_CODE_PAUSE) {
|
||||
value->u.qcode == Q_KEY_CODE_PAUSE)
|
||||
{
|
||||
/* specific case */
|
||||
int v = down ? 0 : 0x80;
|
||||
codes[count++] = 0xe1;
|
||||
|
@ -200,11 +203,13 @@ int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
|
|||
codes[count++] = 0x45 | v;
|
||||
return count;
|
||||
}
|
||||
if (keycode & SCANCODE_GREY) {
|
||||
if (keycode & SCANCODE_GREY)
|
||||
{
|
||||
codes[count++] = SCANCODE_EMUL0;
|
||||
keycode &= ~SCANCODE_GREY;
|
||||
}
|
||||
if (!down) {
|
||||
if (!down)
|
||||
{
|
||||
keycode |= SCANCODE_UP;
|
||||
}
|
||||
codes[count++] = keycode;
|
||||
|
|
|
@ -29,13 +29,17 @@ size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
|
|||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++)
|
||||
{
|
||||
if (offset < iov[i].iov_len)
|
||||
{
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memcpy((char*)iov[i].iov_base + offset, (char*)buf + done, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +52,17 @@ size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
|
|||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++)
|
||||
{
|
||||
if (offset < iov[i].iov_len)
|
||||
{
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memcpy((char*)buf + done, (char*)iov[i].iov_base + offset, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
@ -67,13 +75,17 @@ size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
|
|||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++)
|
||||
{
|
||||
if (offset < iov[i].iov_len)
|
||||
{
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memset((char*)iov[i].iov_base + offset, fillc, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +99,8 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
|
|||
unsigned int i;
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < iov_cnt; i++) {
|
||||
for (i = 0; i < iov_cnt; i++)
|
||||
{
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
return len;
|
||||
|
@ -100,8 +113,10 @@ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
|
|||
size_t len;
|
||||
unsigned int i, j;
|
||||
for (i = 0, j = 0;
|
||||
i < iov_cnt && j < dst_iov_cnt && (offset || bytes); i++) {
|
||||
if (offset >= iov[i].iov_len) {
|
||||
i < iov_cnt && j < dst_iov_cnt && (offset || bytes); i++)
|
||||
{
|
||||
if (offset >= iov[i].iov_len)
|
||||
{
|
||||
offset -= iov[i].iov_len;
|
||||
continue;
|
||||
}
|
||||
|
@ -143,7 +158,8 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
|
|||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
if (qiov->niov == qiov->nalloc) {
|
||||
if (qiov->niov == qiov->nalloc)
|
||||
{
|
||||
qiov->nalloc = 2 * qiov->nalloc + 1;
|
||||
qiov->iov = my_g_renew(struct iovec, qiov->iov, qiov->nalloc);
|
||||
}
|
||||
|
@ -170,17 +186,22 @@ size_t qemu_iovec_concat_iov(QEMUIOVector *dst,
|
|||
unsigned int i;
|
||||
size_t done;
|
||||
|
||||
if (!sbytes) {
|
||||
if (!sbytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
assert(dst->nalloc != -1);
|
||||
for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) {
|
||||
if (soffset < src_iov[i].iov_len) {
|
||||
for (i = 0, done = 0; done < sbytes && i < src_cnt; i++)
|
||||
{
|
||||
if (soffset < src_iov[i].iov_len)
|
||||
{
|
||||
size_t len = MIN(src_iov[i].iov_len - soffset, sbytes - done);
|
||||
qemu_iovec_add(dst, (char*)src_iov[i].iov_base + soffset, len);
|
||||
done += len;
|
||||
soffset = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
soffset -= src_iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
@ -278,26 +299,30 @@ ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
|
|||
ssize_t offset = 0;
|
||||
|
||||
assert(a->niov == b->niov);
|
||||
for (i = 0; i < a->niov; i++) {
|
||||
for (i = 0; i < a->niov; i++)
|
||||
{
|
||||
size_t len = 0;
|
||||
uint8_t* p = (uint8_t*)a->iov[i].iov_base;
|
||||
uint8_t* q = (uint8_t*)b->iov[i].iov_base;
|
||||
|
||||
assert(a->iov[i].iov_len == b->iov[i].iov_len);
|
||||
while (len < a->iov[i].iov_len && *p++ == *q++) {
|
||||
while (len < a->iov[i].iov_len && *p++ == *q++)
|
||||
{
|
||||
len++;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
|
||||
if (len != a->iov[i].iov_len) {
|
||||
if (len != a->iov[i].iov_len)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int src_index;
|
||||
struct iovec* src_iov;
|
||||
void* dest_base;
|
||||
|
@ -309,11 +334,16 @@ static int sortelem_cmp_src_base(const void *a, const void *b)
|
|||
const IOVectorSortElem* elem_b = (const IOVectorSortElem*)b;
|
||||
|
||||
/* Don't overflow */
|
||||
if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base) {
|
||||
if (elem_a->src_iov->iov_base < elem_b->src_iov->iov_base)
|
||||
{
|
||||
return -1;
|
||||
} else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base) {
|
||||
}
|
||||
else if (elem_a->src_iov->iov_base > elem_b->src_iov->iov_base)
|
||||
{
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -332,8 +362,10 @@ size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt,
|
|||
size_t total = 0;
|
||||
struct iovec* cur;
|
||||
|
||||
for (cur = *iov; *iov_cnt > 0; cur++) {
|
||||
if (cur->iov_len > bytes) {
|
||||
for (cur = *iov; *iov_cnt > 0; cur++)
|
||||
{
|
||||
if (cur->iov_len > bytes)
|
||||
{
|
||||
cur->iov_base = (uint8_t*)cur->iov_base + bytes;
|
||||
cur->iov_len -= bytes;
|
||||
total += bytes;
|
||||
|
@ -355,14 +387,17 @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt,
|
|||
size_t total = 0;
|
||||
struct iovec* cur;
|
||||
|
||||
if (*iov_cnt == 0) {
|
||||
if (*iov_cnt == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur = iov + (*iov_cnt - 1);
|
||||
|
||||
while (*iov_cnt > 0) {
|
||||
if (cur->iov_len > bytes) {
|
||||
while (*iov_cnt > 0)
|
||||
{
|
||||
if (cur->iov_len > bytes)
|
||||
{
|
||||
cur->iov_len -= bytes;
|
||||
total += bytes;
|
||||
break;
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
#define IOV_H
|
||||
|
||||
#if !defined(_BITS_UIO_H) && !defined(__iovec_defined) /* /usr/include/bits/uio.h */
|
||||
struct iovec {
|
||||
struct iovec
|
||||
{
|
||||
void* iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
@ -54,10 +55,13 @@ iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
|
|||
size_t offset, const void* buf, size_t bytes)
|
||||
{
|
||||
if (__builtin_constant_p(bytes) && iov_cnt &&
|
||||
offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
|
||||
offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset)
|
||||
{
|
||||
memcpy((char*)iov[0].iov_base + offset, buf, bytes);
|
||||
return bytes;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes);
|
||||
}
|
||||
}
|
||||
|
@ -67,10 +71,13 @@ iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
|
|||
size_t offset, void* buf, size_t bytes)
|
||||
{
|
||||
if (__builtin_constant_p(bytes) && iov_cnt &&
|
||||
offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
|
||||
offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset)
|
||||
{
|
||||
memcpy(buf, (char*)iov[0].iov_base + offset, bytes);
|
||||
return bytes;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +150,8 @@ size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt,
|
|||
size_t iov_discard_back(struct iovec* iov, unsigned int* iov_cnt,
|
||||
size_t bytes);
|
||||
|
||||
typedef struct QEMUIOVector {
|
||||
typedef struct QEMUIOVector
|
||||
{
|
||||
struct iovec* iov;
|
||||
int niov;
|
||||
int nalloc;
|
||||
|
|
|
@ -84,15 +84,19 @@
|
|||
* List definitions.
|
||||
*/
|
||||
#define QLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct name \
|
||||
{ \
|
||||
struct type* lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
{ \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#define QLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct \
|
||||
{ \
|
||||
struct type* le_next; /* next element */ \
|
||||
struct type** le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
@ -100,24 +104,32 @@ struct { \
|
|||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define QLIST_INIT(head) do { \
|
||||
#define QLIST_INIT(head) \
|
||||
do \
|
||||
{ \
|
||||
(head)->lh_first = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QLIST_SWAP(dstlist, srclist, field) do { \
|
||||
#define QLIST_SWAP(dstlist, srclist, field) \
|
||||
do \
|
||||
{ \
|
||||
void* tmplist; \
|
||||
tmplist = (srclist)->lh_first; \
|
||||
(srclist)->lh_first = (dstlist)->lh_first; \
|
||||
if ((srclist)->lh_first != NULL) { \
|
||||
if ((srclist)->lh_first != NULL) \
|
||||
{ \
|
||||
(srclist)->lh_first->field.le_prev = &(srclist)->lh_first; \
|
||||
} \
|
||||
(dstlist)->lh_first = tmplist; \
|
||||
if ((dstlist)->lh_first != NULL) { \
|
||||
if ((dstlist)->lh_first != NULL) \
|
||||
{ \
|
||||
(dstlist)->lh_first->field.le_prev = &(dstlist)->lh_first; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QLIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
#define QLIST_INSERT_AFTER(listelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
|
@ -125,21 +137,27 @@ struct { \
|
|||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QLIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
#define QLIST_INSERT_BEFORE(listelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
#define QLIST_INSERT_HEAD(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next; \
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QLIST_REMOVE(elm, field) do { \
|
||||
#define QLIST_REMOVE(elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
|
@ -168,52 +186,71 @@ struct { \
|
|||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define QSLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct name \
|
||||
{ \
|
||||
struct type* slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define QSLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
{ \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#define QSLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct \
|
||||
{ \
|
||||
struct type* sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define QSLIST_INIT(head) do { \
|
||||
#define QSLIST_INIT(head) \
|
||||
do \
|
||||
{ \
|
||||
(head)->slh_first = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
#define QSLIST_INSERT_AFTER(slistelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
#define QSLIST_INSERT_HEAD(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_INSERT_HEAD_ATOMIC(head, elm, field) do { \
|
||||
#define QSLIST_INSERT_HEAD_ATOMIC(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
typeof(elm) save_sle_next; \
|
||||
do { \
|
||||
do \
|
||||
{ \
|
||||
save_sle_next = (elm)->field.sle_next = (head)->slh_first; \
|
||||
} while (atomic_cmpxchg(&(head)->slh_first, save_sle_next, (elm)) != \
|
||||
save_sle_next); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_MOVE_ATOMIC(dest, src) do { \
|
||||
#define QSLIST_MOVE_ATOMIC(dest, src) \
|
||||
do \
|
||||
{ \
|
||||
(dest)->slh_first = atomic_xchg(&(src)->slh_first, NULL); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_REMOVE_HEAD(head, field) do { \
|
||||
#define QSLIST_REMOVE_HEAD(head, field) \
|
||||
do \
|
||||
{ \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSLIST_REMOVE_AFTER(slistelm, field) do { \
|
||||
#define QSLIST_REMOVE_AFTER(slistelm, field) \
|
||||
do \
|
||||
{ \
|
||||
(slistelm)->field.sle_next = \
|
||||
QSLIST_NEXT(QSLIST_NEXT((slistelm), field), field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
@ -238,54 +275,72 @@ struct { \
|
|||
* Simple queue definitions.
|
||||
*/
|
||||
#define QSIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct name \
|
||||
{ \
|
||||
struct type* sqh_first; /* first element */ \
|
||||
struct type** sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define QSIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
{ \
|
||||
NULL, &(head).sqh_first \
|
||||
}
|
||||
|
||||
#define QSIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct \
|
||||
{ \
|
||||
struct type* sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define QSIMPLEQ_INIT(head) do { \
|
||||
#define QSIMPLEQ_INIT(head) \
|
||||
do \
|
||||
{ \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
#define QSIMPLEQ_INSERT_HEAD(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
#define QSIMPLEQ_INSERT_TAIL(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
#define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
#define QSIMPLEQ_REMOVE_HEAD(head, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_SPLIT_AFTER(head, elm, field, removed) do { \
|
||||
#define QSIMPLEQ_SPLIT_AFTER(head, elm, field, removed) \
|
||||
do \
|
||||
{ \
|
||||
QSIMPLEQ_INIT(removed); \
|
||||
if (((removed)->sqh_first = (head)->sqh_first) != NULL) { \
|
||||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) { \
|
||||
if (((removed)->sqh_first = (head)->sqh_first) != NULL) \
|
||||
{ \
|
||||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
|
||||
{ \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} \
|
||||
(removed)->sqh_last = &(elm)->field.sqe_next; \
|
||||
|
@ -293,10 +348,15 @@ struct { \
|
|||
} \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QSIMPLEQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->sqh_first == (elm)) { \
|
||||
#define QSIMPLEQ_REMOVE(head, elm, type, field) \
|
||||
do \
|
||||
{ \
|
||||
if ((head)->sqh_first == (elm)) \
|
||||
{ \
|
||||
QSIMPLEQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
struct type* curelm = (head)->sqh_first; \
|
||||
while (curelm->field.sqe_next != (elm)) \
|
||||
curelm = curelm->field.sqe_next; \
|
||||
|
@ -316,8 +376,11 @@ struct { \
|
|||
(var) && ((next = ((var)->field.sqe_next)), 1); \
|
||||
(var) = (next))
|
||||
|
||||
#define QSIMPLEQ_CONCAT(head1, head2) do { \
|
||||
if (!QSIMPLEQ_EMPTY((head2))) { \
|
||||
#define QSIMPLEQ_CONCAT(head1, head2) \
|
||||
do \
|
||||
{ \
|
||||
if (!QSIMPLEQ_EMPTY((head2))) \
|
||||
{ \
|
||||
*(head1)->sqh_last = (head2)->sqh_first; \
|
||||
(head1)->sqh_last = (head2)->sqh_last; \
|
||||
QSIMPLEQ_INIT((head2)); \
|
||||
|
@ -327,8 +390,7 @@ struct { \
|
|||
#define QSIMPLEQ_LAST(head, type, field) \
|
||||
(QSIMPLEQ_EMPTY((head)) ? \
|
||||
NULL : \
|
||||
((struct type *)(void *) \
|
||||
((char *)((head)->sqh_last) - offsetof(struct type, field))))
|
||||
((struct type*)(void*)((char*)((head)->sqh_last) - offsetof(struct type, field))))
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
|
@ -342,17 +404,21 @@ struct { \
|
|||
* Tail queue definitions.
|
||||
*/
|
||||
#define Q_TAILQ_HEAD(name, type, qual) \
|
||||
struct name { \
|
||||
struct name \
|
||||
{ \
|
||||
qual type* tqh_first; /* first element */ \
|
||||
qual type* qual* tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type, )
|
||||
|
||||
#define QTAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
{ \
|
||||
NULL, &(head).tqh_first \
|
||||
}
|
||||
|
||||
#define Q_TAILQ_ENTRY(type, qual) \
|
||||
struct { \
|
||||
struct \
|
||||
{ \
|
||||
qual type* tqe_next; /* next element */ \
|
||||
qual type* qual* tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
@ -361,12 +427,16 @@ struct { \
|
|||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define QTAILQ_INIT(head) do { \
|
||||
#define QTAILQ_INIT(head) \
|
||||
do \
|
||||
{ \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QTAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
#define QTAILQ_INSERT_HEAD(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
|
@ -376,14 +446,18 @@ struct { \
|
|||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
#define QTAILQ_INSERT_TAIL(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
|
@ -393,14 +467,18 @@ struct { \
|
|||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
#define QTAILQ_INSERT_BEFORE(listelm, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define QTAILQ_REMOVE(head, elm, field) do { \
|
||||
#define QTAILQ_REMOVE(head, elm, field) \
|
||||
do \
|
||||
{ \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
|
@ -444,12 +522,16 @@ struct { \
|
|||
typedef struct DUMMY_Q_ENTRY DUMMY_Q_ENTRY;
|
||||
typedef struct DUMMY_Q DUMMY_Q;
|
||||
|
||||
struct DUMMY_Q_ENTRY {
|
||||
QTAILQ_ENTRY(DUMMY_Q_ENTRY) next;
|
||||
struct DUMMY_Q_ENTRY
|
||||
{
|
||||
QTAILQ_ENTRY(DUMMY_Q_ENTRY)
|
||||
next;
|
||||
};
|
||||
|
||||
struct DUMMY_Q {
|
||||
QTAILQ_HEAD(DUMMY_Q_HEAD, DUMMY_Q_ENTRY) head;
|
||||
struct DUMMY_Q
|
||||
{
|
||||
QTAILQ_HEAD(DUMMY_Q_HEAD, DUMMY_Q_ENTRY)
|
||||
head;
|
||||
};
|
||||
|
||||
#define dummy_q ((DUMMY_Q*)0)
|
||||
|
@ -491,7 +573,9 @@ struct DUMMY_Q {
|
|||
/*
|
||||
* Tail queue insertion using pointer arithmetic.
|
||||
*/
|
||||
#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do { \
|
||||
#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) \
|
||||
do \
|
||||
{ \
|
||||
QTAILQ_RAW_NEXT(elm, entry) = NULL; \
|
||||
QTAILQ_RAW_TQE_PREV(elm, entry) = QTAILQ_RAW_TQH_LAST(head); \
|
||||
*QTAILQ_RAW_TQH_LAST(head) = (elm); \
|
||||
|
|
|
@ -281,16 +281,19 @@ typedef struct USBDescOther USBDescOther;
|
|||
typedef struct USBDescString USBDescString;
|
||||
typedef struct USBDescMSOS USBDescMSOS;
|
||||
|
||||
struct USBDescString {
|
||||
struct USBDescString
|
||||
{
|
||||
uint8_t index;
|
||||
char* str;
|
||||
QLIST_ENTRY(USBDescString) next;
|
||||
QLIST_ENTRY(USBDescString)
|
||||
next;
|
||||
};
|
||||
|
||||
#define USB_MAX_ENDPOINTS 15
|
||||
#define USB_MAX_INTERFACES 16
|
||||
|
||||
struct USBEndpoint {
|
||||
struct USBEndpoint
|
||||
{
|
||||
uint8_t nr;
|
||||
uint8_t pid;
|
||||
uint8_t type;
|
||||
|
@ -300,10 +303,12 @@ struct USBEndpoint {
|
|||
bool pipeline;
|
||||
bool halted;
|
||||
USBDevice* dev;
|
||||
QTAILQ_HEAD(, USBPacket) queue;
|
||||
QTAILQ_HEAD(, USBPacket)
|
||||
queue;
|
||||
};
|
||||
|
||||
enum USBDeviceFlags {
|
||||
enum USBDeviceFlags
|
||||
{
|
||||
USB_DEV_FLAG_FULL_PATH,
|
||||
USB_DEV_FLAG_IS_HOST,
|
||||
USB_DEV_FLAG_MSOS_DESC_ENABLE,
|
||||
|
@ -313,7 +318,8 @@ enum USBDeviceFlags {
|
|||
typedef void (*USBDeviceRealize)(USBDevice* dev /*, Error **errp*/);
|
||||
typedef void (*USBDeviceUnrealize)(USBDevice* dev /*, Error **errp*/);
|
||||
|
||||
typedef struct USBDeviceClass {
|
||||
typedef struct USBDeviceClass
|
||||
{
|
||||
//DeviceClass parent_class;
|
||||
|
||||
USBDeviceRealize realize;
|
||||
|
@ -391,7 +397,8 @@ typedef struct USBDeviceClass {
|
|||
} USBDeviceClass;
|
||||
|
||||
/* definition of a USB device */
|
||||
struct USBDevice {
|
||||
struct USBDevice
|
||||
{
|
||||
USBDeviceClass klass;
|
||||
USBPort* port;
|
||||
USBBus* bus;
|
||||
|
@ -429,7 +436,8 @@ struct USBDevice {
|
|||
const USBDescIface* ifaces[USB_MAX_INTERFACES];
|
||||
};
|
||||
|
||||
typedef struct USBPortOps {
|
||||
typedef struct USBPortOps
|
||||
{
|
||||
void (*attach)(USBPort* port);
|
||||
void (*detach)(USBPort* port);
|
||||
/*
|
||||
|
@ -446,7 +454,8 @@ typedef struct USBPortOps {
|
|||
} USBPortOps;
|
||||
|
||||
/* USB port on which a device can be connected */
|
||||
struct USBPort {
|
||||
struct USBPort
|
||||
{
|
||||
USBDevice* dev;
|
||||
int speedmask;
|
||||
USBPortOps* ops;
|
||||
|
@ -457,7 +466,8 @@ struct USBPort {
|
|||
|
||||
typedef void USBCallback(USBPacket* packet, void* opaque);
|
||||
|
||||
typedef enum USBPacketState {
|
||||
typedef enum USBPacketState
|
||||
{
|
||||
USB_PACKET_UNDEFINED = 0,
|
||||
USB_PACKET_SETUP,
|
||||
USB_PACKET_QUEUED,
|
||||
|
@ -467,7 +477,8 @@ typedef enum USBPacketState {
|
|||
} USBPacketState;
|
||||
|
||||
/* Structure used to hold information about an active USB packet. */
|
||||
struct USBPacket {
|
||||
struct USBPacket
|
||||
{
|
||||
/* Data fields for use by the driver. */
|
||||
int pid;
|
||||
uint64_t id;
|
||||
|
@ -482,13 +493,17 @@ struct USBPacket {
|
|||
/* Internal use by the USB layer. */
|
||||
USBPacketState state;
|
||||
USBCombinedPacket* combined;
|
||||
QTAILQ_ENTRY(USBPacket) queue;
|
||||
QTAILQ_ENTRY(USBPacket) combined_entry;
|
||||
QTAILQ_ENTRY(USBPacket)
|
||||
queue;
|
||||
QTAILQ_ENTRY(USBPacket)
|
||||
combined_entry;
|
||||
};
|
||||
|
||||
struct USBCombinedPacket {
|
||||
struct USBCombinedPacket
|
||||
{
|
||||
USBPacket* first;
|
||||
QTAILQ_HEAD(packets_head, USBPacket) packets;
|
||||
QTAILQ_HEAD(packets_head, USBPacket)
|
||||
packets;
|
||||
QEMUIOVector iov;
|
||||
};
|
||||
|
||||
|
@ -512,21 +527,27 @@ static inline bool usb_packet_is_inflight(USBPacket *p)
|
|||
p->state == USB_PACKET_ASYNC);
|
||||
}
|
||||
|
||||
struct USBBus {
|
||||
struct USBBus
|
||||
{
|
||||
//BusState qbus;
|
||||
USBBusOps* ops;
|
||||
int busnr;
|
||||
int nfree;
|
||||
int nused;
|
||||
QTAILQ_HEAD(, USBPort) free;
|
||||
QTAILQ_HEAD(, USBPort) used;
|
||||
QTAILQ_ENTRY(USBBus) next;
|
||||
QTAILQ_HEAD(, USBPort)
|
||||
free;
|
||||
QTAILQ_HEAD(, USBPort)
|
||||
used;
|
||||
QTAILQ_ENTRY(USBBus)
|
||||
next;
|
||||
};
|
||||
|
||||
struct USBBusOps {
|
||||
struct USBBusOps
|
||||
{
|
||||
void (*register_companion)(USBBus* bus, USBPort* ports[],
|
||||
uint32_t portcount, uint32_t firstport /*,
|
||||
Error **errp*/);
|
||||
Error **errp*/
|
||||
);
|
||||
void (*wakeup_endpoint)(USBBus* bus, USBEndpoint* ep, unsigned int stream);
|
||||
};
|
||||
|
||||
|
|
|
@ -27,13 +27,15 @@
|
|||
|
||||
#define MAX_PORTS 8
|
||||
|
||||
typedef struct USBHubPort {
|
||||
typedef struct USBHubPort
|
||||
{
|
||||
USBPort port;
|
||||
uint16_t wPortStatus;
|
||||
uint16_t wPortChange;
|
||||
} USBHubPort;
|
||||
|
||||
typedef struct USBHubState {
|
||||
typedef struct USBHubState
|
||||
{
|
||||
USBDevice dev;
|
||||
int nb_ports;
|
||||
USBHubPort ports[MAX_PORTS];
|
||||
|
@ -168,7 +170,8 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev)
|
|||
USBHubState* s = (USBHubState*)port1->opaque;
|
||||
USBHubPort* port = (USBHubPort*)&s->ports[port1->index];
|
||||
|
||||
if (dev) {
|
||||
if (dev)
|
||||
{
|
||||
if (port->port.dev)
|
||||
usb_attach(port1, NULL);
|
||||
|
||||
|
@ -182,12 +185,16 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev)
|
|||
/* send the attach message */
|
||||
dev->handle_packet(dev,
|
||||
USB_MSG_ATTACH, 0, 0, NULL, 0);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dev = port->port.dev;
|
||||
if (dev) {
|
||||
if (dev)
|
||||
{
|
||||
port->wPortStatus &= ~PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->wPortStatus & PORT_STAT_ENABLE) {
|
||||
if (port->wPortStatus & PORT_STAT_ENABLE)
|
||||
{
|
||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||
port->wPortChange |= PORT_STAT_C_ENABLE;
|
||||
}
|
||||
|
@ -210,7 +217,8 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
USBHubState* s = (USBHubState*)dev;
|
||||
int ret;
|
||||
|
||||
switch(request) {
|
||||
switch (request)
|
||||
{
|
||||
case DeviceRequest | USB_REQ_GET_STATUS:
|
||||
data[0] = (1 << USB_DEVICE_SELF_POWERED) |
|
||||
(dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
|
||||
|
@ -218,23 +226,30 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
ret = 2;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->remote_wakeup = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == 0 && index != 0x81) { /* clear ep halt */
|
||||
if (value == 0 && index != 0x81)
|
||||
{ /* clear ep halt */
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP)
|
||||
{
|
||||
dev->remote_wakeup = 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -244,7 +259,8 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
ret = 0;
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch(value >> 8) {
|
||||
switch (value >> 8)
|
||||
{
|
||||
case USB_DT_DEVICE:
|
||||
memcpy(data, qemu_hub_dev_descriptor,
|
||||
sizeof(qemu_hub_dev_descriptor));
|
||||
|
@ -261,7 +277,8 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
ret = sizeof(qemu_hub_config_descriptor);
|
||||
break;
|
||||
case USB_DT_STRING:
|
||||
switch(value & 0xff) {
|
||||
switch (value & 0xff)
|
||||
{
|
||||
case 0:
|
||||
/* language ids */
|
||||
data[0] = 4;
|
||||
|
@ -328,8 +345,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
break;
|
||||
case SetHubFeature:
|
||||
case ClearHubFeature:
|
||||
if (value == 0 || value == 1) {
|
||||
} else {
|
||||
if (value == 0 || value == 1)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -343,12 +363,14 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
goto fail;
|
||||
port = &s->ports[n];
|
||||
dev = port->port.dev;
|
||||
switch(value) {
|
||||
switch (value)
|
||||
{
|
||||
case PORT_SUSPEND:
|
||||
port->wPortStatus |= PORT_STAT_SUSPEND;
|
||||
break;
|
||||
case PORT_RESET:
|
||||
if (dev) {
|
||||
if (dev)
|
||||
{
|
||||
dev->handle_packet(dev,
|
||||
USB_MSG_RESET, 0, 0, NULL, 0);
|
||||
port->wPortChange |= PORT_STAT_C_RESET;
|
||||
|
@ -373,7 +395,8 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
goto fail;
|
||||
port = &s->ports[n];
|
||||
dev = port->port.dev;
|
||||
switch(value) {
|
||||
switch (value)
|
||||
{
|
||||
case PORT_ENABLE:
|
||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||
break;
|
||||
|
@ -410,14 +433,16 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
|
|||
|
||||
/* fill DeviceRemovable bits */
|
||||
limit = ((s->nb_ports + 1 + 7) / 8) + 7;
|
||||
for (n = 7; n < limit; n++) {
|
||||
for (n = 7; n < limit; n++)
|
||||
{
|
||||
data[n] = 0x00;
|
||||
var_hub_size++;
|
||||
}
|
||||
|
||||
/* fill PortPwrCtrlMask bits */
|
||||
limit = limit + ((s->nb_ports + 7) / 8);
|
||||
for (;n < limit; n++) {
|
||||
for (; n < limit; n++)
|
||||
{
|
||||
data[n] = 0xff;
|
||||
var_hub_size++;
|
||||
}
|
||||
|
@ -440,33 +465,45 @@ static int usb_hub_handle_data(USBDevice *dev, int pid,
|
|||
USBHubState* s = (USBHubState*)dev;
|
||||
int ret;
|
||||
|
||||
switch(pid) {
|
||||
switch (pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
if (devep == 1) {
|
||||
if (devep == 1)
|
||||
{
|
||||
USBHubPort* port;
|
||||
unsigned int status;
|
||||
int i, n;
|
||||
n = (s->nb_ports + 1 + 7) / 8;
|
||||
if (len == 1) { /* FreeBSD workaround */
|
||||
if (len == 1)
|
||||
{ /* FreeBSD workaround */
|
||||
n = 1;
|
||||
} else if (n > len) {
|
||||
}
|
||||
else if (n > len)
|
||||
{
|
||||
return USB_RET_BABBLE;
|
||||
}
|
||||
status = 0;
|
||||
for(i = 0; i < s->nb_ports; i++) {
|
||||
for (i = 0; i < s->nb_ports; i++)
|
||||
{
|
||||
port = &s->ports[i];
|
||||
if (port->wPortChange)
|
||||
status |= (1 << (i + 1));
|
||||
}
|
||||
if (status != 0) {
|
||||
for(i = 0; i < n; i++) {
|
||||
if (status != 0)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
data[i] = status >> (8 * i);
|
||||
}
|
||||
ret = n;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = USB_RET_NAK; /* usb11 11.13.1 */
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -487,14 +524,17 @@ static int usb_hub_broadcast_packet(USBHubState *s, int pid,
|
|||
USBDevice* dev;
|
||||
int i, ret;
|
||||
|
||||
for(i = 0; i < s->nb_ports; i++) {
|
||||
for (i = 0; i < s->nb_ports; i++)
|
||||
{
|
||||
port = &s->ports[i];
|
||||
dev = port->port.dev;
|
||||
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
|
||||
if (dev && (port->wPortStatus & PORT_STAT_ENABLE))
|
||||
{
|
||||
ret = dev->handle_packet(dev, pid,
|
||||
devaddr, devep,
|
||||
data, len);
|
||||
if (ret != USB_RET_NODEV) {
|
||||
if (ret != USB_RET_NODEV)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -516,7 +556,8 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid,
|
|||
devaddr != dev->addr &&
|
||||
(pid == USB_TOKEN_SETUP ||
|
||||
pid == USB_TOKEN_OUT ||
|
||||
pid == USB_TOKEN_IN)) {
|
||||
pid == USB_TOKEN_IN))
|
||||
{
|
||||
/* broadcast the packet to the devices */
|
||||
return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
|
||||
}
|
||||
|
@ -553,7 +594,8 @@ USBDevice *usb_hub_init(int nb_ports)
|
|||
strncpy(s->dev.devname, "QEMU USB Hub", sizeof(s->dev.devname));
|
||||
|
||||
s->nb_ports = nb_ports;
|
||||
for(i = 0; i < s->nb_ports; i++) {
|
||||
for (i = 0; i < s->nb_ports; i++)
|
||||
{
|
||||
port = &s->ports[i];
|
||||
port->port.opaque = s;
|
||||
port->port.index = i;
|
||||
|
|
|
@ -96,8 +96,10 @@ static void ohci_attach2(USBPort *port1, USBDevice *dev)
|
|||
OHCIPort* port = (OHCIPort*)&s->rhport[port1->index];
|
||||
uint32_t old_state = port->ctrl;
|
||||
|
||||
if (dev) {
|
||||
if (port1->dev) {
|
||||
if (dev)
|
||||
{
|
||||
if (port1->dev)
|
||||
{
|
||||
ohci_attach2(port1, NULL);
|
||||
}
|
||||
/* set connect status */
|
||||
|
@ -112,19 +114,24 @@ static void ohci_attach2(USBPort *port1, USBDevice *dev)
|
|||
port1->dev = dev;
|
||||
dev->state = USB_STATE_ATTACHED;
|
||||
OSDebugOut(TEXT("usb-ohci: Attached port %d\n"), port1->index);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set connect status */
|
||||
if (port->ctrl & OHCI_PORT_CCS) {
|
||||
if (port->ctrl & OHCI_PORT_CCS)
|
||||
{
|
||||
port->ctrl &= ~OHCI_PORT_CCS;
|
||||
port->ctrl |= OHCI_PORT_CSC;
|
||||
}
|
||||
/* disable port */
|
||||
if (port->ctrl & OHCI_PORT_PES) {
|
||||
if (port->ctrl & OHCI_PORT_PES)
|
||||
{
|
||||
port->ctrl &= ~OHCI_PORT_PES;
|
||||
port->ctrl |= OHCI_PORT_PESC;
|
||||
}
|
||||
dev = port1->dev;
|
||||
if (dev) {
|
||||
if (dev)
|
||||
{
|
||||
dev->port = NULL;
|
||||
/* send the detach message */
|
||||
dev->state = USB_STATE_NOTATTACHED;
|
||||
|
@ -151,20 +158,25 @@ static void ohci_attach(USBPort *port1)
|
|||
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
|
||||
|
||||
/* update speed */
|
||||
if (port->port.dev->speed == USB_SPEED_LOW) {
|
||||
if (port->port.dev->speed == USB_SPEED_LOW)
|
||||
{
|
||||
port->ctrl |= OHCI_PORT_LSDA;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
port->ctrl &= ~OHCI_PORT_LSDA;
|
||||
}
|
||||
|
||||
/* notify of remote-wakeup */
|
||||
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
|
||||
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
|
||||
{
|
||||
ohci_set_interrupt(s, OHCI_INTR_RD);
|
||||
}
|
||||
|
||||
//trace_usb_ohci_port_attach(port1->index);
|
||||
|
||||
if (old_state != port->ctrl) {
|
||||
if (old_state != port->ctrl)
|
||||
{
|
||||
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
@ -180,18 +192,21 @@ static void ohci_detach(USBPort *port1)
|
|||
ohci_async_cancel_device(s, port1->dev);
|
||||
|
||||
/* set connect status */
|
||||
if (port->ctrl & OHCI_PORT_CCS) {
|
||||
if (port->ctrl & OHCI_PORT_CCS)
|
||||
{
|
||||
port->ctrl &= ~OHCI_PORT_CCS;
|
||||
port->ctrl |= OHCI_PORT_CSC;
|
||||
}
|
||||
/* disable port */
|
||||
if (port->ctrl & OHCI_PORT_PES) {
|
||||
if (port->ctrl & OHCI_PORT_PES)
|
||||
{
|
||||
port->ctrl &= ~OHCI_PORT_PES;
|
||||
port->ctrl |= OHCI_PORT_PESC;
|
||||
}
|
||||
//trace_usb_ohci_port_detach(port1->index);
|
||||
|
||||
if (old_state != port->ctrl) {
|
||||
if (old_state != port->ctrl)
|
||||
{
|
||||
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
@ -201,14 +216,16 @@ static void ohci_wakeup(USBPort *port1)
|
|||
OHCIState* s = (OHCIState*)port1->opaque;
|
||||
OHCIPort* port = (OHCIPort*)&s->rhport[port1->index];
|
||||
uint32_t intr = 0;
|
||||
if (port->ctrl & OHCI_PORT_PSS) {
|
||||
if (port->ctrl & OHCI_PORT_PSS)
|
||||
{
|
||||
//trace_usb_ohci_port_wakeup(port1->index);
|
||||
port->ctrl |= OHCI_PORT_PSSC;
|
||||
port->ctrl &= ~OHCI_PORT_PSS;
|
||||
intr = OHCI_INTR_RHSC;
|
||||
}
|
||||
/* Note that the controller can be suspended even if this port is not */
|
||||
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
|
||||
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
|
||||
{
|
||||
//trace_usb_ohci_remote_wakeup(s->name);
|
||||
/* This is the one state transition the controller can do by itself */
|
||||
s->ctl &= ~OHCI_CTL_HCFS;
|
||||
|
@ -226,12 +243,15 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
|
|||
USBDevice* dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++) {
|
||||
if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
|
||||
for (i = 0; i < ohci->num_ports; i++)
|
||||
{
|
||||
if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dev = usb_find_device(&ohci->rhport[i].port, addr);
|
||||
if (dev != NULL) {
|
||||
if (dev != NULL)
|
||||
{
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
@ -244,11 +264,14 @@ static void ohci_stop_endpoints(OHCIState *ohci)
|
|||
USBDevice* dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++) {
|
||||
for (i = 0; i < ohci->num_ports; i++)
|
||||
{
|
||||
dev = ohci->rhport[i].port.dev;
|
||||
if (dev && dev->attached) {
|
||||
if (dev && dev->attached)
|
||||
{
|
||||
usb_device_ep_stopped(dev, &dev->ep_ctl);
|
||||
for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
|
||||
for (j = 0; j < USB_MAX_ENDPOINTS; j++)
|
||||
{
|
||||
usb_device_ep_stopped(dev, &dev->ep_in[j]);
|
||||
usb_device_ep_stopped(dev, &dev->ep_out[j]);
|
||||
}
|
||||
|
@ -266,14 +289,17 @@ static void ohci_roothub_reset(OHCIState *ohci)
|
|||
ohci->rhdesc_b = 0x0; /* Impl. specific */
|
||||
ohci->rhstatus = 0;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++) {
|
||||
for (i = 0; i < ohci->num_ports; i++)
|
||||
{
|
||||
port = &ohci->rhport[i];
|
||||
port->ctrl = 0;
|
||||
if (port->port.dev && port->port.dev->attached) {
|
||||
if (port->port.dev && port->port.dev->attached)
|
||||
{
|
||||
usb_port_reset(&port->port);
|
||||
}
|
||||
}
|
||||
if (ohci->async_td) {
|
||||
if (ohci->async_td)
|
||||
{
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
}
|
||||
|
@ -327,7 +353,8 @@ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf))
|
||||
{
|
||||
if (cpu_physical_memory_rw(addr, (uint8_t*)buf, sizeof(*buf), 0))
|
||||
return 0;
|
||||
*buf = le32_to_cpu(*buf);
|
||||
|
@ -341,7 +368,8 @@ static inline int get_words(uint32_t addr, uint16_t *buf, int num)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf))
|
||||
{
|
||||
if (cpu_physical_memory_rw(addr, (uint8_t*)buf, sizeof(*buf), 0))
|
||||
return 0;
|
||||
*buf = le16_to_cpu(*buf);
|
||||
|
@ -355,7 +383,8 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf))
|
||||
{
|
||||
uint32_t tmp = cpu_to_le32(*buf);
|
||||
if (cpu_physical_memory_rw(addr, (uint8_t*)&tmp, sizeof(tmp), 1))
|
||||
return 0;
|
||||
|
@ -369,7 +398,8 @@ static inline int put_words(uint32_t addr, uint16_t *buf, int num)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
|
||||
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf))
|
||||
{
|
||||
uint16_t tmp = cpu_to_le16(*buf);
|
||||
if (cpu_physical_memory_rw(addr, (uint8_t*)&tmp, sizeof(tmp), 1))
|
||||
return 0;
|
||||
|
@ -497,7 +527,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
|
||||
addr = ed->head & OHCI_DPTR_MASK;
|
||||
|
||||
if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
|
||||
if (!ohci_read_iso_td(ohci, addr, &iso_td))
|
||||
{
|
||||
//trace_usb_ohci_iso_td_read_failed(addr);
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
|
@ -518,10 +549,13 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
iso_td.offset[4], iso_td.offset[5],
|
||||
iso_td.offset[6], iso_td.offset[7]);
|
||||
*/
|
||||
if (relative_frame_number < 0) {
|
||||
if (relative_frame_number < 0)
|
||||
{
|
||||
//trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number);
|
||||
return 1;
|
||||
} else if (relative_frame_number > frame_count) {
|
||||
}
|
||||
else if (relative_frame_number > frame_count)
|
||||
{
|
||||
/* ISO TD expired - retire the TD to the Done Queue and continue with
|
||||
the next ISO TD of the same ED */
|
||||
//trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number,
|
||||
|
@ -534,7 +568,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
i = OHCI_BM(iso_td.flags, TD_DI);
|
||||
if (i < ohci->done_count)
|
||||
ohci->done_count = i;
|
||||
if (!ohci_put_iso_td(ohci, addr, &iso_td)) {
|
||||
if (!ohci_put_iso_td(ohci, addr, &iso_td))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
}
|
||||
|
@ -542,7 +577,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
}
|
||||
|
||||
dir = OHCI_BM(ed->flags, ED_D);
|
||||
switch (dir) {
|
||||
switch (dir)
|
||||
{
|
||||
case OHCI_TD_DIR_IN:
|
||||
str = "in";
|
||||
pid = USB_TOKEN_IN;
|
||||
|
@ -560,7 +596,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!iso_td.bp || !iso_td.be) {
|
||||
if (!iso_td.bp || !iso_td.be)
|
||||
{
|
||||
//trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be);
|
||||
return 1;
|
||||
}
|
||||
|
@ -570,54 +607,70 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
|
||||
if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
|
||||
((relative_frame_number < frame_count) &&
|
||||
!(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
|
||||
!(OHCI_BM(next_offset, TD_PSW_CC) & 0xe)))
|
||||
{
|
||||
//trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
|
||||
if ((relative_frame_number < frame_count) && (start_offset > next_offset))
|
||||
{
|
||||
//trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((start_offset & 0x1000) == 0) {
|
||||
if ((start_offset & 0x1000) == 0)
|
||||
{
|
||||
start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
|
||||
(start_offset & OHCI_OFFSET_MASK);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
start_addr = (iso_td.be & OHCI_PAGE_MASK) |
|
||||
(start_offset & OHCI_OFFSET_MASK);
|
||||
}
|
||||
|
||||
if (relative_frame_number < frame_count) {
|
||||
if (relative_frame_number < frame_count)
|
||||
{
|
||||
end_offset = next_offset - 1;
|
||||
if ((end_offset & 0x1000) == 0) {
|
||||
if ((end_offset & 0x1000) == 0)
|
||||
{
|
||||
end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
|
||||
(end_offset & OHCI_OFFSET_MASK);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
end_addr = (iso_td.be & OHCI_PAGE_MASK) |
|
||||
(end_offset & OHCI_OFFSET_MASK);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Last packet in the ISO TD */
|
||||
end_addr = iso_td.be;
|
||||
}
|
||||
|
||||
if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
|
||||
len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
|
||||
- (start_addr & OHCI_OFFSET_MASK);
|
||||
} else {
|
||||
if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK))
|
||||
{
|
||||
len = (end_addr & OHCI_OFFSET_MASK) + 0x1001 - (start_addr & OHCI_OFFSET_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = end_addr - start_addr + 1;
|
||||
}
|
||||
|
||||
if (len && dir != OHCI_TD_DIR_IN) {
|
||||
if (len && dir != OHCI_TD_DIR_IN)
|
||||
{
|
||||
if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
|
||||
DMA_DIRECTION_TO_DEVICE)) {
|
||||
DMA_DIRECTION_TO_DEVICE))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!completion) {
|
||||
if (!completion)
|
||||
{
|
||||
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));
|
||||
|
@ -625,14 +678,18 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
|
||||
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
|
||||
usb_handle_packet(dev, &ohci->usb_packet);
|
||||
if (ohci->usb_packet.status == USB_RET_ASYNC) {
|
||||
if (ohci->usb_packet.status == USB_RET_ASYNC)
|
||||
{
|
||||
usb_device_flush_ep_queue(dev, ep);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (ohci->usb_packet.status == USB_RET_SUCCESS) {
|
||||
if (ohci->usb_packet.status == USB_RET_SUCCESS)
|
||||
{
|
||||
ret = ohci->usb_packet.actual_length;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ohci->usb_packet.status;
|
||||
}
|
||||
|
||||
|
@ -640,34 +697,46 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
// str, len, ret);
|
||||
|
||||
/* Writeback */
|
||||
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
|
||||
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len)
|
||||
{
|
||||
/* IN transfer succeeded */
|
||||
if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
|
||||
DMA_DIRECTION_FROM_DEVICE)) {
|
||||
DMA_DIRECTION_FROM_DEVICE))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
}
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
|
||||
OHCI_CC_NOERROR);
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
|
||||
} else if (dir == OHCI_TD_DIR_OUT && ret == len) {
|
||||
}
|
||||
else if (dir == OHCI_TD_DIR_OUT && ret == len)
|
||||
{
|
||||
/* OUT transfer succeeded */
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
|
||||
OHCI_CC_NOERROR);
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
|
||||
} else {
|
||||
if (ret > (ssize_t) len) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret > (ssize_t)len)
|
||||
{
|
||||
//trace_usb_ohci_iso_td_data_overrun(ret, len);
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
|
||||
OHCI_CC_DATAOVERRUN);
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
|
||||
len);
|
||||
} else if (ret >= 0) {
|
||||
}
|
||||
else if (ret >= 0)
|
||||
{
|
||||
//trace_usb_ohci_iso_td_data_underrun(ret);
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
|
||||
OHCI_CC_DATAUNDERRUN);
|
||||
} else {
|
||||
switch (ret) {
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
|
||||
|
@ -692,7 +761,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
}
|
||||
}
|
||||
|
||||
if (relative_frame_number == frame_count) {
|
||||
if (relative_frame_number == frame_count)
|
||||
{
|
||||
/* Last data packet of ISO TD - retire the TD to the Done Queue */
|
||||
OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
|
||||
ed->head &= ~OHCI_DPTR_MASK;
|
||||
|
@ -703,7 +773,8 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
|||
if (i < ohci->done_count)
|
||||
ohci->done_count = i;
|
||||
}
|
||||
if (!ohci_put_iso_td(ohci, addr, &iso_td)) {
|
||||
if (!ohci_put_iso_td(ohci, addr, &iso_td))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
}
|
||||
return 1;
|
||||
|
@ -730,18 +801,21 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
addr = ed->head & OHCI_DPTR_MASK;
|
||||
/* See if this TD has already been submitted to the device. */
|
||||
completion = (addr == ohci->async_td);
|
||||
if (completion && !ohci->async_complete) {
|
||||
if (completion && !ohci->async_complete)
|
||||
{
|
||||
//trace_usb_ohci_td_skip_async();
|
||||
return 1;
|
||||
}
|
||||
if (!ohci_read_td(ohci, addr, &td)) {
|
||||
if (!ohci_read_td(ohci, addr, &td))
|
||||
{
|
||||
//trace_usb_ohci_td_read_error(addr);
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dir = OHCI_BM(ed->flags, ED_D);
|
||||
switch (dir) {
|
||||
switch (dir)
|
||||
{
|
||||
case OHCI_TD_DIR_OUT:
|
||||
case OHCI_TD_DIR_IN:
|
||||
/* Same value. */
|
||||
|
@ -751,7 +825,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
break;
|
||||
}
|
||||
|
||||
switch (dir) {
|
||||
switch (dir)
|
||||
{
|
||||
case OHCI_TD_DIR_IN:
|
||||
str = "in";
|
||||
pid = USB_TOKEN_IN;
|
||||
|
@ -768,23 +843,31 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
//trace_usb_ohci_td_bad_direction(dir);
|
||||
return 1;
|
||||
}
|
||||
if (td.cbp && td.be) {
|
||||
if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
|
||||
if (td.cbp && td.be)
|
||||
{
|
||||
if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000))
|
||||
{
|
||||
len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
len = (td.be - td.cbp) + 1;
|
||||
}
|
||||
|
||||
pktlen = len;
|
||||
if (len && dir != OHCI_TD_DIR_IN) {
|
||||
if (len && dir != OHCI_TD_DIR_IN)
|
||||
{
|
||||
/* The endpoint may not allow us to transfer it all now */
|
||||
pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
|
||||
if (pktlen > len) {
|
||||
if (pktlen > len)
|
||||
{
|
||||
pktlen = len;
|
||||
}
|
||||
if (!completion) {
|
||||
if (!completion)
|
||||
{
|
||||
if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen,
|
||||
DMA_DIRECTION_TO_DEVICE)) {
|
||||
DMA_DIRECTION_TO_DEVICE))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
}
|
||||
}
|
||||
|
@ -796,11 +879,15 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
// flag_r, td.cbp, td.be);
|
||||
//ohci_td_pkt("OUT", ohci->usb_buf, pktlen);
|
||||
|
||||
if (completion) {
|
||||
if (completion)
|
||||
{
|
||||
ohci->async_td = 0;
|
||||
ohci->async_complete = false;
|
||||
} else {
|
||||
if (ohci->async_td) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ohci->async_td)
|
||||
{
|
||||
/* ??? The hardware should allow one active packet per
|
||||
endpoint. We only allow one active packet per controller.
|
||||
This should be sufficient as long as devices respond in a
|
||||
|
@ -817,39 +904,55 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
usb_handle_packet(dev, &ohci->usb_packet);
|
||||
//trace_usb_ohci_td_packet_status(ohci->usb_packet.status);
|
||||
|
||||
if (ohci->usb_packet.status == USB_RET_ASYNC) {
|
||||
if (ohci->usb_packet.status == USB_RET_ASYNC)
|
||||
{
|
||||
usb_device_flush_ep_queue(dev, ep);
|
||||
ohci->async_td = addr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (ohci->usb_packet.status == USB_RET_SUCCESS) {
|
||||
if (ohci->usb_packet.status == USB_RET_SUCCESS)
|
||||
{
|
||||
ret = ohci->usb_packet.actual_length;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ohci->usb_packet.status;
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
if (dir == OHCI_TD_DIR_IN) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
if (dir == OHCI_TD_DIR_IN)
|
||||
{
|
||||
if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
|
||||
DMA_DIRECTION_FROM_DEVICE)) {
|
||||
DMA_DIRECTION_FROM_DEVICE))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
}
|
||||
//ohci_td_pkt("IN", ohci->usb_buf, pktlen);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = pktlen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Writeback */
|
||||
if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
|
||||
if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r))
|
||||
{
|
||||
/* Transmission succeeded. */
|
||||
if (ret == len) {
|
||||
if (ret == len)
|
||||
{
|
||||
td.cbp = 0;
|
||||
} else {
|
||||
if ((td.cbp & 0xfff) + ret > 0xfff) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((td.cbp & 0xfff) + ret > 0xfff)
|
||||
{
|
||||
td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
td.cbp += ret;
|
||||
}
|
||||
}
|
||||
|
@ -858,7 +961,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
|
||||
OHCI_SET_BM(td.flags, TD_EC, 0);
|
||||
|
||||
if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
|
||||
if ((dir != OHCI_TD_DIR_IN) && (ret != len))
|
||||
{
|
||||
/* Partial packet transfer: TD not ready to retire yet */
|
||||
goto exit_no_retire;
|
||||
}
|
||||
|
@ -867,12 +971,18 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
ed->head &= ~OHCI_ED_C;
|
||||
if (td.flags & OHCI_TD_T0)
|
||||
ed->head |= OHCI_ED_C;
|
||||
} else {
|
||||
if (ret >= 0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ret >= 0)
|
||||
{
|
||||
//trace_usb_ohci_td_underrun();
|
||||
OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
|
||||
} else {
|
||||
switch (ret) {
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case USB_RET_IOERROR:
|
||||
case USB_RET_NODEV:
|
||||
//trace_usb_ohci_td_dev_error();
|
||||
|
@ -911,7 +1021,8 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
|
|||
if (i < ohci->done_count)
|
||||
ohci->done_count = i;
|
||||
exit_no_retire:
|
||||
if (!ohci_put_td(ohci, addr, &td)) {
|
||||
if (!ohci_put_td(ohci, addr, &td))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 1;
|
||||
}
|
||||
|
@ -931,8 +1042,10 @@ 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) {
|
||||
if (!ohci_read_ed(ohci, cur, &ed)) {
|
||||
for (cur = head; cur; cur = next_ed)
|
||||
{
|
||||
if (!ohci_read_ed(ohci, cur, &ed))
|
||||
{
|
||||
//trace_usb_ohci_ed_read_error(cur);
|
||||
ohci_die(ohci);
|
||||
return 0;
|
||||
|
@ -940,16 +1053,19 @@ 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) {
|
||||
if (++link_cnt > ED_LINK_LIMIT)
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
|
||||
if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K))
|
||||
{
|
||||
uint32_t addr;
|
||||
/* Cancel pending packets for ED that have been paused. */
|
||||
addr = ed.head & OHCI_DPTR_MASK;
|
||||
if (ohci->async_td && addr == ohci->async_td) {
|
||||
if (ohci->async_td && addr == ohci->async_td)
|
||||
{
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
usb_device_ep_stopped(ohci->usb_packet.ep->dev,
|
||||
|
@ -958,7 +1074,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
|||
continue;
|
||||
}
|
||||
|
||||
while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
|
||||
while ((ed.head & OHCI_DPTR_MASK) != ed.tail)
|
||||
{
|
||||
/*trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0,
|
||||
(ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
|
||||
ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
|
||||
|
@ -970,17 +1087,21 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
|||
|
||||
active = 1;
|
||||
|
||||
if ((ed.flags & OHCI_ED_F) == 0) {
|
||||
if ((ed.flags & OHCI_ED_F) == 0)
|
||||
{
|
||||
if (ohci_service_td(ohci, &ed))
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle isochronous endpoints */
|
||||
if (ohci_service_iso_td(ohci, &ed, completion))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ohci_put_ed(ohci, cur, &ed)) {
|
||||
if (!ohci_put_ed(ohci, cur, &ed))
|
||||
{
|
||||
ohci_die(ohci);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1000,18 +1121,23 @@ static void ohci_sof(OHCIState *ohci)
|
|||
/* Process Control and Bulk lists. */
|
||||
static void ohci_process_lists(OHCIState* ohci, int completion)
|
||||
{
|
||||
if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
|
||||
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
|
||||
if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF))
|
||||
{
|
||||
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head)
|
||||
{
|
||||
OSDebugOut(TEXT("usb-ohci: head %x, cur %x\n"), ohci->ctrl_head, ohci->ctrl_cur);
|
||||
}
|
||||
if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
|
||||
if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion))
|
||||
{
|
||||
ohci->ctrl_cur = 0;
|
||||
ohci->status &= ~OHCI_STATUS_CLF;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
|
||||
if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
|
||||
if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF))
|
||||
{
|
||||
if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion))
|
||||
{
|
||||
ohci->bulk_cur = 0;
|
||||
ohci->status &= ~OHCI_STATUS_BLF;
|
||||
}
|
||||
|
@ -1030,10 +1156,12 @@ void ohci_frame_boundary(void *opaque)
|
|||
/* if reset bit was set, don't process possibly invalid descriptors */
|
||||
/* TODO intr_status is interrupts that driver wants, so not quite right to us it here */
|
||||
bool hack = false; // ohci->intr_status & ohci->intr & OHCI_INTR_RHSC;
|
||||
if (hack) OSDebugOut(TEXT("skipping PLE\n"));
|
||||
if (hack)
|
||||
OSDebugOut(TEXT("skipping PLE\n"));
|
||||
|
||||
/* Process all the lists at the end of the frame */
|
||||
if ((ohci->ctl & OHCI_CTL_PLE) && !hack) {
|
||||
if ((ohci->ctl & OHCI_CTL_PLE) && !hack)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = ohci->frame_number & 0x1f;
|
||||
|
@ -1041,8 +1169,10 @@ void ohci_frame_boundary(void *opaque)
|
|||
}
|
||||
|
||||
/* Cancel all pending packets if either of the lists has been disabled. */
|
||||
if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
|
||||
if (ohci->async_td) {
|
||||
if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE))
|
||||
{
|
||||
if (ohci->async_td)
|
||||
{
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
}
|
||||
|
@ -1053,7 +1183,8 @@ void ohci_frame_boundary(void *opaque)
|
|||
ohci_process_lists(ohci, 0);
|
||||
|
||||
/* Stop if UnrecoverableError happened or ohci_sof will crash */
|
||||
if (ohci->intr_status & OHCI_INTR_UE) {
|
||||
if (ohci->intr_status & OHCI_INTR_UE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1064,7 +1195,8 @@ void ohci_frame_boundary(void *opaque)
|
|||
ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
|
||||
hcca.frame = cpu_to_le16(ohci->frame_number);
|
||||
|
||||
if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
|
||||
if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD))
|
||||
{
|
||||
if (!ohci->done)
|
||||
abort();
|
||||
if (ohci->intr & ohci->intr_status)
|
||||
|
@ -1121,9 +1253,11 @@ static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
|
|||
/* If CurrentConnectStatus is cleared we set
|
||||
* ConnectStatusChange
|
||||
*/
|
||||
if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
|
||||
if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS))
|
||||
{
|
||||
ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
|
||||
if (ohci->rhstatus & OHCI_RHS_DRWE) {
|
||||
if (ohci->rhstatus & OHCI_RHS_DRWE)
|
||||
{
|
||||
/* TODO: CSC is a wakeup event */
|
||||
}
|
||||
return 0;
|
||||
|
@ -1143,7 +1277,8 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
|
|||
{
|
||||
val &= OHCI_FMI_FI;
|
||||
|
||||
if (val != ohci->fi) {
|
||||
if (val != ohci->fi)
|
||||
{
|
||||
OSDebugOut(TEXT("usb-ohci: FrameInterval = 0x%x (%u)\n"), ohci->fi, ohci->fi);
|
||||
}
|
||||
|
||||
|
@ -1152,9 +1287,12 @@ static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
|
|||
|
||||
static void ohci_port_power(OHCIState* ohci, int i, int p)
|
||||
{
|
||||
if (p) {
|
||||
if (p)
|
||||
{
|
||||
ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS |
|
||||
OHCI_PORT_CCS |
|
||||
OHCI_PORT_PSS |
|
||||
|
@ -1176,7 +1314,8 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
|
|||
if (old_state == new_state)
|
||||
return;
|
||||
|
||||
switch (new_state) {
|
||||
switch (new_state)
|
||||
{
|
||||
case OHCI_USB_OPERATIONAL:
|
||||
ohci_bus_start(ohci);
|
||||
break;
|
||||
|
@ -1234,7 +1373,8 @@ static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
|
|||
if (val & OHCI_RHS_OCIC)
|
||||
ohci->rhstatus &= ~OHCI_RHS_OCIC;
|
||||
|
||||
if (val & OHCI_RHS_LPS) {
|
||||
if (val & OHCI_RHS_LPS)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++)
|
||||
|
@ -1242,7 +1382,8 @@ static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
|
|||
OSDebugOut(TEXT("usb-ohci: powered down all ports\n"));
|
||||
}
|
||||
|
||||
if (val & OHCI_RHS_LPSC) {
|
||||
if (val & OHCI_RHS_LPSC)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++)
|
||||
|
@ -1278,11 +1419,13 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
|
|||
|
||||
ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
|
||||
|
||||
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
|
||||
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS))
|
||||
{
|
||||
OSDebugOut(TEXT("usb-ohci: port %d: SUSPEND\n"), portnum);
|
||||
}
|
||||
|
||||
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
|
||||
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS))
|
||||
{
|
||||
OSDebugOut(TEXT("usb-ohci: port %d: RESET\n"), portnum);
|
||||
usb_device_reset(port->port.dev);
|
||||
port->ctrl &= ~OHCI_PORT_PRS;
|
||||
|
@ -1309,19 +1452,22 @@ uint32_t ohci_mem_read(OHCIState *ptr, uint32_t addr)
|
|||
addr -= ohci->mem_base;
|
||||
|
||||
/* Only aligned reads are allowed on OHCI */
|
||||
if (addr & 3) {
|
||||
if (addr & 3)
|
||||
{
|
||||
OSDebugOut(TEXT("usb-ohci: Mis-aligned read\n"));
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
|
||||
if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4)
|
||||
{
|
||||
/* 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) {
|
||||
switch (addr >> 2)
|
||||
{
|
||||
case 0: /* HcRevision */
|
||||
return 0x10;
|
||||
|
||||
|
@ -1396,12 +1542,14 @@ void ohci_mem_write(OHCIState *ptr,uint32_t addr, uint32_t val)
|
|||
addr -= ohci->mem_base;
|
||||
|
||||
/* Only aligned reads are allowed on OHCI */
|
||||
if (addr & 3) {
|
||||
if (addr & 3)
|
||||
{
|
||||
fprintf(stderr, "usb-ohci: Mis-aligned write\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((addr >= 0x54) && (addr < (0x54 + ohci->num_ports * 4))) {
|
||||
if ((addr >= 0x54) && (addr < (0x54 + ohci->num_ports * 4)))
|
||||
{
|
||||
/* HcRhPortStatus */
|
||||
OSDebugOut(TEXT("ohci_port_set_status: %d = 0x%08x\n"), (addr - 0x54) >> 2, val);
|
||||
ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
|
||||
|
@ -1410,7 +1558,8 @@ void ohci_mem_write(OHCIState *ptr,uint32_t addr, uint32_t val)
|
|||
#ifdef DEBUG_OHCI
|
||||
OSDebugOut(TEXT("ohci_mem_write: addr %d = 0x%08x\n"), addr >> 2, val);
|
||||
#endif
|
||||
switch (addr >> 2) {
|
||||
switch (addr >> 2)
|
||||
{
|
||||
case 1: /* HcControl */
|
||||
ohci_set_ctl(ohci, val);
|
||||
break;
|
||||
|
@ -1497,7 +1646,8 @@ static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
|
|||
{
|
||||
if (ohci->async_td &&
|
||||
usb_packet_is_inflight(&ohci->usb_packet) &&
|
||||
ohci->usb_packet.ep->dev == dev) {
|
||||
ohci->usb_packet.ep->dev == dev)
|
||||
{
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
}
|
||||
|
@ -1511,13 +1661,13 @@ static USBPortOps ohci_port_ops = {
|
|||
//.complete = ohci_async_complete_packet,
|
||||
};
|
||||
|
||||
static USBBusOps ohci_bus_ops = {
|
||||
};
|
||||
static USBBusOps ohci_bus_ops = {};
|
||||
|
||||
OHCIState* ohci_create(uint32_t base, int ports)
|
||||
{
|
||||
OHCIState* ohci = (OHCIState*)malloc(sizeof(OHCIState));
|
||||
if(!ohci) return NULL;
|
||||
if (!ohci)
|
||||
return NULL;
|
||||
int i;
|
||||
|
||||
const int ticks_per_sec = get_ticks_per_second();
|
||||
|
@ -1526,15 +1676,19 @@ OHCIState *ohci_create(uint32_t base, int ports)
|
|||
|
||||
ohci->mem_base = base;
|
||||
|
||||
if (usb_frame_time == 0) {
|
||||
if (usb_frame_time == 0)
|
||||
{
|
||||
#if OHCI_TIME_WARP
|
||||
usb_frame_time = ticks_per_sec;
|
||||
usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ / 1000);
|
||||
#else
|
||||
usb_frame_time = muldiv64(1, ticks_per_sec, 1000);
|
||||
if (ticks_per_sec >= USB_HZ) {
|
||||
if (ticks_per_sec >= USB_HZ)
|
||||
{
|
||||
usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_bit_time = 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -1543,7 +1697,8 @@ OHCIState *ohci_create(uint32_t base, int ports)
|
|||
}
|
||||
|
||||
ohci->num_ports = ports;
|
||||
for (i = 0; i < ports; i++) {
|
||||
for (i = 0; i < ports; i++)
|
||||
{
|
||||
memset(&(ohci->rhport[i].port), 0, sizeof(USBPort));
|
||||
ohci->rhport[i].port.opaque = ohci;
|
||||
ohci->rhport[i].port.index = i;
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
/* compute with 96 bit intermediate result: (a*b)/c */
|
||||
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
|
||||
{
|
||||
union {
|
||||
union
|
||||
{
|
||||
uint64_t ll;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
uint32_t high, low;
|
||||
#else
|
||||
|
|
|
@ -67,9 +67,11 @@
|
|||
|
||||
// Portable atomic fences implemented below:
|
||||
|
||||
namespace moodycamel {
|
||||
namespace moodycamel
|
||||
{
|
||||
|
||||
enum memory_order {
|
||||
enum memory_order
|
||||
{
|
||||
memory_order_relaxed,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
|
@ -109,17 +111,29 @@ enum memory_order {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
namespace moodycamel {
|
||||
namespace moodycamel
|
||||
{
|
||||
|
||||
AE_FORCEINLINE void compiler_fence(memory_order order)
|
||||
{
|
||||
switch (order) {
|
||||
case memory_order_relaxed: break;
|
||||
case memory_order_acquire: _ReadBarrier(); break;
|
||||
case memory_order_release: _WriteBarrier(); break;
|
||||
case memory_order_acq_rel: _ReadWriteBarrier(); break;
|
||||
case memory_order_seq_cst: _ReadWriteBarrier(); break;
|
||||
default: assert(false);
|
||||
switch (order)
|
||||
{
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
_ReadBarrier();
|
||||
break;
|
||||
case memory_order_release:
|
||||
_WriteBarrier();
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,24 +143,34 @@ AE_FORCEINLINE void compiler_fence(memory_order order)
|
|||
#if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
|
||||
AE_FORCEINLINE void fence(memory_order order)
|
||||
{
|
||||
switch (order) {
|
||||
case memory_order_relaxed: break;
|
||||
case memory_order_acquire: _ReadBarrier(); break;
|
||||
case memory_order_release: _WriteBarrier(); break;
|
||||
case memory_order_acq_rel: _ReadWriteBarrier(); break;
|
||||
switch (order)
|
||||
{
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
_ReadBarrier();
|
||||
break;
|
||||
case memory_order_release:
|
||||
_WriteBarrier();
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
_ReadWriteBarrier();
|
||||
AeFullSync();
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default: assert(false);
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
AE_FORCEINLINE void fence(memory_order order)
|
||||
{
|
||||
// Non-specialized arch, use heavier memory barriers everywhere just in case :-(
|
||||
switch (order) {
|
||||
switch (order)
|
||||
{
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
|
@ -169,7 +193,8 @@ AE_FORCEINLINE void fence(memory_order order)
|
|||
AeFullSync();
|
||||
_ReadWriteBarrier();
|
||||
break;
|
||||
default: assert(false);
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -178,29 +203,52 @@ AE_FORCEINLINE void fence(memory_order order)
|
|||
// Use standard library of atomics
|
||||
#include <atomic>
|
||||
|
||||
namespace moodycamel {
|
||||
namespace moodycamel
|
||||
{
|
||||
|
||||
AE_FORCEINLINE void compiler_fence(memory_order order)
|
||||
{
|
||||
switch (order) {
|
||||
case memory_order_relaxed: break;
|
||||
case memory_order_acquire: std::atomic_signal_fence(std::memory_order_acquire); break;
|
||||
case memory_order_release: std::atomic_signal_fence(std::memory_order_release); break;
|
||||
case memory_order_acq_rel: std::atomic_signal_fence(std::memory_order_acq_rel); break;
|
||||
case memory_order_seq_cst: std::atomic_signal_fence(std::memory_order_seq_cst); break;
|
||||
default: assert(false);
|
||||
switch (order)
|
||||
{
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
std::atomic_signal_fence(std::memory_order_acquire);
|
||||
break;
|
||||
case memory_order_release:
|
||||
std::atomic_signal_fence(std::memory_order_release);
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
std::atomic_signal_fence(std::memory_order_acq_rel);
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
std::atomic_signal_fence(std::memory_order_seq_cst);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
AE_FORCEINLINE void fence(memory_order order)
|
||||
{
|
||||
switch (order) {
|
||||
case memory_order_relaxed: break;
|
||||
case memory_order_acquire: std::atomic_thread_fence(std::memory_order_acquire); break;
|
||||
case memory_order_release: std::atomic_thread_fence(std::memory_order_release); break;
|
||||
case memory_order_acq_rel: std::atomic_thread_fence(std::memory_order_acq_rel); break;
|
||||
case memory_order_seq_cst: std::atomic_thread_fence(std::memory_order_seq_cst); break;
|
||||
default: assert(false);
|
||||
switch (order)
|
||||
{
|
||||
case memory_order_relaxed:
|
||||
break;
|
||||
case memory_order_acquire:
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
break;
|
||||
case memory_order_release:
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
break;
|
||||
case memory_order_acq_rel:
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
break;
|
||||
case memory_order_seq_cst:
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +270,8 @@ AE_FORCEINLINE void fence(memory_order order)
|
|||
// Provides basic support for atomic variables -- no memory ordering guarantees are provided.
|
||||
// The guarantee of atomicity is only made for types that already have atomic load and store guarantees
|
||||
// at the hardware level -- on most platforms this generally means aligned pointers and integers (only).
|
||||
namespace moodycamel {
|
||||
namespace moodycamel
|
||||
{
|
||||
template <typename T>
|
||||
class weak_atomic
|
||||
{
|
||||
|
@ -232,32 +281,59 @@ public:
|
|||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
|
||||
#endif
|
||||
template<typename U> weak_atomic(U&& x) : value(std::forward<U>(x)) { }
|
||||
template <typename U>
|
||||
weak_atomic(U&& x)
|
||||
: value(std::forward<U>(x))
|
||||
{
|
||||
}
|
||||
#ifdef __cplusplus_cli
|
||||
// Work around bug with universal reference/nullptr combination that only appears when /clr is on
|
||||
weak_atomic(nullptr_t) : value(nullptr) { }
|
||||
weak_atomic(nullptr_t)
|
||||
: value(nullptr)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
weak_atomic(weak_atomic const& other) : value(other.value) { }
|
||||
weak_atomic(weak_atomic&& other) : value(std::move(other.value)) { }
|
||||
weak_atomic(weak_atomic const& other)
|
||||
: value(other.value)
|
||||
{
|
||||
}
|
||||
weak_atomic(weak_atomic&& other)
|
||||
: value(std::move(other.value))
|
||||
{
|
||||
}
|
||||
#ifdef AE_VCPP
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
AE_FORCEINLINE operator T() const { return load(); }
|
||||
AE_FORCEINLINE operator T() const
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
|
||||
#ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
|
||||
template<typename U> AE_FORCEINLINE weak_atomic const& operator=(U&& x) { value = std::forward<U>(x); return *this; }
|
||||
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) { value = other.value; return *this; }
|
||||
template <typename U>
|
||||
AE_FORCEINLINE weak_atomic const& operator=(U&& x)
|
||||
{
|
||||
value = std::forward<U>(x);
|
||||
return *this;
|
||||
}
|
||||
AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other)
|
||||
{
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AE_FORCEINLINE T load() const { return value; }
|
||||
|
||||
AE_FORCEINLINE T fetch_add_acquire(T increment)
|
||||
{
|
||||
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
|
||||
if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
if (sizeof(T) == 4)
|
||||
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
#if defined(_M_AMD64)
|
||||
else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
else if (sizeof(T) == 8)
|
||||
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform
|
||||
|
@ -269,9 +345,11 @@ public:
|
|||
AE_FORCEINLINE T fetch_add_release(T increment)
|
||||
{
|
||||
#if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
|
||||
if (sizeof(T) == 4) return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
if (sizeof(T) == 4)
|
||||
return _InterlockedExchangeAdd((long volatile*)&value, (long)increment);
|
||||
#if defined(_M_AMD64)
|
||||
else if (sizeof(T) == 8) return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
else if (sizeof(T) == 8)
|
||||
return _InterlockedExchangeAdd64((long long volatile*)&value, (long long)increment);
|
||||
#endif
|
||||
#else
|
||||
#error Unsupported platform
|
||||
|
@ -503,14 +581,14 @@ namespace moodycamel
|
|||
do
|
||||
{
|
||||
rc = sem_wait(&m_sema);
|
||||
}
|
||||
while (rc == -1 && errno == EINTR);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
}
|
||||
|
||||
bool try_wait()
|
||||
{
|
||||
int rc;
|
||||
do {
|
||||
do
|
||||
{
|
||||
rc = sem_trywait(&m_sema);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return !(rc == -1 && errno == EAGAIN);
|
||||
|
@ -526,13 +604,15 @@ namespace moodycamel
|
|||
ts.tv_nsec += (usecs % usecs_in_1_sec) * 1000;
|
||||
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
|
||||
// so we have to clean things up before passing it in
|
||||
if (ts.tv_nsec >= nsecs_in_1_sec) {
|
||||
if (ts.tv_nsec >= nsecs_in_1_sec)
|
||||
{
|
||||
ts.tv_nsec -= nsecs_in_1_sec;
|
||||
++ts.tv_sec;
|
||||
}
|
||||
|
||||
int rc;
|
||||
do {
|
||||
do
|
||||
{
|
||||
rc = sem_timedwait(&m_sema, &ts);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return !(rc == -1 && errno == ETIMEDOUT);
|
||||
|
@ -611,7 +691,8 @@ namespace moodycamel
|
|||
}
|
||||
|
||||
public:
|
||||
LightweightSemaphore(ssize_t initialCount = 0) : m_count(initialCount)
|
||||
LightweightSemaphore(ssize_t initialCount = 0)
|
||||
: m_count(initialCount)
|
||||
{
|
||||
assert(initialCount >= 0);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@
|
|||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace moodycamel {
|
||||
namespace moodycamel
|
||||
{
|
||||
|
||||
template <typename T, size_t MAX_BLOCK_SIZE = 512>
|
||||
class ReaderWriterQueue
|
||||
|
@ -98,7 +99,8 @@ public:
|
|||
Block* firstBlock = nullptr;
|
||||
|
||||
largestBlockSize = ceilToPow2(maxSize + 1); // We need a spare slot to fit maxSize elements in the block
|
||||
if (largestBlockSize > MAX_BLOCK_SIZE * 2) {
|
||||
if (largestBlockSize > MAX_BLOCK_SIZE * 2)
|
||||
{
|
||||
// We need a spare block in case the producer is writing to a different block the consumer is reading from, and
|
||||
// wants to enqueue the maximum number of elements. We also need a spare element in each block to avoid the ambiguity
|
||||
// between front == tail meaning "empty" and "full".
|
||||
|
@ -107,28 +109,34 @@ public:
|
|||
size_t initialBlockCount = (maxSize + MAX_BLOCK_SIZE * 2 - 3) / (MAX_BLOCK_SIZE - 1);
|
||||
largestBlockSize = MAX_BLOCK_SIZE;
|
||||
Block* lastBlock = nullptr;
|
||||
for (size_t i = 0; i != initialBlockCount; ++i) {
|
||||
for (size_t i = 0; i != initialBlockCount; ++i)
|
||||
{
|
||||
auto block = make_block(largestBlockSize);
|
||||
if (block == nullptr) {
|
||||
if (block == nullptr)
|
||||
{
|
||||
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
if (firstBlock == nullptr) {
|
||||
if (firstBlock == nullptr)
|
||||
{
|
||||
firstBlock = block;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
lastBlock->next = block;
|
||||
}
|
||||
lastBlock = block;
|
||||
block->next = firstBlock;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
firstBlock = make_block(largestBlockSize);
|
||||
if (firstBlock == nullptr) {
|
||||
if (firstBlock == nullptr)
|
||||
{
|
||||
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
|
@ -147,9 +155,9 @@ public:
|
|||
// Note: The queue should not be accessed concurrently while it's
|
||||
// being moved. It's up to the user to synchronize this.
|
||||
ReaderWriterQueue(ReaderWriterQueue&& other)
|
||||
: frontBlock(other.frontBlock.load()),
|
||||
tailBlock(other.tailBlock.load()),
|
||||
largestBlockSize(other.largestBlockSize)
|
||||
: frontBlock(other.frontBlock.load())
|
||||
, tailBlock(other.tailBlock.load())
|
||||
, largestBlockSize(other.largestBlockSize)
|
||||
#ifndef NDEBUG
|
||||
, enqueuing(false)
|
||||
, dequeuing(false)
|
||||
|
@ -157,7 +165,8 @@ public:
|
|||
{
|
||||
other.largestBlockSize = 32;
|
||||
Block* b = other.make_block(other.largestBlockSize);
|
||||
if (b == nullptr) {
|
||||
if (b == nullptr)
|
||||
{
|
||||
#ifdef MOODYCAMEL_EXCEPTIONS_ENABLED
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
|
@ -193,12 +202,14 @@ public:
|
|||
// Destroy any remaining objects in queue and free memory
|
||||
Block* frontBlock_ = frontBlock;
|
||||
Block* block = frontBlock_;
|
||||
do {
|
||||
do
|
||||
{
|
||||
Block* nextBlock = block->next;
|
||||
size_t blockFront = block->front;
|
||||
size_t blockTail = block->tail;
|
||||
|
||||
for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask) {
|
||||
for (size_t i = blockFront; i != blockTail; i = (i + 1) & block->sizeMask)
|
||||
{
|
||||
auto element = reinterpret_cast<T*>(block->data + i * sizeof(T));
|
||||
element->~T();
|
||||
(void)element;
|
||||
|
@ -293,7 +304,8 @@ public:
|
|||
size_t blockTail = frontBlock_->localTail;
|
||||
size_t blockFront = frontBlock_->front.load();
|
||||
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
|
||||
non_empty_front_block:
|
||||
|
@ -307,7 +319,8 @@ public:
|
|||
fence(memory_order_release);
|
||||
frontBlock_->front = blockFront;
|
||||
}
|
||||
else if (frontBlock_ != tailBlock.load()) {
|
||||
else if (frontBlock_ != tailBlock.load())
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
|
||||
frontBlock_ = frontBlock.load();
|
||||
|
@ -315,7 +328,8 @@ public:
|
|||
blockFront = frontBlock_->front.load();
|
||||
fence(memory_order_acquire);
|
||||
|
||||
if (blockFront != blockTail) {
|
||||
if (blockFront != blockTail)
|
||||
{
|
||||
// Oh look, the front block isn't empty after all
|
||||
goto non_empty_front_block;
|
||||
}
|
||||
|
@ -351,7 +365,8 @@ public:
|
|||
fence(memory_order_release);
|
||||
frontBlock_->front = nextBlockFront;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// No elements in current block and no other block to advance to
|
||||
return false;
|
||||
}
|
||||
|
@ -376,19 +391,22 @@ public:
|
|||
size_t blockTail = frontBlock_->localTail;
|
||||
size_t blockFront = frontBlock_->front.load();
|
||||
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
non_empty_front_block:
|
||||
return reinterpret_cast<T*>(frontBlock_->data + blockFront * sizeof(T));
|
||||
}
|
||||
else if (frontBlock_ != tailBlock.load()) {
|
||||
else if (frontBlock_ != tailBlock.load())
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
frontBlock_ = frontBlock.load();
|
||||
blockTail = frontBlock_->localTail = frontBlock_->tail.load();
|
||||
blockFront = frontBlock_->front.load();
|
||||
fence(memory_order_acquire);
|
||||
|
||||
if (blockFront != blockTail) {
|
||||
if (blockFront != blockTail)
|
||||
{
|
||||
goto non_empty_front_block;
|
||||
}
|
||||
|
||||
|
@ -418,7 +436,8 @@ public:
|
|||
size_t blockTail = frontBlock_->localTail;
|
||||
size_t blockFront = frontBlock_->front.load();
|
||||
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load())) {
|
||||
if (blockFront != blockTail || blockFront != (frontBlock_->localTail = frontBlock_->tail.load()))
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
|
||||
non_empty_front_block:
|
||||
|
@ -430,14 +449,16 @@ public:
|
|||
fence(memory_order_release);
|
||||
frontBlock_->front = blockFront;
|
||||
}
|
||||
else if (frontBlock_ != tailBlock.load()) {
|
||||
else if (frontBlock_ != tailBlock.load())
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
frontBlock_ = frontBlock.load();
|
||||
blockTail = frontBlock_->localTail = frontBlock_->tail.load();
|
||||
blockFront = frontBlock_->front.load();
|
||||
fence(memory_order_acquire);
|
||||
|
||||
if (blockFront != blockTail) {
|
||||
if (blockFront != blockTail)
|
||||
{
|
||||
goto non_empty_front_block;
|
||||
}
|
||||
|
||||
|
@ -464,7 +485,8 @@ public:
|
|||
fence(memory_order_release);
|
||||
frontBlock_->front = nextBlockFront;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
// No elements in current block and no other block to advance to
|
||||
return false;
|
||||
}
|
||||
|
@ -479,7 +501,8 @@ public:
|
|||
size_t result = 0;
|
||||
Block* frontBlock_ = frontBlock.load();
|
||||
Block* block = frontBlock_;
|
||||
do {
|
||||
do
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
size_t blockFront = block->front.load();
|
||||
size_t blockTail = block->tail.load();
|
||||
|
@ -491,7 +514,11 @@ public:
|
|||
|
||||
|
||||
private:
|
||||
enum AllocationMode { CanAlloc, CannotAlloc };
|
||||
enum AllocationMode
|
||||
{
|
||||
CanAlloc,
|
||||
CannotAlloc
|
||||
};
|
||||
|
||||
#if MOODYCAMEL_HAS_EMPLACE
|
||||
template <AllocationMode canAlloc, typename... Args>
|
||||
|
@ -517,7 +544,8 @@ private:
|
|||
size_t blockTail = tailBlock_->tail.load();
|
||||
|
||||
size_t nextBlockTail = (blockTail + 1) & tailBlock_->sizeMask;
|
||||
if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load())) {
|
||||
if (nextBlockTail != blockFront || nextBlockTail != (tailBlock_->localFront = tailBlock_->front.load()))
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
// This block has room for at least one more element
|
||||
char* location = tailBlock_->data + blockTail * sizeof(T);
|
||||
|
@ -530,9 +558,11 @@ private:
|
|||
fence(memory_order_release);
|
||||
tailBlock_->tail = nextBlockTail;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
fence(memory_order_acquire);
|
||||
if (tailBlock_->next.load() != frontBlock) {
|
||||
if (tailBlock_->next.load() != frontBlock)
|
||||
{
|
||||
// Note that the reason we can't advance to the frontBlock and start adding new entries there
|
||||
// is because if we did, then dequeue would stay in that block, eventually reading the new values,
|
||||
// instead of advancing to the next full block (whose values were enqueued first and so should be
|
||||
|
@ -563,11 +593,13 @@ private:
|
|||
fence(memory_order_release);
|
||||
tailBlock = tailBlockNext;
|
||||
}
|
||||
else if (canAlloc == CanAlloc) {
|
||||
else if (canAlloc == CanAlloc)
|
||||
{
|
||||
// tailBlock is full and there's no free block ahead; create a new block
|
||||
auto newBlockSize = largestBlockSize >= MAX_BLOCK_SIZE ? largestBlockSize : largestBlockSize * 2;
|
||||
auto newBlock = make_block(newBlockSize);
|
||||
if (newBlock == nullptr) {
|
||||
if (newBlock == nullptr)
|
||||
{
|
||||
// Could not allocate a block!
|
||||
return false;
|
||||
}
|
||||
|
@ -593,11 +625,13 @@ private:
|
|||
fence(memory_order_release);
|
||||
tailBlock = newBlock;
|
||||
}
|
||||
else if (canAlloc == CannotAlloc) {
|
||||
else if (canAlloc == CannotAlloc)
|
||||
{
|
||||
// Would have had to allocate a new block to enqueue, but not allowed
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
assert(false && "Should be unreachable code");
|
||||
return false;
|
||||
}
|
||||
|
@ -622,7 +656,8 @@ private:
|
|||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
for (size_t i = 1; i < sizeof(size_t); i <<= 1) {
|
||||
for (size_t i = 1; i < sizeof(size_t); i <<= 1)
|
||||
{
|
||||
x |= x >> (i << 3);
|
||||
}
|
||||
++x;
|
||||
|
@ -635,6 +670,7 @@ private:
|
|||
const std::size_t alignment = std::alignment_of<U>::value;
|
||||
return ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
struct ReentrantGuard
|
||||
|
@ -676,7 +712,14 @@ private:
|
|||
|
||||
// size must be a power of two (and greater than 0)
|
||||
Block(size_t const& _size, char* _rawThis, char* _data)
|
||||
: front(0), localTail(0), tail(0), localFront(0), next(nullptr), data(_data), sizeMask(_size - 1), rawThis(_rawThis)
|
||||
: front(0)
|
||||
, localTail(0)
|
||||
, tail(0)
|
||||
, localFront(0)
|
||||
, next(nullptr)
|
||||
, data(_data)
|
||||
, sizeMask(_size - 1)
|
||||
, rawThis(_rawThis)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -695,7 +738,8 @@ private:
|
|||
auto size = sizeof(Block) + std::alignment_of<Block>::value - 1;
|
||||
size += sizeof(T) * capacity + std::alignment_of<T>::value - 1;
|
||||
auto newBlockRaw = static_cast<char*>(std::malloc(size));
|
||||
if (newBlockRaw == nullptr) {
|
||||
if (newBlockRaw == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -728,7 +772,8 @@ private:
|
|||
public:
|
||||
explicit BlockingReaderWriterQueue(size_t maxSize = 15)
|
||||
: inner(maxSize)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Enqueues a copy of element if there is room in the queue.
|
||||
|
@ -736,7 +781,8 @@ public:
|
|||
// Does not allocate memory.
|
||||
AE_FORCEINLINE bool try_enqueue(T const& element)
|
||||
{
|
||||
if (inner.try_enqueue(element)) {
|
||||
if (inner.try_enqueue(element))
|
||||
{
|
||||
sema.signal();
|
||||
return true;
|
||||
}
|
||||
|
@ -748,7 +794,8 @@ public:
|
|||
// Does not allocate memory.
|
||||
AE_FORCEINLINE bool try_enqueue(T&& element)
|
||||
{
|
||||
if (inner.try_enqueue(std::forward<T>(element))) {
|
||||
if (inner.try_enqueue(std::forward<T>(element)))
|
||||
{
|
||||
sema.signal();
|
||||
return true;
|
||||
}
|
||||
|
@ -761,7 +808,8 @@ public:
|
|||
// Only fails (returns false) if memory allocation fails.
|
||||
AE_FORCEINLINE bool enqueue(T const& element)
|
||||
{
|
||||
if (inner.enqueue(element)) {
|
||||
if (inner.enqueue(element))
|
||||
{
|
||||
sema.signal();
|
||||
return true;
|
||||
}
|
||||
|
@ -773,7 +821,8 @@ public:
|
|||
// Only fails (returns false) if memory allocation fails.
|
||||
AE_FORCEINLINE bool enqueue(T&& element)
|
||||
{
|
||||
if (inner.enqueue(std::forward<T>(element))) {
|
||||
if (inner.enqueue(std::forward<T>(element)))
|
||||
{
|
||||
sema.signal();
|
||||
return true;
|
||||
}
|
||||
|
@ -787,7 +836,8 @@ public:
|
|||
template <typename U>
|
||||
bool try_dequeue(U& result)
|
||||
{
|
||||
if (sema.tryWait()) {
|
||||
if (sema.tryWait())
|
||||
{
|
||||
bool success = inner.try_dequeue(result);
|
||||
assert(success);
|
||||
AE_UNUSED(success);
|
||||
|
@ -819,7 +869,8 @@ public:
|
|||
template <typename U>
|
||||
bool wait_dequeue_timed(U& result, std::int64_t timeout_usecs)
|
||||
{
|
||||
if (!sema.wait(timeout_usecs)) {
|
||||
if (!sema.wait(timeout_usecs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool success = inner.try_dequeue(result);
|
||||
|
@ -860,7 +911,8 @@ public:
|
|||
// `pop` was called.
|
||||
AE_FORCEINLINE bool pop()
|
||||
{
|
||||
if (sema.tryWait()) {
|
||||
if (sema.tryWait())
|
||||
{
|
||||
bool result = inner.pop();
|
||||
assert(result);
|
||||
AE_UNUSED(result);
|
||||
|
|
|
@ -33,12 +33,15 @@ _HidD_GetProductString HidD_GetProductString = NULL;
|
|||
|
||||
static HMODULE hModHid = 0;
|
||||
|
||||
int InitHid() {
|
||||
if (hModHid) {
|
||||
int InitHid()
|
||||
{
|
||||
if (hModHid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
hModHid = LoadLibraryA("hid.dll");
|
||||
if (hModHid) {
|
||||
if (hModHid)
|
||||
{
|
||||
if ((HidD_GetHidGuid = (_HidD_GetHidGuid)GetProcAddress(hModHid, "HidD_GetHidGuid")) &&
|
||||
(HidD_GetAttributes = (_HidD_GetAttributes)GetProcAddress(hModHid, "HidD_GetAttributes")) &&
|
||||
(HidD_GetPreparsedData = (_HidD_GetPreparsedData)GetProcAddress(hModHid, "HidD_GetPreparsedData")) &&
|
||||
|
@ -51,7 +54,8 @@ int InitHid() {
|
|||
(HidP_GetUsageValue = (_HidP_GetUsageValue)GetProcAddress(hModHid, "HidP_GetUsageValue")) &&
|
||||
(HidD_GetProductString = (_HidD_GetProductString)GetProcAddress(hModHid, "HidD_GetProductString")) &&
|
||||
(HidD_GetFeature = (_HidD_GetFeature)GetProcAddress(hModHid, "HidD_GetFeature")) &&
|
||||
(HidD_SetFeature = (_HidD_SetFeature)GetProcAddress(hModHid, "HidD_SetFeature"))) {
|
||||
(HidD_SetFeature = (_HidD_SetFeature)GetProcAddress(hModHid, "HidD_SetFeature")))
|
||||
{
|
||||
//pHidD_GetHidGuid(&GUID_DEVINTERFACE_HID);
|
||||
return 1;
|
||||
}
|
||||
|
@ -60,8 +64,10 @@ int InitHid() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void UninitHid() {
|
||||
if (hModHid) {
|
||||
void UninitHid()
|
||||
{
|
||||
if (hModHid)
|
||||
{
|
||||
FreeLibrary(hModHid);
|
||||
hModHid = 0;
|
||||
}
|
||||
|
|
|
@ -309,14 +309,17 @@ typedef struct _HIDP_BUTTON_CAPS
|
|||
BOOLEAN IsAbsolute;
|
||||
|
||||
ULONG Reserved[10];
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
USAGE UsageMin, UsageMax;
|
||||
USHORT StringMin, StringMax;
|
||||
USHORT DesignatorMin, DesignatorMax;
|
||||
USHORT DataIndexMin, DataIndexMax;
|
||||
} Range;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
USAGE Usage, Reserved1;
|
||||
USHORT StringIndex, Reserved2;
|
||||
USHORT DesignatorIndex, Reserved3;
|
||||
|
@ -357,15 +360,18 @@ typedef struct _HIDP_VALUE_CAPS
|
|||
LONG LogicalMin, LogicalMax;
|
||||
LONG PhysicalMin, PhysicalMax;
|
||||
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
USAGE UsageMin, UsageMax;
|
||||
USHORT StringMin, StringMax;
|
||||
USHORT DesignatorMin, DesignatorMax;
|
||||
USHORT DataIndexMin, DataIndexMax;
|
||||
} Range;
|
||||
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
USAGE Usage, Reserved1;
|
||||
USHORT StringIndex, Reserved2;
|
||||
USHORT DesignatorIndex, Reserved3;
|
||||
|
@ -374,7 +380,8 @@ typedef struct _HIDP_VALUE_CAPS
|
|||
};
|
||||
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
|
||||
|
||||
typedef struct _HIDD_ATTRIBUTES {
|
||||
typedef struct _HIDD_ATTRIBUTES
|
||||
{
|
||||
ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
|
||||
|
||||
//
|
||||
|
@ -421,7 +428,8 @@ typedef struct _HIDP_DATA
|
|||
{
|
||||
USHORT DataIndex;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
union
|
||||
{
|
||||
ULONG RawValue; // for values
|
||||
BOOLEAN On; // for buttons MUST BE TRUE for buttons.
|
||||
};
|
||||
|
|
|
@ -183,7 +183,13 @@ void CIniFileA::Load( std::istream& input , bool bMerge )
|
|||
|
||||
CIniSectionA* pSection = NULL;
|
||||
std::string sRead;
|
||||
enum { KEY , SECTION , COMMENT , OTHER };
|
||||
enum
|
||||
{
|
||||
KEY,
|
||||
SECTION,
|
||||
COMMENT,
|
||||
OTHER
|
||||
};
|
||||
|
||||
while (std::getline(input, sRead))
|
||||
{
|
||||
|
@ -430,7 +436,9 @@ SecIndexA::iterator CIniFileA::_find_sec( const std::string& sSection )
|
|||
|
||||
// CIniSectionA functions start here
|
||||
|
||||
CIniSectionA::CIniSectionA( CIniFileA* pIniFile , const std::string& sSectionName ) : m_pIniFile(pIniFile) , m_sSectionName(sSectionName)
|
||||
CIniSectionA::CIniSectionA(CIniFileA* pIniFile, const std::string& sSectionName)
|
||||
: m_pIniFile(pIniFile)
|
||||
, m_sSectionName(sSectionName)
|
||||
{
|
||||
#ifdef _CINIFILE_DEBUG
|
||||
std::cout << "CIniSectionA::CIniSectionA()" << std::endl;
|
||||
|
@ -622,7 +630,9 @@ KeyIndexA::iterator CIniSectionA::_find_key( const std::string& sKey )
|
|||
|
||||
// CIniKeyA Functions Start Here
|
||||
|
||||
CIniKeyA::CIniKeyA( CIniSectionA* pSection , const std::string& sKeyName ) : m_pSection(pSection) , m_sKeyName(sKeyName)
|
||||
CIniKeyA::CIniKeyA(CIniSectionA* pSection, const std::string& sKeyName)
|
||||
: m_pSection(pSection)
|
||||
, m_sKeyName(sKeyName)
|
||||
{
|
||||
#ifdef _CINIFILE_DEBUG
|
||||
std::cout << "CIniKeyA::CIniKeyA()" << std::endl;
|
||||
|
@ -819,7 +829,13 @@ void CIniFileW::Load( std::wistream& input , bool bMerge )
|
|||
|
||||
CIniSectionW* pSection = NULL;
|
||||
std::wstring sRead;
|
||||
enum { KEY , SECTION , COMMENT , OTHER };
|
||||
enum
|
||||
{
|
||||
KEY,
|
||||
SECTION,
|
||||
COMMENT,
|
||||
OTHER
|
||||
};
|
||||
|
||||
while (std::getline(input, sRead))
|
||||
{
|
||||
|
@ -1070,7 +1086,9 @@ SecIndexW::iterator CIniFileW::_find_sec( const std::wstring& sSection )
|
|||
|
||||
// CIniSectionW functions start here
|
||||
|
||||
CIniSectionW::CIniSectionW( CIniFileW* pIniFile , const std::wstring& sSectionName ) : m_pIniFile(pIniFile) , m_sSectionName(sSectionName)
|
||||
CIniSectionW::CIniSectionW(CIniFileW* pIniFile, const std::wstring& sSectionName)
|
||||
: m_pIniFile(pIniFile)
|
||||
, m_sSectionName(sSectionName)
|
||||
{
|
||||
#ifdef _CINIFILE_DEBUG
|
||||
std::wcout << L"CIniSectionW::CIniSectionW()" << std::endl;
|
||||
|
@ -1262,7 +1280,9 @@ KeyIndexW::iterator CIniSectionW::_find_key( const std::wstring& sKey )
|
|||
|
||||
// CIniKeyW Functions Start Here
|
||||
|
||||
CIniKeyW::CIniKeyW( CIniSectionW* pSection , const std::wstring& sKeyName ) : m_pSection(pSection) , m_sKeyName(sKeyName)
|
||||
CIniKeyW::CIniKeyW(CIniSectionW* pSection, const std::wstring& sKeyName)
|
||||
: m_pSection(pSection)
|
||||
, m_sKeyName(sKeyName)
|
||||
{
|
||||
#ifdef _CINIFILE_DEBUG
|
||||
std::wcout << L"CIniKeyW::CIniKeyW()" << std::endl;
|
||||
|
|
|
@ -71,6 +71,7 @@ class CIniFileA
|
|||
{
|
||||
public:
|
||||
static const char* const LF;
|
||||
|
||||
public:
|
||||
CIniFileA();
|
||||
~CIniFileA();
|
||||
|
@ -91,15 +92,20 @@ public:
|
|||
class CIniMergeA
|
||||
{
|
||||
public:
|
||||
explicit CIniMergeA(CIniFileA& ini):_ini(ini) {}
|
||||
explicit CIniMergeA(CIniFileA& ini)
|
||||
: _ini(ini)
|
||||
{
|
||||
}
|
||||
std::istream& operator()(std::istream& input) const
|
||||
{
|
||||
_ini.Load(input, true);
|
||||
return input;
|
||||
}
|
||||
|
||||
private:
|
||||
CIniFileA& _ini;
|
||||
};
|
||||
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
// Added for versions earlier than VS2008
|
||||
|
@ -138,6 +144,7 @@ public:
|
|||
CIniKeyA(const CIniKeyA&); // No Copy
|
||||
CIniKeyA& operator=(const CIniKeyA&); // No Copy
|
||||
~CIniKeyA();
|
||||
|
||||
public:
|
||||
// Sets the value of the key
|
||||
void SetValue(const std::string& sValue);
|
||||
|
@ -148,6 +155,7 @@ public:
|
|||
bool SetKeyName(std::string sKeyName);
|
||||
// Returns the name of the Key
|
||||
std::string GetKeyName() const;
|
||||
|
||||
private:
|
||||
// Pointer to the parent CIniSectionA
|
||||
CIniSectionA* m_pSection;
|
||||
|
@ -182,6 +190,7 @@ public:
|
|||
CIniSectionA(const CIniSectionA&); // No Copy
|
||||
CIniSectionA& operator=(const CIniSectionA&); // No Copy
|
||||
~CIniSectionA();
|
||||
|
||||
public:
|
||||
// Adds a key to the CIniSectionA object, returns a CIniKeyA pointer to the new or existing object
|
||||
CIniKeyA* AddKey(std::string sKeyName);
|
||||
|
@ -204,9 +213,11 @@ public:
|
|||
bool SetSectionName(std::string sSectionName);
|
||||
// Returns the section name
|
||||
std::string GetSectionName() const;
|
||||
|
||||
private:
|
||||
KeyIndexA::const_iterator _find_key(const std::string& sKeyName) const;
|
||||
KeyIndexA::iterator _find_key(const std::string& sKeyName);
|
||||
|
||||
private:
|
||||
// CIniFileA pointer back to the object that instanciated the section
|
||||
CIniFileA* m_pIniFile;
|
||||
|
@ -257,9 +268,11 @@ public:
|
|||
bool RenameSection(const std::string& sSectionName, const std::string& sNewSectionName);
|
||||
// Renames an existing key returns true on success, false if the key didn't exist or there was another section with the same sNewSectionName
|
||||
bool RenameKey(const std::string& sSectionName, const std::string& sKeyName, const std::string& sNewKeyName);
|
||||
|
||||
private:
|
||||
SecIndexA::const_iterator _find_sec(const std::string& sSection) const;
|
||||
SecIndexA::iterator _find_sec(const std::string& sSection);
|
||||
|
||||
private:
|
||||
CIniFileA(const CIniFileA&); // No Copy
|
||||
CIniFileA& operator=(const CIniFileA&); // No Copy
|
||||
|
@ -295,6 +308,7 @@ class CIniFileW
|
|||
{
|
||||
public:
|
||||
static const wchar_t* const LF;
|
||||
|
||||
public:
|
||||
CIniFileW();
|
||||
~CIniFileW();
|
||||
|
@ -315,15 +329,20 @@ public:
|
|||
class CIniMergeW
|
||||
{
|
||||
public:
|
||||
explicit CIniMergeW(CIniFileW& ini):_ini(ini) {}
|
||||
explicit CIniMergeW(CIniFileW& ini)
|
||||
: _ini(ini)
|
||||
{
|
||||
}
|
||||
std::wistream& operator()(std::wistream& input) const
|
||||
{
|
||||
_ini.Load(input, true);
|
||||
return input;
|
||||
}
|
||||
|
||||
private:
|
||||
CIniFileW& _ini;
|
||||
};
|
||||
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
// Added for versions earlier than VS2008
|
||||
|
@ -361,6 +380,7 @@ public:
|
|||
CIniKeyW(const CIniKeyW&); // No Copy
|
||||
CIniKeyW& operator=(const CIniKeyW&); // No Copy
|
||||
~CIniKeyW();
|
||||
|
||||
public:
|
||||
// Sets the value of the key
|
||||
void SetValue(const std::wstring& sValue);
|
||||
|
@ -371,6 +391,7 @@ public:
|
|||
bool SetKeyName(std::wstring sKeyName);
|
||||
// Returns the name of the Key
|
||||
std::wstring GetKeyName() const;
|
||||
|
||||
private:
|
||||
// Pointer to the parent CIniSectionW
|
||||
CIniSectionW* m_pSection;
|
||||
|
@ -405,6 +426,7 @@ public:
|
|||
CIniSectionW(const CIniSectionW&); // No Copy
|
||||
CIniSectionW& operator=(const CIniSectionW&); // No Copy
|
||||
~CIniSectionW();
|
||||
|
||||
public:
|
||||
// Adds a key to the CIniSectionW object, returns a CIniKeyW pointer to the new or existing object
|
||||
CIniKeyW* AddKey(std::wstring sKeyName);
|
||||
|
@ -427,9 +449,11 @@ public:
|
|||
bool SetSectionName(std::wstring sSectionName);
|
||||
// Returns the section name
|
||||
std::wstring GetSectionName() const;
|
||||
|
||||
private:
|
||||
KeyIndexW::const_iterator _find_key(const std::wstring& sKeyName) const;
|
||||
KeyIndexW::iterator _find_key(const std::wstring& sKeyName);
|
||||
|
||||
private:
|
||||
// CIniFileW pointer back to the object that instanciated the section
|
||||
CIniFileW* m_pIniFile;
|
||||
|
@ -480,9 +504,11 @@ public:
|
|||
bool RenameSection(const std::wstring& sSectionName, const std::wstring& sNewSectionName);
|
||||
// Renames an existing key returns true on success, false if the key didn't exist or there was another section with the same sNewSectionName
|
||||
bool RenameKey(const std::wstring& sSectionName, const std::wstring& sKeyName, const std::wstring& sNewKeyName);
|
||||
|
||||
private:
|
||||
SecIndexW::const_iterator _find_sec(const std::wstring& sSection) const;
|
||||
SecIndexW::iterator _find_sec(const std::wstring& sSection);
|
||||
|
||||
private:
|
||||
CIniFileW(const CIniFileW&); // No Copy
|
||||
CIniFileW& operator=(const CIniFileW&); // No Copy
|
||||
|
@ -542,4 +568,3 @@ std::wstring str_to_wstr(const std::string& arg);
|
|||
std::string wstr_to_str(const std::wstring& arg);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
|
||||
extern HINSTANCE hInst;
|
||||
|
||||
namespace shared{ namespace rawinput{
|
||||
namespace shared
|
||||
{
|
||||
namespace rawinput
|
||||
{
|
||||
|
||||
static std::vector<ParseRawInputCB*> callbacks;
|
||||
|
||||
|
@ -128,7 +131,8 @@ static int RegisterRaw(HWND hWnd)
|
|||
Rid[3].dwFlags = hWnd ? RIDEV_INPUTSINK : RIDEV_REMOVE;
|
||||
Rid[3].hwndTarget = hWnd;
|
||||
|
||||
if (RegisterRawInputDevices(Rid, countof(Rid), sizeof(Rid[0])) == FALSE) {
|
||||
if (RegisterRawInputDevices(Rid, countof(Rid), sizeof(Rid[0])) == FALSE)
|
||||
{
|
||||
//registration failed. Call GetLastError for the cause of the error.
|
||||
fprintf(stderr, "Could not (de)register raw input devices.\n");
|
||||
return 0;
|
||||
|
@ -138,7 +142,8 @@ static int RegisterRaw(HWND hWnd)
|
|||
|
||||
static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_ACTIVATE:
|
||||
OSDebugOut(TEXT("****** WM_ACTIVATE ****** %p %d\n"), hWnd, LOWORD(wParam) != WA_INACTIVE);
|
||||
skipInput = LOWORD(wParam) == WA_INACTIVE;
|
||||
|
@ -160,13 +165,16 @@ static LRESULT CALLBACK RawInputProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
|
|||
PRAWINPUT pRawInput;
|
||||
UINT bufferSize = 0;
|
||||
|
||||
switch(uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
if (eatenWnd == nullptr)
|
||||
RegisterRaw(hWnd);
|
||||
break;
|
||||
case WM_INPUT: {
|
||||
if (skipInput) break;
|
||||
case WM_INPUT:
|
||||
{
|
||||
if (skipInput)
|
||||
break;
|
||||
|
||||
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER));
|
||||
pRawInput = (PRAWINPUT)malloc(bufferSize);
|
||||
|
@ -174,7 +182,8 @@ static LRESULT CALLBACK RawInputProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
|
|||
if (!pRawInput)
|
||||
break;
|
||||
|
||||
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)) > 0) {
|
||||
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, pRawInput, &bufferSize, sizeof(RAWINPUTHEADER)) > 0)
|
||||
{
|
||||
|
||||
if (pRawInput->header.dwType == RIM_TYPEKEYBOARD)
|
||||
ToggleCursor(hWnd, pRawInput->data.keyboard);
|
||||
|
@ -284,4 +293,5 @@ void Uninitialize()
|
|||
eatenWnd = nullptr;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace rawinput
|
||||
} // namespace shared
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include <setupapi.h>
|
||||
#include "hidapi.h"
|
||||
|
||||
namespace shared{ namespace rawinput{
|
||||
namespace shared
|
||||
{
|
||||
namespace rawinput
|
||||
{
|
||||
|
||||
class ParseRawInputCB
|
||||
{
|
||||
|
@ -31,4 +34,5 @@ namespace shared{ namespace rawinput{
|
|||
|
||||
void RegisterCallback(ParseRawInputCB* cb);
|
||||
void UnregisterCallback(ParseRawInputCB* cb);
|
||||
}}
|
||||
} // namespace rawinput
|
||||
} // namespace shared
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
#if 0
|
||||
#define DPRINTF OSDebugOut
|
||||
#else
|
||||
#define DPRINTF(...) do{}while(0)
|
||||
#define DPRINTF(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
RingBuffer::RingBuffer()
|
||||
|
@ -33,7 +36,8 @@ RingBuffer::RingBuffer()
|
|||
{
|
||||
}
|
||||
|
||||
RingBuffer::RingBuffer(size_t capacity) : RingBuffer()
|
||||
RingBuffer::RingBuffer(size_t capacity)
|
||||
: RingBuffer()
|
||||
{
|
||||
reserve(capacity);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ using sec = std::chrono::seconds;
|
|||
class RingBuffer
|
||||
{
|
||||
RingBuffer(RingBuffer&) = delete;
|
||||
|
||||
public:
|
||||
RingBuffer();
|
||||
RingBuffer(size_t capacity);
|
||||
|
@ -45,10 +46,16 @@ public:
|
|||
void read(size_t bytes);
|
||||
|
||||
template <typename T>
|
||||
void write(size_t samples) { write(samples * sizeof(T)); }
|
||||
void write(size_t samples)
|
||||
{
|
||||
write(samples * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void read(size_t samples) { read (samples * sizeof(T)); }
|
||||
void read(size_t samples)
|
||||
{
|
||||
read(samples * sizeof(T));
|
||||
}
|
||||
|
||||
void reserve(size_t size);
|
||||
// if you care about old data, check how much can be written
|
||||
|
@ -80,15 +87,22 @@ public:
|
|||
char* back() { return m_data + m_end; }
|
||||
|
||||
template <typename T>
|
||||
T* front() { return (T*)(m_data + m_begin); }
|
||||
T* front()
|
||||
{
|
||||
return (T*)(m_data + m_begin);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* back() { return (T*)(m_data + m_end); }
|
||||
T* back()
|
||||
{
|
||||
return (T*)(m_data + m_end);
|
||||
}
|
||||
|
||||
long long MilliSecsSinceLastWrite()
|
||||
{
|
||||
return std::chrono::duration_cast<ms>(hrc::now() - mLastWrite).count();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_capacity;
|
||||
char* m_data;
|
||||
|
@ -96,7 +110,6 @@ private:
|
|||
bool m_overrun;
|
||||
size_t m_end;
|
||||
hrc::time_point mLastWrite = hrc::time_point(ns(0));
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
#include "rawinput.h"
|
||||
#endif
|
||||
|
||||
namespace shared {
|
||||
namespace shared
|
||||
{
|
||||
|
||||
void Initialize(void* ptr)
|
||||
{
|
||||
|
@ -38,4 +39,4 @@ namespace shared {
|
|||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
}; // namespace shared
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
*/
|
||||
|
||||
#pragma once
|
||||
namespace shared {
|
||||
namespace shared
|
||||
{
|
||||
void Initialize(void* ptr);
|
||||
void Uninitialize(/*void *ptr*/);
|
||||
};
|
||||
}; // namespace shared
|
||||
|
|
|
@ -57,28 +57,35 @@ static unsigned int pixelformat;
|
|||
buffer_t mpeg_buffer;
|
||||
std::mutex mpeg_mutex;
|
||||
|
||||
static int xioctl(int fh, unsigned long int request, void *arg) {
|
||||
static int xioctl(int fh, unsigned long int request, void* arg)
|
||||
{
|
||||
int r;
|
||||
do {
|
||||
do
|
||||
{
|
||||
r = ioctl(fh, request, arg);
|
||||
} while (-1 == r && EINTR == errno);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void store_mpeg_frame(unsigned char *data, unsigned int len) {
|
||||
static void store_mpeg_frame(unsigned char* data, unsigned int len)
|
||||
{
|
||||
mpeg_mutex.lock();
|
||||
memcpy(mpeg_buffer.start, data, len);
|
||||
mpeg_buffer.length = len;
|
||||
mpeg_mutex.unlock();
|
||||
}
|
||||
|
||||
static void process_image(const unsigned char *ptr, int size) {
|
||||
if (pixelformat == V4L2_PIX_FMT_YUYV) {
|
||||
static void process_image(const unsigned char* ptr, int size)
|
||||
{
|
||||
if (pixelformat == V4L2_PIX_FMT_YUYV)
|
||||
{
|
||||
unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2);
|
||||
int mpegLen = jo_write_mpeg(mpegData, ptr, 320, 240, JO_YUYV, JO_FLIP_X, JO_NONE);
|
||||
store_mpeg_frame(mpegData, mpegLen);
|
||||
free(mpegData);
|
||||
} else if (pixelformat == V4L2_PIX_FMT_JPEG) {
|
||||
}
|
||||
else if (pixelformat == V4L2_PIX_FMT_JPEG)
|
||||
{
|
||||
int width, height, actual_comps;
|
||||
unsigned char* rgbData = jpgd::decompress_jpeg_image_from_memory(ptr, size, &width, &height, &actual_comps, 3);
|
||||
unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2);
|
||||
|
@ -86,19 +93,24 @@ static void process_image(const unsigned char *ptr, int size) {
|
|||
free(rgbData);
|
||||
store_mpeg_frame(mpegData, mpegLen);
|
||||
free(mpegData);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "unk format %c%c%c%c\n", pixelformat, pixelformat >> 8, pixelformat >> 16, pixelformat >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_frame() {
|
||||
static int read_frame()
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
|
||||
switch (errno) {
|
||||
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
return 0;
|
||||
|
||||
|
@ -113,7 +125,8 @@ static int read_frame() {
|
|||
|
||||
process_image((const unsigned char*)buffers[buf.index].start, buf.bytesused);
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_QBUF", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -121,20 +134,24 @@ static int read_frame() {
|
|||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> getDevList() {
|
||||
std::vector<std::string> getDevList()
|
||||
{
|
||||
std::vector<std::string> devList;
|
||||
char dev_name[64];
|
||||
int fd;
|
||||
struct v4l2_capability cap;
|
||||
|
||||
for (int index = 0; index < 64; index++) {
|
||||
for (int index = 0; index < 64; index++)
|
||||
{
|
||||
snprintf(dev_name, sizeof(dev_name), "/dev/video%d", index);
|
||||
|
||||
if ((fd = open(dev_name, O_RDONLY)) < 0) {
|
||||
if ((fd = open(dev_name, O_RDONLY)) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0)
|
||||
{
|
||||
devList.push_back((char*)cap.card);
|
||||
}
|
||||
|
||||
|
@ -143,22 +160,27 @@ std::vector<std::string> getDevList() {
|
|||
return devList;
|
||||
}
|
||||
|
||||
static int v4l_open(std::string selectedDevice) {
|
||||
static int v4l_open(std::string selectedDevice)
|
||||
{
|
||||
char dev_name[64];
|
||||
struct v4l2_capability cap;
|
||||
|
||||
fd = -1;
|
||||
for (int index = 0; index < 64; index++) {
|
||||
for (int index = 0; index < 64; index++)
|
||||
{
|
||||
snprintf(dev_name, sizeof(dev_name), "/dev/video%d", index);
|
||||
|
||||
if ((fd = open(dev_name, O_RDWR | O_NONBLOCK, 0)) < 0) {
|
||||
if ((fd = open(dev_name, O_RDWR | O_NONBLOCK, 0)) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CLEAR(cap);
|
||||
if(ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0)
|
||||
{
|
||||
fprintf(stderr, "Camera: %s / %s\n", dev_name, (char*)cap.card);
|
||||
if (!selectedDevice.empty() && strcmp(selectedDevice.c_str(), (char*)cap.card) == 0) {
|
||||
if (!selectedDevice.empty() && strcmp(selectedDevice.c_str(), (char*)cap.card) == 0)
|
||||
{
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
|
@ -167,10 +189,12 @@ static int v4l_open(std::string selectedDevice) {
|
|||
fd = -1;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
snprintf(dev_name, sizeof(dev_name), "/dev/video0");
|
||||
fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
|
||||
if (-1 == fd) {
|
||||
if (-1 == fd)
|
||||
{
|
||||
fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -179,22 +203,28 @@ static int v4l_open(std::string selectedDevice) {
|
|||
cont:
|
||||
|
||||
CLEAR(cap);
|
||||
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
|
||||
if (EINVAL == errno) {
|
||||
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||
{
|
||||
if (EINVAL == errno)
|
||||
{
|
||||
fprintf(stderr, "%s is no V4L2 device\n", dev_name);
|
||||
return -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_QUERYCAP", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
||||
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
{
|
||||
fprintf(stderr, "%s is no video capture device\n", dev_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
|
||||
if (!(cap.capabilities & V4L2_CAP_STREAMING))
|
||||
{
|
||||
fprintf(stderr, "%s does not support streaming i/o\n", dev_name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -203,13 +233,16 @@ cont:
|
|||
CLEAR(cropcap);
|
||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
|
||||
if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))
|
||||
{
|
||||
struct v4l2_crop crop;
|
||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
crop.c = cropcap.defrect;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
|
||||
switch (errno) {
|
||||
if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop))
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EINVAL:
|
||||
break;
|
||||
default:
|
||||
|
@ -225,14 +258,14 @@ cont:
|
|||
fmt.fmt.pix.height = 240;
|
||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_S_FMT", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
pixelformat = fmt.fmt.pix.pixelformat;
|
||||
fprintf(stderr, "VIDIOC_S_FMT res=%dx%d, fmt=%c%c%c%c\n", fmt.fmt.pix.width, fmt.fmt.pix.height,
|
||||
pixelformat, pixelformat>>8, pixelformat>>16, pixelformat>>24
|
||||
);
|
||||
pixelformat, pixelformat >> 8, pixelformat >> 16, pixelformat >> 24);
|
||||
|
||||
struct v4l2_requestbuffers req;
|
||||
CLEAR(req);
|
||||
|
@ -240,29 +273,36 @@ cont:
|
|||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
|
||||
if (EINVAL == errno) {
|
||||
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
|
||||
{
|
||||
if (EINVAL == errno)
|
||||
{
|
||||
fprintf(stderr, "%s does not support memory mapping\n", dev_name);
|
||||
return -1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_REQBUFS", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (req.count < 2) {
|
||||
if (req.count < 2)
|
||||
{
|
||||
fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffers = (buffer_t*)calloc(req.count, sizeof(*buffers));
|
||||
|
||||
if (!buffers) {
|
||||
if (!buffers)
|
||||
{
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
|
||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
CLEAR(buf);
|
||||
|
@ -270,7 +310,8 @@ cont:
|
|||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = n_buffers;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_QUERYBUF", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -278,20 +319,23 @@ cont:
|
|||
buffers[n_buffers].length = buf.length;
|
||||
buffers[n_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
|
||||
|
||||
if (MAP_FAILED == buffers[n_buffers].start) {
|
||||
if (MAP_FAILED == buffers[n_buffers].start)
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "mmap", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n_buffers; ++i) {
|
||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
CLEAR(buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_QBUF", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -299,7 +343,8 @@ cont:
|
|||
|
||||
enum v4l2_buf_type type;
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_STREAMON", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -307,9 +352,12 @@ cont:
|
|||
}
|
||||
|
||||
|
||||
static void* v4l_thread(void *arg) {
|
||||
while(eyetoy_running) {
|
||||
for (;;) {
|
||||
static void* v4l_thread(void* arg)
|
||||
{
|
||||
while (eyetoy_running)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
|
@ -318,14 +366,16 @@ static void* v4l_thread(void *arg) {
|
|||
struct timeval timeout = {2, 0}; // 2sec
|
||||
int ret = select(fd + 1, &fds, NULL, NULL, &timeout);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr, "%s error %d, %s\n", "select", errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
{
|
||||
fprintf(stderr, "select timeout\n");
|
||||
break;
|
||||
}
|
||||
|
@ -337,23 +387,28 @@ static void* v4l_thread(void *arg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int v4l_close() {
|
||||
static int v4l_close()
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) {
|
||||
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "VIDIOC_STREAMOFF", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n_buffers; ++i) {
|
||||
if (-1 == munmap(buffers[i].start, buffers[i].length)) {
|
||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
||||
{
|
||||
if (-1 == munmap(buffers[i].start, buffers[i].length))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "munmap", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(buffers);
|
||||
|
||||
if (-1 == close(fd)) {
|
||||
if (-1 == close(fd))
|
||||
{
|
||||
fprintf(stderr, "%s error %d, %s\n", "close", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
@ -361,14 +416,17 @@ static int v4l_close() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void create_dummy_frame() {
|
||||
void create_dummy_frame()
|
||||
{
|
||||
const int width = 320;
|
||||
const int height = 240;
|
||||
const int bytesPerPixel = 3;
|
||||
|
||||
unsigned char* rgbData = (unsigned char*)calloc(1, width * height * bytesPerPixel);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
unsigned char* ptr = rgbData + (y * width + x) * bytesPerPixel;
|
||||
ptr[0] = 255 - y;
|
||||
ptr[1] = y;
|
||||
|
@ -383,10 +441,12 @@ void create_dummy_frame() {
|
|||
free(mpegData);
|
||||
}
|
||||
|
||||
int V4L2::Open() {
|
||||
int V4L2::Open()
|
||||
{
|
||||
mpeg_buffer.start = calloc(1, 320 * 240 * 2);
|
||||
create_dummy_frame();
|
||||
if (eyetoy_running) {
|
||||
if (eyetoy_running)
|
||||
{
|
||||
eyetoy_running = 0;
|
||||
pthread_join(*eyetoy_thread, NULL);
|
||||
v4l_close();
|
||||
|
@ -400,8 +460,10 @@ int V4L2::Open() {
|
|||
return 0;
|
||||
};
|
||||
|
||||
int V4L2::Close() {
|
||||
if (eyetoy_running) {
|
||||
int V4L2::Close()
|
||||
{
|
||||
if (eyetoy_running)
|
||||
{
|
||||
eyetoy_running = 0;
|
||||
pthread_join(*eyetoy_thread, NULL);
|
||||
v4l_close();
|
||||
|
@ -409,20 +471,24 @@ int V4L2::Close() {
|
|||
return 0;
|
||||
};
|
||||
|
||||
int V4L2::GetImage(uint8_t *buf, int len) {
|
||||
int V4L2::GetImage(uint8_t* buf, int len)
|
||||
{
|
||||
mpeg_mutex.lock();
|
||||
int len2 = mpeg_buffer.length;
|
||||
if (len < mpeg_buffer.length) len2 = len;
|
||||
if (len < mpeg_buffer.length)
|
||||
len2 = len;
|
||||
memcpy(buf, mpeg_buffer.start, len2);
|
||||
mpeg_mutex.unlock();
|
||||
return len2;
|
||||
};
|
||||
|
||||
static void deviceChanged(GtkComboBox *widget, gpointer data) {
|
||||
static void deviceChanged(GtkComboBox* widget, gpointer data)
|
||||
{
|
||||
*(int*)data = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
|
||||
}
|
||||
|
||||
int GtkConfigure(int port, const char* dev_type, void *data) {
|
||||
int GtkConfigure(int port, const char* dev_type, void* data)
|
||||
{
|
||||
GtkWidget *ro_frame, *ro_label, *rs_hbox, *rs_label;
|
||||
|
||||
std::string selectedDevice;
|
||||
|
@ -447,9 +513,11 @@ int GtkConfigure(int port, const char* dev_type, void *data) {
|
|||
|
||||
std::vector<std::string> devList = getDevList();
|
||||
int sel_idx = 0;
|
||||
for (auto idx = 0; idx < devList.size(); idx++) {
|
||||
for (auto idx = 0; idx < devList.size(); idx++)
|
||||
{
|
||||
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(rs_cb), devList.at(idx).c_str());
|
||||
if (!selectedDevice.empty() && selectedDevice == devList.at(idx)) {
|
||||
if (!selectedDevice.empty() && selectedDevice == devList.at(idx))
|
||||
{
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(rs_cb), idx);
|
||||
sel_idx = idx;
|
||||
}
|
||||
|
@ -462,13 +530,18 @@ int GtkConfigure(int port, const char* dev_type, void *data) {
|
|||
gint result = gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
|
||||
int ret = RESULT_OK;
|
||||
if (result == GTK_RESPONSE_OK) {
|
||||
if (sel_new != sel_idx) {
|
||||
if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, devList.at(sel_new))) {
|
||||
if (result == GTK_RESPONSE_OK)
|
||||
{
|
||||
if (sel_new != sel_idx)
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, devList.at(sel_new)))
|
||||
{
|
||||
ret = RESULT_FAILED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = RESULT_CANCELED;
|
||||
}
|
||||
|
||||
|
@ -476,7 +549,8 @@ int GtkConfigure(int port, const char* dev_type, void *data) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int V4L2::Configure(int port, const char *dev_type, void *data) {
|
||||
int V4L2::Configure(int port, const char* dev_type, void* data)
|
||||
{
|
||||
return GtkConfigure(port, dev_type, data);
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace usb_eyetoy
|
|||
namespace linux_api
|
||||
{
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
void* start;
|
||||
size_t length;
|
||||
} buffer_t;
|
||||
|
@ -30,14 +31,16 @@ static const char *APINAME = "V4L2";
|
|||
class V4L2 : public VideoDevice
|
||||
{
|
||||
public:
|
||||
V4L2(int port) : mPort(port) {};
|
||||
V4L2(int port)
|
||||
: mPort(port){};
|
||||
~V4L2(){};
|
||||
int Open();
|
||||
int Close();
|
||||
int GetImage(uint8_t* buf, int len);
|
||||
int Reset() { return 0; };
|
||||
|
||||
static const TCHAR *Name() {
|
||||
static const TCHAR* Name()
|
||||
{
|
||||
return TEXT("V4L2");
|
||||
}
|
||||
static int Configure(int port, const char* dev_type, void* data);
|
||||
|
|
|
@ -26,47 +26,57 @@ namespace usb_eyetoy
|
|||
namespace windows_api
|
||||
{
|
||||
|
||||
HRESULT DirectShow::CallbackHandler::SampleCB(double time, IMediaSample *sample) {
|
||||
HRESULT DirectShow::CallbackHandler::SampleCB(double time, IMediaSample* sample)
|
||||
{
|
||||
HRESULT hr;
|
||||
unsigned char* buffer;
|
||||
|
||||
hr = sample->GetPointer((BYTE**)&buffer);
|
||||
if (hr != S_OK) return S_OK;
|
||||
if (hr != S_OK)
|
||||
return S_OK;
|
||||
|
||||
if (callback) callback(buffer, sample->GetActualDataLength(), BITS_PER_PIXEL);
|
||||
if (callback)
|
||||
callback(buffer, sample->GetActualDataLength(), BITS_PER_PIXEL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT DirectShow::CallbackHandler::QueryInterface(REFIID iid, LPVOID *ppv) {
|
||||
if( iid == IID_ISampleGrabberCB || iid == IID_IUnknown ) {
|
||||
HRESULT DirectShow::CallbackHandler::QueryInterface(REFIID iid, LPVOID* ppv)
|
||||
{
|
||||
if (iid == IID_ISampleGrabberCB || iid == IID_IUnknown)
|
||||
{
|
||||
*ppv = (void*)static_cast<ISampleGrabberCB*>(this);
|
||||
return S_OK;
|
||||
}
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> getDevList() {
|
||||
std::vector<std::wstring> getDevList()
|
||||
{
|
||||
std::vector<std::wstring> devList;
|
||||
|
||||
ICreateDevEnum* pCreateDevEnum = 0;
|
||||
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCreateDevEnum));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "Error Creating Device Enumerator");
|
||||
return devList;
|
||||
}
|
||||
|
||||
IEnumMoniker* pEnum = 0;
|
||||
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, NULL);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "You have no video capture hardware");
|
||||
return devList;
|
||||
};
|
||||
|
||||
IMoniker* pMoniker = NULL;
|
||||
while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
|
||||
while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
|
||||
{
|
||||
IPropertyBag* pPropBag;
|
||||
HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pMoniker->Release();
|
||||
continue;
|
||||
}
|
||||
|
@ -74,10 +84,12 @@ std::vector<std::wstring> getDevList() {
|
|||
VARIANT var;
|
||||
VariantInit(&var);
|
||||
hr = pPropBag->Read(L"Description", &var, 0);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = pPropBag->Read(L"FriendlyName", &var, 0);
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
devList.push_back(var.bstrVal);
|
||||
VariantClear(&var);
|
||||
}
|
||||
|
@ -92,30 +104,35 @@ std::vector<std::wstring> getDevList() {
|
|||
return devList;
|
||||
}
|
||||
|
||||
int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
||||
int DirectShow::InitializeDevice(std::wstring selectedDevice)
|
||||
{
|
||||
|
||||
// Create the Capture Graph Builder.
|
||||
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraphBuilder));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "CoCreateInstance CLSID_CaptureGraphBuilder2 err : %x\n", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the Filter Graph Manager.
|
||||
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "CoCreateInstance CLSID_FilterGraph err : %x\n", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = pGraphBuilder->SetFiltergraph(pGraph);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "SetFiltergraph err : %x\n", hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "QueryInterface IID_IMediaControl err : %x\n", hr);
|
||||
return -1;
|
||||
}
|
||||
|
@ -123,14 +140,16 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
// enumerate all video capture devices
|
||||
ICreateDevEnum* pCreateDevEnum = 0;
|
||||
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pCreateDevEnum));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "Error Creating Device Enumerator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
IEnumMoniker* pEnum = 0;
|
||||
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, NULL);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "You have no video capture hardware");
|
||||
return -1;
|
||||
};
|
||||
|
@ -138,10 +157,12 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
pEnum->Reset();
|
||||
|
||||
IMoniker* pMoniker;
|
||||
while (pEnum->Next(1, &pMoniker, NULL) == S_OK && sourcefilter == NULL) {
|
||||
while (pEnum->Next(1, &pMoniker, NULL) == S_OK && sourcefilter == NULL)
|
||||
{
|
||||
IPropertyBag* pPropBag = 0;
|
||||
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "BindToStorage err : %x\n", hr);
|
||||
goto freeMoniker;
|
||||
}
|
||||
|
@ -150,34 +171,41 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
VariantInit(&var);
|
||||
|
||||
hr = pPropBag->Read(L"Description", &var, 0);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = pPropBag->Read(L"FriendlyName", &var, 0);
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "Read name err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
fprintf(stderr, "Camera: '%ls'\n", var.bstrVal);
|
||||
if (!selectedDevice.empty() && selectedDevice != var.bstrVal) {
|
||||
if (!selectedDevice.empty() && selectedDevice != var.bstrVal)
|
||||
{
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
//add a filter for the device
|
||||
hr = pGraph->AddSourceFilterForMoniker(pMoniker, NULL, L"sourcefilter", &sourcefilter);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "AddSourceFilterForMoniker err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
hr = pGraphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, IID_IAMStreamConfig, (void**)&pSourceConfig);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
int iCount = 0, iSize = 0;
|
||||
hr = pSourceConfig->GetNumberOfCapabilities(&iCount, &iSize);
|
||||
|
||||
// Check the size to make sure we pass in the correct structure.
|
||||
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
|
||||
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
|
||||
{
|
||||
// Use the video capabilities structure.
|
||||
for (int iFormat = 0; iFormat < iCount; iFormat++) {
|
||||
for (int iFormat = 0; iFormat < iCount; iFormat++)
|
||||
{
|
||||
VIDEO_STREAM_CONFIG_CAPS scc;
|
||||
AM_MEDIA_TYPE* pmtConfig;
|
||||
hr = pSourceConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
|
||||
|
@ -186,11 +214,13 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
scc.MaxOutputSize.cx, scc.MaxOutputSize.cy,
|
||||
pmtConfig->subtype);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if ((pmtConfig->majortype == MEDIATYPE_Video) &&
|
||||
(pmtConfig->formattype == FORMAT_VideoInfo) &&
|
||||
(pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) &&
|
||||
(pmtConfig->pbFormat != NULL)) {
|
||||
(pmtConfig->pbFormat != NULL))
|
||||
{
|
||||
|
||||
VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
|
||||
pVih->bmiHeader.biWidth = 320;
|
||||
|
@ -206,20 +236,23 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
|
||||
// Create the Sample Grabber filter.
|
||||
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&samplegrabberfilter));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "CoCreateInstance CLSID_SampleGrabber err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
hr = pGraph->AddFilter(samplegrabberfilter, L"samplegrabberfilter");
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "AddFilter samplegrabberfilter err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
//set mediatype on the samplegrabber
|
||||
hr = samplegrabberfilter->QueryInterface(IID_PPV_ARGS(&samplegrabber));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "QueryInterface err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
@ -229,34 +262,39 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
mt.majortype = MEDIATYPE_Video;
|
||||
mt.subtype = MEDIASUBTYPE_RGB24;
|
||||
hr = samplegrabber->SetMediaType(&mt);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "SetMediaType err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
//add the callback to the samplegrabber
|
||||
hr = samplegrabber->SetCallback(callbackhandler, 0);
|
||||
if (hr != S_OK) {
|
||||
if (hr != S_OK)
|
||||
{
|
||||
fprintf(stderr, "SetCallback err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
//set the null renderer
|
||||
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&nullrenderer));
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "CoCreateInstance CLSID_NullRenderer err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
hr = pGraph->AddFilter(nullrenderer, L"nullrenderer");
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "AddFilter nullrenderer err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
||||
//set the render path
|
||||
hr = pGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, sourcefilter, samplegrabberfilter, nullrenderer);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "RenderStream err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
@ -264,7 +302,8 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
// if the stream is started, start capturing immediatly
|
||||
LONGLONG start = 0, stop = MAXLONGLONG;
|
||||
hr = pGraphBuilder->ControlStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, &start, &stop, 1, 2);
|
||||
if (FAILED(hr)) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "ControlStream err : %x\n", hr);
|
||||
goto freeVar;
|
||||
}
|
||||
|
@ -277,63 +316,80 @@ int DirectShow::InitializeDevice(std::wstring selectedDevice) {
|
|||
pMoniker->Release();
|
||||
}
|
||||
pEnum->Release();
|
||||
if (sourcefilter == NULL) {
|
||||
if (sourcefilter == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DirectShow::Start() {
|
||||
void DirectShow::Start()
|
||||
{
|
||||
HRESULT hr = nullrenderer->Run(0);
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
|
||||
hr = samplegrabberfilter->Run(0);
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
|
||||
hr = sourcefilter->Run(0);
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
}
|
||||
|
||||
void DirectShow::Stop() {
|
||||
void DirectShow::Stop()
|
||||
{
|
||||
HRESULT hr = sourcefilter->Stop();
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
|
||||
hr = samplegrabberfilter->Stop();
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
|
||||
hr = nullrenderer->Stop();
|
||||
if (FAILED(hr)) throw hr;
|
||||
if (FAILED(hr))
|
||||
throw hr;
|
||||
}
|
||||
|
||||
buffer_t mpeg_buffer{};
|
||||
std::mutex mpeg_mutex;
|
||||
|
||||
void store_mpeg_frame(unsigned char *data, unsigned int len) {
|
||||
void store_mpeg_frame(unsigned char* data, unsigned int len)
|
||||
{
|
||||
mpeg_mutex.lock();
|
||||
memcpy(mpeg_buffer.start, data, len);
|
||||
mpeg_buffer.length = len;
|
||||
mpeg_mutex.unlock();
|
||||
}
|
||||
|
||||
void dshow_callback(unsigned char *data, int len, int bitsperpixel) {
|
||||
if (bitsperpixel == 24) {
|
||||
void dshow_callback(unsigned char* data, int len, int bitsperpixel)
|
||||
{
|
||||
if (bitsperpixel == 24)
|
||||
{
|
||||
unsigned char* mpegData = (unsigned char*)calloc(1, 320 * 240 * 2);
|
||||
int mpegLen = jo_write_mpeg(mpegData, data, 320, 240, JO_RGB24, JO_FLIP_X, JO_FLIP_Y);
|
||||
store_mpeg_frame(mpegData, mpegLen);
|
||||
free(mpegData);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "dshow_callback: unk format: len=%d bpp=%d\n", len, bitsperpixel);
|
||||
}
|
||||
}
|
||||
|
||||
void create_dummy_frame() {
|
||||
void create_dummy_frame()
|
||||
{
|
||||
const int width = 320;
|
||||
const int height = 240;
|
||||
const int bytesPerPixel = 3;
|
||||
|
||||
unsigned char* rgbData = (unsigned char*)calloc(1, width * height * bytesPerPixel);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
unsigned char* ptr = rgbData + (y * width + x) * bytesPerPixel;
|
||||
ptr[0] = 255 - y;
|
||||
ptr[1] = y;
|
||||
|
@ -348,7 +404,8 @@ void create_dummy_frame() {
|
|||
free(mpegData);
|
||||
}
|
||||
|
||||
DirectShow::DirectShow(int port) {
|
||||
DirectShow::DirectShow(int port)
|
||||
{
|
||||
mPort = port;
|
||||
pGraphBuilder = NULL;
|
||||
pGraph = NULL;
|
||||
|
@ -362,7 +419,8 @@ DirectShow::DirectShow(int port) {
|
|||
CoInitialize(NULL);
|
||||
}
|
||||
|
||||
int DirectShow::Open() {
|
||||
int DirectShow::Open()
|
||||
{
|
||||
mpeg_buffer.start = calloc(1, 320 * 240 * 2);
|
||||
create_dummy_frame();
|
||||
|
||||
|
@ -370,7 +428,8 @@ int DirectShow::Open() {
|
|||
LoadSetting(EyeToyWebCamDevice::TypeName(), Port(), APINAME, N_DEVICE, selectedDevice);
|
||||
|
||||
int ret = InitializeDevice(selectedDevice);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
fprintf(stderr, "Camera: cannot find '%ls'\n", selectedDevice.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
@ -383,8 +442,10 @@ int DirectShow::Open() {
|
|||
return 0;
|
||||
};
|
||||
|
||||
int DirectShow::Close() {
|
||||
if (sourcefilter != NULL) {
|
||||
int DirectShow::Close()
|
||||
{
|
||||
if (sourcefilter != NULL)
|
||||
{
|
||||
this->Stop();
|
||||
pControl->Stop();
|
||||
|
||||
|
@ -399,30 +460,36 @@ int DirectShow::Close() {
|
|||
pGraph->Release();
|
||||
pControl->Release();
|
||||
|
||||
if (mpeg_buffer.start != NULL) {
|
||||
if (mpeg_buffer.start != NULL)
|
||||
{
|
||||
free(mpeg_buffer.start);
|
||||
mpeg_buffer.start = NULL;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
int DirectShow::GetImage(uint8_t *buf, int len) {
|
||||
int DirectShow::GetImage(uint8_t* buf, int len)
|
||||
{
|
||||
mpeg_mutex.lock();
|
||||
int len2 = mpeg_buffer.length;
|
||||
if (len < mpeg_buffer.length) len2 = len;
|
||||
if (len < mpeg_buffer.length)
|
||||
len2 = len;
|
||||
memcpy(buf, mpeg_buffer.start, len2);
|
||||
mpeg_mutex.unlock();
|
||||
return len2;
|
||||
};
|
||||
|
||||
BOOL CALLBACK DirectShowDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
BOOL CALLBACK DirectShowDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int port;
|
||||
|
||||
switch (uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
|
||||
break;
|
||||
case WM_INITDIALOG: {
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
port = (int)lParam;
|
||||
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
|
||||
|
||||
|
@ -431,23 +498,29 @@ BOOL CALLBACK DirectShowDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
SendDlgItemMessage(hW, IDC_COMBO1, CB_RESETCONTENT, 0, 0);
|
||||
|
||||
std::vector<std::wstring> devList = getDevList();
|
||||
for (auto i = 0; i != devList.size(); i++) {
|
||||
for (auto i = 0; i != devList.size(); i++)
|
||||
{
|
||||
SendDlgItemMessageW(hW, IDC_COMBO1, CB_ADDSTRING, 0, (LPARAM)devList[i].c_str());
|
||||
if (selectedDevice == devList.at(i)) {
|
||||
if (selectedDevice == devList.at(i))
|
||||
{
|
||||
SendDlgItemMessage(hW, IDC_COMBO1, CB_SETCURSEL, i, i);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
if (HIWORD(wParam) == BN_CLICKED) {
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDOK: {
|
||||
if (HIWORD(wParam) == BN_CLICKED)
|
||||
{
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
INT_PTR res = RESULT_OK;
|
||||
static wchar_t selectedDevice[500] = {0};
|
||||
GetWindowTextW(GetDlgItem(hW, IDC_COMBO1), selectedDevice, countof(selectedDevice));
|
||||
port = (int)GetWindowLongPtr(hW, GWLP_USERDATA);
|
||||
if (!SaveSetting<std::wstring>(EyeToyWebCamDevice::TypeName(), port, APINAME, N_DEVICE, selectedDevice)) {
|
||||
if (!SaveSetting<std::wstring>(EyeToyWebCamDevice::TypeName(), port, APINAME, N_DEVICE, selectedDevice))
|
||||
{
|
||||
res = RESULT_FAILED;
|
||||
}
|
||||
EndDialog(hW, res);
|
||||
|
@ -462,7 +535,8 @@ BOOL CALLBACK DirectShowDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
int DirectShow::Configure(int port, const char *dev_type, void *data) {
|
||||
int DirectShow::Configure(int port, const char* dev_type, void* data)
|
||||
{
|
||||
Win32Handles handles = *(Win32Handles*)data;
|
||||
return DialogBoxParam(handles.hInst,
|
||||
MAKEINTRESOURCE(IDD_DLG_EYETOY),
|
||||
|
|
|
@ -29,13 +29,15 @@ extern "C" {
|
|||
|
||||
#pragma region qedit.h
|
||||
struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
|
||||
ISampleGrabberCB : IUnknown {
|
||||
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"))
|
||||
ISampleGrabber : IUnknown {
|
||||
ISampleGrabber : IUnknown
|
||||
{
|
||||
virtual HRESULT __stdcall SetOneShot(long OneShot) = 0;
|
||||
virtual HRESULT __stdcall SetMediaType(struct _AMMediaType* pType) = 0;
|
||||
virtual HRESULT __stdcall GetConnectedMediaType(struct _AMMediaType* pType) = 0;
|
||||
|
@ -70,14 +72,16 @@ namespace windows_api
|
|||
|
||||
typedef void (*DShowVideoCaptureCallback)(unsigned char* data, int len, int bitsperpixel);
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
void* start = NULL;
|
||||
size_t length = 0;
|
||||
} buffer_t;
|
||||
|
||||
static const char* APINAME = "DirectShow";
|
||||
|
||||
class DirectShow : public VideoDevice {
|
||||
class DirectShow : public VideoDevice
|
||||
{
|
||||
public:
|
||||
DirectShow(int port);
|
||||
~DirectShow() {}
|
||||
|
@ -86,7 +90,8 @@ public:
|
|||
int GetImage(uint8_t* buf, int len);
|
||||
int Reset() { return 0; };
|
||||
|
||||
static const TCHAR *Name() {
|
||||
static const TCHAR* Name()
|
||||
{
|
||||
return TEXT("DirectShow");
|
||||
}
|
||||
static int Configure(int port, const char* dev_type, void* data);
|
||||
|
|
|
@ -37,35 +37,160 @@
|
|||
static const unsigned char s_jo_HTDC_Y[9][2] = {{4, 3}, {0, 2}, {1, 2}, {5, 3}, {6, 3}, {14, 4}, {30, 5}, {62, 6}, {126, 7}};
|
||||
static const unsigned char s_jo_HTDC_C[9][2] = {{0, 2}, {1, 2}, {2, 2}, {6, 3}, {14, 4}, {30, 5}, {62, 6}, {126, 7}, {254, 8}};
|
||||
static const unsigned char s_jo_HTAC[32][40][2] = {
|
||||
{{6,3},{8,5},{10,6},{12,8},{76,9},{66,9},{20,11},{58,13},{48,13},{38,13},{32,13},{52,14},{50,14},{48,14},{46,14},{62,15},{62,15},{58,15},{56,15},{54,15},{52,15},{50,15},{48,15},{46,15},{44,15},{42,15},{40,15},{38,15},{36,15},{34,15},{32,15},{48,16},{46,16},{44,16},{42,16},{40,16},{38,16},{36,16},{34,16},{32,16},},
|
||||
{
|
||||
{6, 3},
|
||||
{8, 5},
|
||||
{10, 6},
|
||||
{12, 8},
|
||||
{76, 9},
|
||||
{66, 9},
|
||||
{20, 11},
|
||||
{58, 13},
|
||||
{48, 13},
|
||||
{38, 13},
|
||||
{32, 13},
|
||||
{52, 14},
|
||||
{50, 14},
|
||||
{48, 14},
|
||||
{46, 14},
|
||||
{62, 15},
|
||||
{62, 15},
|
||||
{58, 15},
|
||||
{56, 15},
|
||||
{54, 15},
|
||||
{52, 15},
|
||||
{50, 15},
|
||||
{48, 15},
|
||||
{46, 15},
|
||||
{44, 15},
|
||||
{42, 15},
|
||||
{40, 15},
|
||||
{38, 15},
|
||||
{36, 15},
|
||||
{34, 15},
|
||||
{32, 15},
|
||||
{48, 16},
|
||||
{46, 16},
|
||||
{44, 16},
|
||||
{42, 16},
|
||||
{40, 16},
|
||||
{38, 16},
|
||||
{36, 16},
|
||||
{34, 16},
|
||||
{32, 16},
|
||||
},
|
||||
{{6, 4}, {12, 7}, {74, 9}, {24, 11}, {54, 13}, {44, 14}, {42, 14}, {62, 16}, {60, 16}, {58, 16}, {56, 16}, {54, 16}, {52, 16}, {50, 16}, {38, 17}, {36, 17}, {34, 17}, {32, 17}},
|
||||
{{10, 5}, {8, 8}, {22, 11}, {40, 13}, {40, 14}},
|
||||
{{14, 6}, {72, 9}, {56, 13}, {38, 14}},
|
||||
{{12,6},{30,11},{36,13}}, {{14,7},{18,11},{36,14}}, {{10,7},{60,13},{40,17}},
|
||||
{{8,7},{42,13}}, {{14,8},{34,13}}, {{10,8},{34,14}}, {{78,9},{32,14}}, {{70,9},{52,17}}, {{68,9},{50,17}}, {{64,9},{48,17}}, {{28,11},{46,17}}, {{26,11},{44,17}}, {{16,11},{42,17}},
|
||||
{{62,13}}, {{52,13}}, {{50,13}}, {{46,13}}, {{44,13}}, {{62,14}}, {{60,14}}, {{58,14}}, {{56,14}}, {{54,14}}, {{62,17}}, {{60,17}}, {{58,17}}, {{56,17}}, {{54,17}},
|
||||
{{12, 6}, {30, 11}, {36, 13}},
|
||||
{{14, 7}, {18, 11}, {36, 14}},
|
||||
{{10, 7}, {60, 13}, {40, 17}},
|
||||
{{8, 7}, {42, 13}},
|
||||
{{14, 8}, {34, 13}},
|
||||
{{10, 8}, {34, 14}},
|
||||
{{78, 9}, {32, 14}},
|
||||
{{70, 9}, {52, 17}},
|
||||
{{68, 9}, {50, 17}},
|
||||
{{64, 9}, {48, 17}},
|
||||
{{28, 11}, {46, 17}},
|
||||
{{26, 11}, {44, 17}},
|
||||
{{16, 11}, {42, 17}},
|
||||
{{62, 13}},
|
||||
{{52, 13}},
|
||||
{{50, 13}},
|
||||
{{46, 13}},
|
||||
{{44, 13}},
|
||||
{{62, 14}},
|
||||
{{60, 14}},
|
||||
{{58, 14}},
|
||||
{{56, 14}},
|
||||
{{54, 14}},
|
||||
{{62, 17}},
|
||||
{{60, 17}},
|
||||
{{58, 17}},
|
||||
{{56, 17}},
|
||||
{{54, 17}},
|
||||
};
|
||||
static const float s_jo_quantTbl[64] = {
|
||||
0.015625f,0.005632f,0.005035f,0.004832f,0.004808f,0.005892f,0.007964f,0.013325f,
|
||||
0.005632f,0.004061f,0.003135f,0.003193f,0.003338f,0.003955f,0.004898f,0.008828f,
|
||||
0.005035f,0.003135f,0.002816f,0.003013f,0.003299f,0.003581f,0.005199f,0.009125f,
|
||||
0.004832f,0.003484f,0.003129f,0.003348f,0.003666f,0.003979f,0.005309f,0.009632f,
|
||||
0.005682f,0.003466f,0.003543f,0.003666f,0.003906f,0.004546f,0.005774f,0.009439f,
|
||||
0.006119f,0.004248f,0.004199f,0.004228f,0.004546f,0.005062f,0.006124f,0.009942f,
|
||||
0.008883f,0.006167f,0.006096f,0.005777f,0.006078f,0.006391f,0.007621f,0.012133f,
|
||||
0.016780f,0.011263f,0.009907f,0.010139f,0.009849f,0.010297f,0.012133f,0.019785f,
|
||||
0.015625f,
|
||||
0.005632f,
|
||||
0.005035f,
|
||||
0.004832f,
|
||||
0.004808f,
|
||||
0.005892f,
|
||||
0.007964f,
|
||||
0.013325f,
|
||||
0.005632f,
|
||||
0.004061f,
|
||||
0.003135f,
|
||||
0.003193f,
|
||||
0.003338f,
|
||||
0.003955f,
|
||||
0.004898f,
|
||||
0.008828f,
|
||||
0.005035f,
|
||||
0.003135f,
|
||||
0.002816f,
|
||||
0.003013f,
|
||||
0.003299f,
|
||||
0.003581f,
|
||||
0.005199f,
|
||||
0.009125f,
|
||||
0.004832f,
|
||||
0.003484f,
|
||||
0.003129f,
|
||||
0.003348f,
|
||||
0.003666f,
|
||||
0.003979f,
|
||||
0.005309f,
|
||||
0.009632f,
|
||||
0.005682f,
|
||||
0.003466f,
|
||||
0.003543f,
|
||||
0.003666f,
|
||||
0.003906f,
|
||||
0.004546f,
|
||||
0.005774f,
|
||||
0.009439f,
|
||||
0.006119f,
|
||||
0.004248f,
|
||||
0.004199f,
|
||||
0.004228f,
|
||||
0.004546f,
|
||||
0.005062f,
|
||||
0.006124f,
|
||||
0.009942f,
|
||||
0.008883f,
|
||||
0.006167f,
|
||||
0.006096f,
|
||||
0.005777f,
|
||||
0.006078f,
|
||||
0.006391f,
|
||||
0.007621f,
|
||||
0.012133f,
|
||||
0.016780f,
|
||||
0.011263f,
|
||||
0.009907f,
|
||||
0.010139f,
|
||||
0.009849f,
|
||||
0.010297f,
|
||||
0.012133f,
|
||||
0.019785f,
|
||||
};
|
||||
static const unsigned char s_jo_ZigZag[] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* buf_ptr;
|
||||
int buf, cnt;
|
||||
} jo_bits_t;
|
||||
|
||||
static void jo_writeBits(jo_bits_t *b, int value, int count) {
|
||||
static void jo_writeBits(jo_bits_t* b, int value, int count)
|
||||
{
|
||||
b->cnt += count;
|
||||
b->buf |= value << (24 - b->cnt);
|
||||
while(b->cnt >= 8) {
|
||||
while (b->cnt >= 8)
|
||||
{
|
||||
unsigned char c = (b->buf >> 16) & 255;
|
||||
//putc(c, b->fp);
|
||||
*(b->buf_ptr) = c & 0xff;
|
||||
|
@ -75,7 +200,8 @@ static void jo_writeBits(jo_bits_t *b, int value, int count) {
|
|||
}
|
||||
}
|
||||
|
||||
static void jo_DCT(float *d0, float *d1, float *d2, float *d3, float *d4, float *d5, float *d6, float *d7) {
|
||||
static void jo_DCT(float* d0, float* d1, float* d2, float* d3, float* d4, float* d5, float* d6, float* d7)
|
||||
{
|
||||
float tmp0 = *d0 + *d7;
|
||||
float tmp7 = *d0 - *d7;
|
||||
float tmp1 = *d1 + *d6;
|
||||
|
@ -118,15 +244,19 @@ static void jo_DCT(float *d0, float *d1, float *d2, float *d3, float *d4, float
|
|||
*d7 = z11 - z4;
|
||||
}
|
||||
|
||||
static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9][2], int DC) {
|
||||
for(int dataOff=0; dataOff<64; dataOff+=8) {
|
||||
static int jo_processDU(jo_bits_t* bits, float A[64], const unsigned char htdc[9][2], int DC)
|
||||
{
|
||||
for (int dataOff = 0; dataOff < 64; dataOff += 8)
|
||||
{
|
||||
jo_DCT(&A[dataOff], &A[dataOff + 1], &A[dataOff + 2], &A[dataOff + 3], &A[dataOff + 4], &A[dataOff + 5], &A[dataOff + 6], &A[dataOff + 7]);
|
||||
}
|
||||
for(int dataOff=0; dataOff<8; ++dataOff) {
|
||||
for (int dataOff = 0; dataOff < 8; ++dataOff)
|
||||
{
|
||||
jo_DCT(&A[dataOff], &A[dataOff + 8], &A[dataOff + 16], &A[dataOff + 24], &A[dataOff + 32], &A[dataOff + 40], &A[dataOff + 48], &A[dataOff + 56]);
|
||||
}
|
||||
int Q[64];
|
||||
for(int i=0; i<64; ++i) {
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
float v = A[i] * s_jo_quantTbl[i];
|
||||
Q[s_jo_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
|
||||
}
|
||||
|
@ -135,36 +265,48 @@ static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9
|
|||
int aDC = DC < 0 ? -DC : DC;
|
||||
int size = 0;
|
||||
int tempval = aDC;
|
||||
while(tempval) {
|
||||
while (tempval)
|
||||
{
|
||||
size++;
|
||||
tempval >>= 1;
|
||||
}
|
||||
jo_writeBits(bits, htdc[size][0], htdc[size][1]);
|
||||
if(DC < 0) aDC ^= (1 << size) - 1;
|
||||
if (DC < 0)
|
||||
aDC ^= (1 << size) - 1;
|
||||
jo_writeBits(bits, aDC, size);
|
||||
|
||||
int endpos = 63;
|
||||
for(; (endpos>0)&&(Q[endpos]==0); --endpos) { /* do nothing */ }
|
||||
for(int i = 1; i <= endpos;) {
|
||||
for (; (endpos > 0) && (Q[endpos] == 0); --endpos)
|
||||
{ /* do nothing */
|
||||
}
|
||||
for (int i = 1; i <= endpos;)
|
||||
{
|
||||
int run = 0;
|
||||
while (Q[i]==0 && i<endpos) {
|
||||
while (Q[i] == 0 && i < endpos)
|
||||
{
|
||||
++run;
|
||||
++i;
|
||||
}
|
||||
int AC = Q[i++];
|
||||
int aAC = AC < 0 ? -AC : AC;
|
||||
int code = 0, size = 0;
|
||||
if (run<32 && aAC<=40) {
|
||||
if (run < 32 && aAC <= 40)
|
||||
{
|
||||
code = s_jo_HTAC[run][aAC - 1][0];
|
||||
size = s_jo_HTAC[run][aAC - 1][1];
|
||||
if (AC < 0) code += 1;
|
||||
if (AC < 0)
|
||||
code += 1;
|
||||
}
|
||||
if(!size) {
|
||||
if (!size)
|
||||
{
|
||||
jo_writeBits(bits, 1, 6);
|
||||
jo_writeBits(bits, run, 6);
|
||||
if (AC < -127) {
|
||||
if (AC < -127)
|
||||
{
|
||||
jo_writeBits(bits, 128, 12);
|
||||
} else if(AC > 127) {
|
||||
}
|
||||
else if (AC > 127)
|
||||
{
|
||||
jo_writeBits(bits, 0, 12);
|
||||
}
|
||||
code = AC & 0xFFF;
|
||||
|
@ -177,17 +319,23 @@ static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9
|
|||
return Q[0];
|
||||
}
|
||||
|
||||
unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, int width, int height, int format, int flipx, int flipy) {
|
||||
unsigned long jo_write_mpeg(unsigned char* mpeg_buf, const unsigned char* raw, int width, int height, int format, int flipx, int flipy)
|
||||
{
|
||||
int lastDCY = 128, lastDCCR = 128, lastDCCB = 128;
|
||||
unsigned char* head = mpeg_buf;
|
||||
jo_bits_t bits = {mpeg_buf};
|
||||
|
||||
for (int vblock = 0; vblock < (height+15)/16; vblock++) {
|
||||
for (int hblock = 0; hblock < (width+15)/16; hblock++) {
|
||||
if (vblock == 0 && hblock == 0) {
|
||||
for (int vblock = 0; vblock < (height + 15) / 16; vblock++)
|
||||
{
|
||||
for (int hblock = 0; hblock < (width + 15) / 16; hblock++)
|
||||
{
|
||||
if (vblock == 0 && hblock == 0)
|
||||
{
|
||||
jo_writeBits(&bits, 0b01, 2); // macroblock_type = intra+quant
|
||||
jo_writeBits(&bits, 8, 5); // quantiser_scale_code = 8
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
jo_writeBits(&bits, 0b1, 1); // macroblock_address_increment
|
||||
jo_writeBits(&bits, 0b1, 1); // macroblock_type = intra
|
||||
}
|
||||
|
@ -195,19 +343,26 @@ unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, i
|
|||
float Y[256], CBx[256], CRx[256];
|
||||
float CB[64], CR[64];
|
||||
|
||||
if (format == JO_RGBX) {
|
||||
for (int i=0; i<256; ++i) {
|
||||
if (format == JO_RGBX)
|
||||
{
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int y = vblock * 16 + (i / 16);
|
||||
int x = hblock * 16 + (i & 15);
|
||||
x = x >= width ? width - 1 : x;
|
||||
y = y >= height ? height - 1 : y;
|
||||
if (flipx) x = width - 1 - x;
|
||||
if (flipy) y = height - 1 - y;
|
||||
if (flipx)
|
||||
x = width - 1 - x;
|
||||
if (flipy)
|
||||
y = height - 1 - y;
|
||||
const unsigned char* c = raw + y * width * 4 + x * 4;
|
||||
float r, g, b;
|
||||
if (flipx && flipy) {
|
||||
if (flipx && flipy)
|
||||
{
|
||||
r = c[2], g = c[1], b = c[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
r = c[0], g = c[1], b = c[2];
|
||||
}
|
||||
Y[i] = (0.299f * r + 0.587f * g + 0.114f * b) * (219.f / 255) + 16;
|
||||
|
@ -215,25 +370,33 @@ unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, i
|
|||
CRx[i] = (0.701f * r - 0.587f * g - 0.114f * b) * (224.f / 255) + 128;
|
||||
}
|
||||
// Downsample Cb,Cr (420 format)
|
||||
for (int i=0; i<64; ++i) {
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
int j = (i & 7) * 2 + (i & 56) * 4;
|
||||
CB[i] = (CBx[j] + CBx[j + 1] + CBx[j + 16] + CBx[j + 17]) * 0.25f;
|
||||
CR[i] = (CRx[j] + CRx[j + 1] + CRx[j + 16] + CRx[j + 17]) * 0.25f;
|
||||
}
|
||||
} else
|
||||
if (format == JO_RGB24) {
|
||||
for (int i=0; i<256; ++i) {
|
||||
}
|
||||
else if (format == JO_RGB24)
|
||||
{
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int y = vblock * 16 + (i / 16);
|
||||
int x = hblock * 16 + (i & 15);
|
||||
x = x >= width ? width - 1 : x;
|
||||
y = y >= height ? height - 1 : y;
|
||||
if (flipx) x = width - 1 - x;
|
||||
if (flipy) y = height - 1 - y;
|
||||
if (flipx)
|
||||
x = width - 1 - x;
|
||||
if (flipy)
|
||||
y = height - 1 - y;
|
||||
const unsigned char* c = raw + y * width * 3 + x * 3;
|
||||
float r, g, b;
|
||||
if (flipx && flipy) {
|
||||
if (flipx && flipy)
|
||||
{
|
||||
r = c[2], g = c[1], b = c[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
r = c[0], g = c[1], b = c[2];
|
||||
}
|
||||
Y[i] = (0.299f * r + 0.587f * g + 0.114f * b) * (219.f / 255) + 16;
|
||||
|
@ -241,27 +404,35 @@ unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, i
|
|||
CRx[i] = (0.701f * r - 0.587f * g - 0.114f * b) * (224.f / 255) + 128;
|
||||
}
|
||||
// Downsample Cb,Cr (420 format)
|
||||
for (int i=0; i<64; ++i) {
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
int j = (i & 7) * 2 + (i & 56) * 4;
|
||||
CB[i] = (CBx[j] + CBx[j + 1] + CBx[j + 16] + CBx[j + 17]) * 0.25f;
|
||||
CR[i] = (CRx[j] + CRx[j + 1] + CRx[j + 16] + CRx[j + 17]) * 0.25f;
|
||||
}
|
||||
} else
|
||||
if (format == JO_YUYV) {
|
||||
for (int i=0; i<256; i+=2) {
|
||||
}
|
||||
else if (format == JO_YUYV)
|
||||
{
|
||||
for (int i = 0; i < 256; i += 2)
|
||||
{
|
||||
int y = vblock * 16 + (i / 16);
|
||||
int x = hblock * 16 + (i & 15);
|
||||
x = x >= width ? width - 1 : x;
|
||||
y = y >= height ? height - 1 : y;
|
||||
if (flipx) x = width - 1 - x;
|
||||
if (flipy) y = height - 1 - y;
|
||||
if (flipx)
|
||||
x = width - 1 - x;
|
||||
if (flipy)
|
||||
y = height - 1 - y;
|
||||
const unsigned char* c = raw + y * width * 2 + x * 2 - 2;
|
||||
if (flipx) {
|
||||
if (flipx)
|
||||
{
|
||||
Y[i + 1] = c[0];
|
||||
CB[i / 4] = c[1];
|
||||
Y[i] = c[2];
|
||||
CR[i / 4] = c[3];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Y[i] = c[2];
|
||||
CB[i / 4] = c[3];
|
||||
Y[i + 1] = c[4];
|
||||
|
@ -270,10 +441,13 @@ unsigned long jo_write_mpeg(unsigned char *mpeg_buf, const unsigned char *raw, i
|
|||
}
|
||||
}
|
||||
|
||||
for (int k1=0; k1<2; ++k1) {
|
||||
for (int k2=0; k2<2; ++k2) {
|
||||
for (int k1 = 0; k1 < 2; ++k1)
|
||||
{
|
||||
for (int k2 = 0; k2 < 2; ++k2)
|
||||
{
|
||||
float block[64];
|
||||
for (int i=0; i<64; i+=8) {
|
||||
for (int i = 0; i < 64; i += 8)
|
||||
{
|
||||
int j = (i & 7) + (i & 56) * 2 + k1 * 8 * 16 + k2 * 8;
|
||||
memcpy(block + i, Y + j, 8 * sizeof(Y[0]));
|
||||
}
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
JO_RGBX,
|
||||
JO_RGB24,
|
||||
JO_YUYV,
|
||||
} jo_mpeg_format_t;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
JO_NONE,
|
||||
JO_FLIP_X,
|
||||
JO_FLIP_Y,
|
||||
|
|
|
@ -55,7 +55,8 @@
|
|||
#define JPGD_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define JPGD_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
namespace jpgd {
|
||||
namespace jpgd
|
||||
{
|
||||
|
||||
static inline void* jpgd_malloc(size_t nSize) { return malloc(nSize); }
|
||||
static inline void jpgd_free(void* p) { free(p); }
|
||||
|
@ -65,14 +66,56 @@ namespace jpgd {
|
|||
|
||||
enum JPEG_MARKER
|
||||
{
|
||||
M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8,
|
||||
M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC,
|
||||
M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7,
|
||||
M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF,
|
||||
M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0
|
||||
M_SOF0 = 0xC0,
|
||||
M_SOF1 = 0xC1,
|
||||
M_SOF2 = 0xC2,
|
||||
M_SOF3 = 0xC3,
|
||||
M_SOF5 = 0xC5,
|
||||
M_SOF6 = 0xC6,
|
||||
M_SOF7 = 0xC7,
|
||||
M_JPG = 0xC8,
|
||||
M_SOF9 = 0xC9,
|
||||
M_SOF10 = 0xCA,
|
||||
M_SOF11 = 0xCB,
|
||||
M_SOF13 = 0xCD,
|
||||
M_SOF14 = 0xCE,
|
||||
M_SOF15 = 0xCF,
|
||||
M_DHT = 0xC4,
|
||||
M_DAC = 0xCC,
|
||||
M_RST0 = 0xD0,
|
||||
M_RST1 = 0xD1,
|
||||
M_RST2 = 0xD2,
|
||||
M_RST3 = 0xD3,
|
||||
M_RST4 = 0xD4,
|
||||
M_RST5 = 0xD5,
|
||||
M_RST6 = 0xD6,
|
||||
M_RST7 = 0xD7,
|
||||
M_SOI = 0xD8,
|
||||
M_EOI = 0xD9,
|
||||
M_SOS = 0xDA,
|
||||
M_DQT = 0xDB,
|
||||
M_DNL = 0xDC,
|
||||
M_DRI = 0xDD,
|
||||
M_DHP = 0xDE,
|
||||
M_EXP = 0xDF,
|
||||
M_APP0 = 0xE0,
|
||||
M_APP15 = 0xEF,
|
||||
M_JPG0 = 0xF0,
|
||||
M_JPG13 = 0xFD,
|
||||
M_COM = 0xFE,
|
||||
M_TEM = 0x01,
|
||||
M_ERROR = 0x100,
|
||||
RST0 = 0xD0
|
||||
};
|
||||
|
||||
enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 };
|
||||
enum JPEG_SUBSAMPLING
|
||||
{
|
||||
JPGD_GRAYSCALE = 0,
|
||||
JPGD_YH1V1,
|
||||
JPGD_YH2V1,
|
||||
JPGD_YH1V2,
|
||||
JPGD_YH2V2
|
||||
};
|
||||
|
||||
#if JPGD_USE_SSE2
|
||||
#include "jpgd_idct.h"
|
||||
|
@ -263,21 +306,524 @@ namespace jpgd {
|
|||
|
||||
static const uint8 s_idct_row_table[] =
|
||||
{
|
||||
1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
|
||||
4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
|
||||
6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
|
||||
6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
|
||||
8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
|
||||
8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
|
||||
8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
|
||||
8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
5,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
6,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
0,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
2,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
7,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
5,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
4,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
6,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
7,
|
||||
6,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
6,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
};
|
||||
|
||||
static const uint8 s_idct_col_table[] =
|
||||
{
|
||||
1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
|
||||
};
|
||||
7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
|
||||
|
||||
// Scalar "fast pathing" IDCT.
|
||||
static void idct(const jpgd_block_coeff_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag, bool use_simd)
|
||||
|
@ -324,15 +870,33 @@ namespace jpgd {
|
|||
{
|
||||
switch (*pRow_tab)
|
||||
{
|
||||
case 0: Row<0>::idct(pTemp, pSrc); break;
|
||||
case 1: Row<1>::idct(pTemp, pSrc); break;
|
||||
case 2: Row<2>::idct(pTemp, pSrc); break;
|
||||
case 3: Row<3>::idct(pTemp, pSrc); break;
|
||||
case 4: Row<4>::idct(pTemp, pSrc); break;
|
||||
case 5: Row<5>::idct(pTemp, pSrc); break;
|
||||
case 6: Row<6>::idct(pTemp, pSrc); break;
|
||||
case 7: Row<7>::idct(pTemp, pSrc); break;
|
||||
case 8: Row<8>::idct(pTemp, pSrc); break;
|
||||
case 0:
|
||||
Row<0>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 1:
|
||||
Row<1>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 2:
|
||||
Row<2>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 3:
|
||||
Row<3>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 4:
|
||||
Row<4>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 5:
|
||||
Row<5>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 6:
|
||||
Row<6>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 7:
|
||||
Row<7>::idct(pTemp, pSrc);
|
||||
break;
|
||||
case 8:
|
||||
Row<8>::idct(pTemp, pSrc);
|
||||
break;
|
||||
}
|
||||
|
||||
pSrc += 8;
|
||||
|
@ -346,14 +910,30 @@ namespace jpgd {
|
|||
{
|
||||
switch (nonzero_rows)
|
||||
{
|
||||
case 1: Col<1>::idct(pDst_ptr, pTemp); break;
|
||||
case 2: Col<2>::idct(pDst_ptr, pTemp); break;
|
||||
case 3: Col<3>::idct(pDst_ptr, pTemp); break;
|
||||
case 4: Col<4>::idct(pDst_ptr, pTemp); break;
|
||||
case 5: Col<5>::idct(pDst_ptr, pTemp); break;
|
||||
case 6: Col<6>::idct(pDst_ptr, pTemp); break;
|
||||
case 7: Col<7>::idct(pDst_ptr, pTemp); break;
|
||||
case 8: Col<8>::idct(pDst_ptr, pTemp); break;
|
||||
case 1:
|
||||
Col<1>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 2:
|
||||
Col<2>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 3:
|
||||
Col<3>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 4:
|
||||
Col<4>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 5:
|
||||
Col<5>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 6:
|
||||
Col<6>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 7:
|
||||
Col<7>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
case 8:
|
||||
Col<8>::idct(pDst_ptr, pTemp);
|
||||
break;
|
||||
}
|
||||
|
||||
pTemp++;
|
||||
|
@ -671,7 +1251,8 @@ namespace jpgd {
|
|||
b->m_size = capacity;
|
||||
rv = b->m_data;
|
||||
}
|
||||
if (zero) memset(rv, 0, nSize);
|
||||
if (zero)
|
||||
memset(rv, 0, nSize);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1473,7 +2054,11 @@ namespace jpgd {
|
|||
get_bits_no_markers(16);
|
||||
}
|
||||
|
||||
static inline int dequantize_ac(int c, int q) { c *= q; return c; }
|
||||
static inline int dequantize_ac(int c, int q)
|
||||
{
|
||||
c *= q;
|
||||
return c;
|
||||
}
|
||||
|
||||
// Decodes and dequantizes the next row of coefficients.
|
||||
void jpeg_decoder::decode_next_row()
|
||||
|
@ -1919,9 +2504,11 @@ namespace jpgd {
|
|||
|
||||
static const uint8_t s_muls[2][2][4] =
|
||||
{
|
||||
{ { 1, 3, 3, 9 }, { 3, 9, 1, 3 }, },
|
||||
{ { 3, 1, 9, 3 }, { 9, 3, 3, 1 } }
|
||||
};
|
||||
{
|
||||
{1, 3, 3, 9},
|
||||
{3, 9, 1, 3},
|
||||
},
|
||||
{{3, 1, 9, 3}, {9, 3, 3, 1}}};
|
||||
|
||||
if (((row & 15) >= 1) && ((row & 15) <= 14))
|
||||
{
|
||||
|
|
|
@ -40,15 +40,42 @@ namespace jpgd
|
|||
// Success/failure error codes.
|
||||
enum jpgd_status
|
||||
{
|
||||
JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
|
||||
JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
|
||||
JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
|
||||
JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
|
||||
JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
|
||||
JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
|
||||
JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
|
||||
JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER,
|
||||
JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM, JPGD_TOO_MANY_SCANS
|
||||
JPGD_SUCCESS = 0,
|
||||
JPGD_FAILED = -1,
|
||||
JPGD_DONE = 1,
|
||||
JPGD_BAD_DHT_COUNTS = -256,
|
||||
JPGD_BAD_DHT_INDEX,
|
||||
JPGD_BAD_DHT_MARKER,
|
||||
JPGD_BAD_DQT_MARKER,
|
||||
JPGD_BAD_DQT_TABLE,
|
||||
JPGD_BAD_PRECISION,
|
||||
JPGD_BAD_HEIGHT,
|
||||
JPGD_BAD_WIDTH,
|
||||
JPGD_TOO_MANY_COMPONENTS,
|
||||
JPGD_BAD_SOF_LENGTH,
|
||||
JPGD_BAD_VARIABLE_MARKER,
|
||||
JPGD_BAD_DRI_LENGTH,
|
||||
JPGD_BAD_SOS_LENGTH,
|
||||
JPGD_BAD_SOS_COMP_ID,
|
||||
JPGD_W_EXTRA_BYTES_BEFORE_MARKER,
|
||||
JPGD_NO_ARITHMITIC_SUPPORT,
|
||||
JPGD_UNEXPECTED_MARKER,
|
||||
JPGD_NOT_JPEG,
|
||||
JPGD_UNSUPPORTED_MARKER,
|
||||
JPGD_BAD_DQT_LENGTH,
|
||||
JPGD_TOO_MANY_BLOCKS,
|
||||
JPGD_UNDEFINED_QUANT_TABLE,
|
||||
JPGD_UNDEFINED_HUFF_TABLE,
|
||||
JPGD_NOT_SINGLE_SCAN,
|
||||
JPGD_UNSUPPORTED_COLORSPACE,
|
||||
JPGD_UNSUPPORTED_SAMP_FACTORS,
|
||||
JPGD_DECODE_ERROR,
|
||||
JPGD_BAD_RESTART_MARKER,
|
||||
JPGD_BAD_SOS_SPECTRAL,
|
||||
JPGD_BAD_SOS_SUCCESSIVE,
|
||||
JPGD_STREAM_READ,
|
||||
JPGD_NOTENOUGHMEM,
|
||||
JPGD_TOO_MANY_SCANS
|
||||
};
|
||||
|
||||
// Input stream interface.
|
||||
|
@ -98,13 +125,28 @@ namespace jpgd
|
|||
uint m_ofs, m_size;
|
||||
|
||||
public:
|
||||
jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
|
||||
jpeg_decoder_mem_stream(const uint8* pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
|
||||
jpeg_decoder_mem_stream()
|
||||
: m_pSrc_data(NULL)
|
||||
, m_ofs(0)
|
||||
, m_size(0)
|
||||
{
|
||||
}
|
||||
jpeg_decoder_mem_stream(const uint8* pSrc_data, uint size)
|
||||
: m_pSrc_data(pSrc_data)
|
||||
, m_ofs(0)
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~jpeg_decoder_mem_stream() {}
|
||||
|
||||
bool open(const uint8* pSrc_data, uint size);
|
||||
void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
|
||||
void close()
|
||||
{
|
||||
m_pSrc_data = NULL;
|
||||
m_ofs = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag);
|
||||
};
|
||||
|
@ -114,8 +156,15 @@ namespace jpgd
|
|||
|
||||
enum
|
||||
{
|
||||
JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
|
||||
JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 16384, JPGD_MAX_HEIGHT = 32768, JPGD_MAX_WIDTH = 32768
|
||||
JPGD_IN_BUF_SIZE = 8192,
|
||||
JPGD_MAX_BLOCKS_PER_MCU = 10,
|
||||
JPGD_MAX_HUFF_TABLES = 8,
|
||||
JPGD_MAX_QUANT_TABLES = 4,
|
||||
JPGD_MAX_COMPONENTS = 4,
|
||||
JPGD_MAX_COMPS_IN_SCAN = 4,
|
||||
JPGD_MAX_BLOCKS_PER_ROW = 16384,
|
||||
JPGD_MAX_HEIGHT = 32768,
|
||||
JPGD_MAX_WIDTH = 32768
|
||||
};
|
||||
|
||||
typedef int16 jpgd_quant_t;
|
||||
|
@ -275,7 +324,12 @@ namespace jpgd
|
|||
bool m_sample_buf_prev_valid;
|
||||
bool m_has_sse2;
|
||||
|
||||
inline int check_sample_buf_ofs(int ofs) const { assert(ofs >= 0); assert(ofs < m_max_blocks_per_row * 64); return ofs; }
|
||||
inline int check_sample_buf_ofs(int ofs) const
|
||||
{
|
||||
assert(ofs >= 0);
|
||||
assert(ofs < m_max_blocks_per_row * 64);
|
||||
return ofs;
|
||||
}
|
||||
void free_all_blocks();
|
||||
JPGD_NORETURN void stop_decoding(jpgd_status status);
|
||||
void* alloc(size_t n, bool zero = false);
|
||||
|
|
|
@ -53,4 +53,3 @@
|
|||
#define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */
|
||||
#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
|
||||
#define OV7610_REG_COM_I 0x29 /* misc settings */
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#include "ov519.h"
|
||||
#include "../qemu-usb/desc.h"
|
||||
|
||||
namespace usb_eyetoy {
|
||||
namespace usb_eyetoy
|
||||
{
|
||||
|
||||
static const USBDescStrings desc_strings = {
|
||||
"",
|
||||
|
@ -27,7 +28,8 @@ static const USBDescStrings desc_strings = {
|
|||
"EyeToy USB camera Namtai",
|
||||
};
|
||||
|
||||
typedef struct EYETOYState {
|
||||
typedef struct EYETOYState
|
||||
{
|
||||
USBDevice dev;
|
||||
USBDesc desc;
|
||||
USBDescDevice desc_dev;
|
||||
|
@ -328,11 +330,13 @@ static void eyetoy_handle_control(USBDevice *dev, USBPacket *p, int request, int
|
|||
int ret = 0;
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(request) {
|
||||
switch (request)
|
||||
{
|
||||
case VendorDeviceRequest | 0x1: //Read register
|
||||
data[0] = s->regs[index & 0xFF];
|
||||
OSDebugOut(TEXT("=== READ reg 0x%02x = 0x%02x (%d)\n"), index, data[0], data[0]);
|
||||
|
@ -340,7 +344,8 @@ static void eyetoy_handle_control(USBDevice *dev, USBPacket *p, int request, int
|
|||
break;
|
||||
|
||||
case VendorDeviceOutRequest | 0x1: //Write register
|
||||
if (!(index >= R51x_I2C_SADDR_3 && index <= R518_I2C_CTL)) {
|
||||
if (!(index >= R51x_I2C_SADDR_3 && index <= R518_I2C_CTL))
|
||||
{
|
||||
OSDebugOut(TEXT("*** WRITE reg 0x%02x = 0x%02x (%d)\n"), index, data[0], data[0]);
|
||||
}
|
||||
|
||||
|
@ -417,28 +422,30 @@ static void eyetoy_handle_data(USBDevice *dev, USBPacket *p)
|
|||
uint8_t data[max_ep_size];
|
||||
uint8_t devep = p->ep->nr;
|
||||
|
||||
switch(p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
if (devep == 1) {
|
||||
if (devep == 1)
|
||||
{
|
||||
|
||||
memset(data, 0xff, sizeof(data));
|
||||
|
||||
if (s->frame_step == 0) {
|
||||
if (s->frame_step == 0)
|
||||
{
|
||||
|
||||
s->mpeg_frame_size = s->videodev->GetImage(s->mpeg_frame_data, 320 * 240 * 2);
|
||||
if (s->mpeg_frame_size == 0) {
|
||||
if (s->mpeg_frame_size == 0)
|
||||
{
|
||||
goto send_packet;
|
||||
}
|
||||
|
||||
s->mpeg_frame_offset = 0;
|
||||
uint8_t header1[] = {
|
||||
0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
memcpy(data, header1, sizeof(header1));
|
||||
uint8_t header2[] = {
|
||||
0x69, 0x70, 0x75, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xF0, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
0x00};
|
||||
memcpy(data + sizeof(header1), header2, sizeof(header2));
|
||||
|
||||
int data_pk = max_ep_size - sizeof(header1) - sizeof(header2);
|
||||
|
@ -446,7 +453,9 @@ static void eyetoy_handle_data(USBDevice *dev, USBPacket *p)
|
|||
s->mpeg_frame_offset = data_pk;
|
||||
|
||||
s->frame_step++;
|
||||
} else if (s->frame_step < 10) {
|
||||
}
|
||||
else if (s->frame_step < 10)
|
||||
{
|
||||
int data_pk = s->mpeg_frame_size - s->mpeg_frame_offset;
|
||||
if (data_pk > max_ep_size)
|
||||
data_pk = max_ep_size;
|
||||
|
@ -454,10 +463,11 @@ static void eyetoy_handle_data(USBDevice *dev, USBPacket *p)
|
|||
s->mpeg_frame_offset += data_pk;
|
||||
|
||||
s->frame_step++;
|
||||
} else if (s->frame_step == 10) {
|
||||
}
|
||||
else if (s->frame_step == 10)
|
||||
{
|
||||
uint8_t footer[] = {
|
||||
0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
0xFF, 0xFF, 0xFF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
memcpy(data, footer, sizeof(footer));
|
||||
s->frame_step = 0;
|
||||
}
|
||||
|
@ -465,7 +475,8 @@ static void eyetoy_handle_data(USBDevice *dev, USBPacket *p)
|
|||
send_packet:
|
||||
usb_packet_copy(p, data, max_ep_size);
|
||||
}
|
||||
else if (devep == 2) {
|
||||
else if (devep == 2)
|
||||
{
|
||||
// get audio
|
||||
//fprintf(stderr, "get audio %d\n", len);
|
||||
memset(data, 0, p->iov.size);
|
||||
|
@ -589,4 +600,4 @@ int EyeToyWebCamDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_eyetoy
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
#include <mutex>
|
||||
|
||||
|
||||
namespace usb_eyetoy {
|
||||
namespace usb_eyetoy
|
||||
{
|
||||
|
||||
class EyeToyWebCamDevice
|
||||
{
|
||||
|
@ -53,6 +54,6 @@ public:
|
|||
static int Freeze(int mode, USBDevice* dev, void* data);
|
||||
};
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_eyetoy
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#include "../qemu-usb/vl.h"
|
||||
#include "../configuration.h"
|
||||
|
||||
namespace usb_eyetoy {
|
||||
namespace usb_eyetoy
|
||||
{
|
||||
|
||||
class VideoDevice
|
||||
{
|
||||
|
@ -36,5 +37,5 @@ protected:
|
|||
int mPort;
|
||||
};
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_eyetoy
|
||||
#endif
|
||||
|
|
|
@ -24,12 +24,16 @@
|
|||
#include "../helpers.h"
|
||||
#include "../deviceproxy.h"
|
||||
|
||||
namespace usb_eyetoy {
|
||||
namespace usb_eyetoy
|
||||
{
|
||||
|
||||
class VideoDeviceError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
VideoDeviceError(const char* msg) : std::runtime_error(msg) {}
|
||||
VideoDeviceError(const char* msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~VideoDeviceError() throw() {}
|
||||
};
|
||||
|
||||
|
@ -50,7 +54,10 @@ class VideoDeviceProxy : public VideoDeviceProxyBase
|
|||
|
||||
public:
|
||||
VideoDeviceProxy() {}
|
||||
VideoDeviceProxy(const std::string& name): VideoDeviceProxyBase(name) {}
|
||||
VideoDeviceProxy(const std::string& name)
|
||||
: VideoDeviceProxyBase(name)
|
||||
{
|
||||
}
|
||||
VideoDevice* CreateObject(int port) const
|
||||
{
|
||||
try
|
||||
|
@ -79,5 +86,5 @@ class RegisterVideoDevice : public RegisterProxy<VideoDeviceProxyBase>
|
|||
static void Register();
|
||||
};
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_eyetoy
|
||||
#endif
|
||||
|
|
|
@ -23,12 +23,16 @@
|
|||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox); // src/linux/config-gtk.cpp
|
||||
|
||||
namespace usb_hid { namespace evdev {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
#define EVDEV_DIR "/dev/input/by-path/"
|
||||
|
||||
typedef std::vector<std::pair<std::string, std::string>> devs_t;
|
||||
struct ConfigData {
|
||||
struct ConfigData
|
||||
{
|
||||
int port;
|
||||
devs_t devs;
|
||||
devs_t::const_iterator iter;
|
||||
|
@ -44,7 +48,8 @@ static void PopulateHIDs(ConfigData &cfg, HIDType hid_type)
|
|||
cfg.devs.push_back(std::make_pair("None", ""));
|
||||
|
||||
DIR* dirp = opendir(EVDEV_DIR);
|
||||
if(dirp == NULL) {
|
||||
if (dirp == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error opening " EVDEV_DIR ": %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -58,10 +63,12 @@ static void PopulateHIDs(ConfigData &cfg, HIDType hid_type)
|
|||
if (devlen >= len)
|
||||
{
|
||||
const char* const start = dp->d_name + devlen - len;
|
||||
if(strncmp(start, devstr[hid_type], len) == 0) {
|
||||
if (strncmp(start, devstr[hid_type], len) == 0)
|
||||
{
|
||||
OSDebugOut("%s%s\n", EVDEV_DIR, dp->d_name);
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << EVDEV_DIR << dp->d_name;
|
||||
|
||||
char name[1024];
|
||||
|
@ -168,7 +175,8 @@ int GtkHidConfigure(int port, const char* dev_type, HIDType hid_type, GtkWindow
|
|||
int ret = RESULT_OK;
|
||||
if (result == GTK_RESPONSE_OK)
|
||||
{
|
||||
if (cfg.iter != cfg.devs.end()) {
|
||||
if (cfg.iter != cfg.devs.end())
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, APINAME, N_DEVICE, cfg.iter->second))
|
||||
ret = RESULT_FAILED;
|
||||
}
|
||||
|
@ -186,4 +194,5 @@ int EvDev::Configure(int port, const char* dev_type, HIDType hid_type, void *dat
|
|||
}
|
||||
|
||||
#undef EVDEV_DIR
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -27,7 +27,10 @@ extern Display *g_GSdsp;
|
|||
extern Window g_GSwin;
|
||||
#endif
|
||||
|
||||
namespace usb_hid { namespace evdev {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
|
||||
|
@ -43,21 +46,25 @@ bool FindHid(const std::string &evphys, std::string& hid_dev)
|
|||
struct dirent* dp;
|
||||
|
||||
DIR* dirp = opendir("/dev/input/");
|
||||
if(dirp == NULL) {
|
||||
if (dirp == NULL)
|
||||
{
|
||||
perror("Error opening /dev/input/");
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(strncmp(dp->d_name, "hidraw", 6) == 0) {
|
||||
if (strncmp(dp->d_name, "hidraw", 6) == 0)
|
||||
{
|
||||
OSDebugOut("%s\n", dp->d_name);
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "/dev/input/" << dp->d_name;
|
||||
fd = open(str.str().c_str(), O_RDWR | O_NONBLOCK);
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Unable to open device");
|
||||
continue;
|
||||
}
|
||||
|
@ -71,7 +78,8 @@ bool FindHid(const std::string &evphys, std::string& hid_dev)
|
|||
else
|
||||
OSDebugOut("Raw Phys: %s\n", buf);*/
|
||||
close(fd);
|
||||
if (evphys == buf) {
|
||||
if (evphys == buf)
|
||||
{
|
||||
closedir(dirp);
|
||||
hid_dev = str.str();
|
||||
return true;
|
||||
|
@ -249,14 +257,18 @@ void EvDev::ReaderThread(void *ptr)
|
|||
if (event.code == KEY_LEFTSHIFT || event.code == KEY_RIGHTSHIFT)
|
||||
shift = (event.value > 0);
|
||||
|
||||
if (event.code == KEY_F12 && (event.value == 1) && shift) {
|
||||
if (!grabbed) {
|
||||
if (event.code == KEY_F12 && (event.value == 1) && shift)
|
||||
{
|
||||
if (!grabbed)
|
||||
{
|
||||
grabbed = true;
|
||||
XGrabPointer(g_GSdsp, g_GSwin, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, g_GSwin, None, CurrentTime);
|
||||
XGrabKeyboard(g_GSdsp, g_GSwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
// Hides globally :(
|
||||
XFixesHideCursor(g_GSdsp, g_GSwin);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
grabbed = false;
|
||||
XUngrabPointer(g_GSdsp, CurrentTime);
|
||||
XUngrabKeyboard(g_GSdsp, CurrentTime);
|
||||
|
@ -265,13 +277,15 @@ void EvDev::ReaderThread(void *ptr)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (hs->kbd.eh_entry) {
|
||||
if (hs->kbd.eh_entry)
|
||||
{
|
||||
|
||||
QKeyCode qcode = Q_KEY_CODE_UNMAPPED;
|
||||
if (event.code < (uint16_t)qemu_input_map_linux_to_qcode_len)
|
||||
qcode = qemu_input_map_linux_to_qcode[event.code];
|
||||
|
||||
if (event.value < 2) {
|
||||
if (event.value < 2)
|
||||
{
|
||||
ev.type = INPUT_EVENT_KIND_KEY;
|
||||
ev.u.key.down = (event.value == 1); // 2 if repeat
|
||||
ev.u.key.key.type = KEY_VALUE_KIND_QCODE;
|
||||
|
@ -281,7 +295,8 @@ void EvDev::ReaderThread(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
if (hs->ptr.eh_entry) {
|
||||
if (hs->ptr.eh_entry)
|
||||
{
|
||||
ev.type = INPUT_EVENT_KIND_BTN;
|
||||
switch (event.code)
|
||||
{
|
||||
|
@ -309,7 +324,8 @@ void EvDev::ReaderThread(void *ptr)
|
|||
case EV_SYN: //TODO useful?
|
||||
{
|
||||
OSDebugOut("EV_SYN: %d, val: %d\n", event.code, event.value);
|
||||
switch(event.code) {
|
||||
switch (event.code)
|
||||
{
|
||||
case SYN_REPORT:
|
||||
if (hs->ptr.eh_sync) //TODO sync here?
|
||||
hs->ptr.eh_sync(hs);
|
||||
|
@ -339,4 +355,5 @@ void EvDev::ReaderThread(void *ptr)
|
|||
dev->mReaderThreadIsRunning = false;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -22,14 +22,18 @@
|
|||
#include <atomic>
|
||||
#include "../usb-hid.h"
|
||||
|
||||
namespace usb_hid { namespace evdev {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
static const char* APINAME = "evdev";
|
||||
|
||||
class EvDev : public UsbHID
|
||||
{
|
||||
public:
|
||||
EvDev(int port, const char* dev_type): UsbHID(port, dev_type)
|
||||
EvDev(int port, const char* dev_type)
|
||||
: UsbHID(port, dev_type)
|
||||
, mHandle(-1)
|
||||
, mReaderThreadIsRunning(false)
|
||||
{
|
||||
|
@ -48,6 +52,7 @@ public:
|
|||
}
|
||||
|
||||
static int Configure(int port, const char* dev_type, HIDType hid_type, void* data);
|
||||
|
||||
protected:
|
||||
static void ReaderThread(void* ptr);
|
||||
|
||||
|
@ -83,4 +88,5 @@ bool GetEvdevName(const std::string& path, char (&name)[_Size])
|
|||
return false;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -24,12 +24,16 @@
|
|||
#include "../helpers.h"
|
||||
#include "../deviceproxy.h"
|
||||
|
||||
namespace usb_hid {
|
||||
namespace usb_hid
|
||||
{
|
||||
|
||||
class UsbHIDError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
UsbHIDError(const char* msg) : std::runtime_error(msg) {}
|
||||
UsbHIDError(const char* msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~UsbHIDError() throw() {}
|
||||
};
|
||||
|
||||
|
@ -52,7 +56,10 @@ class UsbHIDProxy : public UsbHIDProxyBase
|
|||
|
||||
public:
|
||||
UsbHIDProxy() {}
|
||||
UsbHIDProxy(const std::string& name): UsbHIDProxyBase(name) {}
|
||||
UsbHIDProxy(const std::string& name)
|
||||
: UsbHIDProxyBase(name)
|
||||
{
|
||||
}
|
||||
UsbHID* CreateObject(int port, const char* dev_type) const
|
||||
{
|
||||
try
|
||||
|
@ -85,5 +92,5 @@ class RegisterUsbHID : public RegisterProxy<UsbHIDProxyBase>
|
|||
static void Register();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace usb_hid
|
||||
#endif
|
||||
|
|
|
@ -16,14 +16,20 @@
|
|||
#include "usb-hid.h"
|
||||
#include "hidproxy.h"
|
||||
|
||||
namespace usb_hid { namespace noop {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace noop
|
||||
{
|
||||
|
||||
static const char* APINAME = "noop";
|
||||
|
||||
class NOOP : public UsbHID
|
||||
{
|
||||
public:
|
||||
NOOP(int port, const char* dev_type): UsbHID(port, dev_type) {}
|
||||
NOOP(int port, const char* dev_type)
|
||||
: UsbHID(port, dev_type)
|
||||
{
|
||||
}
|
||||
~NOOP() {}
|
||||
int Open() { return 0; }
|
||||
int Close() { return 0; }
|
||||
|
@ -42,4 +48,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace noop
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -18,10 +18,26 @@
|
|||
#include "qemu-usb/input-keymap.h"
|
||||
#include "qemu-usb/input-keymap-win32-to-qcode.h"
|
||||
|
||||
namespace usb_hid { namespace raw {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace raw
|
||||
{
|
||||
|
||||
#define CHECK(exp) do{ if(!(exp)) goto Error; }while(0)
|
||||
#define SAFE_FREE(p) do{ if(p) { free(p); (p) = NULL; } }while(0)
|
||||
#define CHECK(exp) \
|
||||
do \
|
||||
{ \
|
||||
if (!(exp)) \
|
||||
goto Error; \
|
||||
} while (0)
|
||||
#define SAFE_FREE(p) \
|
||||
do \
|
||||
{ \
|
||||
if (p) \
|
||||
{ \
|
||||
free(p); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// VKEY from https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
|
||||
// and convert to HID usage id from "10 Keyboard/Keypad Page (0x07)"
|
||||
|
@ -91,8 +107,7 @@ static void ParseRawInput(PRAWINPUT pRawInput, HIDState *hs)
|
|||
if (HidP_GetUsageValue(
|
||||
HidP_Input, pValueCaps[i].UsagePage, 0,
|
||||
pValueCaps[i].Range.UsageMin, &value, pPreparsedData,
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid
|
||||
) != HIDP_STATUS_SUCCESS )
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS)
|
||||
{
|
||||
continue; // if here then maybe something is up with HIDP_CAPS.NumberInputValueCaps
|
||||
}
|
||||
|
@ -128,7 +143,8 @@ static void ParseRawInputKB(RAWKEYBOARD &k, HIDState *hs)
|
|||
OSDebugOut(TEXT("%ud kb: %hu %hu %hu %u\n"), nr, k.MakeCode, k.VKey, k.Flags, k.ExtraInformation);
|
||||
|
||||
nr++;
|
||||
if (nr > 10) nr = 0;
|
||||
if (nr > 10)
|
||||
nr = 0;
|
||||
if (KEYBOARD_OVERRUN_MAKE_CODE == k.MakeCode)
|
||||
return;
|
||||
|
||||
|
@ -137,7 +153,8 @@ static void ParseRawInputKB(RAWKEYBOARD &k, HIDState *hs)
|
|||
qcode = qemu_input_map_win32_to_qcode[k.VKey];
|
||||
|
||||
//TODO
|
||||
if (k.Flags & RI_KEY_E0) {
|
||||
if (k.Flags & RI_KEY_E0)
|
||||
{
|
||||
if (Q_KEY_CODE_SHIFT == qcode)
|
||||
qcode = Q_KEY_CODE_SHIFT_R;
|
||||
else if (Q_KEY_CODE_CTRL == qcode)
|
||||
|
@ -157,7 +174,8 @@ static void ParseRawInputKB(RAWKEYBOARD &k, HIDState *hs)
|
|||
|
||||
static void SendPointerEvent(InputEvent& ev, HIDState* hs)
|
||||
{
|
||||
if (hs->ptr.eh_entry) {
|
||||
if (hs->ptr.eh_entry)
|
||||
{
|
||||
hs->ptr.eh_entry(hs, &ev);
|
||||
}
|
||||
}
|
||||
|
@ -284,4 +302,5 @@ int RawInput::Configure(int port, const char* dev_type, HIDType type, void *data
|
|||
return res;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace raw
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -17,14 +17,18 @@
|
|||
#include "../hidproxy.h"
|
||||
#include "../usb-hid.h"
|
||||
|
||||
namespace usb_hid { namespace raw {
|
||||
namespace usb_hid
|
||||
{
|
||||
namespace raw
|
||||
{
|
||||
|
||||
static const char* APINAME = "rawinput";
|
||||
|
||||
class RawInput : public UsbHID, shared::rawinput::ParseRawInputCB
|
||||
{
|
||||
public:
|
||||
RawInput(int port, const char* dev_type) : UsbHID(port, dev_type)
|
||||
RawInput(int port, const char* dev_type)
|
||||
: UsbHID(port, dev_type)
|
||||
{
|
||||
}
|
||||
~RawInput()
|
||||
|
@ -46,4 +50,5 @@ public:
|
|||
static int Configure(int port, const char* dev_type, HIDType, void* data);
|
||||
};
|
||||
|
||||
}} // namespace
|
||||
} // namespace raw
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -30,9 +30,11 @@
|
|||
|
||||
#define CONTAINER_OF(p, type, field) ((type*)((char*)p - ((ptrdiff_t) & ((type*)0)->field)))
|
||||
|
||||
namespace usb_hid {
|
||||
namespace usb_hid
|
||||
{
|
||||
|
||||
typedef struct UsbHIDState {
|
||||
typedef struct UsbHIDState
|
||||
{
|
||||
USBDevice dev;
|
||||
USBDesc desc;
|
||||
USBDescDevice desc_dev;
|
||||
|
@ -41,7 +43,8 @@ typedef struct UsbHIDState {
|
|||
|
||||
USBEndpoint* intr;
|
||||
uint8_t port;
|
||||
struct freeze {
|
||||
struct freeze
|
||||
{
|
||||
HIDState hid;
|
||||
int ep;
|
||||
} f;
|
||||
|
@ -74,7 +77,8 @@ const TCHAR* HIDMouseDevice::LongAPIName(const std::string& name)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT_MOUSE,
|
||||
STR_PRODUCT_TABLET,
|
||||
|
@ -433,24 +437,32 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
|||
|
||||
OSDebugOut(TEXT("usb-hid: req %04X val: %04X idx: %04X len: %d\n"), request, value, index, length);
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
switch (request)
|
||||
{
|
||||
/* hid specific requests */
|
||||
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch (value >> 8) {
|
||||
switch (value >> 8)
|
||||
{
|
||||
case 0x22:
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
if (hs->kind == HID_MOUSE)
|
||||
{
|
||||
memcpy(data, qemu_mouse_hid_report_descriptor,
|
||||
sizeof(qemu_mouse_hid_report_descriptor));
|
||||
p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
|
||||
} else if (hs->kind == HID_TABLET) {
|
||||
}
|
||||
else if (hs->kind == HID_TABLET)
|
||||
{
|
||||
memcpy(data, qemu_tablet_hid_report_descriptor,
|
||||
sizeof(qemu_tablet_hid_report_descriptor));
|
||||
p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
}
|
||||
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);
|
||||
|
@ -461,28 +473,36 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
|||
}
|
||||
break;
|
||||
case GET_REPORT:
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET)
|
||||
{
|
||||
p->actual_length = hid_pointer_poll(hs, data, length);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
}
|
||||
else if (hs->kind == HID_KEYBOARD)
|
||||
{
|
||||
p->actual_length = hid_keyboard_poll(hs, data, length);
|
||||
}
|
||||
break;
|
||||
case SET_REPORT:
|
||||
if (hs->kind == HID_KEYBOARD) {
|
||||
if (hs->kind == HID_KEYBOARD)
|
||||
{
|
||||
p->actual_length = hid_keyboard_write(hs, data, length);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case GET_PROTOCOL:
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
data[0] = hs->protocol;
|
||||
p->actual_length = 1;
|
||||
break;
|
||||
case SET_PROTOCOL:
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
|
||||
if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
hs->protocol = value;
|
||||
|
@ -495,7 +515,8 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
|||
hs->idle = (uint8_t)(value >> 8);
|
||||
OSDebugOut(TEXT("IDLE %d\n"), hs->idle);
|
||||
hid_set_next_idle(hs);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET)
|
||||
{
|
||||
hid_pointer_activate(hs);
|
||||
}
|
||||
break;
|
||||
|
@ -513,24 +534,33 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
|||
std::vector<uint8_t> buf(p->iov.size);
|
||||
size_t len = 0;
|
||||
|
||||
switch (p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
if (p->ep->nr == 1) {
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
if (p->ep->nr == 1)
|
||||
{
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET)
|
||||
{
|
||||
hid_pointer_activate(hs);
|
||||
}
|
||||
if (!hid_has_events(hs)) {
|
||||
if (!hid_has_events(hs))
|
||||
{
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
hid_set_next_idle(hs);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET)
|
||||
{
|
||||
len = hid_pointer_poll(hs, buf.data(), p->iov.size);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
}
|
||||
else if (hs->kind == HID_KEYBOARD)
|
||||
{
|
||||
len = hid_keyboard_poll(hs, buf.data(), p->iov.size);
|
||||
}
|
||||
usb_packet_copy(p, buf.data(), len);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
@ -566,7 +596,8 @@ void usb_hid_close(USBDevice *dev)
|
|||
s->usbhid->Close();
|
||||
}
|
||||
|
||||
USBDevice *HIDKbdDevice::CreateDevice(int port){
|
||||
USBDevice* HIDKbdDevice::CreateDevice(int port)
|
||||
{
|
||||
UsbHIDState* s;
|
||||
|
||||
std::string varApi;
|
||||
|
@ -637,11 +668,13 @@ int HIDKbdDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
switch (mode)
|
||||
{
|
||||
case FREEZE_LOAD:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
s->f = *freezed;
|
||||
return sizeof(UsbHIDState::freeze);
|
||||
case FREEZE_SAVE:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
*freezed = s->f;
|
||||
return sizeof(UsbHIDState::freeze);
|
||||
case FREEZE_SIZE:
|
||||
|
@ -652,7 +685,8 @@ int HIDKbdDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
USBDevice *HIDMouseDevice::CreateDevice(int port) {
|
||||
USBDevice* HIDMouseDevice::CreateDevice(int port)
|
||||
{
|
||||
UsbHIDState* s;
|
||||
|
||||
std::string varApi;
|
||||
|
@ -720,4 +754,4 @@ int HIDMouseDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return HIDKbdDevice::Freeze(mode, dev, data);
|
||||
}
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace usb_hid {
|
||||
namespace usb_hid
|
||||
{
|
||||
|
||||
enum HIDType
|
||||
{
|
||||
|
@ -30,7 +31,11 @@ enum HIDType
|
|||
class UsbHID
|
||||
{
|
||||
public:
|
||||
UsbHID(int port, const char* dev_type) : mPort(port), mDevType(dev_type) {}
|
||||
UsbHID(int port, const char* dev_type)
|
||||
: mPort(port)
|
||||
, mDevType(dev_type)
|
||||
{
|
||||
}
|
||||
virtual ~UsbHID() {}
|
||||
virtual int Open() = 0;
|
||||
virtual int Close() = 0;
|
||||
|
@ -88,4 +93,4 @@ public:
|
|||
static int Freeze(int mode, USBDevice* dev, void* data);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace usb_hid
|
||||
|
|
|
@ -16,14 +16,20 @@
|
|||
#pragma once
|
||||
#include "audiodeviceproxy.h"
|
||||
|
||||
namespace usb_mic { namespace audiodev_noop {
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_noop
|
||||
{
|
||||
|
||||
static const char* APINAME = "noop";
|
||||
|
||||
class NoopAudioDevice : public AudioDevice
|
||||
{
|
||||
public:
|
||||
NoopAudioDevice(int port, const char* dev_type, int mic, AudioDir dir): AudioDevice(port, dev_type, mic, dir) {}
|
||||
NoopAudioDevice(int port, const char* dev_type, int mic, AudioDir dir)
|
||||
: AudioDevice(port, dev_type, mic, dir)
|
||||
{
|
||||
}
|
||||
~NoopAudioDevice() {}
|
||||
void Start() {}
|
||||
void Stop() {}
|
||||
|
@ -78,4 +84,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
}}
|
||||
} // namespace audiodev_noop
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox); // src/linux/config-gtk.cpp
|
||||
|
||||
namespace usb_mic { namespace audiodev_pulse {
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_pulse
|
||||
{
|
||||
|
||||
static void pa_context_state_cb(pa_context* c, void* userdata)
|
||||
{
|
||||
|
@ -30,7 +33,8 @@ static void pa_context_state_cb(pa_context *c, void *userdata)
|
|||
|
||||
state = pa_context_get_state(c);
|
||||
OSDebugOut("pa_context_get_state() %d\n", state);
|
||||
switch (state) {
|
||||
switch (state)
|
||||
{
|
||||
// There are just here for reference
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
*pa_ready = 3;
|
||||
|
@ -54,7 +58,8 @@ static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, vo
|
|||
{
|
||||
AudioDeviceInfoList* devicelist = static_cast<AudioDeviceInfoList*>(userdata);
|
||||
|
||||
if (eol > 0) {
|
||||
if (eol > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -69,7 +74,8 @@ static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *
|
|||
{
|
||||
AudioDeviceInfoList* devicelist = static_cast<AudioDeviceInfoList*>(userdata);
|
||||
|
||||
if (eol > 0) {
|
||||
if (eol > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -99,7 +105,8 @@ static int pa_get_devicelist(AudioDeviceInfoList& list, AudioDir dir)
|
|||
pa_context_set_state_callback(pa_ctx, pa_context_state_cb, &pa_ready);
|
||||
|
||||
OSDebugOut("pa_get_devicelist\n");
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
|
||||
if (pa_ready == 0)
|
||||
{
|
||||
|
@ -334,8 +341,7 @@ uint32_t PulseAudioDevice::GetBuffer(short *buff, uint32_t frames)
|
|||
int ret = pa_context_connect(mPContext,
|
||||
mServer,
|
||||
PA_CONTEXT_NOFLAGS,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
//TODO reconnect stream as well?
|
||||
|
||||
|
@ -382,8 +388,7 @@ uint32_t PulseAudioDevice::SetBuffer(short *buff, uint32_t frames)
|
|||
int ret = pa_context_connect(mPContext,
|
||||
mServer,
|
||||
PA_CONTEXT_NOFLAGS,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
//TODO reconnect stream as well?
|
||||
|
||||
|
@ -466,22 +471,26 @@ bool PulseAudioDevice::Compare(AudioDevice* compare)
|
|||
void PulseAudioDevice::Uninit()
|
||||
{
|
||||
int ret;
|
||||
if (mStream) {
|
||||
if (mStream)
|
||||
{
|
||||
pa_threaded_mainloop_lock(mPMainLoop);
|
||||
ret = pa_stream_disconnect(mStream);
|
||||
pa_stream_unref(mStream);
|
||||
mStream = nullptr;
|
||||
pa_threaded_mainloop_unlock(mPMainLoop);
|
||||
}
|
||||
if (mPMainLoop) {
|
||||
if (mPMainLoop)
|
||||
{
|
||||
pa_threaded_mainloop_stop(mPMainLoop);
|
||||
}
|
||||
if (mPContext) {
|
||||
if (mPContext)
|
||||
{
|
||||
pa_context_disconnect(mPContext);
|
||||
pa_context_unref(mPContext);
|
||||
mPContext = nullptr;
|
||||
}
|
||||
if (mPMainLoop) {
|
||||
if (mPMainLoop)
|
||||
{
|
||||
pa_threaded_mainloop_free(mPMainLoop);
|
||||
mPMainLoop = nullptr;
|
||||
}
|
||||
|
@ -499,8 +508,7 @@ bool PulseAudioDevice::Init()
|
|||
|
||||
pa_context_set_state_callback(mPContext,
|
||||
context_state_cb,
|
||||
this
|
||||
);
|
||||
this);
|
||||
|
||||
// Lock the mainloop so that it does not run and crash before the context is ready
|
||||
pa_threaded_mainloop_lock(mPMainLoop);
|
||||
|
@ -509,8 +517,7 @@ bool PulseAudioDevice::Init()
|
|||
ret = pa_context_connect(mPContext,
|
||||
mServer,
|
||||
PA_CONTEXT_NOFLAGS,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
OSDebugOut("pa_context_connect %s\n", pa_strerror(ret));
|
||||
if (ret != PA_OK)
|
||||
|
@ -519,16 +526,17 @@ bool PulseAudioDevice::Init()
|
|||
// wait for pa_context_state_cb
|
||||
for (;;)
|
||||
{
|
||||
if(mPAready == 1) break;
|
||||
if(mPAready == 2 || mQuit) goto unlock_and_fail;
|
||||
if (mPAready == 1)
|
||||
break;
|
||||
if (mPAready == 2 || mQuit)
|
||||
goto unlock_and_fail;
|
||||
pa_threaded_mainloop_wait(mPMainLoop);
|
||||
}
|
||||
|
||||
mStream = pa_stream_new(mPContext,
|
||||
"USBqemu-pulse",
|
||||
&mSSpec,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
if (!mStream)
|
||||
goto unlock_and_fail;
|
||||
|
@ -550,29 +558,25 @@ bool PulseAudioDevice::Init()
|
|||
{
|
||||
pa_stream_set_read_callback(mStream,
|
||||
stream_read_cb,
|
||||
this
|
||||
);
|
||||
this);
|
||||
|
||||
ret = pa_stream_connect_record(mStream,
|
||||
mDeviceName.c_str(),
|
||||
&buffer_attr,
|
||||
PA_STREAM_ADJUST_LATENCY
|
||||
);
|
||||
PA_STREAM_ADJUST_LATENCY);
|
||||
OSDebugOut("pa_stream_connect_record %s\n", pa_strerror(ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
pa_stream_set_write_callback(mStream,
|
||||
stream_write_cb,
|
||||
this
|
||||
);
|
||||
this);
|
||||
|
||||
buffer_attr.maxlength = pa_bytes_per_second(&mSSpec);
|
||||
buffer_attr.prebuf = 0; // Don't stop on underrun but then
|
||||
// stream also only starts manually with uncorking.
|
||||
buffer_attr.tlength = pa_usec_to_bytes(mBuffering * 1000, &mSSpec);
|
||||
pa_stream_flags_t flags = (pa_stream_flags_t)
|
||||
(PA_STREAM_INTERPOLATE_TIMING |
|
||||
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING |
|
||||
PA_STREAM_NOT_MONOTONIC |
|
||||
PA_STREAM_AUTO_TIMING_UPDATE |
|
||||
//PA_STREAM_VARIABLE_RATE |
|
||||
|
@ -583,8 +587,7 @@ bool PulseAudioDevice::Init()
|
|||
&buffer_attr,
|
||||
flags,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
nullptr);
|
||||
OSDebugOut("pa_stream_connect_playback %s\n", pa_strerror(ret));
|
||||
}
|
||||
|
||||
|
@ -592,11 +595,14 @@ bool PulseAudioDevice::Init()
|
|||
goto unlock_and_fail;
|
||||
|
||||
// Wait for the stream to be ready
|
||||
for(;;) {
|
||||
for (;;)
|
||||
{
|
||||
pa_stream_state_t stream_state = pa_stream_get_state(mStream);
|
||||
assert(PA_STREAM_IS_GOOD(stream_state));
|
||||
if (stream_state == PA_STREAM_READY) break;
|
||||
if (stream_state == PA_STREAM_FAILED) goto unlock_and_fail;
|
||||
if (stream_state == PA_STREAM_READY)
|
||||
break;
|
||||
if (stream_state == PA_STREAM_FAILED)
|
||||
goto unlock_and_fail;
|
||||
pa_threaded_mainloop_wait(mPMainLoop);
|
||||
}
|
||||
|
||||
|
@ -711,7 +717,8 @@ void PulseAudioDevice::context_state_cb(pa_context *c, void *userdata)
|
|||
|
||||
state = pa_context_get_state(c);
|
||||
OSDebugOut("pa_context_get_state %d\n", state);
|
||||
switch (state) {
|
||||
switch (state)
|
||||
{
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
|
@ -757,7 +764,8 @@ void PulseAudioDevice::stream_read_cb (pa_stream *p, size_t nbytes, void *userda
|
|||
return;
|
||||
|
||||
auto dur = std::chrono::duration_cast<ms>(hrc::now() - padev->mLastGetBuffer).count();
|
||||
if (padev->mPaused /*|| dur > 5000*/ || (!padata && nbytes /* hole */)) {
|
||||
if (padev->mPaused /*|| dur > 5000*/ || (!padata && nbytes /* hole */))
|
||||
{
|
||||
ret = pa_stream_drop(p);
|
||||
if (ret != PA_OK)
|
||||
OSDebugOut("pa_stream_drop %d: %s\n", ret, pa_strerror(ret));
|
||||
|
@ -799,7 +807,8 @@ void PulseAudioDevice::stream_read_cb (pa_stream *p, size_t nbytes, void *userda
|
|||
input_frames_used += data.input_frames_used;
|
||||
|
||||
size_t samples = data.input_frames_used * padev->GetChannels();
|
||||
if (!samples) break; //TODO happens?
|
||||
if (!samples)
|
||||
break; //TODO happens?
|
||||
padev->mInBuffer.read<float>(samples);
|
||||
}
|
||||
|
||||
|
@ -924,4 +933,5 @@ exit:
|
|||
return;
|
||||
}
|
||||
|
||||
}}
|
||||
} // namespace audiodev_pulse
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
#include <mutex>
|
||||
#include <chrono>
|
||||
|
||||
namespace usb_mic { namespace audiodev_pulse {
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_pulse
|
||||
{
|
||||
|
||||
// macros for string concat
|
||||
#undef APINAME_
|
||||
|
@ -42,7 +45,8 @@ using sec = std::chrono::seconds;
|
|||
class PulseAudioDevice : public AudioDevice
|
||||
{
|
||||
public:
|
||||
PulseAudioDevice(int port, const char* dev_type, int device, AudioDir dir): AudioDevice(port, dev_type, device, dir)
|
||||
PulseAudioDevice(int port, const char* dev_type, int device, AudioDir dir)
|
||||
: AudioDevice(port, dev_type, device, dir)
|
||||
, mBuffering(50)
|
||||
, mPaused(true)
|
||||
, mQuit(false)
|
||||
|
@ -62,8 +66,7 @@ public:
|
|||
N_AUDIO_SOURCE0,
|
||||
N_AUDIO_SOURCE1,
|
||||
N_AUDIO_SINK0,
|
||||
N_AUDIO_SINK1
|
||||
};
|
||||
N_AUDIO_SINK1};
|
||||
|
||||
if (!LoadSetting(mDevType, mPort, APINAME, (device ? var_names[i + 1] : var_names[i]), mDeviceName) || mDeviceName.empty())
|
||||
throw AudioDeviceError(APINAME_ ": failed to load device settings");
|
||||
|
@ -89,7 +92,8 @@ public:
|
|||
Uninit();
|
||||
AudioDeinit();
|
||||
mResampler = src_delete(mResampler);
|
||||
if (file) fclose(file);
|
||||
if (file)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
uint32_t GetBuffer(short* buff, uint32_t frames);
|
||||
|
@ -161,4 +165,5 @@ protected:
|
|||
hrc::time_point mLastOut;
|
||||
FILE* file = nullptr;
|
||||
};
|
||||
}}
|
||||
} // namespace audiodev_pulse
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -24,10 +24,18 @@
|
|||
#include "../Win32/Config.h"
|
||||
#include "../Win32/resource.h"
|
||||
|
||||
#define SafeRelease(x) if(x){x->Release(); x = NULL;}
|
||||
#define SafeRelease(x) \
|
||||
if (x) \
|
||||
{ \
|
||||
x->Release(); \
|
||||
x = NULL; \
|
||||
}
|
||||
#define ConvertMSTo100NanoSec(ms) (ms * 1000 * 10) //1000 microseconds, then 10 "100nanosecond" segments
|
||||
|
||||
namespace usb_mic { namespace audiodev_wasapi {
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_wasapi
|
||||
{
|
||||
|
||||
static FILE* file = nullptr;
|
||||
|
||||
|
@ -436,7 +444,8 @@ unsigned WINAPI MMAudioDevice::CaptureThread(LPVOID ptr)
|
|||
pBegin += srcData.output_frames_gen * src->GetChannels();
|
||||
|
||||
size_t samples = srcData.input_frames_used * src->GetChannels();
|
||||
if (!samples) break; //TODO happens?
|
||||
if (!samples)
|
||||
break; //TODO happens?
|
||||
src->mInBuffer.read<float>(samples);
|
||||
}
|
||||
|
||||
|
@ -565,7 +574,6 @@ unsigned WINAPI MMAudioDevice::RenderThread(LPVOID ptr)
|
|||
|
||||
read -= srcData.input_frames_used * src->GetChannels();
|
||||
src->mInBuffer.read<short>(srcData.input_frames_used * src->GetChannels());
|
||||
|
||||
}
|
||||
}
|
||||
// TODO WASAPI seems to stop playing when buffer underrun, so skip this
|
||||
|
@ -590,8 +598,10 @@ unsigned WINAPI MMAudioDevice::RenderThread(LPVOID ptr)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (hr == AUDCLNT_E_DEVICE_INVALIDATED)
|
||||
{
|
||||
src->mDeviceLost = true;
|
||||
OSDebugOut(TEXT("Audio device has been lost, attempting to reinitialize\n"));
|
||||
}
|
||||
|
@ -600,7 +610,6 @@ unsigned WINAPI MMAudioDevice::RenderThread(LPVOID ptr)
|
|||
}
|
||||
|
||||
Sleep(src->mDeviceLost ? 1000 : 10);
|
||||
|
||||
}
|
||||
|
||||
quit:
|
||||
|
@ -718,8 +727,10 @@ uint32_t MMAudioDevice::GetMMBuffer()
|
|||
UINT32 captureSize = 0;
|
||||
HRESULT hRes = mmCapture->GetNextPacketSize(&captureSize);
|
||||
|
||||
if (FAILED(hRes)) {
|
||||
if (hRes == AUDCLNT_E_DEVICE_INVALIDATED) {
|
||||
if (FAILED(hRes))
|
||||
{
|
||||
if (hRes == AUDCLNT_E_DEVICE_INVALIDATED)
|
||||
{
|
||||
mDeviceLost = true;
|
||||
FreeData();
|
||||
OSDebugOut(TEXT("Audio device has been lost, attempting to reinitialize\n"));
|
||||
|
@ -907,11 +918,13 @@ static void RefreshOutputAudioList(HWND hW, LRESULT idx, WASAPISettings *setting
|
|||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int tmp = 0;
|
||||
WASAPISettings* s;
|
||||
|
||||
switch (uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
SetWindowLongPtr(hW, GWLP_USERDATA, (LONG)lParam);
|
||||
break;
|
||||
|
@ -981,7 +994,8 @@ static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lPa
|
|||
break;
|
||||
case BN_CLICKED:
|
||||
{
|
||||
switch (LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
int p[3];
|
||||
|
@ -1026,4 +1040,5 @@ static BOOL CALLBACK WASAPIDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lPa
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
} // namespace audiodev_wasapi
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -22,14 +22,18 @@
|
|||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
namespace usb_mic { namespace audiodev_wasapi {
|
||||
namespace usb_mic
|
||||
{
|
||||
namespace audiodev_wasapi
|
||||
{
|
||||
|
||||
static const char* APINAME = "wasapi";
|
||||
|
||||
class MMAudioDevice : public AudioDevice
|
||||
{
|
||||
public:
|
||||
MMAudioDevice(int port, const char* dev_type, int device, AudioDir dir): AudioDevice(port, dev_type, device, dir)
|
||||
MMAudioDevice(int port, const char* dev_type, int device, AudioDir dir)
|
||||
: AudioDevice(port, dev_type, device, dir)
|
||||
, mmCapture(NULL)
|
||||
, mmRender(NULL)
|
||||
, mmClient(NULL)
|
||||
|
@ -153,4 +157,5 @@ private:
|
|||
LONGLONG mLastTimeNS = 0;
|
||||
};
|
||||
|
||||
}} // namespace
|
||||
} // namespace audiodev_wasapi
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
#define N_BUFFER_LEN_SRC TEXT("buffer_len_src")
|
||||
#define N_BUFFER_LEN_SINK TEXT("buffer_len_sink")
|
||||
|
||||
enum MicMode {
|
||||
enum MicMode
|
||||
{
|
||||
MIC_MODE_NONE,
|
||||
MIC_MODE_SINGLE,
|
||||
MIC_MODE_SEPARATE,
|
||||
|
@ -46,7 +47,8 @@ enum MicMode {
|
|||
MIC_MODE_SHARED
|
||||
};
|
||||
|
||||
enum AudioDir {
|
||||
enum AudioDir
|
||||
{
|
||||
AUDIODIR_SOURCE = 0,
|
||||
AUDIODIR_SINK
|
||||
};
|
||||
|
@ -75,18 +77,20 @@ struct AudioDeviceInfoW
|
|||
class AudioDevice
|
||||
{
|
||||
public:
|
||||
AudioDevice(int port, const char* dev_type, int device, AudioDir dir): mPort(port)
|
||||
AudioDevice(int port, const char* dev_type, int device, AudioDir dir)
|
||||
: mPort(port)
|
||||
, mDevType(dev_type)
|
||||
, mDevice(device)
|
||||
, mAudioDir(dir)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
int mPort;
|
||||
const char* mDevType;
|
||||
int mDevice;
|
||||
AudioDir mAudioDir;
|
||||
|
||||
public:
|
||||
virtual ~AudioDevice() {}
|
||||
//get buffer, converted to 16bit int format
|
||||
|
|
|
@ -27,12 +27,16 @@
|
|||
#include "../osdebugout.h"
|
||||
#include "audiodev.h"
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
|
||||
class AudioDeviceError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
AudioDeviceError(const char* msg) : std::runtime_error(msg) {}
|
||||
AudioDeviceError(const char* msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~AudioDeviceError() throw() {}
|
||||
};
|
||||
|
||||
|
@ -57,7 +61,10 @@ class AudioDeviceProxy : public AudioDeviceProxyBase
|
|||
|
||||
public:
|
||||
AudioDeviceProxy() {}
|
||||
AudioDeviceProxy(const std::string& name): AudioDeviceProxyBase(name) {} //Why can't it automagically, ugh
|
||||
AudioDeviceProxy(const std::string& name)
|
||||
: AudioDeviceProxyBase(name)
|
||||
{
|
||||
} //Why can't it automagically, ugh
|
||||
~AudioDeviceProxy() { OSDebugOut(TEXT("%p\n"), this); }
|
||||
|
||||
AudioDevice* CreateObject(int port, const char* dev_type, int mic, AudioDir dir) const
|
||||
|
@ -100,5 +107,5 @@ class RegisterAudioDevice : public RegisterProxy<AudioDeviceProxyBase>
|
|||
public:
|
||||
static void Register();
|
||||
};
|
||||
}
|
||||
} // namespace usb_mic
|
||||
#endif
|
||||
|
|
|
@ -40,34 +40,40 @@
|
|||
#define USBAUDIO_SAMPLE_RATE 48000
|
||||
#define USBAUDIO_PACKET_INTERVAL 1
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
|
||||
static FILE* file = NULL;
|
||||
|
||||
typedef struct HeadsetState {
|
||||
typedef struct HeadsetState
|
||||
{
|
||||
USBDevice dev;
|
||||
AudioDevice* audsrc;
|
||||
AudioDevice* audsink;
|
||||
AudioDeviceProxyBase* audsrcproxy;
|
||||
|
||||
struct freeze {
|
||||
struct freeze
|
||||
{
|
||||
int intf;
|
||||
MicMode mode;
|
||||
|
||||
/* state */
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
bool mute;
|
||||
uint8_t vol[2];
|
||||
uint32_t srate;
|
||||
} out;
|
||||
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
bool mute;
|
||||
uint8_t vol;
|
||||
uint32_t srate;
|
||||
} in;
|
||||
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
bool mute;
|
||||
uint8_t vol[2];
|
||||
} mixer; //TODO
|
||||
|
@ -170,8 +176,7 @@ static const uint8_t headset_config_descriptor[] = {
|
|||
WBVAL(AUDIO_TERMINAL_USB_STREAMING), /* wTerminalType */
|
||||
0x00, /* bAssocTerminal */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL((AUDIO_CHANNEL_L
|
||||
| AUDIO_CHANNEL_R)), /* wChannelConfig */
|
||||
WBVAL((AUDIO_CHANNEL_L | AUDIO_CHANNEL_R)), /* wChannelConfig */
|
||||
0x00, /* iChannelNames */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
|
@ -183,8 +188,7 @@ static const uint8_t headset_config_descriptor[] = {
|
|||
0x0c, /* baSourceID( 0) */
|
||||
0x06, /* baSourceID( 1) */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL((AUDIO_CHANNEL_L
|
||||
| AUDIO_CHANNEL_R)), /* wChannelConfig */
|
||||
WBVAL((AUDIO_CHANNEL_L | AUDIO_CHANNEL_R)), /* wChannelConfig */
|
||||
0, /* iChannelNames */
|
||||
0x00, /* bmControls */
|
||||
0, /* iMixer */
|
||||
|
@ -305,8 +309,7 @@ static const uint8_t headset_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_OUT(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
WBVAL(0x00c0), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -358,8 +361,7 @@ static const uint8_t headset_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_OUT(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
WBVAL(0x0060), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -422,8 +424,7 @@ static const uint8_t headset_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength : 9 */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(4), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ADAPTIVE, /* bmAttributes */
|
||||
WBVAL(0x0060), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -445,8 +446,7 @@ static const USBDescStrings desc_strings = {
|
|||
"",
|
||||
"Logitech", // Atleast SOCOM II checks this (liblgaud?)
|
||||
"Logitech USB Headset",
|
||||
"00000000"
|
||||
};
|
||||
"00000000"};
|
||||
|
||||
static void headset_handle_reset(USBDevice* dev)
|
||||
{
|
||||
|
@ -475,7 +475,8 @@ static int usb_audio_get_control(HeadsetState *s, uint8_t attrib,
|
|||
int ret = USB_RET_STALL;
|
||||
|
||||
OSDebugOut(TEXT("cs: %02x attr: %02x cn: %d, unit: %04x\n"), cs, attrib, cn, idif);
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0600):
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0200):
|
||||
data[0] = s->f.in.mute;
|
||||
|
@ -590,7 +591,8 @@ static int usb_audio_set_control(HeadsetState *s, uint8_t attrib,
|
|||
int ret = USB_RET_STALL;
|
||||
bool set_vol = false;
|
||||
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0600):
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0200):
|
||||
s->f.in.mute = data[0] & 1;
|
||||
|
@ -605,11 +607,13 @@ static int usb_audio_set_control(HeadsetState *s, uint8_t attrib,
|
|||
//qemu usb audiocard formula
|
||||
vol -= 0x8000;
|
||||
vol = (vol * 255 + 0x4400) / 0x8800;
|
||||
if (vol > 255) {
|
||||
if (vol > 255)
|
||||
{
|
||||
vol = 255;
|
||||
}
|
||||
|
||||
if (s->f.in.vol != vol) {
|
||||
if (s->f.in.vol != vol)
|
||||
{
|
||||
s->f.in.vol = (uint8_t)vol;
|
||||
set_vol = true;
|
||||
}
|
||||
|
@ -624,16 +628,19 @@ static int usb_audio_set_control(HeadsetState *s, uint8_t attrib,
|
|||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0100):
|
||||
vol = data[0] + (data[1] << 8);
|
||||
OSDebugOut(TEXT("=> headphones set cn %d volume %04x\n"), cn, vol);
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
|
||||
//qemu usb audiocard formula
|
||||
vol -= 0x8000;
|
||||
vol = (vol * 255 + 0x4400) / 0x8800;
|
||||
if (vol > 255) {
|
||||
if (vol > 255)
|
||||
{
|
||||
vol = 255;
|
||||
}
|
||||
|
||||
if (s->f.out.vol[cn] != vol) {
|
||||
if (s->f.out.vol[cn] != vol)
|
||||
{
|
||||
s->f.out.vol[cn] = (uint8_t)vol;
|
||||
set_vol = true;
|
||||
}
|
||||
|
@ -642,7 +649,8 @@ static int usb_audio_set_control(HeadsetState *s, uint8_t attrib,
|
|||
break;
|
||||
}
|
||||
|
||||
if (set_vol) {
|
||||
if (set_vol)
|
||||
{
|
||||
//if (s->f.debug) {
|
||||
OSDebugOut(TEXT("headset: mute %d, vol %3d; mute %d vol %d %d\n"),
|
||||
s->f.in.mute, s->f.in.vol,
|
||||
|
@ -667,7 +675,8 @@ static int usb_audio_ep_control(HeadsetState *s, uint8_t attrib,
|
|||
fprintf(stderr, "%02X ", data[i]);
|
||||
fprintf(stderr, "\n");*/
|
||||
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_SAMPLING_FREQ_CONTROL, AUDIO_REQUEST_SET_CUR, 0x84):
|
||||
s->f.in.srate = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
OSDebugOut(TEXT("=> mic set cn %d sampling to %d\n"), cn, s->f.in.srate);
|
||||
|
@ -711,11 +720,13 @@ static void headset_handle_control(USBDevice *dev, USBPacket *p, int request, in
|
|||
OSDebugOut(TEXT("headset: req %04X val: %04X idx: %04X len: %d\n"), request, value, index, length);
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(request) {
|
||||
switch (request)
|
||||
{
|
||||
/*
|
||||
* Audio device specific request
|
||||
*/
|
||||
|
@ -725,7 +736,8 @@ static void headset_handle_control(USBDevice *dev, USBPacket *p, int request, in
|
|||
case ClassInterfaceRequest | AUDIO_REQUEST_GET_RES:
|
||||
ret = usb_audio_get_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
//if (s->debug) {
|
||||
fprintf(stderr, "headset: fail: get control\n");
|
||||
//}
|
||||
|
@ -740,7 +752,8 @@ static void headset_handle_control(USBDevice *dev, USBPacket *p, int request, in
|
|||
case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_RES:
|
||||
ret = usb_audio_set_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
//if (s->debug) {
|
||||
fprintf(stderr, "headset: fail: set control\n data:");
|
||||
//}
|
||||
|
@ -758,7 +771,8 @@ static void headset_handle_control(USBDevice *dev, USBPacket *p, int request, in
|
|||
case ClassEndpointOutRequest | AUDIO_REQUEST_SET_RES:
|
||||
ret = usb_audio_ep_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) goto fail;
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
|
@ -780,11 +794,13 @@ static void headset_handle_data(USBDevice *dev, USBPacket *p)
|
|||
int ret = USB_RET_STALL;
|
||||
uint8_t devep = p->ep->nr;
|
||||
|
||||
switch(p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
//fprintf(stderr, "token in ep: %d len: %zd\n", devep, p->iov.size);
|
||||
OSDebugOut(TEXT("token in ep: %d len: %zd\n"), devep, p->iov.size);
|
||||
if (devep == 4 && s->dev.altsetting[2] && s->audsrc) {
|
||||
if (devep == 4 && s->dev.altsetting[2] && s->audsrc)
|
||||
{
|
||||
|
||||
uint32_t outChns = 1; //s->dev.altsetting[2] == 1 ? 2 : 1;
|
||||
uint32_t inChns = s->audsrc->GetChannels();
|
||||
|
@ -847,7 +863,8 @@ static void headset_handle_data(USBDevice *dev, USBPacket *p)
|
|||
if (!s->audsink)
|
||||
return;
|
||||
|
||||
if (devep == 1 && s->dev.altsetting[1]) {
|
||||
if (devep == 1 && s->dev.altsetting[1])
|
||||
{
|
||||
uint32_t inChns = s->dev.altsetting[1] == 1 ? 2 : 1;
|
||||
uint32_t outChns = s->audsink->GetChannels();
|
||||
size_t len = p->iov.size;
|
||||
|
@ -914,7 +931,8 @@ static void headset_handle_destroy(USBDevice *dev)
|
|||
fclose(file);
|
||||
file = NULL;
|
||||
|
||||
if (!s) return;
|
||||
if (!s)
|
||||
return;
|
||||
if (s->audsrc)
|
||||
{
|
||||
s->audsrc->Stop();
|
||||
|
@ -1047,7 +1065,8 @@ int HeadsetDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
switch (mode)
|
||||
{
|
||||
case FREEZE_LOAD:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
s->f = *(HeadsetState::freeze*)data;
|
||||
if (s->audsrc)
|
||||
s->audsrc->SetResampling(s->f.in.srate);
|
||||
|
@ -1055,7 +1074,8 @@ int HeadsetDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
s->audsink->SetResampling(s->f.out.srate);
|
||||
return sizeof(HeadsetState::freeze);
|
||||
case FREEZE_SAVE:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
*(HeadsetState::freeze*)data = s->f;
|
||||
return sizeof(HeadsetState::freeze);
|
||||
case FREEZE_SIZE:
|
||||
|
@ -1066,4 +1086,4 @@ int HeadsetDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
#include "../deviceproxy.h"
|
||||
#include "audiodeviceproxy.h"
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
|
||||
class HeadsetDevice
|
||||
{
|
||||
|
@ -38,4 +39,4 @@ public:
|
|||
static int Freeze(int mode, USBDevice* dev, void* data);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#include "audio.h"
|
||||
#include "../qemu-usb/desc.h"
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
|
||||
static const uint8_t logitech_mic_dev_descriptor[] = {
|
||||
/* bLength */ 0x12, //(18)
|
||||
|
@ -77,8 +78,7 @@ static const uint8_t logitech_mic_config_descriptor[] = {
|
|||
WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */
|
||||
0x02, /* bAssocTerminal */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL(AUDIO_CHANNEL_L
|
||||
| AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
WBVAL(AUDIO_CHANNEL_L | AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
0x00, /* iChannelNames */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
|
@ -153,8 +153,7 @@ static const uint8_t logitech_mic_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x0064), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -206,8 +205,7 @@ static const uint8_t logitech_mic_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x00c8), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -232,7 +230,8 @@ static const USBDescStrings lt_desc_strings = {
|
|||
};
|
||||
|
||||
//Minified state
|
||||
typedef struct SINGSTARMICMINIState {
|
||||
typedef struct SINGSTARMICMINIState
|
||||
{
|
||||
USBDevice dev;
|
||||
|
||||
USBDesc desc;
|
||||
|
@ -270,4 +269,4 @@ fail:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -42,7 +42,8 @@ static FILE *file = NULL;
|
|||
#define USBAUDIO_SAMPLE_RATE 48000
|
||||
#define USBAUDIO_PACKET_INTERVAL 1
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
|
||||
/*
|
||||
* A USB audio device supports an arbitrary number of alternate
|
||||
|
@ -52,12 +53,14 @@ namespace usb_mic {
|
|||
* block diagrams. Alternative setting 0 is always the null block diagram,
|
||||
* which is used by a disabled device.
|
||||
*/
|
||||
enum usb_audio_altset : int8_t {
|
||||
enum usb_audio_altset : int8_t
|
||||
{
|
||||
ALTSET_OFF = 0x00, /* No endpoint */
|
||||
ALTSET_ON = 0x01, /* Single endpoint */
|
||||
};
|
||||
|
||||
typedef struct SINGSTARMICState {
|
||||
typedef struct SINGSTARMICState
|
||||
{
|
||||
USBDevice dev;
|
||||
|
||||
USBDesc desc;
|
||||
|
@ -66,7 +69,8 @@ typedef struct SINGSTARMICState {
|
|||
AudioDevice* audsrc[2];
|
||||
AudioDeviceProxyBase* audsrcproxy;
|
||||
|
||||
struct freeze {
|
||||
struct freeze
|
||||
{
|
||||
int port;
|
||||
int intf;
|
||||
MicMode mode;
|
||||
|
@ -149,8 +153,7 @@ static const uint8_t singstar_mic_config_descriptor[] = {
|
|||
WBVAL(AUDIO_TERMINAL_MICROPHONE), /* wTerminalType */
|
||||
0x02, /* bAssocTerminal */
|
||||
0x02, /* bNrChannels */
|
||||
WBVAL(AUDIO_CHANNEL_L
|
||||
|AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
WBVAL(AUDIO_CHANNEL_L | AUDIO_CHANNEL_R), /* wChannelConfig */
|
||||
0x00, /* iChannelNames */
|
||||
0x00, /* iTerminal */
|
||||
|
||||
|
@ -225,8 +228,7 @@ static const uint8_t singstar_mic_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x0064), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -278,8 +280,7 @@ static const uint8_t singstar_mic_config_descriptor[] = {
|
|||
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
|
||||
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
|
||||
USB_ENDPOINT_IN(1), /* bEndpointAddress */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS
|
||||
| USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_SYNC_ASYNCHRONOUS, /* bmAttributes */
|
||||
WBVAL(0x00c8), /* wMaxPacketSize */
|
||||
0x01, /* bInterval */
|
||||
0x00, /* bRefresh */
|
||||
|
@ -321,13 +322,15 @@ static int usb_audio_get_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
uint32_t aid = ATTRIB_ID(cs, attrib, idif);
|
||||
int ret = USB_RET_STALL;
|
||||
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0300):
|
||||
data[0] = s->f.mute;
|
||||
ret = 1;
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_CUR, 0x0300):
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
//uint16_t vol = (s->f.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
|
||||
uint16_t vol = (s->f.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
|
||||
data[0] = (uint8_t)(vol & 0xFF);
|
||||
|
@ -336,7 +339,8 @@ static int usb_audio_get_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_MIN, 0x0300):
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
data[0] = 0x01;
|
||||
data[1] = 0x80;
|
||||
//data[0] = 0x00;
|
||||
|
@ -345,7 +349,8 @@ static int usb_audio_get_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_MAX, 0x0300):
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x08;
|
||||
//data[0] = 0x00;
|
||||
|
@ -354,7 +359,8 @@ static int usb_audio_get_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
}
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_GET_RES, 0x0300):
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
data[0] = 0x88;
|
||||
data[1] = 0x00;
|
||||
//data[0] = 0x00;
|
||||
|
@ -377,24 +383,28 @@ static int usb_audio_set_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
int ret = USB_RET_STALL;
|
||||
bool set_vol = false;
|
||||
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_MUTE_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0300):
|
||||
s->f.mute = data[0] & 1;
|
||||
set_vol = true;
|
||||
ret = 0;
|
||||
break;
|
||||
case ATTRIB_ID(AUDIO_VOLUME_CONTROL, AUDIO_REQUEST_SET_CUR, 0x0300):
|
||||
if (cn < 2) {
|
||||
if (cn < 2)
|
||||
{
|
||||
uint16_t vol = data[0] + (data[1] << 8);
|
||||
|
||||
//qemu usb audiocard formula, singstar has a bit different range
|
||||
vol -= 0x8000;
|
||||
vol = (vol * 255 + 0x4400) / 0x8800;
|
||||
if (vol > 255) {
|
||||
if (vol > 255)
|
||||
{
|
||||
vol = 255;
|
||||
}
|
||||
|
||||
if (s->f.vol[cn] != vol) {
|
||||
if (s->f.vol[cn] != vol)
|
||||
{
|
||||
s->f.vol[cn] = (uint8_t)vol;
|
||||
set_vol = true;
|
||||
}
|
||||
|
@ -403,7 +413,8 @@ static int usb_audio_set_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
break;
|
||||
}
|
||||
|
||||
if (set_vol) {
|
||||
if (set_vol)
|
||||
{
|
||||
//if (s->debug) {
|
||||
fprintf(stderr, "singstar: mute %d, lvol %3d, rvol %3d\n",
|
||||
s->f.mute, s->f.vol[0], s->f.vol[1]);
|
||||
|
@ -431,9 +442,11 @@ static int usb_audio_ep_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
fprintf(stderr, "%02X ", data[i]);
|
||||
fprintf(stderr, "\n");*/
|
||||
|
||||
switch (aid) {
|
||||
switch (aid)
|
||||
{
|
||||
case ATTRIB_ID(AUDIO_SAMPLING_FREQ_CONTROL, AUDIO_REQUEST_SET_CUR, 0x81):
|
||||
if( cn == 0xFF) {
|
||||
if (cn == 0xFF)
|
||||
{
|
||||
s->f.srate[0] = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
s->f.srate[1] = s->f.srate[0];
|
||||
|
||||
|
@ -444,7 +457,9 @@ static int usb_audio_ep_control(SINGSTARMICState *s, uint8_t attrib,
|
|||
s->audsrc[1]->SetResampling(s->f.srate[1]);
|
||||
|
||||
OSDebugOut(TEXT("singstar: set sampling to %d\n"), s->f.srate[0]);
|
||||
} else if( cn < 2) {
|
||||
}
|
||||
else if (cn < 2)
|
||||
{
|
||||
|
||||
s->f.srate[cn] = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
OSDebugOut(TEXT("singstar: set cn %d sampling to %d\n"), cn, s->f.srate[cn]);
|
||||
|
@ -472,7 +487,8 @@ static void singstar_mic_set_interface(USBDevice *dev, int intf,
|
|||
OSDebugOut(TEXT("singstar: intf:%d alt:%d -> %d\n"), intf, alt_old, alt_new);
|
||||
#if defined(_DEBUG)
|
||||
/* close previous debug audio output file */
|
||||
if (file && intf > 0 && alt_old != alt_new) {
|
||||
if (file && intf > 0 && alt_old != alt_new)
|
||||
{
|
||||
fclose(file);
|
||||
file = nullptr;
|
||||
}
|
||||
|
@ -488,11 +504,13 @@ static void singstar_mic_handle_control(USBDevice *dev, USBPacket *p, int reques
|
|||
OSDebugOut(TEXT("singstar: req %04X val: %04X idx: %04X len: %d\n"), request, value, index, length);
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch(request) {
|
||||
switch (request)
|
||||
{
|
||||
/*
|
||||
* Audio device specific request
|
||||
*/
|
||||
|
@ -502,7 +520,8 @@ static void singstar_mic_handle_control(USBDevice *dev, USBPacket *p, int reques
|
|||
case ClassInterfaceRequest | AUDIO_REQUEST_GET_RES:
|
||||
ret = usb_audio_get_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
//if (s->debug) {
|
||||
fprintf(stderr, "singstar: fail: get control\n");
|
||||
//}
|
||||
|
@ -517,7 +536,8 @@ static void singstar_mic_handle_control(USBDevice *dev, USBPacket *p, int reques
|
|||
case ClassInterfaceOutRequest | AUDIO_REQUEST_SET_RES:
|
||||
ret = usb_audio_set_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
{
|
||||
//if (s->debug) {
|
||||
fprintf(stderr, "singstar: fail: set control\n data:");
|
||||
//}
|
||||
|
@ -535,7 +555,8 @@ static void singstar_mic_handle_control(USBDevice *dev, USBPacket *p, int reques
|
|||
case ClassEndpointOutRequest | AUDIO_REQUEST_SET_RES:
|
||||
ret = usb_audio_ep_control(s, request & 0xff, value, index,
|
||||
length, data);
|
||||
if (ret < 0) goto fail;
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
|
@ -557,11 +578,13 @@ static void singstar_mic_handle_data(USBDevice *dev, USBPacket *p)
|
|||
int ret = 0;
|
||||
uint8_t devep = p->ep->nr;
|
||||
|
||||
switch(p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_IN:
|
||||
//fprintf(stderr, "token in ep: %d len: %zd\n", devep, p->iov.size);
|
||||
//OSDebugOut(TEXT("token in ep: %d len: %zd\n"), devep, p->iov.size);
|
||||
if (devep == 1) {
|
||||
if (devep == 1)
|
||||
{
|
||||
|
||||
//TODO
|
||||
int outChns = s->f.intf == 1 ? 1 : 2;
|
||||
|
@ -605,7 +628,8 @@ static void singstar_mic_handle_data(USBDevice *dev, USBPacket *p)
|
|||
|
||||
//TODO well, it is 16bit interleaved, right?
|
||||
//Merge with MIC_MODE_SHARED case?
|
||||
switch(s->f.mode) {
|
||||
switch (s->f.mode)
|
||||
{
|
||||
case MIC_MODE_SINGLE:
|
||||
{
|
||||
int k = s->audsrc[0] ? 0 : 1;
|
||||
|
@ -709,7 +733,8 @@ static void singstar_mic_handle_destroy(USBDevice *dev)
|
|||
fclose(file);
|
||||
file = NULL;
|
||||
|
||||
if (!s) return;
|
||||
if (!s)
|
||||
return;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (s->audsrc[i])
|
||||
|
@ -730,7 +755,8 @@ static int singstar_mic_handle_open(USBDevice *dev)
|
|||
if (s)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (s->audsrc[i]) s->audsrc[i]->Start();
|
||||
if (s->audsrc[i])
|
||||
s->audsrc[i]->Start();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -741,7 +767,8 @@ static void singstar_mic_handle_close(USBDevice *dev)
|
|||
if (s)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (s->audsrc[i]) s->audsrc[i]->Stop();
|
||||
if (s->audsrc[i])
|
||||
s->audsrc[i]->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -842,7 +869,8 @@ int SingstarDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
switch (mode)
|
||||
{
|
||||
case FREEZE_LOAD:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
s->f = *(SINGSTARMICState::freeze*)data;
|
||||
if (s->audsrc[0])
|
||||
s->audsrc[0]->SetResampling(s->f.srate[0]);
|
||||
|
@ -850,7 +878,8 @@ int SingstarDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
s->audsrc[1]->SetResampling(s->f.srate[1]);
|
||||
return sizeof(SINGSTARMICState::freeze);
|
||||
case FREEZE_SAVE:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
*(SINGSTARMICState::freeze*)data = s->f;
|
||||
return sizeof(SINGSTARMICState::freeze);
|
||||
case FREEZE_SIZE:
|
||||
|
@ -861,4 +890,4 @@ int SingstarDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace usb_mic
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
|
||||
struct USBDevice;
|
||||
|
||||
namespace usb_mic {
|
||||
namespace usb_mic
|
||||
{
|
||||
class SingstarDevice
|
||||
{
|
||||
public:
|
||||
|
@ -65,5 +66,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace usb_mic
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
#include "../configuration.h"
|
||||
#include "../gtk.h"
|
||||
|
||||
namespace usb_msd {
|
||||
namespace usb_msd
|
||||
{
|
||||
|
||||
static void entryChanged(GtkWidget* widget, gpointer data)
|
||||
{
|
||||
|
@ -118,4 +119,4 @@ int MsdDevice::Configure(int port, const std::string& api, void *data)
|
|||
return RESULT_CANCELED;
|
||||
}
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_msd
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
#include "../Win32/Config.h"
|
||||
#include "../Win32/resource.h"
|
||||
|
||||
namespace usb_msd {
|
||||
namespace usb_msd
|
||||
{
|
||||
|
||||
static OPENFILENAMEW ofn;
|
||||
BOOL CALLBACK MsdDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
BOOL CALLBACK MsdDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int port;
|
||||
static wchar_t buff[4096] = {0};
|
||||
|
||||
switch (uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
@ -42,8 +45,10 @@ BOOL CALLBACK MsdDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|||
break;
|
||||
case WM_COMMAND:
|
||||
|
||||
if (HIWORD(wParam) == BN_CLICKED) {
|
||||
switch (LOWORD(wParam)) {
|
||||
if (HIWORD(wParam) == BN_CLICKED)
|
||||
{
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_BUTTON1:
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
|
@ -58,7 +63,8 @@ BOOL CALLBACK MsdDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|||
ofn.lpstrInitialDir = NULL;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
|
||||
|
||||
if (GetOpenFileName(&ofn)) {
|
||||
if (GetOpenFileName(&ofn))
|
||||
{
|
||||
SetWindowText(GetDlgItem(hW, IDC_EDIT1), ofn.lpstrFile);
|
||||
}
|
||||
break;
|
||||
|
@ -91,4 +97,4 @@ int MsdDevice::Configure(int port, const std::string& api, void *data)
|
|||
(DLGPROC)MsdDlgProc, port);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace usb_msd
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#define le32_to_cpu(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
|
||||
namespace usb_msd {
|
||||
namespace usb_msd
|
||||
{
|
||||
|
||||
struct usb_msd_cbw {
|
||||
struct usb_msd_cbw
|
||||
{
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t data_len;
|
||||
|
@ -29,7 +31,8 @@ struct usb_msd_cbw {
|
|||
uint8_t cmd[16];
|
||||
};
|
||||
|
||||
struct usb_msd_csw {
|
||||
struct usb_msd_csw
|
||||
{
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t residue;
|
||||
|
@ -44,23 +47,27 @@ struct usb_msd_csw {
|
|||
#define MassStorageReset 0xff
|
||||
#define GetMaxLun 0xfe
|
||||
|
||||
enum USBMSDMode : int8_t {
|
||||
enum USBMSDMode : int8_t
|
||||
{
|
||||
USB_MSDM_CBW, /* Command Block. */
|
||||
USB_MSDM_DATAOUT, /* Tranfer data to device. */
|
||||
USB_MSDM_DATAIN, /* Transfer data from device. */
|
||||
USB_MSDM_CSW /* Command Status. */
|
||||
};
|
||||
|
||||
typedef struct ReqState {
|
||||
typedef struct ReqState
|
||||
{
|
||||
uint32_t tag;
|
||||
//
|
||||
bool valid;
|
||||
} ReqState;
|
||||
|
||||
typedef struct MSDState {
|
||||
typedef struct MSDState
|
||||
{
|
||||
USBDevice dev;
|
||||
|
||||
struct freeze {
|
||||
struct freeze
|
||||
{
|
||||
struct usb_msd_csw csw;
|
||||
enum USBMSDMode mode;
|
||||
uint32_t data_len;
|
||||
|
@ -155,7 +162,8 @@ static const uint8_t qemu_msd_config_descriptor[] = {
|
|||
0x00 /* u8 ep_bInterval; */
|
||||
};
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
|
@ -356,7 +364,8 @@ static const USBDescStrings desc_strings = {
|
|||
#define COMMAND_FAILED 0x01
|
||||
#define PHASE_ERROR 0x02
|
||||
|
||||
typedef struct SCSISense {
|
||||
typedef struct SCSISense
|
||||
{
|
||||
uint8_t key;
|
||||
uint8_t asc;
|
||||
uint8_t ascq;
|
||||
|
@ -370,42 +379,33 @@ typedef struct SCSISense {
|
|||
|
||||
/* No sense data available */
|
||||
const struct SCSISense sense_code_NO_SENSE = {
|
||||
NO_SENSE , 0x00 , 0x00
|
||||
};
|
||||
NO_SENSE, 0x00, 0x00};
|
||||
|
||||
/* LUN not ready, Manual intervention required */
|
||||
const struct SCSISense sense_code_LUN_NOT_READY = {
|
||||
NOT_READY, 0x04, 0x03
|
||||
};
|
||||
NOT_READY, 0x04, 0x03};
|
||||
|
||||
/* LUN not ready, Medium not present */
|
||||
const struct SCSISense sense_code_NO_MEDIUM = {
|
||||
NOT_READY, 0x3a, 0x00
|
||||
};
|
||||
NOT_READY, 0x3a, 0x00};
|
||||
|
||||
const struct SCSISense sense_code_UNKNOWN_ERROR = {
|
||||
NOT_READY , 0xFF , 0xFF
|
||||
};
|
||||
NOT_READY, 0xFF, 0xFF};
|
||||
|
||||
const struct SCSISense sense_code_NO_SEEK_COMPLETE = {
|
||||
MEDIUM_ERROR, 0x02, 0x00
|
||||
};
|
||||
MEDIUM_ERROR, 0x02, 0x00};
|
||||
|
||||
const struct SCSISense sense_code_WRITE_FAULT = {
|
||||
MEDIUM_ERROR, 0x03, 0x00
|
||||
};
|
||||
MEDIUM_ERROR, 0x03, 0x00};
|
||||
|
||||
const struct SCSISense sense_code_UNRECOVERED_READ_ERROR = {
|
||||
MEDIUM_ERROR, 0x11, 0x00
|
||||
};
|
||||
MEDIUM_ERROR, 0x11, 0x00};
|
||||
|
||||
const struct SCSISense sense_code_INVALID_OPCODE = {
|
||||
ILLEGAL_REQUEST, 0x20, 0x00
|
||||
};
|
||||
ILLEGAL_REQUEST, 0x20, 0x00};
|
||||
|
||||
const struct SCSISense sense_code_OUT_OF_RANGE = {
|
||||
ILLEGAL_REQUEST, 0x21, 0x00
|
||||
};
|
||||
ILLEGAL_REQUEST, 0x21, 0x00};
|
||||
|
||||
/* Illegal request, Invalid Transfer Tag */
|
||||
//const struct SCSISense sense_code_INVALID_TAG = {
|
||||
|
@ -431,7 +431,6 @@ static int64_t get_file_size(FILE *file)
|
|||
#else
|
||||
#error Unknown platform
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void usb_msd_handle_reset(USBDevice* dev)
|
||||
|
@ -444,14 +443,10 @@ static void usb_msd_handle_reset(USBDevice *dev)
|
|||
|
||||
#ifndef bswap32
|
||||
#define bswap32(x) ( \
|
||||
(((x)>>24)&0xff)\
|
||||
|\
|
||||
(((x)>>8)&0xff00)\
|
||||
|\
|
||||
(((x)<<8)&0xff0000)\
|
||||
|\
|
||||
(((x)<<24)&0xff000000)\
|
||||
)
|
||||
(((x) >> 24) & 0xff) | \
|
||||
(((x) >> 8) & 0xff00) | \
|
||||
(((x) << 8) & 0xff0000) | \
|
||||
(((x) << 24) & 0xff000000))
|
||||
|
||||
#define bswap16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
|
||||
#endif
|
||||
|
@ -529,28 +524,38 @@ static void usb_msd_command_complete(MSDState *req, uint32_t status)
|
|||
s->f.csw.residue = cpu_to_le32(s->f.data_len);
|
||||
s->f.csw.status = status != 0;
|
||||
|
||||
if (s->packet) {
|
||||
if (s->f.data_len == 0 && s->f.mode == USB_MSDM_DATAOUT) {
|
||||
if (s->packet)
|
||||
{
|
||||
if (s->f.data_len == 0 && s->f.mode == USB_MSDM_DATAOUT)
|
||||
{
|
||||
/* A deferred packet with no write data remaining must be
|
||||
the status read packet. */
|
||||
usb_msd_send_status(s, p);
|
||||
s->f.mode = USB_MSDM_CBW;
|
||||
} else if (s->f.mode == USB_MSDM_CSW) {
|
||||
}
|
||||
else if (s->f.mode == USB_MSDM_CSW)
|
||||
{
|
||||
usb_msd_send_status(s, p);
|
||||
s->f.mode = USB_MSDM_CBW;
|
||||
} else {
|
||||
if (s->f.data_len) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->f.data_len)
|
||||
{
|
||||
int len = (p->iov.size - p->actual_length);
|
||||
usb_packet_skip(p, len);
|
||||
s->f.data_len -= len;
|
||||
}
|
||||
if (s->f.data_len == 0) {
|
||||
if (s->f.data_len == 0)
|
||||
{
|
||||
s->f.mode = USB_MSDM_CSW;
|
||||
}
|
||||
}
|
||||
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
|
||||
usb_msd_packet_complete(s);
|
||||
} else if (s->f.data_len == 0) {
|
||||
}
|
||||
else if (s->f.data_len == 0)
|
||||
{
|
||||
s->f.mode = USB_MSDM_CSW;
|
||||
}
|
||||
s->f.req.valid = false;
|
||||
|
@ -569,7 +574,8 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
|||
//TODO No async reader/writer so do it right here
|
||||
if (s->f.tag == s->f.file_op_tag)
|
||||
{
|
||||
switch (s->f.mode) {
|
||||
switch (s->f.mode)
|
||||
{
|
||||
case USB_MSDM_DATAOUT:
|
||||
usb_packet_copy(p, s->f.buf, len);
|
||||
if (len > 0 && (file_ret = fwrite(s->f.buf, 1, len, s->file)) < len)
|
||||
|
@ -581,7 +587,8 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p)
|
|||
}
|
||||
break;
|
||||
case USB_MSDM_DATAIN:
|
||||
if((file_ret = fread(s->f.buf, 1, p->iov.size, s->file)) < p->iov.size) {
|
||||
if ((file_ret = fread(s->f.buf, 1, p->iov.size, s->file)) < p->iov.size)
|
||||
{
|
||||
s->f.result = COMMAND_FAILED;
|
||||
set_sense(s, SENSE_CODE(UNRECOVERED_READ_ERROR));
|
||||
goto fail;
|
||||
|
@ -667,7 +674,8 @@ static void send_command(void *opaque, struct usb_msd_cbw *cbw)
|
|||
*blk_len = LBA_BLOCK_SIZE; //descriptor is currently max 64 bytes for bulk though
|
||||
|
||||
lbas = fsize / LBA_BLOCK_SIZE;
|
||||
if (lbas > 0xFFFFFFFF) {
|
||||
if (lbas > 0xFFFFFFFF)
|
||||
{
|
||||
DPRINTF("Maximum LBA is out of range!\n");
|
||||
s->f.result = COMMAND_FAILED;
|
||||
set_sense(s, SENSE_CODE(OUT_OF_RANGE));
|
||||
|
@ -698,7 +706,8 @@ static void send_command(void *opaque, struct usb_msd_cbw *cbw)
|
|||
if (xfer_len == 0) // nothing to do
|
||||
break;
|
||||
|
||||
if(fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET)) {
|
||||
if (fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET))
|
||||
{
|
||||
s->f.result = COMMAND_FAILED;
|
||||
//TODO use errno
|
||||
int64_t fsize = get_file_size(s->file);
|
||||
|
@ -732,7 +741,8 @@ static void send_command(void *opaque, struct usb_msd_cbw *cbw)
|
|||
|
||||
if (xfer_len == 0) //nothing to do
|
||||
break;
|
||||
if(fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET)) {
|
||||
if (fseeko64(s->file, lba * LBA_BLOCK_SIZE, SEEK_SET))
|
||||
{
|
||||
s->f.result = COMMAND_FAILED;
|
||||
//TODO use errno
|
||||
int64_t fsize = get_file_size(s->file);
|
||||
|
@ -761,13 +771,15 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, in
|
|||
int ret = 0;
|
||||
|
||||
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
if (ret >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OSDebugOut(TEXT("request %04x %04x %04x\n"), request, value, index);
|
||||
|
||||
switch (request) {
|
||||
switch (request)
|
||||
{
|
||||
/* Class specific requests. */
|
||||
case ClassInterfaceOutRequest | MassStorageReset:
|
||||
/* Reset state ready for the next CBW. */
|
||||
|
@ -792,7 +804,8 @@ static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
|
|||
assert(s->packet == p);
|
||||
s->packet = NULL;
|
||||
|
||||
if (s->f.req.valid) {
|
||||
if (s->f.req.valid)
|
||||
{
|
||||
//scsi_req_cancel(s->req);
|
||||
}
|
||||
}
|
||||
|
@ -809,35 +822,45 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
// 3.) USB_MSDM_CSW: return USB_RET_ASYNC status if command is still in progress
|
||||
// or complete and set mode to USB_MSDM_CBW.
|
||||
|
||||
switch (p->pid) {
|
||||
switch (p->pid)
|
||||
{
|
||||
case USB_TOKEN_OUT:
|
||||
if (devep != 2)
|
||||
goto fail;
|
||||
|
||||
switch (s->f.mode) {
|
||||
switch (s->f.mode)
|
||||
{
|
||||
case USB_MSDM_CBW:
|
||||
if (p->iov.size != 31) {
|
||||
if (p->iov.size != 31)
|
||||
{
|
||||
fprintf(stderr, "usb-msd: Bad CBW size\n");
|
||||
goto fail;
|
||||
}
|
||||
usb_packet_copy(p, &cbw, 31);
|
||||
if (le32_to_cpu(cbw.sig) != 0x43425355) {
|
||||
if (le32_to_cpu(cbw.sig) != 0x43425355)
|
||||
{
|
||||
fprintf(stderr, "usb-msd: Bad signature %08x\n",
|
||||
le32_to_cpu(cbw.sig));
|
||||
goto fail;
|
||||
}
|
||||
DPRINTF("Command on LUN %d\n", cbw.lun);
|
||||
if (cbw.lun != 0) {
|
||||
if (cbw.lun != 0)
|
||||
{
|
||||
fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
|
||||
goto fail;
|
||||
}
|
||||
s->f.tag = le32_to_cpu(cbw.tag);
|
||||
s->f.data_len = le32_to_cpu(cbw.data_len);
|
||||
if (s->f.data_len == 0) {
|
||||
if (s->f.data_len == 0)
|
||||
{
|
||||
s->f.mode = USB_MSDM_CSW;
|
||||
} else if (cbw.flags & 0x80) {
|
||||
}
|
||||
else if (cbw.flags & 0x80)
|
||||
{
|
||||
s->f.mode = USB_MSDM_DATAIN;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
s->f.mode = USB_MSDM_DATAOUT;
|
||||
}
|
||||
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
|
||||
|
@ -853,7 +876,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
DPRINTF("Data out: write %d bytes of %d remaining\n", p->iov.size, s->f.data_len);
|
||||
//TODO check if CBW still falls into here on write error a.k.a s->f.mode is set wrong
|
||||
DPRINTF("Data out %zd/%d\n", p->iov.size, s->f.data_len);
|
||||
if (p->iov.size > s->f.data_len) {
|
||||
if (p->iov.size > s->f.data_len)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -864,17 +888,21 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
{
|
||||
usb_msd_copy_data(s, p);
|
||||
}
|
||||
if (le32_to_cpu(s->f.csw.residue)) {
|
||||
if (le32_to_cpu(s->f.csw.residue))
|
||||
{
|
||||
int len = p->iov.size - p->actual_length;
|
||||
if (len) {
|
||||
if (len)
|
||||
{
|
||||
usb_packet_skip(p, len);
|
||||
s->f.data_len -= len;
|
||||
if (s->f.data_len == 0) {
|
||||
if (s->f.data_len == 0)
|
||||
{
|
||||
s->f.mode = USB_MSDM_CSW;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((size_t)p->actual_length < p->iov.size) {
|
||||
if ((size_t)p->actual_length < p->iov.size)
|
||||
{
|
||||
DPRINTF("Deferring packet %p [wait data-out]\n", p);
|
||||
s->packet = p;
|
||||
p->status = USB_RET_ASYNC;
|
||||
|
@ -894,9 +922,11 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
if (devep != 1)
|
||||
goto fail;
|
||||
|
||||
switch (s->f.mode) {
|
||||
switch (s->f.mode)
|
||||
{
|
||||
case USB_MSDM_DATAOUT:
|
||||
if (s->f.data_len != 0 || p->iov.size < 13) {
|
||||
if (s->f.data_len != 0 || p->iov.size < 13)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
/* Waiting for SCSI write to complete. */
|
||||
|
@ -908,16 +938,20 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
send_csw:
|
||||
DPRINTF("Command status %d tag 0x%x, len %d\n",
|
||||
s->f.result, s->f.tag, p->iov.size);
|
||||
if (p->iov.size < 13) {
|
||||
if (p->iov.size < 13)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (false && s->f.req.valid) { // If reading/writing using something asynchronous
|
||||
if (false && s->f.req.valid)
|
||||
{ // If reading/writing using something asynchronous
|
||||
/* still in flight */
|
||||
DPRINTF("Deferring packet %p [wait status]\n", p);
|
||||
s->packet = p;
|
||||
p->status = USB_RET_ASYNC;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO primarily for setting csw.sig with correct value
|
||||
usb_msd_command_complete(s, s->f.result);
|
||||
|
||||
|
@ -941,18 +975,22 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
{
|
||||
usb_msd_copy_data(s, p);
|
||||
}
|
||||
if (le32_to_cpu(s->f.csw.residue)) {
|
||||
if (le32_to_cpu(s->f.csw.residue))
|
||||
{
|
||||
int len = p->iov.size - p->actual_length;
|
||||
if (len) {
|
||||
if (len)
|
||||
{
|
||||
usb_packet_skip(p, len);
|
||||
s->f.data_len -= len;
|
||||
if (s->f.data_len == 0) {
|
||||
if (s->f.data_len == 0)
|
||||
{
|
||||
s->f.mode = USB_MSDM_CSW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((size_t)p->actual_length < p->iov.size) {
|
||||
if ((size_t)p->actual_length < p->iov.size)
|
||||
{
|
||||
DPRINTF("Deferring packet %p [wait data-in]\n", p);
|
||||
s->packet = p;
|
||||
p->status = USB_RET_ASYNC;
|
||||
|
@ -1003,7 +1041,8 @@ USBDevice *MsdDevice::CreateDevice(int port)
|
|||
}
|
||||
|
||||
s->file = wfopen(var.c_str(), TEXT("r+b"));
|
||||
if (!s->file) {
|
||||
if (!s->file)
|
||||
{
|
||||
SysMessage(TEXT("usb-msd: Could not open image file '%s'\n"), var.c_str());
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1052,7 +1091,8 @@ int MsdDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
switch (mode)
|
||||
{
|
||||
case FREEZE_LOAD:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
//if (s->f.req) free (s->f.req);
|
||||
|
||||
tmp = (MSDState::freeze*)data;
|
||||
|
@ -1067,7 +1107,8 @@ int MsdDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
return sizeof(MSDState::freeze); // + sizeof(ReqState);
|
||||
|
||||
case FREEZE_SAVE:
|
||||
if (!s) return -1;
|
||||
if (!s)
|
||||
return -1;
|
||||
tmp = (MSDState::freeze*)data;
|
||||
*tmp = s->f;
|
||||
return sizeof(MSDState::freeze);
|
||||
|
@ -1081,4 +1122,4 @@ int MsdDevice::Freeze(int mode, USBDevice *dev, void *data)
|
|||
}
|
||||
|
||||
#undef DPRINTF
|
||||
} //namespace
|
||||
} // namespace usb_msd
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#define USBMSD_H
|
||||
#include "../deviceproxy.h"
|
||||
|
||||
namespace usb_msd {
|
||||
namespace usb_msd
|
||||
{
|
||||
|
||||
static const char* APINAME = "cstdio";
|
||||
|
||||
|
@ -43,5 +44,5 @@ public:
|
|||
static int Freeze(int mode, USBDevice* dev, void* data);
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace usb_msd
|
||||
#endif
|
||||
|
|
|
@ -24,20 +24,23 @@
|
|||
//
|
||||
|
||||
#define PREPARE_FIRST_COPY() \
|
||||
do { \
|
||||
if (src_len >= (CHAR_BIT - dst_offset_modulo)) { \
|
||||
do \
|
||||
{ \
|
||||
if (src_len >= (CHAR_BIT - dst_offset_modulo)) \
|
||||
{ \
|
||||
*dst &= reverse_mask[dst_offset_modulo]; \
|
||||
src_len -= CHAR_BIT - dst_offset_modulo; \
|
||||
} else { \
|
||||
*dst &= reverse_mask[dst_offset_modulo] \
|
||||
| reverse_mask_xor[dst_offset_modulo + src_len + 1];\
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
*dst &= reverse_mask[dst_offset_modulo] | reverse_mask_xor[dst_offset_modulo + src_len + 1]; \
|
||||
c &= reverse_mask[dst_offset_modulo + src_len]; \
|
||||
src_len = 0; \
|
||||
} } while (0)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
//But copies bits in reverse?
|
||||
void
|
||||
bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
||||
void bitarray_copy(const uint8_t* src_org, int src_offset, int src_len,
|
||||
uint8_t* dst_org, int dst_offset)
|
||||
{
|
||||
static const unsigned char mask[] =
|
||||
|
@ -47,7 +50,8 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
static const unsigned char reverse_mask_xor[] =
|
||||
{0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00};
|
||||
|
||||
if (src_len) {
|
||||
if (src_len)
|
||||
{
|
||||
const unsigned char* src;
|
||||
unsigned char* dst;
|
||||
int src_offset_modulo,
|
||||
|
@ -59,10 +63,12 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
src_offset_modulo = src_offset % CHAR_BIT;
|
||||
dst_offset_modulo = dst_offset % CHAR_BIT;
|
||||
|
||||
if (src_offset_modulo == dst_offset_modulo) {
|
||||
if (src_offset_modulo == dst_offset_modulo)
|
||||
{
|
||||
int byte_len;
|
||||
int src_len_modulo;
|
||||
if (src_offset_modulo) {
|
||||
if (src_offset_modulo)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
c = reverse_mask_xor[dst_offset_modulo] & *src++;
|
||||
|
@ -74,16 +80,20 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
byte_len = src_len / CHAR_BIT;
|
||||
src_len_modulo = src_len % CHAR_BIT;
|
||||
|
||||
if (byte_len) {
|
||||
if (byte_len)
|
||||
{
|
||||
memcpy(dst, src, byte_len);
|
||||
src += byte_len;
|
||||
dst += byte_len;
|
||||
}
|
||||
if (src_len_modulo) {
|
||||
if (src_len_modulo)
|
||||
{
|
||||
*dst &= reverse_mask_xor[src_len_modulo];
|
||||
*dst |= reverse_mask[src_len_modulo] & *src;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int bit_diff_ls,
|
||||
bit_diff_rs;
|
||||
int byte_len;
|
||||
|
@ -92,14 +102,17 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
/*
|
||||
* Begin: Line things up on destination.
|
||||
*/
|
||||
if (src_offset_modulo > dst_offset_modulo) {
|
||||
if (src_offset_modulo > dst_offset_modulo)
|
||||
{
|
||||
bit_diff_ls = src_offset_modulo - dst_offset_modulo;
|
||||
bit_diff_rs = CHAR_BIT - bit_diff_ls;
|
||||
|
||||
c = *src++ << bit_diff_ls;
|
||||
c |= *src >> bit_diff_rs;
|
||||
c &= reverse_mask_xor[dst_offset_modulo];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
bit_diff_rs = dst_offset_modulo - src_offset_modulo;
|
||||
bit_diff_ls = CHAR_BIT - bit_diff_rs;
|
||||
|
||||
|
@ -114,7 +127,8 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
*/
|
||||
byte_len = src_len / CHAR_BIT;
|
||||
|
||||
while (--byte_len >= 0) {
|
||||
while (--byte_len >= 0)
|
||||
{
|
||||
c = *src++ << bit_diff_ls;
|
||||
c |= *src >> bit_diff_rs;
|
||||
*dst++ = c;
|
||||
|
@ -124,7 +138,8 @@ bitarray_copy(const uint8_t*src_org, int src_offset, int src_len,
|
|||
* End: copy the remaing bits;
|
||||
*/
|
||||
src_len_modulo = src_len % CHAR_BIT;
|
||||
if (src_len_modulo) {
|
||||
if (src_len_modulo)
|
||||
{
|
||||
c = *src++ << bit_diff_ls;
|
||||
c |= *src >> bit_diff_rs;
|
||||
c &= reverse_mask[src_len_modulo];
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
|
||||
#include "usb-pad-dx.h"
|
||||
|
||||
namespace usb_pad { namespace dx {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace dx
|
||||
{
|
||||
|
||||
static int32_t useRamp = 0;
|
||||
|
||||
|
@ -133,7 +136,8 @@ void SetControlLabel(int cid, const InputMapped& im)
|
|||
//config only
|
||||
void ListenUpdate()
|
||||
{
|
||||
for (size_t i=0; i<g_pJoysticks.size(); i++) {
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++)
|
||||
{
|
||||
jso[i] = g_pJoysticks[i]->GetDeviceState();
|
||||
}
|
||||
PollDevices();
|
||||
|
@ -143,7 +147,8 @@ void ListenUpdate()
|
|||
void ListenAxis()
|
||||
{
|
||||
PollDevices();
|
||||
for (size_t i=0; i<g_pJoysticks.size(); i++) {
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++)
|
||||
{
|
||||
if (g_pJoysticks[i]->GetControlType() != CT_JOYSTICK)
|
||||
continue;
|
||||
jso[i] = g_pJoysticks[i]->GetDeviceState();
|
||||
|
@ -169,16 +174,16 @@ bool AxisDown(size_t ijoy, InputMapped& im)
|
|||
return false;
|
||||
|
||||
DIJOYSTATE2 js = g_pJoysticks[ijoy]->GetDeviceState();
|
||||
std::cerr << __func__ << ": joystick[" << ijoy << "]: " <<
|
||||
"\tlX " << js.lX << "\n" <<
|
||||
"\tlY " << js.lY << "\n" <<
|
||||
"\tlZ " << js.lZ << "\n" <<
|
||||
"\tlRx " << js.lRx << "\n" <<
|
||||
"\tlRy " << js.lRy << "\n" <<
|
||||
"\tlRz " << js.lRz << "\n" <<
|
||||
"\trglSlider0 " << js.rglSlider[0] << "\n" <<
|
||||
"\trglSlider1 " << js.rglSlider[1] << "\n" <<
|
||||
std::endl;
|
||||
std::cerr << __func__ << ": joystick[" << ijoy << "]: "
|
||||
<< "\tlX " << js.lX << "\n"
|
||||
<< "\tlY " << js.lY << "\n"
|
||||
<< "\tlZ " << js.lZ << "\n"
|
||||
<< "\tlRx " << js.lRx << "\n"
|
||||
<< "\tlRy " << js.lRy << "\n"
|
||||
<< "\tlRz " << js.lRz << "\n"
|
||||
<< "\trglSlider0 " << js.rglSlider[0] << "\n"
|
||||
<< "\trglSlider1 " << js.rglSlider[1] << "\n"
|
||||
<< std::endl;
|
||||
|
||||
LONG detectrange = 2000;
|
||||
for (int32_t axisid = 0; axisid < DINPUT_AXES_COUNT; axisid++)
|
||||
|
@ -190,13 +195,15 @@ bool AxisDown(size_t ijoy, InputMapped& im)
|
|||
|
||||
// TODO mind the POV axes, one axis for all directions?
|
||||
diff = GetAxisValueFromOffset(axisid, js) - GetAxisValueFromOffset(axisid, jso[ijoy]);
|
||||
if (diff > detectrange) {
|
||||
if (diff > detectrange)
|
||||
{
|
||||
im.HALF = GetAxisValueFromOffset(axisid, jsi[ijoy]);
|
||||
im.INVERTED = true;
|
||||
im.type = MappingType::MT_AXIS;
|
||||
return true;
|
||||
}
|
||||
if (diff < -detectrange) {
|
||||
if (diff < -detectrange)
|
||||
{
|
||||
im.HALF = GetAxisValueFromOffset(axisid, jsi[ijoy]);
|
||||
im.INVERTED = false;
|
||||
im.type = MappingType::MT_AXIS;
|
||||
|
@ -219,7 +226,8 @@ bool KeyDown(size_t ijoy, InputMapped& im)
|
|||
|
||||
int buttons = 0;
|
||||
|
||||
switch (joy->GetControlType()) {
|
||||
switch (joy->GetControlType())
|
||||
{
|
||||
case CT_JOYSTICK:
|
||||
buttons = ARRAY_SIZE(DIJOYSTATE2::rgbButtons) + 16 /* POV */;
|
||||
break;
|
||||
|
@ -233,8 +241,10 @@ bool KeyDown(size_t ijoy, InputMapped& im)
|
|||
break;
|
||||
}
|
||||
|
||||
for (int b = 0; b < buttons; b++) {
|
||||
if (joy->GetButton(b)) {
|
||||
for (int b = 0; b < buttons; b++)
|
||||
{
|
||||
if (joy->GetButton(b))
|
||||
{
|
||||
im.mapped = b;
|
||||
im.type = MT_BUTTON;
|
||||
return true;
|
||||
|
@ -247,7 +257,8 @@ bool KeyDown(size_t ijoy, InputMapped& im)
|
|||
//search all axis/buttons (config only)
|
||||
bool FindControl(LONG port, ControlID cid, InputMapped& im)
|
||||
{
|
||||
if (listening==true) {
|
||||
if (listening == true)
|
||||
{
|
||||
if (listenend > GetTickCount())
|
||||
{
|
||||
if (listennext < GetTickCount())
|
||||
|
@ -255,23 +266,29 @@ bool FindControl(LONG port, ControlID cid, InputMapped& im)
|
|||
listennext = listeninterval + GetTickCount();
|
||||
ListenUpdate();
|
||||
|
||||
for (size_t i = 0; i<g_pJoysticks.size(); i++) {
|
||||
if (AxisDown(i, im)) {
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++)
|
||||
{
|
||||
if (AxisDown(i, im))
|
||||
{
|
||||
listening = false;
|
||||
if (CID_STEERING == cid) {
|
||||
if (CID_STEERING == cid)
|
||||
{
|
||||
CreateFFB(port, g_pJoysticks[im.index]->GetDevice(), im.mapped);
|
||||
}
|
||||
AddInputMap(port, cid, im);
|
||||
return true;
|
||||
}
|
||||
else if (KeyDown(i, im)) {
|
||||
else if (KeyDown(i, im))
|
||||
{
|
||||
listening = false;
|
||||
AddInputMap(port, cid, im);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
GetInputMap(port, cid, im);
|
||||
SetControlLabel(cid, im);
|
||||
listening = false;
|
||||
|
@ -285,7 +302,8 @@ void ApplyFilter(int port)
|
|||
{
|
||||
filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0);
|
||||
|
||||
if(filtercontrol==-1)return;
|
||||
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;
|
||||
|
@ -308,7 +326,8 @@ void ApplyFilter(int port)
|
|||
void LoadFilter(int port)
|
||||
{
|
||||
filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0);
|
||||
if(filtercontrol==-1)return;
|
||||
if (filtercontrol == -1)
|
||||
return;
|
||||
//InputMapped im = {};
|
||||
//GetInputMap(port, (ControlID)filtercontrol, im);
|
||||
//slider
|
||||
|
@ -384,7 +403,9 @@ void ControlTest(int port) //thread: waits for window
|
|||
MapWindowPoints(GetDlgItem(hWnd, IDC_PICTURE), hWnd, (POINT*)&rect, 2);
|
||||
InvalidateRect(hWnd, &rect, TRUE);
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
TESTV = 0;
|
||||
}
|
||||
|
||||
|
@ -397,7 +418,8 @@ void ListenForControl(int port)
|
|||
|
||||
if (FindControl(port, CID, im))
|
||||
{
|
||||
if (CID <= CID_BRAKE) {
|
||||
if (CID <= CID_BRAKE)
|
||||
{
|
||||
LINEAR[port][CID] = im.LINEAR;
|
||||
OFFSET[port][CID] = im.OFFSET;
|
||||
DEADZONE[port][CID] = im.DEADZONE;
|
||||
|
@ -406,7 +428,8 @@ void ListenForControl(int port)
|
|||
AddInputMap(port, CID, im);
|
||||
SetControlLabel(CID, im);
|
||||
}
|
||||
else if(listening) {
|
||||
else if (listening)
|
||||
{
|
||||
swprintf_s(text, L"Listening... %u", GetListenTimeout() / 1000 + 1);
|
||||
SetWindowText(GetDlgItem(hWnd, LABELS[CID]), text);
|
||||
}
|
||||
|
@ -414,10 +437,12 @@ void ListenForControl(int port)
|
|||
|
||||
void StartListen(ControlID controlid)
|
||||
{
|
||||
if(listening)return;
|
||||
if (listening)
|
||||
return;
|
||||
|
||||
CID = controlid;
|
||||
swprintf_s(text, L"Listening...");SetWindowText(GetDlgItem(hWnd,LABELS[CID]),text);
|
||||
swprintf_s(text, L"Listening...");
|
||||
SetWindowText(GetDlgItem(hWnd, LABELS[CID]), text);
|
||||
OSDebugOut(TEXT("Begin Listen %i\n"), -1);
|
||||
ListenAxis();
|
||||
}
|
||||
|
@ -474,7 +499,8 @@ void CreateDrawing(int port, HDC hDrawingDC, int scale)
|
|||
}
|
||||
|
||||
filtercontrol = SendMessage(GetDlgItem(hWnd, IDC_COMBO1), CB_GETCURSEL, 0, 0);
|
||||
if(filtercontrol>=0){
|
||||
if (filtercontrol >= 0)
|
||||
{
|
||||
|
||||
//draw nonlinear line
|
||||
SelectObject(hDrawingDC, bluepen);
|
||||
|
@ -661,7 +687,8 @@ void OnPaint(int port)
|
|||
|
||||
int px = rect.left;
|
||||
int py = rect.top;
|
||||
if (px <= 0 || py <= 0) {
|
||||
if (px <= 0 || py <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int pwidth = rect.right - rect.left;
|
||||
|
@ -829,7 +856,8 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
hWnd = hDlg;
|
||||
SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
|
||||
InitDialog(s->port, s->dev_type);
|
||||
}break;
|
||||
}
|
||||
break;
|
||||
case WM_CTLCOLORSTATIC:
|
||||
{
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_GROUP1) || (HWND)lParam == GetDlgItem(hWnd, IDC_GROUP2) || (HWND)lParam == GetDlgItem(hWnd, IDC_GROUP3))
|
||||
|
@ -838,42 +866,32 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
}
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL1)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL1)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL1)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL1)) {
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL1) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL1))
|
||||
{
|
||||
SetTextColor((HDC)wParam, RGB(255, 0, 0));
|
||||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
}
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL2)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL2)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL2)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL2)) {
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL2) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL2))
|
||||
{
|
||||
SetTextColor((HDC)wParam, RGB(0, 192, 255));
|
||||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
}
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL3)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL3)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL3)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL3)) {
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL3) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL3))
|
||||
{
|
||||
SetTextColor((HDC)wParam, RGB(255, 165, 0));
|
||||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
}
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL4)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL4)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL4)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL4)) {
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL4) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL4))
|
||||
{
|
||||
SetTextColor((HDC)wParam, RGB(0, 140, 0));
|
||||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
}
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL5)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL5)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL5)
|
||||
|| (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL5)) {
|
||||
if ((HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL1_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL2_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL3_LBL5) || (HWND)lParam == GetDlgItem(hWnd, IDC_BZ_CTL4_LBL5))
|
||||
{
|
||||
SetTextColor((HDC)wParam, RGB(204, 204, 0));
|
||||
SetBkMode((HDC)wParam, TRANSPARENT);
|
||||
return (INT_PTR)GetStockObject(NULL_BRUSH);
|
||||
|
@ -889,11 +907,11 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
case 22:
|
||||
{
|
||||
s = (DXDlgSettings*)GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
||||
if(listening) ListenForControl(s->port);
|
||||
if (listening)
|
||||
ListenForControl(s->port);
|
||||
ControlTest(s->port);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -944,7 +962,6 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
FreeDirectInput();
|
||||
EndDialog(hWnd, TRUE);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
//break; //Fall through
|
||||
case IDCANCEL:
|
||||
|
@ -955,7 +972,6 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
FreeDirectInput();
|
||||
EndDialog(hWnd, FALSE);
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
break;
|
||||
case IDC_BUTTON1:
|
||||
|
@ -965,51 +981,223 @@ INT_PTR CALLBACK DxDialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam
|
|||
}
|
||||
break;
|
||||
|
||||
case IDC_ASS0: { StartListen(CID_STEERING); break; }
|
||||
case IDC_ASS1: { StartListen(CID_STEERING_R); break; }
|
||||
case IDC_ASS2: { StartListen(CID_THROTTLE); break; }
|
||||
case IDC_ASS3: { StartListen(CID_BRAKE); break; }
|
||||
case IDC_ASS4: { StartListen(CID_HATUP); break; }
|
||||
case IDC_ASS5: { StartListen(CID_HATDOWN); break; }
|
||||
case IDC_ASS6: { StartListen(CID_HATLEFT); break; }
|
||||
case IDC_ASS7: { StartListen(CID_HATRIGHT); break; }
|
||||
case IDC_ASS8: { StartListen(CID_SQUARE); break; }
|
||||
case IDC_ASS9: { StartListen(CID_TRIANGLE); break; }
|
||||
case IDC_ASS10: { StartListen(CID_CROSS); break; }
|
||||
case IDC_ASS11: { StartListen(CID_CIRCLE); break; }
|
||||
case IDC_ASS12: { StartListen(CID_L1); break; }
|
||||
case IDC_ASS13: { StartListen(CID_R1); break; }
|
||||
case IDC_ASS14: { StartListen(CID_L2); break; }
|
||||
case IDC_ASS15: { StartListen(CID_R2); break; }
|
||||
case IDC_ASS16: { StartListen(CID_L3); break; }
|
||||
case IDC_ASS17: { StartListen(CID_R3); break; }
|
||||
case IDC_ASS18: { StartListen(CID_SELECT); break; }
|
||||
case IDC_ASS19: { StartListen(CID_START); break; }
|
||||
case IDC_DEL0: { DeleteControl(s->port, CID_STEERING); break; }
|
||||
case IDC_DEL1: { DeleteControl(s->port, CID_STEERING_R); break; }
|
||||
case IDC_DEL2: { DeleteControl(s->port, CID_THROTTLE); break; }
|
||||
case IDC_DEL3: { DeleteControl(s->port, CID_BRAKE); break; }
|
||||
case IDC_DEL4: { DeleteControl(s->port, CID_HATUP); break; }
|
||||
case IDC_DEL5: { DeleteControl(s->port, CID_HATDOWN); break; }
|
||||
case IDC_DEL6: { DeleteControl(s->port, CID_HATLEFT); break; }
|
||||
case IDC_DEL7: { DeleteControl(s->port, CID_HATRIGHT); break; }
|
||||
case IDC_DEL8: { DeleteControl(s->port, CID_SQUARE); break; }
|
||||
case IDC_DEL9: { DeleteControl(s->port, CID_TRIANGLE); break; }
|
||||
case IDC_DEL10: { DeleteControl(s->port, CID_CROSS); break; }
|
||||
case IDC_DEL11: { DeleteControl(s->port, CID_CIRCLE); break; }
|
||||
case IDC_DEL12: { DeleteControl(s->port, CID_L1); break; }
|
||||
case IDC_DEL13: { DeleteControl(s->port, CID_R1); break; }
|
||||
case IDC_DEL14: { DeleteControl(s->port, CID_L2); break; }
|
||||
case IDC_DEL15: { DeleteControl(s->port, CID_R2); break; }
|
||||
case IDC_DEL16: { DeleteControl(s->port, CID_L3); break; }
|
||||
case IDC_DEL17: { DeleteControl(s->port, CID_R3); break; }
|
||||
case IDC_DEL18: { DeleteControl(s->port, CID_SELECT); break; }
|
||||
case IDC_DEL19: { DeleteControl(s->port, CID_START); break; }
|
||||
case IDC_ASS0:
|
||||
{
|
||||
StartListen(CID_STEERING);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS1:
|
||||
{
|
||||
StartListen(CID_STEERING_R);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS2:
|
||||
{
|
||||
StartListen(CID_THROTTLE);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS3:
|
||||
{
|
||||
StartListen(CID_BRAKE);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS4:
|
||||
{
|
||||
StartListen(CID_HATUP);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS5:
|
||||
{
|
||||
StartListen(CID_HATDOWN);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS6:
|
||||
{
|
||||
StartListen(CID_HATLEFT);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS7:
|
||||
{
|
||||
StartListen(CID_HATRIGHT);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS8:
|
||||
{
|
||||
StartListen(CID_SQUARE);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS9:
|
||||
{
|
||||
StartListen(CID_TRIANGLE);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS10:
|
||||
{
|
||||
StartListen(CID_CROSS);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS11:
|
||||
{
|
||||
StartListen(CID_CIRCLE);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS12:
|
||||
{
|
||||
StartListen(CID_L1);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS13:
|
||||
{
|
||||
StartListen(CID_R1);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS14:
|
||||
{
|
||||
StartListen(CID_L2);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS15:
|
||||
{
|
||||
StartListen(CID_R2);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS16:
|
||||
{
|
||||
StartListen(CID_L3);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS17:
|
||||
{
|
||||
StartListen(CID_R3);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS18:
|
||||
{
|
||||
StartListen(CID_SELECT);
|
||||
break;
|
||||
}
|
||||
case IDC_ASS19:
|
||||
{
|
||||
StartListen(CID_START);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL0:
|
||||
{
|
||||
DeleteControl(s->port, CID_STEERING);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL1:
|
||||
{
|
||||
DeleteControl(s->port, CID_STEERING_R);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL2:
|
||||
{
|
||||
DeleteControl(s->port, CID_THROTTLE);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL3:
|
||||
{
|
||||
DeleteControl(s->port, CID_BRAKE);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL4:
|
||||
{
|
||||
DeleteControl(s->port, CID_HATUP);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL5:
|
||||
{
|
||||
DeleteControl(s->port, CID_HATDOWN);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL6:
|
||||
{
|
||||
DeleteControl(s->port, CID_HATLEFT);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL7:
|
||||
{
|
||||
DeleteControl(s->port, CID_HATRIGHT);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL8:
|
||||
{
|
||||
DeleteControl(s->port, CID_SQUARE);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL9:
|
||||
{
|
||||
DeleteControl(s->port, CID_TRIANGLE);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL10:
|
||||
{
|
||||
DeleteControl(s->port, CID_CROSS);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL11:
|
||||
{
|
||||
DeleteControl(s->port, CID_CIRCLE);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL12:
|
||||
{
|
||||
DeleteControl(s->port, CID_L1);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL13:
|
||||
{
|
||||
DeleteControl(s->port, CID_R1);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL14:
|
||||
{
|
||||
DeleteControl(s->port, CID_L2);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL15:
|
||||
{
|
||||
DeleteControl(s->port, CID_R2);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL16:
|
||||
{
|
||||
DeleteControl(s->port, CID_L3);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL17:
|
||||
{
|
||||
DeleteControl(s->port, CID_R3);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL18:
|
||||
{
|
||||
DeleteControl(s->port, CID_SELECT);
|
||||
break;
|
||||
}
|
||||
case IDC_DEL19:
|
||||
{
|
||||
DeleteControl(s->port, CID_START);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case IDC_PICTURELINK1:{ShellExecuteA(NULL, "open", "http://www.ecsimhardware.com",NULL, NULL, SW_SHOWNORMAL);break;}
|
||||
case IDC_PICTURELINK2:{ShellExecuteA(NULL, "open", "http://www.ecsimshop.com",NULL, NULL, SW_SHOWNORMAL);break;}
|
||||
case IDC_PICTURELINK3:{ShellExecuteA(NULL, "open", "http://www.tocaedit.com",NULL, NULL, SW_SHOWNORMAL);break;}
|
||||
case IDC_PICTURELINK1:
|
||||
{
|
||||
ShellExecuteA(NULL, "open", "http://www.ecsimhardware.com", NULL, NULL, SW_SHOWNORMAL);
|
||||
break;
|
||||
}
|
||||
case IDC_PICTURELINK2:
|
||||
{
|
||||
ShellExecuteA(NULL, "open", "http://www.ecsimshop.com", NULL, NULL, SW_SHOWNORMAL);
|
||||
break;
|
||||
}
|
||||
case IDC_PICTURELINK3:
|
||||
{
|
||||
ShellExecuteA(NULL, "open", "http://www.tocaedit.com", NULL, NULL, SW_SHOWNORMAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1060,7 +1248,8 @@ void SaveDInputConfig(int port, const char *dev_type)
|
|||
ss << joy->GetGUID() << "," << im.type << "," << im.mapped;
|
||||
//SaveSetting(section, _T("ProductName"), joy->Product());
|
||||
|
||||
if (joy->GetControlType() == CT_JOYSTICK) {
|
||||
if (joy->GetControlType() == CT_JOYSTICK)
|
||||
{
|
||||
ss << "," << im.INVERTED
|
||||
<< "," << im.HALF
|
||||
<< "," << im.LINEAR
|
||||
|
@ -1110,10 +1299,12 @@ void LoadDInputConfig(int port, const char* dev_type)
|
|||
ss << control;
|
||||
std::getline(ss, guid, ',');
|
||||
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++) {
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++)
|
||||
{
|
||||
std::stringstream ss_guid;
|
||||
ss_guid << g_pJoysticks[i]->GetGUID();
|
||||
if (ss_guid.str() == guid) {
|
||||
if (ss_guid.str() == guid)
|
||||
{
|
||||
im.index = i;
|
||||
found = true;
|
||||
break;
|
||||
|
@ -1126,7 +1317,8 @@ void LoadDInputConfig(int port, const char* dev_type)
|
|||
std::getline(ss, value, ',');
|
||||
im.type = (MappingType)std::stoi(value);
|
||||
|
||||
if (im.type == MT_NONE) {
|
||||
if (im.type == MT_NONE)
|
||||
{
|
||||
OSDebugOut(_T("Skipping control %d (%s), mapping type is None\n"), cid, g_pJoysticks[im.index]->Product().c_str());
|
||||
continue;
|
||||
}
|
||||
|
@ -1158,7 +1350,8 @@ void LoadDInputConfig(int port, const char* dev_type)
|
|||
AddInputMap(port, (ControlID)cid, im);
|
||||
}
|
||||
}
|
||||
catch (std::exception& err) {
|
||||
catch (std::exception& err)
|
||||
{
|
||||
OSDebugOut(TEXT("%" SFMTs "\n"), err.what());
|
||||
}
|
||||
|
||||
|
@ -1171,11 +1364,13 @@ int DInputPad::Configure(int port, const char* dev_type, void *data)
|
|||
struct DXDlgSettings s;
|
||||
s.port = port;
|
||||
s.dev_type = dev_type;
|
||||
if (strcmp(dev_type, "buzz_device") == 0) {
|
||||
if (strcmp(dev_type, "buzz_device") == 0)
|
||||
{
|
||||
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DLG_BUZZ), h.hWnd, DxDialogProc, (LPARAM)&s);
|
||||
}
|
||||
return DialogBoxParam(h.hInst, MAKEINTRESOURCE(IDD_DIALOG1), h.hWnd, DxDialogProc, (LPARAM)&s);
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace dx
|
||||
} // namespace usb_pad
|
||||
#pragma warning(pop)
|
||||
|
|
|
@ -16,13 +16,30 @@
|
|||
#include <math.h>
|
||||
#include "dx.h"
|
||||
|
||||
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
|
||||
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
|
||||
#define SAFE_DELETE(p) \
|
||||
{ \
|
||||
if (p) \
|
||||
{ \
|
||||
delete (p); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
}
|
||||
#define SAFE_RELEASE(p) \
|
||||
{ \
|
||||
if (p) \
|
||||
{ \
|
||||
(p)->Release(); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
//dialog window stuff
|
||||
extern HWND gsWnd;
|
||||
|
||||
namespace usb_pad { namespace dx {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace dx
|
||||
{
|
||||
|
||||
static std::atomic<int> refCount(0);
|
||||
static bool useRamp = false;
|
||||
|
@ -58,7 +75,8 @@ static DICONDITION cFriction;
|
|||
static DIRAMPFORCE cRamp;
|
||||
static DICONDITION cDamper;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, REFGUID guid) {
|
||||
std::ostream& operator<<(std::ostream& os, REFGUID guid)
|
||||
{
|
||||
std::ios_base::fmtflags f(os.flags());
|
||||
os << std::uppercase;
|
||||
os.width(8);
|
||||
|
@ -90,42 +108,106 @@ LONG GetAxisValueFromOffset(int axis, const DIJOYSTATE2& j)
|
|||
#define LVX_OFFSET 8 // count POVs or not?
|
||||
switch (axis)
|
||||
{
|
||||
case 0: return j.lX; break;
|
||||
case 1: return j.lY; break;
|
||||
case 2: return j.lZ; break;
|
||||
case 3: return j.lRx; break;
|
||||
case 4: return j.lRy; break;
|
||||
case 5: return j.lRz; break;
|
||||
case 6: return j.rglSlider[0]; break;
|
||||
case 7: return j.rglSlider[1]; break;
|
||||
case 0:
|
||||
return j.lX;
|
||||
break;
|
||||
case 1:
|
||||
return j.lY;
|
||||
break;
|
||||
case 2:
|
||||
return j.lZ;
|
||||
break;
|
||||
case 3:
|
||||
return j.lRx;
|
||||
break;
|
||||
case 4:
|
||||
return j.lRy;
|
||||
break;
|
||||
case 5:
|
||||
return j.lRz;
|
||||
break;
|
||||
case 6:
|
||||
return j.rglSlider[0];
|
||||
break;
|
||||
case 7:
|
||||
return j.rglSlider[1];
|
||||
break;
|
||||
//case 8: return j.rgdwPOV[0]; break;
|
||||
//case 9: return j.rgdwPOV[1]; break;
|
||||
//case 10: return j.rgdwPOV[2]; break;
|
||||
//case 11: return j.rgdwPOV[3]; break;
|
||||
case LVX_OFFSET + 0: return j.lVX; break; /* 'v' as in velocity */
|
||||
case LVX_OFFSET + 1: return j.lVY; break;
|
||||
case LVX_OFFSET + 2: return j.lVZ; break;
|
||||
case LVX_OFFSET + 3: return j.lVRx; break;
|
||||
case LVX_OFFSET + 4: return j.lVRy; break;
|
||||
case LVX_OFFSET + 5: return j.lVRz; break;
|
||||
case LVX_OFFSET + 6: return j.rglVSlider[0]; break;
|
||||
case LVX_OFFSET + 7: return j.rglVSlider[1]; break;
|
||||
case LVX_OFFSET + 8: return j.lAX; break; /* 'a' as in acceleration */
|
||||
case LVX_OFFSET + 9: return j.lAY; break;
|
||||
case LVX_OFFSET + 10: return j.lAZ; break;
|
||||
case LVX_OFFSET + 11: return j.lARx; break;
|
||||
case LVX_OFFSET + 12: return j.lARy; break;
|
||||
case LVX_OFFSET + 13: return j.lARz; break;
|
||||
case LVX_OFFSET + 14: return j.rglASlider[0]; break;
|
||||
case LVX_OFFSET + 15: return j.rglASlider[1]; break;
|
||||
case LVX_OFFSET + 16: return j.lFX; break; /* 'f' as in force */
|
||||
case LVX_OFFSET + 17: return j.lFY; break;
|
||||
case LVX_OFFSET + 18: return j.lFZ; break;
|
||||
case LVX_OFFSET + 19: return j.lFRx; break; /* 'fr' as in rotational force aka torque */
|
||||
case LVX_OFFSET + 20: return j.lFRy; break;
|
||||
case LVX_OFFSET + 21: return j.lFRz; break;
|
||||
case LVX_OFFSET + 22: return j.rglFSlider[0]; break;
|
||||
case LVX_OFFSET + 23: return j.rglFSlider[1]; break;
|
||||
case LVX_OFFSET + 0:
|
||||
return j.lVX;
|
||||
break; /* 'v' as in velocity */
|
||||
case LVX_OFFSET + 1:
|
||||
return j.lVY;
|
||||
break;
|
||||
case LVX_OFFSET + 2:
|
||||
return j.lVZ;
|
||||
break;
|
||||
case LVX_OFFSET + 3:
|
||||
return j.lVRx;
|
||||
break;
|
||||
case LVX_OFFSET + 4:
|
||||
return j.lVRy;
|
||||
break;
|
||||
case LVX_OFFSET + 5:
|
||||
return j.lVRz;
|
||||
break;
|
||||
case LVX_OFFSET + 6:
|
||||
return j.rglVSlider[0];
|
||||
break;
|
||||
case LVX_OFFSET + 7:
|
||||
return j.rglVSlider[1];
|
||||
break;
|
||||
case LVX_OFFSET + 8:
|
||||
return j.lAX;
|
||||
break; /* 'a' as in acceleration */
|
||||
case LVX_OFFSET + 9:
|
||||
return j.lAY;
|
||||
break;
|
||||
case LVX_OFFSET + 10:
|
||||
return j.lAZ;
|
||||
break;
|
||||
case LVX_OFFSET + 11:
|
||||
return j.lARx;
|
||||
break;
|
||||
case LVX_OFFSET + 12:
|
||||
return j.lARy;
|
||||
break;
|
||||
case LVX_OFFSET + 13:
|
||||
return j.lARz;
|
||||
break;
|
||||
case LVX_OFFSET + 14:
|
||||
return j.rglASlider[0];
|
||||
break;
|
||||
case LVX_OFFSET + 15:
|
||||
return j.rglASlider[1];
|
||||
break;
|
||||
case LVX_OFFSET + 16:
|
||||
return j.lFX;
|
||||
break; /* 'f' as in force */
|
||||
case LVX_OFFSET + 17:
|
||||
return j.lFY;
|
||||
break;
|
||||
case LVX_OFFSET + 18:
|
||||
return j.lFZ;
|
||||
break;
|
||||
case LVX_OFFSET + 19:
|
||||
return j.lFRx;
|
||||
break; /* 'fr' as in rotational force aka torque */
|
||||
case LVX_OFFSET + 20:
|
||||
return j.lFRy;
|
||||
break;
|
||||
case LVX_OFFSET + 21:
|
||||
return j.lFRz;
|
||||
break;
|
||||
case LVX_OFFSET + 22:
|
||||
return j.rglFSlider[0];
|
||||
break;
|
||||
case LVX_OFFSET + 23:
|
||||
return j.rglFSlider[1];
|
||||
break;
|
||||
}
|
||||
#undef LVX_OFFSET
|
||||
return 0;
|
||||
|
@ -144,11 +226,16 @@ bool JoystickDevice::Poll()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (m_type == CT_JOYSTICK) {
|
||||
if (m_type == CT_JOYSTICK)
|
||||
{
|
||||
m_device->GetDeviceState(sizeof(DIJOYSTATE2), &m_controls);
|
||||
} else if (m_type == CT_MOUSE) {
|
||||
}
|
||||
else if (m_type == CT_MOUSE)
|
||||
{
|
||||
m_device->GetDeviceState(sizeof(DIMOUSESTATE2), &m_controls);
|
||||
} else if (m_type == CT_KEYBOARD) {
|
||||
}
|
||||
else if (m_type == CT_KEYBOARD)
|
||||
{
|
||||
m_device->GetDeviceState(sizeof(m_controls.kbd), &m_controls);
|
||||
}
|
||||
return true;
|
||||
|
@ -159,7 +246,8 @@ bool JoystickDevice::Poll()
|
|||
|
||||
bool JoystickDevice::GetButton(int b)
|
||||
{
|
||||
if (m_type == CT_JOYSTICK) {
|
||||
if (m_type == CT_JOYSTICK)
|
||||
{
|
||||
if (b < ARRAY_SIZE(DIJOYSTATE2::rgbButtons) && m_controls.js2.rgbButtons[b] & 0x80)
|
||||
return true;
|
||||
|
||||
|
@ -171,31 +259,38 @@ bool JoystickDevice::GetButton(int b)
|
|||
switch (b % 4)
|
||||
{
|
||||
case 0:
|
||||
if ((m_controls.js2.rgdwPOV[i] <= 4500 || m_controls.js2.rgdwPOV[i] >= 31500) && m_controls.js2.rgdwPOV[i] != -1) {
|
||||
if ((m_controls.js2.rgdwPOV[i] <= 4500 || m_controls.js2.rgdwPOV[i] >= 31500) && m_controls.js2.rgdwPOV[i] != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (m_controls.js2.rgdwPOV[i] >= 4500 && m_controls.js2.rgdwPOV[i] <= 13500) {
|
||||
if (m_controls.js2.rgdwPOV[i] >= 4500 && m_controls.js2.rgdwPOV[i] <= 13500)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (m_controls.js2.rgdwPOV[i] >= 13500 && m_controls.js2.rgdwPOV[i] <= 22500) {
|
||||
if (m_controls.js2.rgdwPOV[i] >= 13500 && m_controls.js2.rgdwPOV[i] <= 22500)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (m_controls.js2.rgdwPOV[i] >= 22500 && m_controls.js2.rgdwPOV[i] <= 31500) {
|
||||
if (m_controls.js2.rgdwPOV[i] >= 22500 && m_controls.js2.rgdwPOV[i] <= 31500)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_type == CT_KEYBOARD) {
|
||||
else if (m_type == CT_KEYBOARD)
|
||||
{
|
||||
return (b < ARRAY_SIZE(m_controls.kbd) && m_controls.kbd[b] & 0x80);
|
||||
} else if (m_type == CT_MOUSE) {
|
||||
}
|
||||
else if (m_type == CT_MOUSE)
|
||||
{
|
||||
return (b < ARRAY_SIZE(DIMOUSESTATE2::rgbButtons) && m_controls.ms2.rgbButtons[b] & 0x80);
|
||||
}
|
||||
return false;
|
||||
|
@ -208,7 +303,8 @@ LONG JoystickDevice::GetAxis(int a)
|
|||
|
||||
JoystickDevice::~JoystickDevice()
|
||||
{
|
||||
if (m_device) {
|
||||
if (m_device)
|
||||
{
|
||||
m_device->Unacquire();
|
||||
m_device->Release();
|
||||
}
|
||||
|
@ -251,7 +347,8 @@ void RemoveInputMap(int port, int cid)
|
|||
bool GetInputMap(int port, int cid, InputMapped& im)
|
||||
{
|
||||
auto it = g_Controls[port].find(cid);
|
||||
if (it != g_Controls[port].end()) {
|
||||
if (it != g_Controls[port].end())
|
||||
{
|
||||
im = it->second;
|
||||
return true;
|
||||
}
|
||||
|
@ -266,7 +363,8 @@ void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis)
|
|||
if (!device)
|
||||
return;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
rgdwAxes[0] = axis;
|
||||
//LPDIRECTINPUTDEVICE8 device = joy->GetDevice();
|
||||
//create the constant force effect
|
||||
|
@ -324,7 +422,9 @@ void CreateFFB(int port, LPDIRECTINPUTDEVICE8 device, DWORD axis)
|
|||
|
||||
FFB[port] = true;
|
||||
}
|
||||
catch (...) {};
|
||||
catch (...)
|
||||
{
|
||||
};
|
||||
|
||||
//start the effect
|
||||
if (g_pEffectConstant[port])
|
||||
|
@ -394,7 +494,8 @@ BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
|
|||
//read all joystick states
|
||||
void PollDevices()
|
||||
{
|
||||
for (auto& joy : g_pJoysticks) {
|
||||
for (auto& joy : g_pJoysticks)
|
||||
{
|
||||
joy->Poll();
|
||||
}
|
||||
}
|
||||
|
@ -420,12 +521,15 @@ float FilterControl(float input, LONG linear, LONG offset, LONG dead)
|
|||
v = (v * (1.0f + (d * 2.0f))) - d;
|
||||
|
||||
//clamp
|
||||
if (v < 0.0f) v = 0.0f;
|
||||
if (v > 1.0f) v = 1.0f;
|
||||
if (v < 0.0f)
|
||||
v = 0.0f;
|
||||
if (v > 1.0f)
|
||||
v = 1.0f;
|
||||
|
||||
//clamp negdead
|
||||
//if (v == -d) v = 0.0;
|
||||
if (fabs(v + d) < FLT_EPSILON) v = 0.0f;
|
||||
if (fabs(v + d) < FLT_EPSILON)
|
||||
v = 0.0f;
|
||||
|
||||
//possibilities
|
||||
float c1 = v - (1.0f - (pow((1.0f - v), (1.0f / hs))));
|
||||
|
@ -434,9 +538,12 @@ float FilterControl(float input, LONG linear, LONG offset, LONG dead)
|
|||
float c4 = ((v - pow(v, (1.0f / hs))));
|
||||
float res = 0;
|
||||
|
||||
if (linear < 0) {
|
||||
if (linear < 0)
|
||||
{
|
||||
res = v - (((1.0f - hs2) * c3) + (hs2 * c4)); //get negative result
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
res = v - (((1.0f - hs2) * c1) + (hs2 * c2)); //get positive result
|
||||
}
|
||||
|
||||
|
@ -477,7 +584,8 @@ float ReadAxis(const InputMapped& im)
|
|||
retval = value * (1.0f / 65535);
|
||||
}
|
||||
|
||||
if (retval < 0.0f) retval = 0.0f;
|
||||
if (retval < 0.0f)
|
||||
retval = 0.0f;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -501,7 +609,8 @@ float ReadAxisFiltered(int port, int cid)
|
|||
|
||||
void AutoCenter(LPDIRECTINPUTDEVICE8 device, bool onoff)
|
||||
{
|
||||
if (!device) return;
|
||||
if (!device)
|
||||
return;
|
||||
//disable the auto-centering spring.
|
||||
DIPROPDWORD dipdw;
|
||||
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
||||
|
@ -519,7 +628,8 @@ void SetRamp(int port, const ramp& var)
|
|||
|
||||
void SetRampVariable(int port, int forceids, const variable& var)
|
||||
{
|
||||
if (!FFB[port]) return;
|
||||
if (!FFB[port])
|
||||
return;
|
||||
|
||||
// one main loop is 2ms, too erratic
|
||||
effRamp.dwDuration = 2000 * (var.t1 + 1) * 25;
|
||||
|
@ -534,7 +644,8 @@ void SetRampVariable(int port, int forceids, const variable& var)
|
|||
{
|
||||
cRamp.lStart = (127 - force) * DI_FFNOMINALMAX / 127;
|
||||
int sign = 1;
|
||||
if (cRamp.lStart < 0) sign = -1; // pull to force's direction?
|
||||
if (cRamp.lStart < 0)
|
||||
sign = -1; // pull to force's direction?
|
||||
cRamp.lEnd = sign * DI_FFNOMINALMAX * dir;
|
||||
}
|
||||
else
|
||||
|
@ -585,7 +696,8 @@ void JoystickDeviceFF::SetConstantForce(int level)
|
|||
if (FFMULTI[m_port][0] > 0)
|
||||
cfw.lMagnitude *= 1 + FFMULTI[m_port][0];
|
||||
|
||||
if(g_pEffectConstant[m_port]) {
|
||||
if (g_pEffectConstant[m_port])
|
||||
{
|
||||
g_pEffectConstant[m_port]->SetParameters(&eff, DIEP_TYPESPECIFICPARAMS | DIEP_START);
|
||||
|
||||
//DWORD flags;
|
||||
|
@ -690,7 +802,8 @@ void JoystickDeviceFF::SetAutoCenter(int value)
|
|||
|
||||
void FreeDirectInput()
|
||||
{
|
||||
if (!refCount || --refCount > 0) return;
|
||||
if (!refCount || --refCount > 0)
|
||||
return;
|
||||
|
||||
ReleaseFFB(0);
|
||||
ReleaseFFB(1);
|
||||
|
@ -750,7 +863,8 @@ HRESULT InitDirectInput( HWND hWindow, int port )
|
|||
g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY);
|
||||
|
||||
//loop through all attached joysticks
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++) {
|
||||
for (size_t i = 0; i < g_pJoysticks.size(); i++)
|
||||
{
|
||||
auto joy = g_pJoysticks[i];
|
||||
auto device = joy->GetDevice();
|
||||
OSDebugOut(_T("DINPUT: SetDataFormat Joystick %s\n"), joy->Product().c_str());
|
||||
|
@ -760,7 +874,8 @@ HRESULT InitDirectInput( HWND hWindow, int port )
|
|||
diCaps.dwSize = sizeof(DIDEVCAPS);
|
||||
device->GetCapabilities(&diCaps);
|
||||
|
||||
if (diCaps.dwFlags & DIDC_FORCEFEEDBACK) {
|
||||
if (diCaps.dwFlags & DIDC_FORCEFEEDBACK)
|
||||
{
|
||||
OSDebugOut(_T("DINPUT: SetCooperativeLevel Joystick %s\n"), joy->Product().c_str());
|
||||
//Exclusive
|
||||
device->SetCooperativeLevel(hWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND);
|
||||
|
@ -786,7 +901,6 @@ HRESULT InitDirectInput( HWND hWindow, int port )
|
|||
|
||||
didDIinit = true;
|
||||
return S_OK;
|
||||
|
||||
}
|
||||
|
||||
HWND GetWindowHandle(DWORD tPID)
|
||||
|
@ -825,7 +939,8 @@ bool FindFFDevice(int port)
|
|||
device->GetCapabilities(&diCaps);
|
||||
|
||||
//has ffb?
|
||||
if (!FFB[port] && (diCaps.dwFlags & DIDC_FORCEFEEDBACK)) {
|
||||
if (!FFB[port] && (diCaps.dwFlags & DIDC_FORCEFEEDBACK))
|
||||
{
|
||||
|
||||
//FIXME im.mapped is offset to GetAxisValueFromOffset, compatibility with DIEFFECT::rgdwAxes is questionable after DIJOYSTATE2::rglSlider
|
||||
CreateFFB(port, device, im.mapped);
|
||||
|
@ -845,11 +960,17 @@ bool FindFFDevice(int port)
|
|||
//use direct input
|
||||
void InitDI(int port, const char* dev_type)
|
||||
{
|
||||
if(gsWnd) {
|
||||
if (gsWnd)
|
||||
{
|
||||
hWin = gsWnd;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pid = GetCurrentProcessId();
|
||||
while(hWin == 0){ hWin = GetWindowHandle(pid);}
|
||||
while (hWin == 0)
|
||||
{
|
||||
hWin = GetWindowHandle(pid);
|
||||
}
|
||||
}
|
||||
|
||||
InitDirectInput(hWin, port);
|
||||
|
@ -869,10 +990,12 @@ bool GetControl(int port, int id)
|
|||
|
||||
auto joy = g_pJoysticks[im.index];
|
||||
|
||||
if (im.type == MT_AXIS) {
|
||||
if (im.type == MT_AXIS)
|
||||
{
|
||||
return ReadAxisFiltered(port, id) >= 0.5f;
|
||||
}
|
||||
else if (im.type == MT_BUTTON) {
|
||||
else if (im.type == MT_BUTTON)
|
||||
{
|
||||
return joy->GetButton(im.mapped);
|
||||
}
|
||||
return false;
|
||||
|
@ -883,12 +1006,18 @@ float GetAxisControl(int port, ControlID id)
|
|||
if (id == CID_STEERING)
|
||||
{
|
||||
//apply steering, single axis is split to two for filtering
|
||||
if (ReadAxisFiltered(port, CID_STEERING) > 0.0) {
|
||||
if (ReadAxisFiltered(port, CID_STEERING) > 0.0)
|
||||
{
|
||||
return -ReadAxisFiltered(port, CID_STEERING);
|
||||
} else {
|
||||
if (ReadAxisFiltered(port, CID_STEERING_R) > 0.0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ReadAxisFiltered(port, CID_STEERING_R) > 0.0)
|
||||
{
|
||||
return ReadAxisFiltered(port, CID_STEERING_R);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -901,7 +1030,8 @@ float GetAxisControl(int port, ControlID id)
|
|||
void SetConstantForce(int port, LONG magnitude)
|
||||
{
|
||||
OSDebugOut(TEXT("constant force: %d\n"), magnitude);
|
||||
if (!FFB[port]) return;
|
||||
if (!FFB[port])
|
||||
return;
|
||||
|
||||
if (INVERTFORCES[port])
|
||||
cfw.lMagnitude = -magnitude;
|
||||
|
@ -931,12 +1061,13 @@ void TestForce(int port)
|
|||
Sleep(500);
|
||||
SetConstantForce(port, 0);
|
||||
|
||||
if (dev) { //FIXME actually center, maybe
|
||||
if (dev)
|
||||
{ //FIXME actually center, maybe
|
||||
AutoCenter(dev, true);
|
||||
Sleep(1500);
|
||||
AutoCenter(dev, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace dx
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
|
||||
#define DINPUT_AXES_COUNT 32
|
||||
|
||||
namespace usb_pad { namespace dx {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace dx
|
||||
{
|
||||
|
||||
extern int32_t BYPASSCAL;
|
||||
|
||||
|
@ -78,7 +81,10 @@ enum ControlID
|
|||
class JoystickDeviceFF : public FFDevice
|
||||
{
|
||||
public:
|
||||
JoystickDeviceFF(int port): m_port(port) {}
|
||||
JoystickDeviceFF(int port)
|
||||
: m_port(port)
|
||||
{
|
||||
}
|
||||
~JoystickDeviceFF() {}
|
||||
|
||||
void SetConstantForce(int level);
|
||||
|
@ -170,12 +176,14 @@ public:
|
|||
ControlType GetControlType() { return m_type; }
|
||||
|
||||
~JoystickDevice();
|
||||
|
||||
private:
|
||||
GUID m_guid;
|
||||
TSTDSTRING m_product;
|
||||
LPDIRECTINPUTDEVICE8 m_device;
|
||||
ControlType m_type = CT_NONE;
|
||||
union {
|
||||
union
|
||||
{
|
||||
DIJOYSTATE2 js2;
|
||||
DIMOUSESTATE2 ms2;
|
||||
BYTE kbd[256];
|
||||
|
@ -207,4 +215,5 @@ void AddInputMap(int port, int cid, const InputMapped& im);
|
|||
void RemoveInputMap(int port, int cid);
|
||||
bool GetInputMap(int port, int cid, InputMapped& im);
|
||||
|
||||
}} //namespace
|
||||
} // namespace dx
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
#include "dx.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace usb_pad { namespace dx {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace dx
|
||||
{
|
||||
|
||||
static bool bdown = false;
|
||||
static DWORD calibrationtime = 0;
|
||||
|
@ -41,9 +44,12 @@ int DInputPad::TokenIn(uint8_t *buf, int len)
|
|||
|
||||
PollDevices();
|
||||
|
||||
if (mType == WT_BUZZ_CONTROLLER) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (GetControl(mPort, i)) {
|
||||
if (mType == WT_BUZZ_CONTROLLER)
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
if (GetControl(mPort, i))
|
||||
{
|
||||
mWheelData.buttons |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
@ -55,40 +61,59 @@ int DInputPad::TokenIn(uint8_t *buf, int len)
|
|||
//if(idx == 0){
|
||||
//mWheelData.steering = 8191 + (int)(GetControl(STEERING, false)* 8191.0f) ;
|
||||
|
||||
if(calibrating){
|
||||
if (calibrating)
|
||||
{
|
||||
//Alternate full extents
|
||||
if (alternate)calidata--;
|
||||
else calidata++;
|
||||
if (alternate)
|
||||
calidata--;
|
||||
else
|
||||
calidata++;
|
||||
|
||||
if(calidata>range-1 || calidata < 1) alternate = !alternate; //invert
|
||||
if (calidata > range - 1 || calidata < 1)
|
||||
alternate = !alternate; //invert
|
||||
|
||||
mWheelData.steering = calidata; //pass fake
|
||||
|
||||
//breakout after 11 seconds
|
||||
if(GetTickCount()-calibrationtime > 11000){
|
||||
if (GetTickCount() - calibrationtime > 11000)
|
||||
{
|
||||
calibrating = false;
|
||||
mWheelData.steering = range >> 1;
|
||||
}
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
mWheelData.steering = (range >> 1) + std::lround(GetAxisControl(mPort, CID_STEERING) * (float)(range >> 1));
|
||||
}
|
||||
|
||||
mWheelData.throttle = std::lround(255.f - (GetAxisControl(mPort, CID_THROTTLE) * 255.0f));
|
||||
mWheelData.brake = std::lround(255.f - (GetAxisControl(mPort, CID_BRAKE) * 255.0f));
|
||||
|
||||
if(GetControl(mPort, CID_CROSS)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CROSS);
|
||||
if(GetControl(mPort, CID_SQUARE)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SQUARE);
|
||||
if(GetControl(mPort, CID_CIRCLE)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CIRCLE);
|
||||
if(GetControl(mPort, CID_TRIANGLE)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_TRIANGLE);
|
||||
if(GetControl(mPort, CID_R1)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R1);
|
||||
if(GetControl(mPort, CID_L1)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L1);
|
||||
if(GetControl(mPort, CID_R2)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R2);
|
||||
if(GetControl(mPort, CID_L2)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L2);
|
||||
if (GetControl(mPort, CID_CROSS))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CROSS);
|
||||
if (GetControl(mPort, CID_SQUARE))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SQUARE);
|
||||
if (GetControl(mPort, CID_CIRCLE))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_CIRCLE);
|
||||
if (GetControl(mPort, CID_TRIANGLE))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_TRIANGLE);
|
||||
if (GetControl(mPort, CID_R1))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R1);
|
||||
if (GetControl(mPort, CID_L1))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L1);
|
||||
if (GetControl(mPort, CID_R2))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R2);
|
||||
if (GetControl(mPort, CID_L2))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L2);
|
||||
|
||||
if(GetControl(mPort, CID_SELECT)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SELECT);
|
||||
if(GetControl(mPort, CID_START)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_START);
|
||||
if(GetControl(mPort, CID_R3)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R3);
|
||||
if(GetControl(mPort, CID_L3)) mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L3);
|
||||
if (GetControl(mPort, CID_SELECT))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_SELECT);
|
||||
if (GetControl(mPort, CID_START))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_START);
|
||||
if (GetControl(mPort, CID_R3))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_R3);
|
||||
if (GetControl(mPort, CID_L3))
|
||||
mWheelData.buttons |= 1 << convert_wt_btn(mType, PAD_L3);
|
||||
|
||||
//diagonal
|
||||
if (GetControl(mPort, CID_HATUP) && GetControl(mPort, CID_HATRIGHT))
|
||||
|
@ -101,7 +126,8 @@ int DInputPad::TokenIn(uint8_t *buf, int len)
|
|||
mWheelData.hatswitch = 7;
|
||||
|
||||
//regular
|
||||
if(mWheelData.hatswitch==0x8){
|
||||
if (mWheelData.hatswitch == 0x8)
|
||||
{
|
||||
if (GetControl(mPort, CID_HATUP))
|
||||
mWheelData.hatswitch = 0;
|
||||
if (GetControl(mPort, CID_HATRIGHT))
|
||||
|
@ -141,4 +167,5 @@ int DInputPad::Close()
|
|||
return 0;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace dx
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -16,14 +16,21 @@
|
|||
#include "../padproxy.h"
|
||||
#include "../../Win32/Config.h"
|
||||
|
||||
namespace usb_pad { namespace dx {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace dx
|
||||
{
|
||||
|
||||
static const char* APINAME = "dinput";
|
||||
|
||||
class DInputPad : public Pad
|
||||
{
|
||||
public:
|
||||
DInputPad(int port, const char* dev_type) : Pad(port, dev_type), mUseRamp(0){}
|
||||
DInputPad(int port, const char* dev_type)
|
||||
: Pad(port, dev_type)
|
||||
, mUseRamp(0)
|
||||
{
|
||||
}
|
||||
~DInputPad();
|
||||
int Open();
|
||||
int Close();
|
||||
|
@ -37,8 +44,10 @@ public:
|
|||
}
|
||||
|
||||
static int Configure(int port, const char* dev_type, void* data);
|
||||
|
||||
private:
|
||||
int32_t mUseRamp;
|
||||
};
|
||||
|
||||
}} //namespace
|
||||
} // namespace dx
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -20,43 +20,55 @@
|
|||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
#define BITS_TO_UCHAR(x) \
|
||||
(((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): mHandle(fd), mUseRumble(false)
|
||||
EvdevFF::EvdevFF(int fd)
|
||||
: mHandle(fd)
|
||||
, mUseRumble(false)
|
||||
{
|
||||
unsigned char features[BITS_TO_UCHAR(FF_MAX)];
|
||||
if (ioctl(mHandle, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
|
||||
if (ioctl(mHandle, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0)
|
||||
{
|
||||
OSDebugOut("Get features failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
int effects = 0;
|
||||
if (ioctl(mHandle, EVIOCGEFFECTS, &effects) < 0) {
|
||||
if (ioctl(mHandle, EVIOCGEFFECTS, &effects) < 0)
|
||||
{
|
||||
OSDebugOut("Get effects failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (!testBit(FF_CONSTANT, features)) {
|
||||
if (!testBit(FF_CONSTANT, features))
|
||||
{
|
||||
OSDebugOut("device does not support FF_CONSTANT\n");
|
||||
if (testBit(FF_RUMBLE, features))
|
||||
mUseRumble = true;
|
||||
}
|
||||
|
||||
if (!testBit(FF_SPRING, features)) {
|
||||
if (!testBit(FF_SPRING, features))
|
||||
{
|
||||
OSDebugOut("device does not support FF_SPRING\n");
|
||||
}
|
||||
|
||||
if (!testBit(FF_DAMPER, features)) {
|
||||
if (!testBit(FF_DAMPER, features))
|
||||
{
|
||||
OSDebugOut("device does not support FF_DAMPER\n");
|
||||
}
|
||||
|
||||
if (!testBit(FF_GAIN, features)) {
|
||||
if (!testBit(FF_GAIN, features))
|
||||
{
|
||||
OSDebugOut("device does not support FF_GAIN\n");
|
||||
}
|
||||
|
||||
if (!testBit(FF_AUTOCENTER, features)) {
|
||||
if (!testBit(FF_AUTOCENTER, features))
|
||||
{
|
||||
OSDebugOut("device does not support FF_AUTOCENTER\n");
|
||||
}
|
||||
|
||||
|
@ -85,7 +97,8 @@ EvdevFF::~EvdevFF()
|
|||
{
|
||||
for (int i = 0; i < countof(mEffIds); i++)
|
||||
{
|
||||
if (mEffIds[i] != -1 && ioctl(mHandle, EVIOCRMFF, mEffIds[i]) == -1) {
|
||||
if (mEffIds[i] != -1 && ioctl(mHandle, EVIOCRMFF, mEffIds[i]) == -1)
|
||||
{
|
||||
OSDebugOut("Failed to unload EffectID(%d) effect.\n", i);
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +110,8 @@ void EvdevFF::DisableForce(EffectID force)
|
|||
play.type = EV_FF;
|
||||
play.code = mEffIds[force];
|
||||
play.value = 0;
|
||||
if (write(mHandle, (const void*) &play, sizeof(play)) == -1) {
|
||||
if (write(mHandle, (const void*)&play, sizeof(play)) == -1)
|
||||
{
|
||||
OSDebugOut("Stop effect failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -109,19 +123,23 @@ void EvdevFF::SetConstantForce(/*const parsed_ff_data& ff*/ int level)
|
|||
play.value = 1;
|
||||
mEffect.u = {};
|
||||
|
||||
if (!mUseRumble) {
|
||||
if (!mUseRumble)
|
||||
{
|
||||
mEffect.type = FF_CONSTANT;
|
||||
mEffect.id = mEffIds[EFF_CONSTANT];
|
||||
mEffect.u.constant.level = /*ff.u.constant.*/ level;
|
||||
|
||||
OSDebugOut("Constant force: %d\n", level);
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) {
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
|
||||
{
|
||||
OSDebugOut("Failed to upload constant effect: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
play.code = mEffect.id;
|
||||
mEffIds[EFF_CONSTANT] = mEffect.id;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
mEffect.type = FF_RUMBLE;
|
||||
mEffect.id = mEffIds[EFF_RUMBLE];
|
||||
|
@ -142,7 +160,8 @@ void EvdevFF::SetConstantForce(/*const parsed_ff_data& ff*/ int level)
|
|||
|
||||
mLastValue = mag;
|
||||
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) {
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
|
||||
{
|
||||
OSDebugOut("Failed to upload constant effect: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -150,10 +169,10 @@ void EvdevFF::SetConstantForce(/*const parsed_ff_data& ff*/ int level)
|
|||
mEffIds[EFF_RUMBLE] = mEffect.id;
|
||||
}
|
||||
|
||||
if (write(mHandle, (const void*) &play, sizeof(play)) == -1) {
|
||||
if (write(mHandle, (const void*)&play, sizeof(play)) == -1)
|
||||
{
|
||||
OSDebugOut("Play effect failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EvdevFF::SetSpringForce(const parsed_ff_data& ff)
|
||||
|
@ -176,7 +195,8 @@ void EvdevFF::SetSpringForce(const parsed_ff_data& ff)
|
|||
mEffect.u.condition[0].left_coeff, mEffect.u.condition[0].right_coeff,
|
||||
mEffect.u.condition[0].left_saturation, mEffect.u.condition[0].right_saturation);
|
||||
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) {
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
|
||||
{
|
||||
OSDebugOut("Failed to upload spring effect: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -184,7 +204,8 @@ void EvdevFF::SetSpringForce(const parsed_ff_data& ff)
|
|||
play.code = mEffect.id;
|
||||
mEffIds[EFF_SPRING] = mEffect.id;
|
||||
|
||||
if (write(mHandle, (const void*) &play, sizeof(play)) == -1) {
|
||||
if (write(mHandle, (const void*)&play, sizeof(play)) == -1)
|
||||
{
|
||||
OSDebugOut("Play effect failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +228,8 @@ void EvdevFF::SetDamperForce(const parsed_ff_data& ff)
|
|||
|
||||
OSDebugOut("Damper force: %d/%d\n", mEffect.u.condition[0].left_coeff, mEffect.u.condition[0].right_coeff);
|
||||
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) {
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
|
||||
{
|
||||
OSDebugOut("Failed to upload damper effect: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -215,7 +237,8 @@ void EvdevFF::SetDamperForce(const parsed_ff_data& ff)
|
|||
play.code = mEffect.id;
|
||||
mEffIds[EFF_DAMPER] = mEffect.id;
|
||||
|
||||
if (write(mHandle, (const void*) &play, sizeof(play)) == -1) {
|
||||
if (write(mHandle, (const void*)&play, sizeof(play)) == -1)
|
||||
{
|
||||
OSDebugOut("Play effect failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +260,8 @@ void EvdevFF::SetFrictionForce(const parsed_ff_data& ff)
|
|||
mEffect.u.condition[0].deadband = ff.u.condition.deadband;
|
||||
|
||||
OSDebugOut("Friction force: %d/%d\n", mEffect.u.condition[0].left_coeff, mEffect.u.condition[0].right_coeff);
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0) {
|
||||
if (ioctl(mHandle, EVIOCSFF, &(mEffect)) < 0)
|
||||
{
|
||||
OSDebugOut("Failed to upload friction effect: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
@ -245,7 +269,8 @@ void EvdevFF::SetFrictionForce(const parsed_ff_data& ff)
|
|||
play.code = mEffect.id;
|
||||
mEffIds[EFF_FRICTION] = mEffect.id;
|
||||
|
||||
if (write(mHandle, (const void*) &play, sizeof(play)) == -1) {
|
||||
if (write(mHandle, (const void*)&play, sizeof(play)) == -1)
|
||||
{
|
||||
OSDebugOut("Play effect failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -276,4 +301,5 @@ void EvdevFF::SetGain(int gain /* between 0 and 100 */)
|
|||
OSDebugOut("Failed to set gain: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
#include <linux/input.h>
|
||||
#include "../usb-pad.h"
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
class EvdevFF : public FFDevice
|
||||
{
|
||||
|
@ -44,5 +47,6 @@ private:
|
|||
int mLastValue;
|
||||
};
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
#include <sstream>
|
||||
#include "../../gtk.h"
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
using sys_clock = std::chrono::system_clock;
|
||||
using ms = std::chrono::milliseconds;
|
||||
|
@ -562,8 +565,10 @@ static bool GetEventName(const char *dev_type, int map, int event, const char **
|
|||
if (!name)
|
||||
return false;
|
||||
|
||||
if (map < JOY_STEERING || !strcmp(dev_type, BuzzDevice::TypeName())) {
|
||||
if (event < key_to_str.size()) {
|
||||
if (map < JOY_STEERING || !strcmp(dev_type, BuzzDevice::TypeName()))
|
||||
{
|
||||
if (event < key_to_str.size())
|
||||
{
|
||||
*name = key_to_str[event];
|
||||
return true;
|
||||
}
|
||||
|
@ -582,7 +587,11 @@ static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping> >&
|
|||
int event_fd = -1, t;
|
||||
ssize_t len;
|
||||
input_event event;
|
||||
struct AxisValue { int16_t value; bool initial; };
|
||||
struct AxisValue
|
||||
{
|
||||
int16_t value;
|
||||
bool initial;
|
||||
};
|
||||
AxisValue axisVal[ABS_MAX + 1]{};
|
||||
unsigned long absbit[NBITS(ABS_MAX)]{};
|
||||
struct axis_correct abs_correct[ABS_MAX]{};
|
||||
|
@ -593,9 +602,11 @@ static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping> >&
|
|||
int maxfd = -1;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
for (const auto& js: fds) {
|
||||
for (const auto& js : fds)
|
||||
{
|
||||
FD_SET(js.second.fd, &fdset);
|
||||
if (maxfd < js.second.fd) maxfd = js.second.fd;
|
||||
if (maxfd < js.second.fd)
|
||||
maxfd = js.second.fd;
|
||||
}
|
||||
|
||||
// wait to avoid some false positives like mouse movement
|
||||
|
@ -603,22 +614,27 @@ static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping> >&
|
|||
|
||||
// empty event queues
|
||||
for (const auto& js : fds)
|
||||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0);
|
||||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0)
|
||||
;
|
||||
|
||||
struct timeval timeout {};
|
||||
struct timeval timeout
|
||||
{
|
||||
};
|
||||
timeout.tv_sec = 5;
|
||||
int result = select(maxfd + 1, &fdset, NULL, NULL, &timeout);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
if (result == -1) {
|
||||
if (result == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& js : fds)
|
||||
{
|
||||
if (FD_ISSET(js.second.fd, &fdset)) {
|
||||
if (FD_ISSET(js.second.fd, &fdset))
|
||||
{
|
||||
event_fd = js.second.fd;
|
||||
dev_name = js.first;
|
||||
break;
|
||||
|
@ -628,12 +644,16 @@ static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping> >&
|
|||
if (event_fd == -1)
|
||||
return false;
|
||||
|
||||
if (isaxis && ioctl(event_fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) {
|
||||
for (int i = 0; i < ABS_MAX; ++i) {
|
||||
if (test_bit(i, absbit)) {
|
||||
if (isaxis && ioctl(event_fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0)
|
||||
{
|
||||
for (int i = 0; i < ABS_MAX; ++i)
|
||||
{
|
||||
if (test_bit(i, absbit))
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
|
||||
if (ioctl(event_fd, EVIOCGABS(i), &absinfo) < 0) {
|
||||
if (ioctl(event_fd, EVIOCGABS(i), &absinfo) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -649,13 +669,16 @@ static bool PollInput(const std::vector<std::pair<std::string, ConfigMapping> >&
|
|||
while (true)
|
||||
{
|
||||
auto dur = std::chrono::duration_cast<ms>(sys_clock::now() - last).count();
|
||||
if (dur > 5000) goto error;
|
||||
if (dur > 5000)
|
||||
goto error;
|
||||
|
||||
if (!isaxis) {
|
||||
if (!isaxis)
|
||||
{
|
||||
event_fd = -1;
|
||||
for (const auto& js : fds)
|
||||
{
|
||||
if (FD_ISSET(js.second.fd, &fdset)) {
|
||||
if (FD_ISSET(js.second.fd, &fdset))
|
||||
{
|
||||
event_fd = js.second.fd;
|
||||
dev_name = js.first;
|
||||
|
||||
|
@ -733,4 +756,5 @@ int EvDevPad::Configure(int port, const char* dev_type, void *data)
|
|||
}
|
||||
|
||||
#undef EVDEV_DIR
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#include <linux/hidraw.h>
|
||||
#include "../../linux/util.h"
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
// hidraw* to input/event*:
|
||||
// /sys/class/hidraw/hidraw*/device/input/input*/event*/uevent
|
||||
|
@ -52,22 +55,26 @@ bool FindHidraw(const std::string &evphys, std::string& hid_dev, int *vid, int *
|
|||
struct dirent* dp;
|
||||
|
||||
DIR* dirp = opendir("/dev/");
|
||||
if (!dirp) {
|
||||
if (!dirp)
|
||||
{
|
||||
perror("Error opening /dev/");
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp)))
|
||||
{
|
||||
if(strncmp(dp->d_name, "hidraw", 6) == 0) {
|
||||
if (strncmp(dp->d_name, "hidraw", 6) == 0)
|
||||
{
|
||||
OSDebugOut("%s\n", dp->d_name);
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "/dev/" << dp->d_name;
|
||||
std::string path = str.str();
|
||||
fd = open(path.c_str(), O_RDWR | O_NONBLOCK);
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Unable to open device");
|
||||
continue;
|
||||
}
|
||||
|
@ -84,15 +91,21 @@ bool FindHidraw(const std::string &evphys, std::string& hid_dev, int *vid, int *
|
|||
struct hidraw_devinfo info;
|
||||
memset(&info, 0x0, sizeof(info));
|
||||
|
||||
if (ioctl(fd, HIDIOCGRAWINFO, &info) < 0) {
|
||||
if (ioctl(fd, HIDIOCGRAWINFO, &info) < 0)
|
||||
{
|
||||
perror("HIDIOCGRAWINFO");
|
||||
} else {
|
||||
if (vid) *vid = info.vendor;
|
||||
if (pid) *pid = info.product;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vid)
|
||||
*vid = info.vendor;
|
||||
if (pid)
|
||||
*pid = info.product;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (evphys == buf) {
|
||||
if (evphys == buf)
|
||||
{
|
||||
closedir(dirp);
|
||||
hid_dev = path;
|
||||
return true;
|
||||
|
@ -118,13 +131,15 @@ void EnumerateDevices(vstring& list)
|
|||
static vstring list_cache;
|
||||
|
||||
DIR* dirp = opendir(EVDEV_DIR);
|
||||
if (!dirp) {
|
||||
if (!dirp)
|
||||
{
|
||||
perror("Error opening " EVDEV_DIR);
|
||||
return;
|
||||
}
|
||||
|
||||
// get rid of unplugged devices
|
||||
for (int i=0; i < list_cache.size(); ) {
|
||||
for (int i = 0; i < list_cache.size();)
|
||||
{
|
||||
if (!file_exists(list_cache[i].second))
|
||||
list_cache.erase(list_cache.begin() + i);
|
||||
else
|
||||
|
@ -134,13 +149,12 @@ void EnumerateDevices(vstring& list)
|
|||
while ((dp = readdir(dirp)))
|
||||
{
|
||||
//if (strncmp(dp->d_name, "event", 5) == 0) {
|
||||
if (str_ends_with(dp->d_name, "event-kbd")
|
||||
|| str_ends_with(dp->d_name, "event-mouse")
|
||||
|| str_ends_with(dp->d_name, "event-joystick"))
|
||||
if (str_ends_with(dp->d_name, "event-kbd") || str_ends_with(dp->d_name, "event-mouse") || str_ends_with(dp->d_name, "event-joystick"))
|
||||
{
|
||||
OSDebugOut(EVDEV_DIR "%s\n", dp->d_name);
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << EVDEV_DIR << dp->d_name;
|
||||
std::string path = str.str();
|
||||
|
||||
|
@ -153,7 +167,8 @@ void EnumerateDevices(vstring& list)
|
|||
|
||||
fd = open(path.c_str(), O_RDWR | O_NONBLOCK);
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Unable to open device");
|
||||
continue;
|
||||
}
|
||||
|
@ -183,11 +198,13 @@ void EvDevPad::PollAxesValues(const device_data& device)
|
|||
struct input_absinfo absinfo;
|
||||
|
||||
/* Poll all axis */
|
||||
for (int i = ABS_X; i < ABS_MAX; i++) {
|
||||
for (int i = ABS_X; i < ABS_MAX; i++)
|
||||
{
|
||||
absinfo = {};
|
||||
|
||||
if ((ioctl(device.cfg.fd, EVIOCGABS(i), &absinfo) >= 0) &&
|
||||
device.abs_correct[i].used) {
|
||||
device.abs_correct[i].used)
|
||||
{
|
||||
absinfo.value = AxisCorrect(device.abs_correct[i], absinfo.value);
|
||||
}
|
||||
SetAxis(device, i, absinfo.value);
|
||||
|
@ -203,7 +220,9 @@ void EvDevPad::SetAxis(const device_data& device, int event_code, int value)
|
|||
switch (code)
|
||||
{
|
||||
case 0x80 | JOY_STEERING:
|
||||
case ABS_X: mWheelData.steering = device.cfg.inverted[0] ? range - NORM(value, range) : NORM(value, range); break;
|
||||
case ABS_X:
|
||||
mWheelData.steering = device.cfg.inverted[0] ? range - NORM(value, range) : NORM(value, range);
|
||||
break;
|
||||
//case ABS_Y: mWheelData.clutch = NORM(value, 0xFF); break; //no wheel on PS2 has one, afaik
|
||||
//case ABS_RX: mWheelData.axis_rx = NORM(event.value, 0xFF); break;
|
||||
case ABS_RY:
|
||||
|
@ -255,7 +274,8 @@ void EvDevPad::SetAxis(const device_data& device, int event_code, int value)
|
|||
else
|
||||
mWheelData.hat_vert = PAD_HAT_COUNT;
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,22 +290,26 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
FD_ZERO(&fds);
|
||||
maxfd = -1;
|
||||
|
||||
for (auto& device: mDevices) {
|
||||
for (auto& device : mDevices)
|
||||
{
|
||||
FD_SET(device.cfg.fd, &fds);
|
||||
if (maxfd < device.cfg.fd) maxfd = device.cfg.fd;
|
||||
if (maxfd < device.cfg.fd)
|
||||
maxfd = device.cfg.fd;
|
||||
}
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_usec = timeout.tv_sec = 0; // 0 - return from select immediately
|
||||
int result = select(maxfd + 1, &fds, NULL, NULL, &timeout);
|
||||
|
||||
if (result <= 0) {
|
||||
if (result <= 0)
|
||||
{
|
||||
return USB_RET_NAK; // If no new data, NAK it
|
||||
}
|
||||
|
||||
for (auto& device : mDevices)
|
||||
{
|
||||
if (!FD_ISSET(device.cfg.fd, &fds)) {
|
||||
if (!FD_ISSET(device.cfg.fd, &fds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -318,9 +342,11 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
OSDebugOut("%s Button: 0x%02x, mapped: 0x%02x, val: %d\n",
|
||||
device.name.c_str(), event.code, device.btn_map[event.code], event.value);
|
||||
|
||||
if (mType == WT_BUZZ_CONTROLLER) {
|
||||
if (mType == WT_BUZZ_CONTROLLER)
|
||||
{
|
||||
OSDebugOut("evdev buzz: code: %d, map: %08x\n", event.code, device.btn_map[event.code]);
|
||||
if (device.btn_map[event.code] != (uint16_t)-1) {
|
||||
if (device.btn_map[event.code] != (uint16_t)-1)
|
||||
{
|
||||
if (event.value)
|
||||
mWheelData.buttons |= 1 << (code & ~0x8000); //on
|
||||
else
|
||||
|
@ -358,16 +384,36 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
case 0x8000 | JOY_DOWN:
|
||||
mWheelData.hat_vert = (!event.value ? PAD_HAT_COUNT : PAD_HAT_S);
|
||||
break;
|
||||
case BTN_WEST: button = PAD_SQUARE; break;
|
||||
case BTN_NORTH: button = PAD_TRIANGLE; break;
|
||||
case BTN_EAST: button = PAD_CIRCLE; break;
|
||||
case BTN_SOUTH: button = PAD_CROSS; break;
|
||||
case BTN_SELECT: button = PAD_SELECT; break;
|
||||
case BTN_START: button = PAD_START; break;
|
||||
case BTN_TR: button = PAD_R1; break;
|
||||
case BTN_TL: button = PAD_L1; break;
|
||||
case BTN_THUMBR: button = PAD_R2; break;
|
||||
case BTN_THUMBL: button = PAD_L2; break;
|
||||
case BTN_WEST:
|
||||
button = PAD_SQUARE;
|
||||
break;
|
||||
case BTN_NORTH:
|
||||
button = PAD_TRIANGLE;
|
||||
break;
|
||||
case BTN_EAST:
|
||||
button = PAD_CIRCLE;
|
||||
break;
|
||||
case BTN_SOUTH:
|
||||
button = PAD_CROSS;
|
||||
break;
|
||||
case BTN_SELECT:
|
||||
button = PAD_SELECT;
|
||||
break;
|
||||
case BTN_START:
|
||||
button = PAD_START;
|
||||
break;
|
||||
case BTN_TR:
|
||||
button = PAD_R1;
|
||||
break;
|
||||
case BTN_TL:
|
||||
button = PAD_L1;
|
||||
break;
|
||||
case BTN_THUMBR:
|
||||
button = PAD_R2;
|
||||
break;
|
||||
case BTN_THUMBL:
|
||||
button = PAD_L2;
|
||||
break;
|
||||
default:
|
||||
OSDebugOut("Unmapped Button: %d, %d\n", code, event.value);
|
||||
break;
|
||||
|
@ -385,7 +431,8 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
break;
|
||||
case EV_SYN: //TODO useful?
|
||||
{
|
||||
switch(event.code) {
|
||||
switch (event.code)
|
||||
{
|
||||
case SYN_DROPPED:
|
||||
//restore last good state
|
||||
mWheelData = {};
|
||||
|
@ -412,17 +459,29 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
case PAD_HAT_N:
|
||||
switch (mWheelData.hat_horz)
|
||||
{
|
||||
case PAD_HAT_W: mWheelData.hatswitch = PAD_HAT_NW; break;
|
||||
case PAD_HAT_E: mWheelData.hatswitch = PAD_HAT_NE; break;
|
||||
default: mWheelData.hatswitch = PAD_HAT_N; break;
|
||||
case PAD_HAT_W:
|
||||
mWheelData.hatswitch = PAD_HAT_NW;
|
||||
break;
|
||||
case PAD_HAT_E:
|
||||
mWheelData.hatswitch = PAD_HAT_NE;
|
||||
break;
|
||||
default:
|
||||
mWheelData.hatswitch = PAD_HAT_N;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PAD_HAT_S:
|
||||
switch (mWheelData.hat_horz)
|
||||
{
|
||||
case PAD_HAT_W: mWheelData.hatswitch = PAD_HAT_SW; break;
|
||||
case PAD_HAT_E: mWheelData.hatswitch = PAD_HAT_SE; break;
|
||||
default: mWheelData.hatswitch = PAD_HAT_S; break;
|
||||
case PAD_HAT_W:
|
||||
mWheelData.hatswitch = PAD_HAT_SW;
|
||||
break;
|
||||
case PAD_HAT_E:
|
||||
mWheelData.hatswitch = PAD_HAT_SE;
|
||||
break;
|
||||
default:
|
||||
mWheelData.hatswitch = PAD_HAT_S;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -436,12 +495,14 @@ int EvDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
|
||||
int EvDevPad::TokenOut(const uint8_t* data, int len)
|
||||
{
|
||||
if (mUseRawFF) {
|
||||
if (mUseRawFF)
|
||||
{
|
||||
|
||||
OSDebugOut("FF: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
|
||||
|
||||
if (data[0] == 0x8 || data[0] == 0xB) return len;
|
||||
if (data[0] == 0x8 || data[0] == 0xB)
|
||||
return len;
|
||||
if (data[0] == 0xF8 &&
|
||||
/* Allow range changes */
|
||||
!(data[1] == 0x81 || data[1] == 0x02 || data[1] == 0x03))
|
||||
|
@ -451,7 +512,8 @@ int EvDevPad::TokenOut(const uint8_t *data, int len)
|
|||
|
||||
memcpy(report.data() + 1, data, report.size() - 1);
|
||||
|
||||
if (!mFFData.enqueue(report)) {
|
||||
if (!mFFData.enqueue(report))
|
||||
{
|
||||
OSDebugOut("Failed to enqueue ffb command\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -494,7 +556,8 @@ int EvDevPad::Open()
|
|||
|
||||
std::string evphys, hid_dev;
|
||||
|
||||
switch(mType) {
|
||||
switch (mType)
|
||||
{
|
||||
case WT_GENERIC:
|
||||
case WT_GT_FORCE:
|
||||
case WT_DRIVING_FORCE_PRO:
|
||||
|
@ -507,10 +570,12 @@ int EvDevPad::Open()
|
|||
break;
|
||||
}
|
||||
|
||||
if (mUseRawFF) {
|
||||
if (mUseRawFF)
|
||||
{
|
||||
// TODO could just use device fd below whose axis is mapped to steering
|
||||
std::string joypath;
|
||||
if (!LoadSetting(mDevType, mPort, APINAME, N_JOYSTICK, joypath)) {
|
||||
if (!LoadSetting(mDevType, mPort, APINAME, N_JOYSTICK, joypath))
|
||||
{
|
||||
OSDebugOut("Cannot load device setting: %s\n", N_JOYSTICK);
|
||||
return 1;
|
||||
}
|
||||
|
@ -526,18 +591,21 @@ int EvDevPad::Open()
|
|||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (ioctl(fd, EVIOCGPHYS(sizeof(buf) - 1), buf) > 0) {
|
||||
if (ioctl(fd, EVIOCGPHYS(sizeof(buf) - 1), buf) > 0)
|
||||
{
|
||||
evphys = buf;
|
||||
OSDebugOut("Evdev Phys: %s\n", evphys.c_str());
|
||||
|
||||
int pid, vid;
|
||||
if ((mUseRawFF = FindHidraw(evphys, hid_dev, &vid, &pid))) {
|
||||
if ((mUseRawFF = FindHidraw(evphys, hid_dev, &vid, &pid)))
|
||||
{
|
||||
|
||||
// For safety, only allow Logitech (classic ffb) devices
|
||||
if (vid != 0x046D /* Logitech */ /*|| info.bustype != BUS_USB*/
|
||||
|| pid == 0xc262 /* G920 hid mode */
|
||||
|| pid == 0xc261 /* G920 xbox mode */
|
||||
) {
|
||||
)
|
||||
{
|
||||
mUseRawFF = 0;
|
||||
}
|
||||
|
||||
|
@ -549,7 +617,9 @@ int EvDevPad::Open()
|
|||
mWriterThread = std::thread(EvDevPad::WriterThread, this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("EVIOCGPHYS failed");
|
||||
}
|
||||
close(fd);
|
||||
|
@ -576,7 +646,8 @@ int EvDevPad::Open()
|
|||
memset(device.axis_map, 0xFF, sizeof(device.axis_map));
|
||||
memset(device.btn_map, 0xFF, sizeof(device.btn_map));
|
||||
|
||||
if ((ret_abs < 0) && (ret_key < 0)) {
|
||||
if ((ret_abs < 0) && (ret_key < 0))
|
||||
{
|
||||
// Probably isn't a evdev joystick
|
||||
SysMessage("%s: Getting atleast some of the bits failed: %s\n", APINAME, strerror(errno));
|
||||
continue;
|
||||
|
@ -590,7 +661,8 @@ int EvDevPad::Open()
|
|||
}*/
|
||||
|
||||
int max_buttons = JOY_STEERING;
|
||||
switch(mType) {
|
||||
switch (mType)
|
||||
{
|
||||
case WT_BUZZ_CONTROLLER:
|
||||
LoadBuzzMappings(mDevType, mPort, device.name, device.cfg);
|
||||
max_buttons = 20;
|
||||
|
@ -602,16 +674,20 @@ int EvDevPad::Open()
|
|||
|
||||
// Map hatswitches automatically
|
||||
//FIXME has_mappings is gonna ignore hatsw only devices
|
||||
for (int i = ABS_HAT0X; i <= ABS_HAT3Y; ++i) {
|
||||
for (int i = ABS_HAT0X; i <= ABS_HAT3Y; ++i)
|
||||
{
|
||||
device.axis_map[i] = i;
|
||||
}
|
||||
|
||||
// SDL2
|
||||
for (int i = 0; i < ABS_MAX; ++i) {
|
||||
if (test_bit(i, absbit)) {
|
||||
for (int i = 0; i < ABS_MAX; ++i)
|
||||
{
|
||||
if (test_bit(i, absbit))
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
|
||||
if (ioctl(device.cfg.fd, EVIOCGABS(i), &absinfo) < 0) {
|
||||
if (ioctl(device.cfg.fd, EVIOCGABS(i), &absinfo) < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -623,7 +699,8 @@ int EvDevPad::Open()
|
|||
CalcAxisCorr(device.abs_correct[i], absinfo);
|
||||
|
||||
//TODO joystick/gamepad is dual analog?
|
||||
if (i == ABS_RZ) {
|
||||
if (i == ABS_RZ)
|
||||
{
|
||||
//absinfo.value = AxisCorrect(mAbsCorrect[i], absinfo.value);
|
||||
if (std::abs(absinfo.value) < 200) /* 200 is random, allows for some dead zone */
|
||||
device.is_dualanalog = true;
|
||||
|
@ -632,7 +709,8 @@ int EvDevPad::Open()
|
|||
// FIXME axes as buttons
|
||||
for (int k = max_buttons /*JOY_STEERING*/; k < JOY_MAPS_COUNT; k++)
|
||||
{
|
||||
if (i == device.cfg.controls[k]) {
|
||||
if (i == device.cfg.controls[k])
|
||||
{
|
||||
has_mappings = true;
|
||||
device.axis_map[i] = 0x80 | k;
|
||||
// TODO Instead of single FF instance, create for every device with X-axis???
|
||||
|
@ -645,22 +723,28 @@ int EvDevPad::Open()
|
|||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
for(int i = 0; i < ABS_MAX; ++i) {
|
||||
for (int i = 0; i < ABS_MAX; ++i)
|
||||
{
|
||||
if (device.axis_map[i] != (uint8_t)-1 && (device.axis_map[i] & 0x80))
|
||||
OSDebugOut("Axis: 0x%02x -> %s\n", i, JoystickMapNames[device.axis_map[i] & ~0x80]);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
|
||||
if (test_bit(i, keybit)) {
|
||||
for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i)
|
||||
{
|
||||
if (test_bit(i, keybit))
|
||||
{
|
||||
//OSDebugOut("Device has button: 0x%x\n", i);
|
||||
device.btn_map[i] = -1; //device.buttons;
|
||||
if (i == BTN_GAMEPAD) {
|
||||
if (i == BTN_GAMEPAD)
|
||||
{
|
||||
device.is_gamepad = true;
|
||||
OSDebugOut("Device is a gamepad\n");
|
||||
}
|
||||
for (int k = 0; k < max_buttons; k++) {
|
||||
if (i == device.cfg.controls[k]) {
|
||||
for (int k = 0; k < max_buttons; k++)
|
||||
{
|
||||
if (i == device.cfg.controls[k])
|
||||
{
|
||||
has_mappings = true;
|
||||
device.btn_map[i] = 0x8000 | k;
|
||||
OSDebugOut("Remap button: 0x%x -> %s\n", i, JoystickMapNames[k]);
|
||||
|
@ -668,19 +752,24 @@ int EvDevPad::Open()
|
|||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < BTN_JOYSTICK; ++i) {
|
||||
if (test_bit(i, keybit)) {
|
||||
for (int i = 0; i < BTN_JOYSTICK; ++i)
|
||||
{
|
||||
if (test_bit(i, keybit))
|
||||
{
|
||||
OSDebugOut("Device has button: 0x%x\n", i);
|
||||
device.btn_map[i] = -1; //device.buttons;
|
||||
for (int k = 0; k < max_buttons; k++) {
|
||||
if (i == device.cfg.controls[k]) {
|
||||
for (int k = 0; k < max_buttons; k++)
|
||||
{
|
||||
if (i == device.cfg.controls[k])
|
||||
{
|
||||
has_mappings = true;
|
||||
device.btn_map[i] = 0x8000 | k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_mappings) {
|
||||
if (!has_mappings)
|
||||
{
|
||||
OSDebugOut("Device %s [%s] has no mappings, discarding\n", device.name.c_str(), ""); //it.second.c_str());
|
||||
close(device.cfg.fd);
|
||||
mDevices.pop_back();
|
||||
|
@ -699,7 +788,8 @@ int EvDevPad::Close()
|
|||
delete mFFdev;
|
||||
mFFdev = nullptr;
|
||||
|
||||
if (mHidHandle != -1) {
|
||||
if (mHidHandle != -1)
|
||||
{
|
||||
uint8_t reset[7] = {0};
|
||||
reset[0] = 0xF3; //stop forces
|
||||
write(mHidHandle, reset, sizeof(reset));
|
||||
|
@ -707,7 +797,8 @@ int EvDevPad::Close()
|
|||
}
|
||||
|
||||
mHidHandle = -1;
|
||||
for (auto& it : mDevices) {
|
||||
for (auto& it : mDevices)
|
||||
{
|
||||
close(it.cfg.fd);
|
||||
it.cfg.fd = -1;
|
||||
}
|
||||
|
@ -728,11 +819,14 @@ void EvDevPad::WriterThread(void *ptr)
|
|||
if (pad->mFFData.try_dequeue(buf))
|
||||
{
|
||||
res = write(pad->mHidHandle, buf.data(), buf.size());
|
||||
if (res < 0) {
|
||||
if (res < 0)
|
||||
{
|
||||
printf("Error: %d\n", errno);
|
||||
perror("write");
|
||||
}
|
||||
} else { // TODO skip sleep for few while cycles?
|
||||
}
|
||||
else
|
||||
{ // TODO skip sleep for few while cycles?
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
@ -741,4 +835,5 @@ void EvDevPad::WriterThread(void *ptr)
|
|||
pad->mWriterThreadIsRunning = false;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -23,7 +23,10 @@
|
|||
#include "shared.h"
|
||||
#include "../../readerwriterqueue/readerwriterqueue.h"
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
|
||||
|
@ -36,7 +39,8 @@ static const char* APINAME = "evdev";
|
|||
class EvDevPad : public Pad
|
||||
{
|
||||
public:
|
||||
EvDevPad(int port, const char* dev_type): Pad(port, dev_type)
|
||||
EvDevPad(int port, const char* dev_type)
|
||||
: Pad(port, dev_type)
|
||||
, mUseRawFF(0)
|
||||
, mHidHandle(-1)
|
||||
, mWriterThreadIsRunning(false)
|
||||
|
@ -56,6 +60,7 @@ public:
|
|||
}
|
||||
|
||||
static int Configure(int port, const char* dev_type, void* data);
|
||||
|
||||
protected:
|
||||
void PollAxesValues(const device_data& device);
|
||||
void SetAxis(const device_data& device, int code, int value);
|
||||
|
@ -97,19 +102,25 @@ static void CalcAxisCorr(axis_correct& abs_correct, struct input_absinfo absinfo
|
|||
{
|
||||
int t;
|
||||
// convert values into 16 bit range
|
||||
if (absinfo.minimum == absinfo.maximum) {
|
||||
if (absinfo.minimum == absinfo.maximum)
|
||||
{
|
||||
abs_correct.used = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_correct.used = 1;
|
||||
abs_correct.coef[0] =
|
||||
(absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
|
||||
abs_correct.coef[1] =
|
||||
(absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
|
||||
t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
|
||||
if (t != 0) {
|
||||
if (t != 0)
|
||||
{
|
||||
abs_correct.coef[2] =
|
||||
(1 << 28) / t;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_correct.coef[2] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -119,14 +130,19 @@ static void CalcAxisCorr(axis_correct& abs_correct, struct input_absinfo absinfo
|
|||
// convert values into 16 bit range
|
||||
static int AxisCorrect(const axis_correct& correct, int value)
|
||||
{
|
||||
if (correct.used) {
|
||||
if (correct.used)
|
||||
{
|
||||
value *= 2;
|
||||
if (value > correct.coef[0]) {
|
||||
if (value < correct.coef[1]) {
|
||||
if (value > correct.coef[0])
|
||||
{
|
||||
if (value < correct.coef[1])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
value -= correct.coef[1];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
value -= correct.coef[0];
|
||||
}
|
||||
value *= correct.coef[2];
|
||||
|
@ -142,4 +158,5 @@ static int AxisCorrect(const axis_correct& correct, int value)
|
|||
return value;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
using sys_clock = std::chrono::system_clock;
|
||||
using ms = std::chrono::milliseconds;
|
||||
|
@ -55,7 +58,8 @@ bool LoadMappings(const char *dev_type, int port, const std::string& joyname, Co
|
|||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "inverted_" << JoystickMapNames[JOY_STEERING + i];
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
|
@ -63,7 +67,8 @@ bool LoadMappings(const char *dev_type, int port, const std::string& joyname, Co
|
|||
cfg.inverted[i] = 0;
|
||||
}
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "initial_" << JoystickMapNames[JOY_STEERING + i];
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
|
@ -93,7 +98,8 @@ bool SaveMappings(const char *dev_type, int port, const std::string& joyname, co
|
|||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "inverted_" << JoystickMapNames[JOY_STEERING + i];
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
|
@ -101,7 +107,8 @@ bool SaveMappings(const char *dev_type, int port, const std::string& joyname, co
|
|||
return false;
|
||||
}
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "initial_" << JoystickMapNames[JOY_STEERING + i];
|
||||
{
|
||||
const std::string& name = str.str();
|
||||
|
@ -175,7 +182,8 @@ static void refresh_store(ConfigData *cfg)
|
|||
|
||||
gtk_list_store_append(cfg->store, &iter);
|
||||
|
||||
if (!strcmp(cfg->dev_type, BuzzDevice::TypeName())) {
|
||||
if (!strcmp(cfg->dev_type, BuzzDevice::TypeName()))
|
||||
{
|
||||
|
||||
std::stringstream ss;
|
||||
ss << (1 + i / countof(buzz_map_names));
|
||||
|
@ -191,7 +199,9 @@ static void refresh_store(ConfigData *cfg)
|
|||
COL_COLUMN_WIDTH, 50,
|
||||
COL_BINDING, i,
|
||||
-1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_list_store_set(cfg->store, &iter,
|
||||
COL_NAME, it.first.c_str(),
|
||||
COL_PS2, JoystickMapNames[i],
|
||||
|
@ -213,7 +223,8 @@ static void joystick_changed (GtkComboBox *widget, gpointer data)
|
|||
if (!cfg)
|
||||
return;
|
||||
|
||||
if (idx > -1) {
|
||||
if (idx > -1)
|
||||
{
|
||||
std::string name = (cfg->joysticks.begin() + idx)->first;
|
||||
cfg->js_iter = (cfg->joysticks.begin() + idx);
|
||||
OSDebugOut("Selected player %d idx: %d dev: '%s'\n", 2 - port, idx, name.c_str());
|
||||
|
@ -250,7 +261,8 @@ static void button_clicked (GtkComboBox *widget, gpointer data)
|
|||
if (it != cfg->jsconf.end() && type < it->second.controls.size())
|
||||
{
|
||||
it->second.controls[type] = value;
|
||||
if (is_axis) {
|
||||
if (is_axis)
|
||||
{
|
||||
it->second.inverted[type - JOY_STEERING] = inverted;
|
||||
it->second.initial[type - JOY_STEERING] = initial;
|
||||
}
|
||||
|
@ -324,7 +336,8 @@ static void view_remove_binding (GtkTreeModel *model,
|
|||
[&dev_name](auto i) {
|
||||
return i.first == dev_name;
|
||||
});
|
||||
if (it != js.end()) {
|
||||
if (it != js.end())
|
||||
{
|
||||
it->second.controls[binding] = (uint16_t)-1;
|
||||
OSDebugOut("Delete binding '%d' for '%s'\n", binding, it->first.c_str());
|
||||
}
|
||||
|
@ -354,7 +367,8 @@ static void clear_binding_clicked (GtkWidget *widget, gpointer data)
|
|||
|
||||
GList* list = gtk_tree_selection_get_selected_rows(sel, &model);
|
||||
// remove rows from store pointed to by row references
|
||||
for (node = g_list_first(rr_list); node != nullptr; node = node->next) {
|
||||
for (node = g_list_first(rr_list); node != nullptr; node = node->next)
|
||||
{
|
||||
GtkTreePath* path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)node->data);
|
||||
if (path)
|
||||
{
|
||||
|
@ -384,7 +398,8 @@ static void hidraw_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) {
|
||||
if (cfg)
|
||||
{
|
||||
cfg->use_hidraw_ff_pt = (bool)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
||||
}
|
||||
}
|
||||
|
@ -407,14 +422,16 @@ int GtkPadConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
cfg.cb = &apicbs;
|
||||
cfg.dev_type = dev_type;
|
||||
|
||||
for (const auto& it: cfg.joysticks) {
|
||||
for (const auto& it : cfg.joysticks)
|
||||
{
|
||||
if ((fd = open(it.second.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
||||
{
|
||||
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigMapping c; c.fd = fd;
|
||||
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());
|
||||
|
@ -509,10 +526,20 @@ int GtkPadConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
GtkAttachOptions opt = (GtkAttachOptions)(GTK_FILL);
|
||||
|
||||
const char* button_labels[] = {
|
||||
"L2", "L1 / L", "R2", "R1 / R / Orange",
|
||||
"Left", "Up", "Right", "Down",
|
||||
"Square / X / Green", "Cross / A / Blue", "Circle / B / Red", "Triangle / Y / Yellow",
|
||||
"Select", "Start",
|
||||
"L2",
|
||||
"L1 / L",
|
||||
"R2",
|
||||
"R1 / R / Orange",
|
||||
"Left",
|
||||
"Up",
|
||||
"Right",
|
||||
"Down",
|
||||
"Square / X / Green",
|
||||
"Cross / A / Blue",
|
||||
"Circle / B / Red",
|
||||
"Triangle / Y / Yellow",
|
||||
"Select",
|
||||
"Start",
|
||||
};
|
||||
|
||||
const Point button_pos[] = {
|
||||
|
@ -611,7 +638,8 @@ int GtkPadConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
int ret = RESULT_OK;
|
||||
if (result == GTK_RESPONSE_OK)
|
||||
{
|
||||
if (cfg.js_iter != cfg.joysticks.end()) {
|
||||
if (cfg.js_iter != cfg.joysticks.end())
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->second))
|
||||
ret = RESULT_FAILED;
|
||||
}
|
||||
|
@ -619,7 +647,8 @@ int GtkPadConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
for (auto& it : cfg.jsconf)
|
||||
SaveMappings(dev_type, port, it.first, it.second);
|
||||
|
||||
if (is_evdev) {
|
||||
if (is_evdev)
|
||||
{
|
||||
SaveSetting(dev_type, port, apiname, N_HIDRAW_FF_PT, cfg.use_hidraw_ff_pt);
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +667,8 @@ GtkWidget * make_color_icon(uint32_t rgb)
|
|||
GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 24, 24);
|
||||
guchar* data = gdk_pixbuf_get_pixels(pixbuf);
|
||||
|
||||
for (size_t i=0; i<24*24; i++) {
|
||||
for (size_t i = 0; i < 24 * 24; i++)
|
||||
{
|
||||
data[i * 4 + 0] = rgb & 0xFF;
|
||||
data[i * 4 + 1] = (rgb >> 8) & 0xFF;
|
||||
data[i * 4 + 2] = (rgb >> 16) & 0xFF;
|
||||
|
@ -667,14 +697,16 @@ int GtkBuzzConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
cfg.cb = &apicbs;
|
||||
cfg.dev_type = dev_type;
|
||||
|
||||
for (const auto& it: cfg.joysticks) {
|
||||
for (const auto& it : cfg.joysticks)
|
||||
{
|
||||
if ((fd = open(it.second.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
||||
{
|
||||
OSDebugOut("Cannot open device: %s\n", it.second.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigMapping c; c.fd = fd;
|
||||
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());
|
||||
|
@ -779,7 +811,8 @@ int GtkBuzzConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
0x00FFFF,
|
||||
};
|
||||
|
||||
for (int j=0; j < 4; j++) {
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
for (int i = 0; i < countof(button_labels); i++)
|
||||
{
|
||||
GtkWidget* button = gtk_button_new_with_label(button_labels[i]);
|
||||
|
@ -817,7 +850,6 @@ int GtkBuzzConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
2, 3, 0, 1, opt, opt, 5, 1);
|
||||
gtk_table_attach(GTK_TABLE(table), gtk_label_new("Player 4"),
|
||||
3, 4, 0, 1, opt, opt, 5, 1);
|
||||
|
||||
}
|
||||
|
||||
GtkWidget* hbox = gtk_hbox_new(false, 5);
|
||||
|
@ -833,14 +865,14 @@ int GtkBuzzConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
int ret = RESULT_OK;
|
||||
if (result == GTK_RESPONSE_OK)
|
||||
{
|
||||
if (cfg.js_iter != cfg.joysticks.end()) {
|
||||
if (cfg.js_iter != cfg.joysticks.end())
|
||||
{
|
||||
if (!SaveSetting(dev_type, port, apiname, N_JOYSTICK, cfg.js_iter->second))
|
||||
ret = RESULT_FAILED;
|
||||
}
|
||||
|
||||
for (auto& it : cfg.jsconf)
|
||||
SaveBuzzMappings(dev_type, port, it.first, it.second);
|
||||
|
||||
}
|
||||
else
|
||||
ret = RESULT_CANCELED;
|
||||
|
@ -852,4 +884,5 @@ int GtkBuzzConfigure(int port, const char* dev_type, const char *apititle, const
|
|||
return ret;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
typedef std::vector<std::pair<std::string, std::string>> vstring;
|
||||
GtkWidget* new_combobox(const char* label, GtkWidget* vbox);
|
||||
|
||||
namespace usb_pad { namespace evdev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace evdev
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -50,7 +53,8 @@ enum JoystickMap
|
|||
JOY_L2,
|
||||
JOY_SELECT,
|
||||
JOY_START,
|
||||
JOY_R3, JOY_L3, //order, afaik not used on any PS2 wheel anyway
|
||||
JOY_R3,
|
||||
JOY_L3, //order, afaik not used on any PS2 wheel anyway
|
||||
JOY_DOWN,
|
||||
JOY_LEFT,
|
||||
JOY_UP,
|
||||
|
@ -80,8 +84,7 @@ static const char* JoystickMapNames [] = {
|
|||
"right",
|
||||
"steering",
|
||||
"throttle",
|
||||
"brake"
|
||||
};
|
||||
"brake"};
|
||||
|
||||
static const char* buzz_map_names[] = {
|
||||
"red",
|
||||
|
@ -91,7 +94,12 @@ static const char* buzz_map_names[] = {
|
|||
"blue",
|
||||
};
|
||||
|
||||
struct Point { int x; int y; JoystickMap type; };
|
||||
struct Point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
JoystickMap type;
|
||||
};
|
||||
|
||||
struct ConfigMapping
|
||||
{
|
||||
|
@ -137,7 +145,6 @@ struct device_data
|
|||
bool is_gamepad; //xboxish gamepad
|
||||
bool is_dualanalog; // tricky, have to read the AXIS_RZ somehow and
|
||||
// determine if its unpressed value is zero
|
||||
|
||||
};
|
||||
|
||||
int GtkPadConfigure(int port, const char* dev_type, const char* title, const char* apiname, GtkWindow* parent, ApiCallbacks& apicbs);
|
||||
|
@ -146,4 +153,5 @@ bool LoadMappings(const char *dev_type, int port, const std::string& joyname, Co
|
|||
bool SaveMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg);
|
||||
bool LoadBuzzMappings(const char* dev_type, int port, const std::string& joyname, ConfigMapping& cfg);
|
||||
bool SaveBuzzMappings(const char* dev_type, int port, const std::string& joyname, const ConfigMapping& cfg);
|
||||
}} //namespace
|
||||
} // namespace evdev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -22,7 +22,10 @@
|
|||
#include <sstream>
|
||||
#include "../../gtk.h"
|
||||
|
||||
namespace usb_pad { namespace joydev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace joydev
|
||||
{
|
||||
|
||||
using sys_clock = std::chrono::system_clock;
|
||||
using ms = std::chrono::milliseconds;
|
||||
|
@ -33,9 +36,12 @@ using ms = std::chrono::milliseconds;
|
|||
static bool GetEventName(const char* dev_type, int map, int event, const char** name)
|
||||
{
|
||||
static char buf[256] = {0};
|
||||
if (map < evdev::JOY_STEERING) {
|
||||
if (map < evdev::JOY_STEERING)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "Button %d", event);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// assuming that PS2 axes are always mapped to PC axes
|
||||
snprintf(buf, sizeof(buf), "Axis %d", event);
|
||||
}
|
||||
|
@ -53,34 +59,45 @@ static bool PollInput(const std::vector<std::pair<std::string, usb_pad::evdev::C
|
|||
int maxfd = -1;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
for (const auto& js: fds) {
|
||||
for (const auto& js : fds)
|
||||
{
|
||||
FD_SET(js.second.fd, &fdset);
|
||||
if (maxfd < js.second.fd) maxfd = js.second.fd;
|
||||
if (maxfd < js.second.fd)
|
||||
maxfd = js.second.fd;
|
||||
}
|
||||
|
||||
inverted = false;
|
||||
|
||||
// empty event queues
|
||||
for (const auto& js : fds)
|
||||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0);
|
||||
while ((len = read(js.second.fd, &event, sizeof(event))) > 0)
|
||||
;
|
||||
|
||||
struct axis_value { int16_t value; bool initial; };
|
||||
struct axis_value
|
||||
{
|
||||
int16_t value;
|
||||
bool initial;
|
||||
};
|
||||
axis_value axisVal[ABS_MAX + 1] = {0};
|
||||
|
||||
struct timeval timeout {};
|
||||
struct timeval timeout
|
||||
{
|
||||
};
|
||||
timeout.tv_sec = 5;
|
||||
int result = select(maxfd + 1, &fdset, NULL, NULL, &timeout);
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
if (result == -1) {
|
||||
if (result == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& js : fds)
|
||||
{
|
||||
if (FD_ISSET(js.second.fd, &fdset)) {
|
||||
if (FD_ISSET(js.second.fd, &fdset))
|
||||
{
|
||||
event_fd = js.second.fd;
|
||||
dev_name = js.first;
|
||||
break;
|
||||
|
@ -95,7 +112,8 @@ static bool PollInput(const std::vector<std::pair<std::string, usb_pad::evdev::C
|
|||
while (true)
|
||||
{
|
||||
auto dur = std::chrono::duration_cast<ms>(sys_clock::now() - last).count();
|
||||
if (dur > 5000) goto error;
|
||||
if (dur > 5000)
|
||||
goto error;
|
||||
|
||||
if ((len = read(event_fd, &event, sizeof(event))) > -1 && (len == sizeof(event)))
|
||||
{
|
||||
|
@ -112,7 +130,8 @@ static bool PollInput(const std::vector<std::pair<std::string, usb_pad::evdev::C
|
|||
{
|
||||
int diff = event.value - val.value;
|
||||
OSDebugOut("Axis %d value: %d, difference: %d\n", event.number, event.value, diff);
|
||||
if (std::abs(diff) > 2047) {
|
||||
if (std::abs(diff) > 2047)
|
||||
{
|
||||
value = event.number;
|
||||
inverted = (diff < 0);
|
||||
initial = val.value;
|
||||
|
@ -158,4 +177,5 @@ int JoyDevPad::Configure(int port, const char* dev_type, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace joydev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
#include <sstream>
|
||||
#include "../../linux/util.h"
|
||||
|
||||
namespace usb_pad { namespace joydev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace joydev
|
||||
{
|
||||
|
||||
using namespace evdev;
|
||||
|
||||
|
@ -36,22 +39,26 @@ void EnumerateDevices(vstring& list)
|
|||
struct dirent* dp;
|
||||
|
||||
DIR* dirp = opendir("/dev/input/");
|
||||
if (!dirp) {
|
||||
if (!dirp)
|
||||
{
|
||||
perror("Error opening /dev/input/");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp)))
|
||||
{
|
||||
if (strncmp(dp->d_name, "js", 2) == 0) {
|
||||
if (strncmp(dp->d_name, "js", 2) == 0)
|
||||
{
|
||||
OSDebugOut("%s\n", dp->d_name);
|
||||
|
||||
str.clear(); str.str("");
|
||||
str.clear();
|
||||
str.str("");
|
||||
str << "/dev/input/" << dp->d_name;
|
||||
const std::string& path = str.str();
|
||||
fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
|
||||
if (fd < 0) {
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("Unable to open device");
|
||||
continue;
|
||||
}
|
||||
|
@ -84,22 +91,26 @@ int JoyDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
FD_ZERO(&fds);
|
||||
maxfd = -1;
|
||||
|
||||
for (auto& device: mDevices) {
|
||||
for (auto& device : mDevices)
|
||||
{
|
||||
FD_SET(device.cfg.fd, &fds);
|
||||
if (maxfd < device.cfg.fd) maxfd = device.cfg.fd;
|
||||
if (maxfd < device.cfg.fd)
|
||||
maxfd = device.cfg.fd;
|
||||
}
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_usec = timeout.tv_sec = 0; // 0 - return from select immediately
|
||||
int result = select(maxfd + 1, &fds, NULL, NULL, &timeout);
|
||||
|
||||
if (result <= 0) {
|
||||
if (result <= 0)
|
||||
{
|
||||
return USB_RET_NAK; // If no new data, NAK it
|
||||
}
|
||||
|
||||
for (auto& device : mDevices)
|
||||
{
|
||||
if (!FD_ISSET(device.cfg.fd, &fds)) {
|
||||
if (!FD_ISSET(device.cfg.fd, &fds))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -117,8 +128,12 @@ int JoyDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
switch (device.axis_map[event.number])
|
||||
{
|
||||
case 0x80 | JOY_STEERING:
|
||||
case ABS_X: mWheelData.steering = device.cfg.inverted[0] ? range - NORM(event.value, range) : NORM(event.value, range); break;
|
||||
case ABS_Y: mWheelData.clutch = NORM(event.value, 0xFF); break;
|
||||
case ABS_X:
|
||||
mWheelData.steering = device.cfg.inverted[0] ? range - NORM(event.value, range) : NORM(event.value, range);
|
||||
break;
|
||||
case ABS_Y:
|
||||
mWheelData.clutch = NORM(event.value, 0xFF);
|
||||
break;
|
||||
//case ABS_RX: mWheelData.axis_rx = NORM(event.value, 0xFF); break;
|
||||
case ABS_RY:
|
||||
treat_me_like_ABS_RY:
|
||||
|
@ -169,7 +184,8 @@ int JoyDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
else
|
||||
mWheelData.hat_vert = PAD_HAT_COUNT;
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON)
|
||||
|
@ -205,16 +221,36 @@ int JoyDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
case 0x8000 | JOY_DOWN:
|
||||
mWheelData.hat_vert = PAD_HAT_S;
|
||||
break;
|
||||
case BTN_WEST: button = PAD_SQUARE; break;
|
||||
case BTN_NORTH: button = PAD_TRIANGLE; break;
|
||||
case BTN_EAST: button = PAD_CIRCLE; break;
|
||||
case BTN_SOUTH: button = PAD_CROSS; break;
|
||||
case BTN_SELECT: button = PAD_SELECT; break;
|
||||
case BTN_START: button = PAD_START; break;
|
||||
case BTN_TR: button = PAD_R1; break;
|
||||
case BTN_TL: button = PAD_L1; break;
|
||||
case BTN_THUMBR: button = PAD_R2; break;
|
||||
case BTN_THUMBL: button = PAD_L2; break;
|
||||
case BTN_WEST:
|
||||
button = PAD_SQUARE;
|
||||
break;
|
||||
case BTN_NORTH:
|
||||
button = PAD_TRIANGLE;
|
||||
break;
|
||||
case BTN_EAST:
|
||||
button = PAD_CIRCLE;
|
||||
break;
|
||||
case BTN_SOUTH:
|
||||
button = PAD_CROSS;
|
||||
break;
|
||||
case BTN_SELECT:
|
||||
button = PAD_SELECT;
|
||||
break;
|
||||
case BTN_START:
|
||||
button = PAD_START;
|
||||
break;
|
||||
case BTN_TR:
|
||||
button = PAD_R1;
|
||||
break;
|
||||
case BTN_TL:
|
||||
button = PAD_L1;
|
||||
break;
|
||||
case BTN_THUMBR:
|
||||
button = PAD_R2;
|
||||
break;
|
||||
case BTN_THUMBL:
|
||||
button = PAD_L2;
|
||||
break;
|
||||
default:
|
||||
OSDebugOut("Unmapped Button: %d, %d\n", event.number, event.value);
|
||||
break;
|
||||
|
@ -244,17 +280,29 @@ int JoyDevPad::TokenIn(uint8_t *buf, int buflen)
|
|||
case PAD_HAT_N:
|
||||
switch (mWheelData.hat_horz)
|
||||
{
|
||||
case PAD_HAT_W: mWheelData.hatswitch = PAD_HAT_NW; break;
|
||||
case PAD_HAT_E: mWheelData.hatswitch = PAD_HAT_NE; break;
|
||||
default: mWheelData.hatswitch = PAD_HAT_N; break;
|
||||
case PAD_HAT_W:
|
||||
mWheelData.hatswitch = PAD_HAT_NW;
|
||||
break;
|
||||
case PAD_HAT_E:
|
||||
mWheelData.hatswitch = PAD_HAT_NE;
|
||||
break;
|
||||
default:
|
||||
mWheelData.hatswitch = PAD_HAT_N;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PAD_HAT_S:
|
||||
switch (mWheelData.hat_horz)
|
||||
{
|
||||
case PAD_HAT_W: mWheelData.hatswitch = PAD_HAT_SW; break;
|
||||
case PAD_HAT_E: mWheelData.hatswitch = PAD_HAT_SE; break;
|
||||
default: mWheelData.hatswitch = PAD_HAT_S; break;
|
||||
case PAD_HAT_W:
|
||||
mWheelData.hatswitch = PAD_HAT_SW;
|
||||
break;
|
||||
case PAD_HAT_E:
|
||||
mWheelData.hatswitch = PAD_HAT_SE;
|
||||
break;
|
||||
default:
|
||||
mWheelData.hatswitch = PAD_HAT_S;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -342,13 +390,17 @@ int JoyDevPad::Open()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(device.cfg.fd, JSIOCGAXES, &(count)) >= 0) {
|
||||
if (ioctl(device.cfg.fd, JSIOCGAXES, &(count)) >= 0)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
OSDebugOut("Axis: %d -> %d\n", i, device.axis_map[i]);
|
||||
|
||||
for (int k = 0; k < count; k++) {
|
||||
for (int i = JOY_STEERING; i < JOY_MAPS_COUNT; i++) {
|
||||
if (k == device.cfg.controls[i]) {
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
for (int i = JOY_STEERING; i < JOY_MAPS_COUNT; i++)
|
||||
{
|
||||
if (k == device.cfg.controls[i])
|
||||
{
|
||||
device.axis_map[k] = 0x80 | i;
|
||||
if (i == JOY_STEERING)
|
||||
has_steering = true;
|
||||
|
@ -366,7 +418,8 @@ int JoyDevPad::Open()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(device.cfg.fd, JSIOCGBUTTONS, &(count)) >= 0) {
|
||||
if (ioctl(device.cfg.fd, JSIOCGBUTTONS, &(count)) >= 0)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
OSDebugOut("Button: %d -> %d BTN_[GAMEPAD|SOUTH]: %d\n", i, device.btn_map[i], device.btn_map[i] == BTN_GAMEPAD);
|
||||
|
@ -375,8 +428,10 @@ int JoyDevPad::Open()
|
|||
}
|
||||
|
||||
if (!device.is_gamepad) //TODO Don't remap if gamepad?
|
||||
for (int k = 0; k < count; k++) {
|
||||
for (int i = 0; i < JOY_STEERING; i++) {
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
for (int i = 0; i < JOY_STEERING; i++)
|
||||
{
|
||||
if (k == device.cfg.controls[i])
|
||||
device.btn_map[k] = 0x8000 | i;
|
||||
}
|
||||
|
@ -396,18 +451,22 @@ int JoyDevPad::Open()
|
|||
//TODO kernel limit is 32?
|
||||
for (int j = 0; j <= 99; j++)
|
||||
{
|
||||
event.clear(); event.str(std::string());
|
||||
event.clear();
|
||||
event.str(std::string());
|
||||
/* Try to discover the corresponding event number */
|
||||
event << "/sys/class/input/js" << index << "/device/event" << j;
|
||||
if (dir_exists(event.str())){
|
||||
if (dir_exists(event.str()))
|
||||
{
|
||||
|
||||
event.clear(); event.str(std::string());
|
||||
event.clear();
|
||||
event.str(std::string());
|
||||
event << "/dev/input/event" << j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mFFdev && has_steering) {
|
||||
if (!mFFdev && has_steering)
|
||||
{
|
||||
if ((mHandleFF = open(event.str().c_str(), /*O_WRONLY*/ O_RDWR)) < 0)
|
||||
{
|
||||
OSDebugOut("%s: Cannot open '%s'\n", APINAME, event.str().c_str());
|
||||
|
@ -433,11 +492,13 @@ int JoyDevPad::Close()
|
|||
close(mHandleFF);
|
||||
|
||||
mHandleFF = -1;
|
||||
for (auto& it : mDevices) {
|
||||
for (auto& it : mDevices)
|
||||
{
|
||||
close(it.cfg.fd);
|
||||
it.cfg.fd = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace joydev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include "../evdev/evdev-ff.h"
|
||||
#include "../evdev/shared.h"
|
||||
|
||||
namespace usb_pad { namespace joydev {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace joydev
|
||||
{
|
||||
|
||||
void EnumerateDevices(vstring& list);
|
||||
|
||||
|
@ -27,7 +30,8 @@ static const char *APINAME = "joydev";
|
|||
class JoyDevPad : public Pad
|
||||
{
|
||||
public:
|
||||
JoyDevPad(int port, const char* dev_type): Pad(port, dev_type)
|
||||
JoyDevPad(int port, const char* dev_type)
|
||||
: Pad(port, dev_type)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,6 +48,7 @@ public:
|
|||
}
|
||||
|
||||
static int Configure(int port, const char* dev_type, void* data);
|
||||
|
||||
protected:
|
||||
int mHandleFF;
|
||||
struct wheel_data_t mWheelData;
|
||||
|
@ -72,4 +77,5 @@ bool GetJoystickName(const std::string& path, char (&name)[_Size])
|
|||
return false;
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace joydev
|
||||
} // namespace usb_pad
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
#include "lg_ff.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
unsigned char num;
|
||||
unsigned char den;
|
||||
} s_coef;
|
||||
|
@ -18,18 +19,25 @@ typedef struct {
|
|||
*
|
||||
* \return the force coefficient
|
||||
*/
|
||||
static s_coef ff_lg_get_force_coefficient(uint8_t caps, unsigned char k) {
|
||||
static s_coef ff_lg_get_force_coefficient(uint8_t caps, unsigned char k)
|
||||
{
|
||||
|
||||
s_coef coef;
|
||||
|
||||
if (caps & FF_LG_CAPS_HIGH_RES_COEF) {
|
||||
if (caps & FF_LG_CAPS_HIGH_RES_COEF)
|
||||
{
|
||||
coef.num = k;
|
||||
coef.den = 0x0F;
|
||||
} else {
|
||||
if (caps & FF_LG_CAPS_OLD_LOW_RES_COEF) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (caps & FF_LG_CAPS_OLD_LOW_RES_COEF)
|
||||
{
|
||||
static const s_coef old_coefs[] = {{1, 16}, {1, 8}, {3, 16}, {1, 4}, {3, 8}, {3, 4}, {2, 4}, {4, 4}};
|
||||
coef = old_coefs[k];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
static const s_coef coefs[] = {{1, 16}, {1, 8}, {3, 16}, {1, 4}, {3, 8}, {2, 4}, {3, 4}, {4, 4}};
|
||||
coef = coefs[k];
|
||||
}
|
||||
|
@ -37,30 +45,39 @@ static s_coef ff_lg_get_force_coefficient(uint8_t caps, unsigned char k) {
|
|||
return coef;
|
||||
}
|
||||
|
||||
int16_t ff_lg_get_condition_coef(uint8_t caps, unsigned char k, unsigned char s, int16_t max /*= SHRT_MAX*/) {
|
||||
int16_t ff_lg_get_condition_coef(uint8_t caps, unsigned char k, unsigned char s, int16_t max /*= SHRT_MAX*/)
|
||||
{
|
||||
|
||||
s_coef coef = ff_lg_get_force_coefficient(caps, k);
|
||||
int value = (s ? -max : max) * coef.num / coef.den;
|
||||
return value;
|
||||
}
|
||||
|
||||
uint16_t ff_lg_get_spring_deadband(uint8_t caps, unsigned char d, unsigned char dL, uint16_t max /*= USHRT_MAX*/) {
|
||||
uint16_t ff_lg_get_spring_deadband(uint8_t caps, unsigned char d, unsigned char dL, uint16_t max /*= USHRT_MAX*/)
|
||||
{
|
||||
|
||||
uint16_t deadband;
|
||||
if (caps & FF_LG_CAPS_HIGH_RES_DEADBAND) {
|
||||
if (caps & FF_LG_CAPS_HIGH_RES_DEADBAND)
|
||||
{
|
||||
deadband = ((d << 3) | dL) * max / 0x7FF;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
deadband = d * max / UCHAR_MAX;
|
||||
}
|
||||
return deadband;
|
||||
}
|
||||
|
||||
uint16_t ff_lg_get_damper_clip(uint8_t caps, unsigned char c) {
|
||||
uint16_t ff_lg_get_damper_clip(uint8_t caps, unsigned char c)
|
||||
{
|
||||
|
||||
uint16_t clip;
|
||||
if (caps & FF_LG_CAPS_DAMPER_CLIP) {
|
||||
if (caps & FF_LG_CAPS_DAMPER_CLIP)
|
||||
{
|
||||
clip = c * USHRT_MAX / UCHAR_MAX;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
clip = USHRT_MAX;
|
||||
}
|
||||
return clip;
|
||||
|
|
|
@ -18,23 +18,28 @@
|
|||
*
|
||||
* input values 127 and 128 are center positions and are translated to output value 0
|
||||
*/
|
||||
static inline int16_t ff_lg_u8_to_s16(uint8_t c, int16_t max = SHRT_MAX) {
|
||||
static inline int16_t ff_lg_u8_to_s16(uint8_t c, int16_t max = SHRT_MAX)
|
||||
{
|
||||
// 127 and 128 are center positions
|
||||
if (c < 128) {
|
||||
if (c < 128)
|
||||
{
|
||||
++c;
|
||||
}
|
||||
int value = (c - 128) * max / 127;
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint16_t ff_lg_u8_to_u16(uint8_t c, uint16_t max = USHRT_MAX) {
|
||||
static inline uint16_t ff_lg_u8_to_u16(uint8_t c, uint16_t max = USHRT_MAX)
|
||||
{
|
||||
return c * max / UCHAR_MAX;
|
||||
}
|
||||
|
||||
static inline int16_t ff_lg_u16_to_s16(uint16_t s) {
|
||||
static inline int16_t ff_lg_u16_to_s16(uint16_t s)
|
||||
{
|
||||
// 32767 and 32768 are center positions
|
||||
int value = s - 32768;
|
||||
if (value < 0) {
|
||||
if (value < 0)
|
||||
{
|
||||
++value;
|
||||
}
|
||||
return value;
|
||||
|
|
|
@ -25,12 +25,16 @@
|
|||
#include "../helpers.h"
|
||||
#include "../deviceproxy.h"
|
||||
|
||||
namespace usb_pad {
|
||||
namespace usb_pad
|
||||
{
|
||||
|
||||
class PadError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
PadError(const char* msg) : std::runtime_error(msg) {}
|
||||
PadError(const char* msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~PadError() {}
|
||||
};
|
||||
|
||||
|
@ -80,5 +84,5 @@ class RegisterPad : public RegisterProxy<PadProxyBase>
|
|||
static void Register();
|
||||
};
|
||||
|
||||
} //namespace
|
||||
} // namespace usb_pad
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
extern HINSTANCE hInst;
|
||||
#define MSG_PRESS_ESC(wnd) SendDlgItemMessageW(wnd, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)L"Capturing, press ESC to cancel")
|
||||
|
||||
namespace usb_pad { namespace raw {
|
||||
namespace usb_pad
|
||||
{
|
||||
namespace raw
|
||||
{
|
||||
|
||||
inline bool MapExists(const MapVector& maps, const std::wstring& hid)
|
||||
{
|
||||
|
@ -51,8 +54,7 @@ void LoadMappings(const char *dev_type, MapVector& maps)
|
|||
std::wstring hid, tmp;
|
||||
//swprintf_s(sec, TEXT("%S RAW DEVICE %d"), dev_type, j++);
|
||||
|
||||
if(LoadSetting(dev_type, j, "RAW DEVICE", _T("HID"), hid)
|
||||
&& !hid.empty() && !MapExists(maps, hid))
|
||||
if (LoadSetting(dev_type, j, "RAW DEVICE", _T("HID"), hid) && !hid.empty() && !MapExists(maps, hid))
|
||||
{
|
||||
Mappings m;
|
||||
ZeroMemory(&m, sizeof(Mappings));
|
||||
|
@ -145,8 +147,7 @@ const char *BTN2TXT[] = {
|
|||
"Select",
|
||||
"Start",
|
||||
"R3",
|
||||
"L3"
|
||||
};
|
||||
"L3"};
|
||||
|
||||
const char* AXIS2TXT[] = {
|
||||
"Axis X",
|
||||
|
@ -155,8 +156,7 @@ const char *AXIS2TXT[] = {
|
|||
//"Axis RX",
|
||||
//"Axis RY",
|
||||
"Axis RZ",
|
||||
"Hat Switch"
|
||||
};
|
||||
"Hat Switch"};
|
||||
|
||||
void resetState(HWND hW);
|
||||
HWND dgHwnd = NULL;
|
||||
|
@ -170,7 +170,8 @@ typedef struct _DevInfo
|
|||
int ply;
|
||||
RID_DEVICE_INFO_HID hid;
|
||||
|
||||
bool operator==(const _DevInfo &t) const{
|
||||
bool operator==(const _DevInfo& t) const
|
||||
{
|
||||
if (ply == t.ply && hid.dwProductId == t.hid.dwProductId &&
|
||||
hid.dwVendorId == t.hid.dwVendorId &&
|
||||
hid.dwVersionNumber == t.hid.dwVersionNumber &&
|
||||
|
@ -180,11 +181,16 @@ typedef struct _DevInfo
|
|||
return false;
|
||||
}
|
||||
|
||||
bool operator<(const _DevInfo &t) const{
|
||||
if(ply < t.ply) return true;
|
||||
if(hid.dwProductId < t.hid.dwProductId) return true;
|
||||
if(hid.dwVendorId < t.hid.dwVendorId) return true;
|
||||
if(hid.dwVersionNumber < t.hid.dwVersionNumber) return true;
|
||||
bool operator<(const _DevInfo& t) const
|
||||
{
|
||||
if (ply < t.ply)
|
||||
return true;
|
||||
if (hid.dwProductId < t.hid.dwProductId)
|
||||
return true;
|
||||
if (hid.dwVendorId < t.hid.dwVendorId)
|
||||
return true;
|
||||
if (hid.dwVersionNumber < t.hid.dwVersionNumber)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -230,7 +236,8 @@ void populate(HWND hW, RawDlgConfig *cfg)
|
|||
HidD_GetHidGuid(&guid);
|
||||
|
||||
devInfo = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_DEVICEINTERFACE);
|
||||
if(!devInfo) return;
|
||||
if (!devInfo)
|
||||
return;
|
||||
|
||||
diData.cbSize = sizeof(diData);
|
||||
|
||||
|
@ -268,7 +275,8 @@ void populate(HWND hW, RawDlgConfig *cfg)
|
|||
SendDlgItemMessageA(hW, IDC_COMBO_FFB, CB_ADDSTRING, 0, (LPARAM) "None");
|
||||
SendDlgItemMessage(hW, IDC_COMBO_FFB, CB_SETCURSEL, 0, 0);
|
||||
|
||||
while(SetupDiEnumDeviceInterfaces(devInfo, 0, &guid, i, &diData)){
|
||||
while (SetupDiEnumDeviceInterfaces(devInfo, 0, &guid, i, &diData))
|
||||
{
|
||||
if (usbHandle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(usbHandle);
|
||||
|
||||
|
@ -278,7 +286,8 @@ void populate(HWND hW, RawDlgConfig *cfg)
|
|||
if (!didData)
|
||||
break;
|
||||
didData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
if(!SetupDiGetDeviceInterfaceDetail(devInfo, &diData, didData, needed, 0, 0)){
|
||||
if (!SetupDiGetDeviceInterfaceDetail(devInfo, &diData, didData, needed, 0, 0))
|
||||
{
|
||||
free(didData);
|
||||
break;
|
||||
}
|
||||
|
@ -286,7 +295,8 @@ void populate(HWND hW, RawDlgConfig *cfg)
|
|||
usbHandle = CreateFile(didData->DevicePath, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
|
||||
if(usbHandle == INVALID_HANDLE_VALUE){
|
||||
if (usbHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "Could not open device %i\n", i);
|
||||
free(didData);
|
||||
i++;
|
||||
|
@ -432,7 +442,6 @@ void populateMappings(HWND hW)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ParseRawInput(PRAWINPUT pRawInput, HWND hW)
|
||||
|
@ -497,13 +506,16 @@ static void ParseRawInput(PRAWINPUT pRawInput, HWND hW)
|
|||
mapping->hidPath = devName;
|
||||
}
|
||||
//TODO get real dev name, probably from registry (see lilypad)
|
||||
if(!mapping->devName.length()) mapping->devName = devName;
|
||||
if (!mapping->devName.length())
|
||||
mapping->devName = devName;
|
||||
|
||||
if (devInfo.dwType == RIM_TYPEKEYBOARD &&
|
||||
(pRawInput->data.keyboard.Flags & RI_KEY_BREAK) != RI_KEY_BREAK)
|
||||
{
|
||||
if(pRawInput->data.keyboard.VKey == 0xff) return; //TODO
|
||||
if(pRawInput->data.keyboard.VKey == VK_ESCAPE) {
|
||||
if (pRawInput->data.keyboard.VKey == 0xff)
|
||||
return; //TODO
|
||||
if (pRawInput->data.keyboard.VKey == VK_ESCAPE)
|
||||
{
|
||||
resetState(hW);
|
||||
return;
|
||||
}
|
||||
|
@ -549,8 +561,7 @@ static void ParseRawInput(PRAWINPUT pRawInput, HWND hW)
|
|||
CHECK(
|
||||
HidP_GetUsages(
|
||||
HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData,
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid
|
||||
) == HIDP_STATUS_SUCCESS );
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS);
|
||||
|
||||
if (usageLength > 0) //Using first button only though
|
||||
{
|
||||
|
@ -578,8 +589,7 @@ static void ParseRawInput(PRAWINPUT pRawInput, HWND hW)
|
|||
CHECK(
|
||||
HidP_GetUsageValue(
|
||||
HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData,
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid
|
||||
) == HIDP_STATUS_SUCCESS );
|
||||
(PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid) == HIDP_STATUS_SUCCESS);
|
||||
|
||||
uint32_t logical = pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin;
|
||||
|
||||
|
@ -610,7 +620,8 @@ static void ParseRawInput(PRAWINPUT pRawInput, HWND hW)
|
|||
break;
|
||||
|
||||
case 0x39: // Hat Switch
|
||||
if (value < 0x8) {
|
||||
if (value < 0x8)
|
||||
{
|
||||
mapping->axisMap[6] = PLY_SET_MAPPED(plyCapturing, axisCapturing);
|
||||
axisPass2 = false;
|
||||
OSDebugOut(TEXT("Selected hat switch\n"));
|
||||
|
@ -665,18 +676,21 @@ static void Register(HWND hW)
|
|||
rid[2].dwFlags = hW ? RIDEV_INPUTSINK /*| RIDEV_NOLEGACY*/ : RIDEV_REMOVE; // adds HID keyboard and also ignores legacy keyboard messages
|
||||
rid[2].hwndTarget = hW;
|
||||
|
||||
if (!RegisterRawInputDevices(rid, 3, sizeof(rid[0]))) {
|
||||
if (!RegisterRawInputDevices(rid, 3, sizeof(rid[0])))
|
||||
{
|
||||
SendDlgItemMessage(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)TEXT("Could not register raw input devices."));
|
||||
}
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
||||
TCHAR buf[256];
|
||||
LVITEM lv;
|
||||
RawDlgConfig* cfg = (RawDlgConfig*)GetWindowLongPtr(hW, GWLP_USERDATA);
|
||||
int ret = 0;
|
||||
switch(uMsg) {
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
if (!InitHid())
|
||||
return FALSE;
|
||||
|
@ -795,7 +809,8 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
LOWORD(wParam) >= IDC_BUTTON13 &&
|
||||
LOWORD(wParam) <= IDC_BUTTON16)
|
||||
{
|
||||
switch (LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_BUTTON13:
|
||||
hatCapturing = PAD_HAT_N;
|
||||
break;
|
||||
|
@ -813,7 +828,8 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
SetTimer(hW, 1, 5000, nullptr);
|
||||
}
|
||||
|
||||
switch(LOWORD(wParam)) {
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_DFP_PASS:
|
||||
cfg->pt[plyCapturing] = IsDlgButtonChecked(hW, IDC_DFP_PASS) > 0;
|
||||
break;
|
||||
|
@ -821,10 +837,12 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
int sel;
|
||||
HWND lhW;
|
||||
lhW = GetDlgItem(hW, IDC_LIST1);
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
ZeroMemory(&lv, sizeof(LVITEM));
|
||||
sel = ListView_GetNextItem(lhW, -1, LVNI_SELECTED);
|
||||
if (sel < 0) break;
|
||||
if (sel < 0)
|
||||
break;
|
||||
lv.iItem = sel;
|
||||
lv.mask = LVIF_PARAM;
|
||||
ListView_GetItem(lhW, &lv);
|
||||
|
@ -850,7 +868,8 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
case IDC_BUTTON11: //L3
|
||||
case IDC_BUTTON12: //R3
|
||||
if (axisCapturing == PAD_AXIS_COUNT &&
|
||||
hatCapturing == PAD_HAT_COUNT) {
|
||||
hatCapturing == PAD_HAT_COUNT)
|
||||
{
|
||||
btnCapturing = (PS2Buttons)(LOWORD(wParam) - IDC_BUTTON1);
|
||||
MSG_PRESS_ESC(hW);
|
||||
SetTimer(hW, 1, 5000, nullptr);
|
||||
|
@ -862,7 +881,8 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
case IDC_BUTTON20: //rz
|
||||
case IDC_BUTTON21: //hat
|
||||
if (btnCapturing == PAD_BUTTON_COUNT &&
|
||||
hatCapturing == PAD_HAT_COUNT) {
|
||||
hatCapturing == PAD_HAT_COUNT)
|
||||
{
|
||||
axisCapturing = (PS2Axis)(LOWORD(wParam) - IDC_BUTTON17);
|
||||
swprintf_s(buf, TEXT("Capturing for axis %u, press ESC to cancel"), axisCapturing);
|
||||
SendDlgItemMessage(hW, IDC_STATIC_CAP, WM_SETTEXT, 0, (LPARAM)buf);
|
||||
|
@ -901,10 +921,10 @@ INT_PTR CALLBACK ConfigureRawDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM l
|
|||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return S_OK; //DefWindowProc(hW, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
}} //namespace
|
||||
} // namespace raw
|
||||
} // namespace usb_pad
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue