Add Linux Pacdrive

This commit is contained in:
teejusb
2023-02-17 12:27:58 -08:00
parent 11ac50e7d1
commit 4e19ce0d5d
7 changed files with 406 additions and 0 deletions
+1
View File
@@ -20,6 +20,7 @@ jobs:
libmad0-dev
libpulse-dev
libudev-dev
libusb-dev
libxinerama-dev
libx11-dev
libxrandr-dev
+105
View File
@@ -0,0 +1,105 @@
# - Find libusb for portable USB support
# This module will find libusb as published by
# http://libusb.sf.net and
# http://libusb-win32.sf.net
#
# It will use PkgConfig if present and supported, else search
# it on its own. If the LibUSB_ROOT_DIR environment variable
# is defined, it will be used as base path.
# The following standard variables get defined:
# LIBUSB_FOUND: true if LibUSB was found
# LIBUSB_INCLUDE_DIRS: the directory that contains the include file
# LIBUSB_LIBRARIES: the library
if( WIN32 )
return()
endif()
include ( CheckLibraryExists )
include ( CheckIncludeFile )
find_package ( PkgConfig )
if ( PKG_CONFIG_FOUND )
pkg_check_modules ( PKGCONFIG_LIBUSB libusb )
endif ( PKG_CONFIG_FOUND )
if ( PKGCONFIG_LIBUSB_FOUND )
set ( LIBUSB_FOUND ${PKGCONFIG_LIBUSB_FOUND} )
set ( LIBUSB_INCLUDE_DIRS ${PKGCONFIG_LIBUSB_INCLUDE_DIRS} )
foreach ( i ${PKGCONFIG_LIBUSB_LIBRARIES} )
find_library ( ${i}_LIBRARY
NAMES ${i}
PATHS ${PKGCONFIG_LIBUSB_LIBRARY_DIRS}
)
if ( ${i}_LIBRARY )
list ( APPEND LIBUSB_LIBRARIES ${${i}_LIBRARY} )
endif ( ${i}_LIBRARY )
mark_as_advanced ( ${i}_LIBRARY )
endforeach ( i )
else ( PKGCONFIG_LIBUSB_FOUND )
find_path ( LIBUSB_INCLUDE_DIRS
NAMES
usb.h
PATHS
$ENV{ProgramFiles}/LibUSB-Win32
$ENV{LibUSB_ROOT_DIR}
PATH_SUFFIXES
include
)
mark_as_advanced ( LIBUSB_INCLUDE_DIRS )
# message ( STATUS "LibUSB include dir: ${LIBUSB_INCLUDE_DIRS}" )
if ( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
# LibUSB-Win32 binary distribution contains several libs.
# Use the lib that got compiled with the same compiler.
if ( MSVC )
if ( WIN32 )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/msvc )
else ( WIN32 )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/msvc_x64 )
endif ( WIN32 )
elseif ( BORLAND )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/bcc )
elseif ( CMAKE_COMPILER_IS_GNUCC )
set ( LibUSB_LIBRARY_PATH_SUFFIX lib/gcc )
endif ( MSVC )
endif ( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
find_library ( usb_LIBRARY
NAMES
libusb usb
PATHS
$ENV{ProgramFiles}/LibUSB-Win32
$ENV{LibUSB_ROOT_DIR}
PATH_SUFFIXES
${LibUSB_LIBRARY_PATH_SUFFIX}
)
mark_as_advanced ( usb_LIBRARY )
if ( usb_LIBRARY )
set ( LIBUSB_LIBRARIES ${usb_LIBRARY} )
endif ( usb_LIBRARY )
if ( LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES )
set ( LIBUSB_FOUND true )
endif ( LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES )
endif ( PKGCONFIG_LIBUSB_FOUND )
if ( LIBUSB_FOUND )
set ( CMAKE_REQUIRED_INCLUDES "${LIBUSB_INCLUDE_DIRS}" )
check_include_file ( usb.h LIBUSB_FOUND )
# message ( STATUS "LibUSB: usb.h is usable: ${LIBUSB_FOUND}" )
endif ( LIBUSB_FOUND )
if ( LIBUSB_FOUND )
check_library_exists ( "${LIBUSB_LIBRARIES}" usb_open "" LIBUSB_FOUND )
# message ( STATUS "LibUSB: library is usable: ${LIBUSB_FOUND}" )
endif ( LIBUSB_FOUND )
if ( NOT LIBUSB_FOUND )
if ( NOT LibUSB_FIND_QUIETLY )
message ( STATUS "LibUSB not found, try setting LibUSB_ROOT_DIR environment variable." )
endif ( NOT LibUSB_FIND_QUIETLY )
if ( LibUSB_FIND_REQUIRED )
message ( FATAL_ERROR "" )
endif ( LibUSB_FIND_REQUIRED )
endif ( NOT LIBUSB_FOUND )
#message ( STATUS "LibUSB: ${LIBUSB_FOUND}" )
+5
View File
@@ -370,6 +370,11 @@ elseif(LINUX)
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
find_package(Libusb)
if(NOT LIBUSB_FOUND)
message(FATAL_ERROR "libusb was not found.")
endif()
endif(WIN32) # LINUX, APPLE
configure_file("${SM_SRC_DIR}/config.in.hpp"
+2
View File
@@ -209,6 +209,7 @@ if(NOT APPLE)
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.cpp"
"arch/Lights/LightsDriver_Linux_ITGIO.cpp"
"arch/Lights/LightsDriver_Linux_stac.cpp"
"arch/Lights/LightsDriver_Linux_PacDrive.cpp"
"arch/Lights/LightsDriver_LinuxMinimaid.cpp"
"arch/Lights/LightsDriver_LinuxWeedTech.cpp")
list(APPEND SMDATA_ARCH_LIGHTS_HPP
@@ -218,6 +219,7 @@ if(NOT APPLE)
"arch/Lights/LightsDriver_Linux_PIUIOBTN_Leds.h"
"arch/Lights/LightsDriver_Linux_ITGIO.h"
"arch/Lights/LightsDriver_Linux_stac.h"
"arch/Lights/LightsDriver_Linux_PacDrive.h"
"arch/Lights/LightsDriver_LinuxMinimaid.h"
"arch/Lights/LightsDriver_LinuxWeedTech.h")
if(WITH_PARALLEL_PORT)
+4
View File
@@ -441,6 +441,8 @@ else() # Unix / Linux TODO: Remember to find and locate the zip archive files.
list(APPEND SMDATA_LINK_LIB ${LIBXTST_LIBRARY})
endif()
list(APPEND SMDATA_LINK_LIB ${LIBUSB_LIBRARIES})
list(APPEND SMDATA_LINK_LIB ${XRANDR_LIBRARIES} ${XINERAMA_LIBRARIES})
list(REMOVE_DUPLICATES SMDATA_LINK_LIB)
@@ -466,6 +468,8 @@ else()
if(X11_FOUND)
list(APPEND SM_INCLUDE_DIRS "${X11_INCLUDE_DIR}")
endif()
list(APPEND SM_INCLUDE_DIRS "${LIBUSB_INCLUDE_DIRS}")
endif()
endif()
@@ -0,0 +1,234 @@
// Cross-platform, libusb-based driver for outputting lights
// via a PacDrive (http://www.ultimarc.com/pacdrive.html)
#include "global.h"
#include "RageLog.h"
#include "LightsDriver_Linux_PacDrive.h"
extern "C" {
#include <usb.h>
}
REGISTER_LIGHTS_DRIVER_CLASS( Linux_PacDrive );
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#define HID_GET_REPORT 0x01
#define HID_SET_REPORT 0x09
#define HID_IFACE_IN 256
#define HID_IFACE_OUT 512
/* PacDrives have PIDs 1500 - 1507, but we'll handle that later. */
const int PACDRIVE_VENDOR_ID = 0xD209;
const int PACDRIVE_PRODUCT_ID = 0x1500;
/* I/O request timeout, in microseconds (so, 10 ms) */
const unsigned PACDRIVE_TIMEOUT = 10000;
/* static struct to ensure the USB subsystem is initialized on start */
struct USBInit
{
USBInit() { usb_init(); usb_find_busses(); usb_find_devices(); }
};
static struct USBInit g_USBInit;
LightsDriver_Linux_PacDrive::LightsDriver_Linux_PacDrive()
{
Device = NULL;
DeviceHandle = NULL;
FindDevice();
OpenDevice();
// clear all lights
WriteDevice( 0 );
}
LightsDriver_Linux_PacDrive::~LightsDriver_Linux_PacDrive()
{
// clear all lights and close the connection
WriteDevice( 0 );
CloseDevice();
}
void LightsDriver_Linux_PacDrive::Set( const LightsState *ls )
{
if ( !DeviceHandle ) return;
uint16_t outb = 0;
// This is original order from openitg-beta-2
if (ls->m_bCabinetLights[LIGHT_MARQUEE_UP_LEFT]) outb|=BIT(0);
if (ls->m_bCabinetLights[LIGHT_MARQUEE_UP_RIGHT]) outb|=BIT(1);
if (ls->m_bCabinetLights[LIGHT_MARQUEE_LR_LEFT]) outb|=BIT(2);
if (ls->m_bCabinetLights[LIGHT_MARQUEE_LR_RIGHT]) outb|=BIT(3);
if (ls->m_bGameButtonLights[GameController_1][GAME_BUTTON_START]) outb|=BIT(4);
if (ls->m_bGameButtonLights[GameController_2][GAME_BUTTON_START]) outb|=BIT(5);
if (ls->m_bCabinetLights[LIGHT_BASS_LEFT]) outb|=BIT(6);
if (ls->m_bCabinetLights[LIGHT_BASS_RIGHT]) outb|=BIT(7);
if (ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_LEFT]) outb|=BIT(8);
if (ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_RIGHT]) outb|=BIT(9);
if (ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_UP]) outb|=BIT(10);
if (ls->m_bGameButtonLights[GameController_1][DANCE_BUTTON_DOWN]) outb|=BIT(11);
if (ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_LEFT]) outb|=BIT(12);
if (ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_RIGHT]) outb|=BIT(13);
if (ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_UP]) outb|=BIT(14);
if (ls->m_bGameButtonLights[GameController_2][DANCE_BUTTON_DOWN]) outb|=BIT(15);
WriteDevice(outb);
}
void LightsDriver_Linux_PacDrive::FindDevice()
{
if ( usb_find_busses() < 0 )
{
LOG->Warn( "libusb: usb_find_busses: %s", usb_strerror() );
return;
}
if ( usb_find_devices() < 0 )
{
LOG->Warn( "libusb: usb_find_devices: %s", usb_strerror() );
return;
}
for ( usb_bus *bus = usb_get_busses(); bus; bus = bus->next )
for ( struct usb_device *dev = bus->devices; dev; dev = dev->next )
if ( PACDRIVE_VENDOR_ID == dev->descriptor.idVendor &&
PACDRIVE_PRODUCT_ID <= dev->descriptor.idProduct &&
PACDRIVE_PRODUCT_ID + 8 > dev->descriptor.idProduct ) {
Device = dev;
LOG->Info( "PacDrive device was found vid: 0x%04x pid: 0x%04x", dev->descriptor.idVendor, dev->descriptor.idProduct );
return;
}
LOG->Warn( "PacDrive was not found!" );
Device = NULL;
}
void LightsDriver_Linux_PacDrive::OpenDevice()
{
CloseDevice();
if ( !Device ) return;
DeviceHandle = usb_open( Device );
if ( DeviceHandle == NULL ) {
LOG->Warn( "libusb: usb_open: %s", usb_strerror() );
return;
}
// The device may be claimed by a kernel driver. Attempt to reclaim it.
for ( unsigned iface = 0; iface < Device->config->bNumInterfaces; iface++ )
{
int result = usb_detach_kernel_driver_np( DeviceHandle, iface );
// device doesn't understand message, no attached driver, no error -- ignore these
if( result == -EINVAL || result == -ENODATA || result == 0 )
continue;
/* we have an error we can't handle; try and get more info. */
LOG->Warn( "usb_detach_kernel_driver_np: %s\n", usb_strerror() );
// on EPERM, a driver exists and we can't detach - report which one
if ( result == -EPERM )
{
char szDriverName[16];
strcpy( szDriverName, "(unknown)" );
usb_get_driver_np(DeviceHandle, iface, szDriverName, 16);
LOG->Warn( "(cannot detach kernel driver \"%s\")", szDriverName );
}
CloseDevice();
return;
}
if ( usb_set_configuration( DeviceHandle, Device->config->bConfigurationValue) ) {
LOG->Warn( "libusb: usb_set_configuration: %s", usb_strerror() );
CloseDevice();
return;
}
// attempt to claim all interfaces for this device
for ( unsigned i = 0; i < Device->config->bNumInterfaces; i++ )
{
if ( usb_claim_interface( DeviceHandle, i ) ) {
LOG->Warn( "Libusb: usb_claim_interface(%i): %s", i, usb_strerror() );
CloseDevice();
return;
}
}
}
void LightsDriver_Linux_PacDrive::WriteDevice(uint16_t out)
{
if ( !DeviceHandle ) return;
// output is within the first 16 bits - accept a
// 16-bit arg and cast it, for simplicity's sake.
uint32_t data = (out << 16);
int expected = sizeof(data);
int result = usb_control_msg( DeviceHandle, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
HID_SET_REPORT, HID_IFACE_OUT, 0, (char *)&data, expected,
PACDRIVE_TIMEOUT );
if( result != expected ) {
LOG->Warn( "PacDrive writing failed: %i (%s)\n", result, usb_strerror() );
CloseDevice();
}
}
void LightsDriver_Linux_PacDrive::CloseDevice()
{
if ( !DeviceHandle )
return;
usb_set_altinterface( DeviceHandle, 0 );
usb_reset( DeviceHandle );
usb_close( DeviceHandle );
DeviceHandle = NULL;
}
/*
* Copyright (c) 2008 BoXoRRoXoRs
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
@@ -0,0 +1,55 @@
#ifndef LIGHTSDRIVER_LINUX_PACDRIVE_H
#define LIGHTSDRIVER_LINUX_PACDRIVE_H
#include "LightsDriver.h"
extern "C" {
#include <usb.h>
}
#define BIT(i) (1<<(i))
class LightsDriver_Linux_PacDrive: public LightsDriver
{
public:
LightsDriver_Linux_PacDrive();
~LightsDriver_Linux_PacDrive();
void Set( const LightsState *ls );
private:
void FindDevice();
void OpenDevice();
void WriteDevice(uint16_t out);
void CloseDevice();
struct usb_device *Device;
usb_dev_handle *DeviceHandle;
};
#endif // LIGHTSDRIVER_LINUX_PACDRIVE_H
/*
* Copyright (c) 2008 BoXoRRoXoRs
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/