* Add a JoystickProtocolHandler to usb_hid that supports the BJoystick protocol.
This includes input scaling, so the resulting input ranges should always match the ones of the BJoystick data (hence no calibration should be required). * It supports joysticks, gamepads and multi-axis controllers. I've only tested it with a Microsoft SideWinder Gamepad Pro so far, which now works as expected with stickit. * Fixes #7429. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41851 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers input usb_hid ;
|
|||||||
SubDirC++Flags -fno-rtti ;
|
SubDirC++Flags -fno-rtti ;
|
||||||
|
|
||||||
SubDirSysHdrs $(HAIKU_TOP) headers os drivers ;
|
SubDirSysHdrs $(HAIKU_TOP) headers os drivers ;
|
||||||
UsePrivateHeaders [ FDirName kernel util ] input drivers ;
|
UsePrivateHeaders [ FDirName kernel util ] input drivers device ;
|
||||||
UsePrivateKernelHeaders ;
|
UsePrivateKernelHeaders ;
|
||||||
|
|
||||||
KernelAddon usb_hid :
|
KernelAddon usb_hid :
|
||||||
@@ -17,6 +17,8 @@ KernelAddon usb_hid :
|
|||||||
HIDReportItem.cpp
|
HIDReportItem.cpp
|
||||||
|
|
||||||
ProtocolHandler.cpp
|
ProtocolHandler.cpp
|
||||||
|
|
||||||
|
JoystickProtocolHandler.cpp
|
||||||
KeyboardProtocolHandler.cpp
|
KeyboardProtocolHandler.cpp
|
||||||
MouseProtocolHandler.cpp
|
MouseProtocolHandler.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011 Michael Lotz <[email protected]>
|
||||||
|
* Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//! Driver for USB Human Interface Devices.
|
||||||
|
|
||||||
|
|
||||||
|
#include "Driver.h"
|
||||||
|
#include "JoystickProtocolHandler.h"
|
||||||
|
|
||||||
|
#include "HIDCollection.h"
|
||||||
|
#include "HIDDevice.h"
|
||||||
|
#include "HIDReport.h"
|
||||||
|
#include "HIDReportItem.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <string.h>
|
||||||
|
#include <usb/USB_hid.h>
|
||||||
|
|
||||||
|
|
||||||
|
JoystickProtocolHandler::JoystickProtocolHandler(HIDReport &report)
|
||||||
|
:
|
||||||
|
ProtocolHandler(report.Device(), "joystick/usb/", 512),
|
||||||
|
fReport(report)
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < MAX_AXES; i++)
|
||||||
|
fAxis[i] = NULL;
|
||||||
|
|
||||||
|
uint32 buttonCount = 0;
|
||||||
|
for (uint32 i = 0; i < report.CountItems(); i++) {
|
||||||
|
HIDReportItem *item = report.ItemAt(i);
|
||||||
|
if (!item->HasData())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (item->UsagePage()) {
|
||||||
|
case B_HID_USAGE_PAGE_BUTTON:
|
||||||
|
{
|
||||||
|
if (item->UsageID() - 1 < MAX_BUTTONS)
|
||||||
|
fButtons[buttonCount++] = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_HID_USAGE_PAGE_GENERIC_DESKTOP:
|
||||||
|
{
|
||||||
|
switch (item->UsageID()) {
|
||||||
|
case B_HID_UID_GD_X:
|
||||||
|
case B_HID_UID_GD_Y:
|
||||||
|
case B_HID_UID_GD_Z:
|
||||||
|
case B_HID_UID_GD_RX:
|
||||||
|
case B_HID_UID_GD_RY:
|
||||||
|
case B_HID_UID_GD_RZ:
|
||||||
|
uint16 axis = item->UsageID() - B_HID_UID_GD_X;
|
||||||
|
if (axis >= MAX_AXES)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fAxis[axis] = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fButtons[buttonCount] = NULL;
|
||||||
|
|
||||||
|
TRACE("joystick device with %lu buttons\n", buttonCount);
|
||||||
|
TRACE("report id: %u\n", report.ID());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
JoystickProtocolHandler::AddHandlers(HIDDevice &device,
|
||||||
|
HIDCollection &collection, ProtocolHandler *&handlerList)
|
||||||
|
{
|
||||||
|
if (collection.UsagePage() != B_HID_USAGE_PAGE_GENERIC_DESKTOP
|
||||||
|
|| (collection.UsageID() != B_HID_UID_GD_JOYSTICK
|
||||||
|
&& collection.UsageID() != B_HID_UID_GD_GAMEPAD
|
||||||
|
&& collection.UsageID() != B_HID_UID_GD_MULTIAXIS)) {
|
||||||
|
TRACE("collection not a joystick or gamepad\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIDParser &parser = device.Parser();
|
||||||
|
uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT);
|
||||||
|
if (maxReportCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 inputReportCount = 0;
|
||||||
|
HIDReport *inputReports[maxReportCount];
|
||||||
|
collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports,
|
||||||
|
inputReportCount);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < inputReportCount; i++) {
|
||||||
|
HIDReport *inputReport = inputReports[i];
|
||||||
|
|
||||||
|
// try to find at least one axis
|
||||||
|
bool foundAxis = false;
|
||||||
|
for (uint32 j = 0; j < inputReport->CountItems(); j++) {
|
||||||
|
HIDReportItem *item = inputReport->ItemAt(j);
|
||||||
|
if (item == NULL || !item->HasData())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->UsagePage() != B_HID_USAGE_PAGE_GENERIC_DESKTOP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->UsageID() >= B_HID_UID_GD_X
|
||||||
|
&& item->UsageID() <= B_HID_UID_GD_RZ) {
|
||||||
|
foundAxis = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundAxis)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ProtocolHandler *newHandler
|
||||||
|
= new(std::nothrow) JoystickProtocolHandler(*inputReport);
|
||||||
|
if (newHandler == NULL) {
|
||||||
|
TRACE("failed to allocated joystick protocol handler\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newHandler->SetNextHandler(handlerList);
|
||||||
|
handlerList = newHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
JoystickProtocolHandler::Read(uint32 *cookie, off_t position, void *buffer,
|
||||||
|
size_t *numBytes)
|
||||||
|
{
|
||||||
|
if (*numBytes < sizeof(extended_joystick))
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
while (RingBufferReadable() == 0) {
|
||||||
|
status_t result = _ReadReport();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t result = RingBufferRead(buffer, sizeof(extended_joystick));
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
*numBytes = sizeof(extended_joystick);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
JoystickProtocolHandler::Write(uint32 *cookie, off_t position,
|
||||||
|
const void *buffer, size_t *numBytes)
|
||||||
|
{
|
||||||
|
*numBytes = 0;
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
JoystickProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_JOYSTICK_SET_DEVICE_MODULE:
|
||||||
|
{
|
||||||
|
if (length < sizeof(joystick_module_info))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
fJoystickModuleInfo = *(joystick_module_info *)buffer;
|
||||||
|
|
||||||
|
fJoystickModuleInfo.num_axes = 0;
|
||||||
|
for (uint32 i = 0; i < MAX_AXES; i++) {
|
||||||
|
if (fAxis[i] != NULL)
|
||||||
|
fJoystickModuleInfo.num_axes = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fJoystickModuleInfo.num_buttons = 0;
|
||||||
|
for (uint32 i = 0; i < MAX_BUTTONS; i++) {
|
||||||
|
if (fButtons[i] == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint8 button = fButtons[i]->UsageID();
|
||||||
|
if (button > fJoystickModuleInfo.num_buttons)
|
||||||
|
fJoystickModuleInfo.num_buttons = button;
|
||||||
|
}
|
||||||
|
|
||||||
|
fJoystickModuleInfo.num_hats = 0;
|
||||||
|
fJoystickModuleInfo.num_sticks = 1;
|
||||||
|
fJoystickModuleInfo.config_size = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_JOYSTICK_GET_DEVICE_MODULE:
|
||||||
|
if (length < sizeof(joystick_module_info))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
*(joystick_module_info *)buffer = fJoystickModuleInfo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
JoystickProtocolHandler::_ReadReport()
|
||||||
|
{
|
||||||
|
status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
|
||||||
|
if (result != B_OK) {
|
||||||
|
if (fReport.Device()->IsRemoved()) {
|
||||||
|
TRACE("device has been removed\n");
|
||||||
|
return B_DEV_NOT_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != B_INTERRUPTED) {
|
||||||
|
// interrupts happen when other reports come in on the same
|
||||||
|
// input as ours
|
||||||
|
TRACE_ALWAYS("error waiting for report: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
// signal that we simply want to try again
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
extended_joystick info;
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < MAX_AXES; i++) {
|
||||||
|
if (fAxis[i] == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fAxis[i]->Extract() == B_OK && fAxis[i]->Valid())
|
||||||
|
info.axes[i] = (int16)fAxis[i]->ScaledData(16, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < MAX_BUTTONS; i++) {
|
||||||
|
HIDReportItem *button = fButtons[i];
|
||||||
|
if (button == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (button->Extract() == B_OK && button->Valid())
|
||||||
|
info.buttons |= (button->Data() & 1) << (button->UsageID() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fReport.DoneProcessing();
|
||||||
|
TRACE("got joystick report\n");
|
||||||
|
|
||||||
|
info.timestamp = system_time();
|
||||||
|
return RingBufferWrite(&info, sizeof(info));
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2011 Michael Lotz <[email protected]>
|
||||||
|
* Distributed under the terms of the MIT license.
|
||||||
|
*/
|
||||||
|
#ifndef USB_JOYSTICK_PROTOCOL_HANDLER_H
|
||||||
|
#define USB_JOYSTICK_PROTOCOL_HANDLER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <InterfaceDefs.h>
|
||||||
|
|
||||||
|
#include "ProtocolHandler.h"
|
||||||
|
|
||||||
|
#include <joystick_driver.h>
|
||||||
|
|
||||||
|
|
||||||
|
class HIDCollection;
|
||||||
|
class HIDReportItem;
|
||||||
|
|
||||||
|
|
||||||
|
class JoystickProtocolHandler : public ProtocolHandler {
|
||||||
|
public:
|
||||||
|
JoystickProtocolHandler(HIDReport &report);
|
||||||
|
|
||||||
|
static void AddHandlers(HIDDevice &device,
|
||||||
|
HIDCollection &collection,
|
||||||
|
ProtocolHandler *&handlerList);
|
||||||
|
|
||||||
|
virtual status_t Read(uint32 *cookie, off_t position,
|
||||||
|
void *buffer, size_t *numBytes);
|
||||||
|
virtual status_t Write(uint32 *cookie, off_t position,
|
||||||
|
const void *buffer, size_t *numBytes);
|
||||||
|
|
||||||
|
virtual status_t Control(uint32 *cookie, uint32 op,
|
||||||
|
void *buffer, size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ReadReport();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HIDReport & fReport;
|
||||||
|
|
||||||
|
HIDReportItem * fAxis[MAX_AXES];
|
||||||
|
HIDReportItem * fButtons[MAX_BUTTONS];
|
||||||
|
|
||||||
|
joystick_module_info fJoystickModuleInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USB_JOYSTICK_PROTOCOL_HANDLER_H
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
// includes for the different protocol handlers
|
// includes for the different protocol handlers
|
||||||
#include "KeyboardProtocolHandler.h"
|
#include "KeyboardProtocolHandler.h"
|
||||||
#include "MouseProtocolHandler.h"
|
#include "MouseProtocolHandler.h"
|
||||||
//#include "JoystickProtocolHandler.h"
|
#include "JoystickProtocolHandler.h"
|
||||||
|
|
||||||
|
|
||||||
ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath,
|
ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath,
|
||||||
@@ -88,7 +88,7 @@ ProtocolHandler::AddHandlers(HIDDevice &device, ProtocolHandler *&handlerList,
|
|||||||
|
|
||||||
KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList);
|
KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
MouseProtocolHandler::AddHandlers(device, *collection, handlerList);
|
MouseProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
//JoystickProtocolHandler::AddHandlers(device, *collection, handlerList);
|
JoystickProtocolHandler::AddHandlers(device, *collection, handlerList);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolHandler *handler = handlerList;
|
ProtocolHandler *handler = handlerList;
|
||||||
|
|||||||
Reference in New Issue
Block a user