#define _SPACEORB_C_
#include <misc.h>
#include <xf86.h>
#define NEED_XF86_TYPES
#include <xf86_ansic.h>
#include <xf86_OSproc.h>
#include <xf86Xinput.h>
#include <xisb.h>
#include <exevents.h>
#include "spaceorb.h"
InputDriverRec SPACEORB = {
1,
"spaceorb",
NULL,
SpaceorbPreInit,
NULL,
NULL,
0
};
#ifdef XFree86LOADER
static XF86ModuleVersionInfo VersionRec =
{
"spaceorb",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XF86_VERSION_CURRENT,
1, 0, 0,
ABI_CLASS_XINPUT,
ABI_XINPUT_VERSION,
MOD_CLASS_XINPUT,
{0, 0, 0, 0}
};
static const char *reqSymbols[] = {
"AddEnabledDevice",
"ErrorF",
"InitButtonClassDeviceStruct",
"InitProximityClassDeviceStruct",
"InitValuatorAxisStruct",
"InitValuatorClassDeviceStruct",
"InitPtrFeedbackClassDeviceStruct",
"RemoveEnabledDevice",
"Xcalloc",
"Xfree",
"XisbBlockDuration",
"XisbFree",
"XisbNew",
"XisbRead",
"XisbTrace",
"screenInfo",
"xf86AddInputDriver",
"xf86AllocateInput",
"xf86CloseSerial",
"xf86CollectInputOptions",
"xf86ErrorFVerb",
"xf86FindOptionValue",
"xf86GetMotionEvents",
"xf86GetVerbosity",
"xf86MotionHistoryAllocate",
"xf86NameCmp",
"xf86OpenSerial",
"xf86OptionListCreate",
"xf86OptionListMerge",
"xf86OptionListReport",
"xf86PostButtonEvent",
"xf86PostMotionEvent",
"xf86PostProximityEvent",
"xf86ProcessCommonOptions",
"xf86ScaleAxis",
"xf86SetIntOption",
"xf86SetStrOption",
"xf86XInputSetScreen",
"xf86XInputSetSendCoreEvents",
NULL
};
static pointer
SPACEORBSetupProc(pointer module,
pointer options,
int *errmaj,
int *errmin ) {
xf86LoaderReqSymLists(reqSymbols, NULL);
xf86AddInputDriver(&SPACEORB, module, 0);
return (pointer) 1;
}
static void
TearDownProc( pointer p )
{
if (!xf86ServerIsOnlyDetecting()) {
InputInfoPtr pInfo = (InputInfoPtr) p;
SPACEORBPrivatePtr priv = (SPACEORBPrivatePtr) pInfo->private;
DeviceOff (pInfo->dev);
xf86CloseSerial (pInfo->fd);
XisbFree (priv->buffer);
xfree (priv);
xfree (pInfo->name);
xfree (pInfo);
}
}
XF86ModuleData spaceorbModuleData = { &VersionRec, SPACEORBSetupProc, TearDownProc };
#endif
static const char *default_options[] =
{
"BaudRate", "9600",
"StopBits", "1",
"DataBits", "8",
"Parity", "None",
"Vmin", "5",
"Vtime", "1",
"FlowControl", "None",
NULL,
};
static char spaceware[] = "0SpaceWare!";
static InputInfoPtr
SpaceorbPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
InputInfoPtr pInfo;
SPACEORBPrivatePtr priv = xcalloc (1, sizeof (SPACEORBPrivateRec));
if (!priv)
return NULL;
if (!(pInfo = xf86AllocateInput(drv, 0))) {
xfree(priv);
return NULL;
}
priv->lex_mode = SPACEORB_normal;
priv->packeti = 0;
priv->old_buttons=0;
priv->buffer= NULL;
pInfo->type_name = XI_SPACEBALL;
pInfo->device_control = DeviceControl;
pInfo->read_input = ReadInput;
pInfo->control_proc = ControlProc;
pInfo->close_proc = CloseProc;
pInfo->switch_mode = SwitchMode;
pInfo->conversion_proc = ConvertProc;
pInfo->dev = NULL;
pInfo->private = priv;
pInfo->private_flags = 0;
pInfo->flags = 0;
pInfo->conf_idev = dev;
xf86CollectInputOptions(pInfo, default_options, NULL);
xf86OptionListReport( pInfo->options );
pInfo->fd = xf86OpenSerial (pInfo->options);
if (pInfo->fd == -1)
{
ErrorF ("SPACEORB driver unable to open device\n");
goto SetupProc_fail;
}
priv->buffer = XisbNew (pInfo->fd, 200);
DBG (9, XisbTrace (priv->buffer, 1));
if (QueryHardware (priv) != Success)
{
ErrorF ("Unable to query/initialize SpaceOrb hardware.\n");
goto SetupProc_fail;
}
pInfo->name = xf86SetStrOption( pInfo->options, "DeviceName", "SpaceOrb XInput Device");
pInfo->history_size = xf86SetIntOption( pInfo->options, "HistorySize", 0 );
xf86ProcessCommonOptions(pInfo, pInfo->options);
pInfo->flags |= XI86_CONFIGURED;
return (pInfo);
SetupProc_fail:
if ((pInfo) && (pInfo->fd))
xf86CloseSerial (pInfo->fd);
if ((pInfo) && (pInfo->name))
xfree (pInfo->name);
if ((priv) && (priv->buffer))
XisbFree (priv->buffer);
if (priv)
xfree (priv);
return (pInfo);
}
static Bool
DeviceControl (DeviceIntPtr dev, int mode)
{
Bool RetValue;
switch (mode)
{
case DEVICE_INIT:
DeviceInit (dev);
RetValue = Success;
break;
case DEVICE_ON:
RetValue = DeviceOn( dev );
break;
case DEVICE_OFF:
RetValue = DeviceOff( dev );
break;
case DEVICE_CLOSE:
RetValue = DeviceClose( dev );
break;
default:
RetValue = BadValue;
}
return( RetValue );
}
static Bool
DeviceOn (DeviceIntPtr dev)
{
InputInfoPtr pInfo = dev->public.devicePrivate;
AddEnabledDevice (pInfo->fd);
dev->public.on = TRUE;
return (Success);
}
static Bool
DeviceOff (DeviceIntPtr dev)
{
InputInfoPtr pInfo = dev->public.devicePrivate;
RemoveEnabledDevice (pInfo->fd);
dev->public.on = FALSE;
return (Success);
}
static Bool
DeviceClose (DeviceIntPtr dev)
{
return (Success);
}
static Bool
DeviceInit (DeviceIntPtr dev)
{
InputInfoPtr pInfo = dev->public.devicePrivate;
unsigned char map[] = {0, 1, 2, 3, 4, 5, 6, 7};
if (InitButtonClassDeviceStruct (dev, 7, map) == FALSE) {
ErrorF ("Unable to allocate SPACEORB ButtonClassDeviceStruct\n");
return !Success;
}
if (InitFocusClassDeviceStruct (dev) == FALSE) {
ErrorF("Unable to allocate SPACEORB FocusClassDeviceStruct\n");
return !Success;
}
if (InitValuatorClassDeviceStruct (dev, 6, xf86GetMotionEvents,
pInfo->history_size, Absolute) == FALSE)
{
ErrorF ("Unable to allocate SPACEORB ValuatorClassDeviceStruct\n");
return !Success;
}
else
{
InitValuatorAxisStruct(dev, 0, -512, 511, 9600,0,9600);
InitValuatorAxisStruct(dev, 1, -512, 511, 9600,0,9600);
InitValuatorAxisStruct(dev, 2, -512, 511, 9600,0,9600);
InitValuatorAxisStruct(dev, 3, -512, 511, 9600,0,9600);
InitValuatorAxisStruct(dev, 4, -512, 511, 9600,0,9600);
InitValuatorAxisStruct(dev, 5, -512, 511, 9600,0,9600);
}
xf86MotionHistoryAllocate (pInfo);
return (Success);
}
static void
ReadInput (LocalDevicePtr local)
{
int x, y, z, u, v, r;
int buttons;
int i;
SPACEORBPrivatePtr priv = (SPACEORBPrivatePtr) (local->private);
XisbBlockDuration (priv->buffer, -1);
while (SPACEORBGetPacket (priv) == Success)
{
switch (priv->packet_type)
{
case SPACEORB_D_PACKET:
x = ((priv->packet[1] & 0177)<<3)|((priv->packet[2] & 0160)>>4);
y = ((priv->packet[2] & 0017)<<6)|((priv->packet[3] & 0176)>>1);
z = ((priv->packet[3] & 0001)<<9)|((priv->packet[4] & 0177)<<2)|((priv->packet[5] & 0140)>>5);
u = ((priv->packet[5] & 0037)<<5)|((priv->packet[6] & 0174)>>2);
v = ((priv->packet[6] & 0003)<<8)|((priv->packet[7] & 0177)<<1)|((priv->packet[8] & 0100)>>6);
r = ((priv->packet[8] & 0077)<<4)|((priv->packet[9] & 0170)>>3);
if (x > 511) x -= 1024;
if (y > 511) y -= 1024;
if (z > 511) z -= 1024;
if (u > 511) u -= 1024;
if (v > 511) v -= 1024;
if (r > 511) r -= 1024;
xf86ErrorFVerb( 9, "SpaceOrb motion %d %d %d -- %d %d %d\n",
x, y, z, u, v, r );
xf86PostMotionEvent(local->dev, TRUE, 0, 6, x, y, z, u, v, r);
break;
case SPACEORB_K_PACKET:
buttons = priv->packet[1];
if (priv->old_buttons != buttons)
for (i = 0; i < 7; i++)
{
if ((priv->old_buttons&(1<<i)) != (buttons&(1<<i)))
{
xf86PostButtonEvent(local->dev, FALSE, i+1,
(buttons&(1<<i)), 0, 0);
xf86ErrorFVerb( 9, "SpaceOrb setting button %d to %d\n",
i+1, (buttons&(1<<i)) );
}
}
priv->old_buttons = buttons;
break;
}
}
}
static int
ControlProc (LocalDevicePtr local, xDeviceCtl * control)
{
return (Success);
}
static void
CloseProc (LocalDevicePtr local)
{
}
static int
SwitchMode (ClientPtr client, DeviceIntPtr dev, int mode)
{
return (Success);
}
static Bool
ConvertProc (LocalDevicePtr local,
int first,
int num,
int v0,
int v1,
int v2,
int v3,
int v4,
int v5,
int *x,
int *y)
{
*x = v3;
*y = v4;
return (Success);
}
static Bool
QueryHardware (SPACEORBPrivatePtr priv)
{
XisbBlockDuration (priv->buffer, 1000000);
if ((SPACEORBGetPacket (priv) == Success) &&
(priv->packet_type == SPACEORB_R_PACKET))
return (Success);
else
{
ErrorF ("No response from SpaceOrb hardware.\n");
return (!Success);
}
}
static void
NewPacket (SPACEORBPrivatePtr priv)
{
priv->lex_mode = SPACEORB_normal;
priv->packeti = 0;
}
static Bool
SPACEORBGetPacket (SPACEORBPrivatePtr priv)
{
int count = 0;
int c;
while ((c = XisbRead (priv->buffer)) >= 0)
{
if (count++ > 500)
{
NewPacket (priv);
return (!Success);
}
if (c == '\r')
continue;
switch (priv->lex_mode)
{
case SPACEORB_normal:
if (c == SPACEORB_R_PACKET)
{
xf86ErrorFVerb( 9, "SpaceOrb got an R packet\n" );
priv->packet_type = SPACEORB_R_PACKET;
priv->lex_mode = SPACEORB_body;
priv->expected_len = SPACEORB_R_BODY_LEN;
}
else if (c == SPACEORB_K_PACKET)
{
priv->packet_type = SPACEORB_K_PACKET;
priv->lex_mode = SPACEORB_body;
priv->expected_len = SPACEORB_K_BODY_LEN;
}
else if (c == SPACEORB_D_PACKET)
{
xf86ErrorFVerb( 9, "SpaceOrb got a D packet\n" );
priv->packet_type = SPACEORB_D_PACKET;
priv->lex_mode = SPACEORB_Dbody;
priv->expected_len = SPACEORB_D_BODY_LEN;
}
break;
case SPACEORB_Dbody:
if (priv->packeti < priv->expected_len)
{
xf86ErrorFVerb( 9, "\t%d = %c data = %c %d\n",
priv->packeti, spaceware[priv->packeti],
(c & 0x7F), (c & 0x7F) );
priv->packet[priv->packeti] =
(unsigned char) (c & 0x7F) ^ spaceware[priv->packeti];
priv->packeti++;
}
if (priv->packeti == priv->expected_len)
{
#ifdef DEBUG
ErrorF ("returning packet <");
{
int i;
for (i = 0; i < priv->expected_len; i++)
ErrorF ("%c", priv->packet[i]);
ErrorF (">\n");
}
#endif
NewPacket (priv);
return (Success);
}
break;
case SPACEORB_body:
if (priv->packeti < priv->expected_len)
priv->packet[priv->packeti++] = (unsigned char) c & 0x7F;
if (priv->packeti == priv->expected_len)
{
NewPacket (priv);
return (Success);
}
break;
}
}
return (!Success);
}