/* * * Copyright 2004 by Kenan Esau , Baltmannsweiler, * Germany. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the names of copyright holders not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. The copyright holders * make no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR 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. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _evdev_touch_C_ #include #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(3,9,0,0,0) #define XFREE86_V4 #endif /***************************************************************************** * Standard Headers ****************************************************************************/ #ifdef XFREE86_V4 #include #else #include #include #endif #include #include #include #include #include #include #ifndef EVIOCGRAB #define EVIOCGRAB _IOW('E', 0x90, int) #endif #define NEED_EVENTS #include #include #include "xf86.h" #ifdef XINPUT #include #include #include "extnsionst.h" #include "extinit.h" #else #include "inputstr.h" #endif #include "xf86_OSproc.h" #include "xf86Xinput.h" #include "exevents.h" #include "xf86OSmouse.h" #include "randrstr.h" #ifndef NEED_XF86_TYPES #define NEED_XF86_TYPES /* for xisb.h when !XFree86LOADER */ #endif #define DBG(lvl, f) {if ((lvl) <= debug_level) f;} #include "compiler.h" #include "xisb.h" #include /***************************************************************************** * Local Headers ****************************************************************************/ #include "libtouch.h" #include "evtouch.h" /***************************************************************************** * Variables without includable headers ****************************************************************************/ /***************************************************************************** * Local Variables ****************************************************************************/ static InputInfoPtr EVTouchPreInit(InputDriverPtr drv, IDevPtr dev, int flags); static void EVTouchPtrCtrl(DeviceIntPtr device, PtrCtrl *ctrl); 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 ); static int debug_level = 0; InputDriverRec EVTOUCH = { 1, "evtouch", NULL, EVTouchPreInit, /*EVTouchUnInit*/ NULL, NULL, 0 }; #ifdef XFree86LOADER static XF86ModuleVersionInfo VersionRec = { "evtouch", "Kenan Esau", MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, 0, 8, 8, ABI_CLASS_XINPUT, ABI_XINPUT_VERSION, MOD_CLASS_XINPUT, {0, 0, 0, 0} /* signature, to be patched into the file by * a tool */ }; static pointer Plug( pointer module, pointer options, int *errmaj, int *errmin ) { xf86AddInputDriver(&EVTOUCH, module, 0); return module; } static void Unplug(pointer p) { DBGOUT(1, "EVTouch: Unplug\n"); } XF86ModuleData evtouchModuleData = {&VersionRec, Plug, Unplug }; #endif /* XFree86LOADER */ static const char *default_options[] = { "BaudRate", "9600", "StopBits", "1", "DataBits", "8", "Parity", "None", "Vmin", "5", "Vtime", "1", "FlowControl", "None" }; static int ControlProc(LocalDevicePtr device, xDeviceCtl *ctrl); /***************************************************************************** * Function Definitions ****************************************************************************/ static CARD32 emulate3Timer(OsTimerPtr timer, CARD32 now, pointer _local) { int sigstate; DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); LocalDevicePtr local = (LocalDevicePtr)_local; EVTouchPrivatePtr priv = (EVTouchPrivatePtr) local->private; sigstate = xf86BlockSIGIO(); xf86PostMotionEvent(local->dev, TRUE, 0, 2, priv->cur_x, priv->cur_y); /* * Emit a button press -- release is handled in EVTouchLBRBEvent */ if ( ( priv->touch_flags & LB_STAT ) && !( priv->touch_flags & RB_STAT ) ) { DBGOUT(2, "EVTouch: Left Press\n"); xf86PostButtonEvent (local->dev, TRUE, 1, 1, 0, 2, priv->cur_x, priv->cur_y); } if ( ( priv->touch_flags & RB_STAT ) && !( priv->touch_flags & LB_STAT ) ) { DBGOUT(2, "EVTouch: Right Press\n"); xf86PostButtonEvent (local->dev, TRUE, 3, 1, 0, 2, priv->cur_x, priv->cur_y); } /* Handling "middle" button press */ if ( ( priv->touch_flags & RB_STAT ) && ( priv->touch_flags & LB_STAT ) ) { DBGOUT(2, "EVTouch: Middle Press\n"); xf86PostButtonEvent (local->dev, TRUE, 2, 1, 0, 2, priv->cur_x, priv->cur_y); } priv->emulate3_timer_expired = TRUE; xf86UnblockSIGIO(sigstate); return 0; } static void DoBtnAction(EVTouchPrivatePtr priv) { int btn = 0; LocalDevicePtr local = priv->local; DBGOUT(2, "EVTouch: %s btn_count=%d\n", __FUNCTION__, priv->btn_count); for (btn = 0; btn < priv->btn_count; btn++) { DBGOUT(9, "EVTouch: %s do_it = %d \n", __FUNCTION__, priv->btn_actions[btn].do_it); if (priv->btn_actions[btn].do_it != 0) { if (priv->emulate3_timer != NULL) { TimerFree(priv->emulate3_timer); priv->emulate3_timer=NULL; priv->emulate3_timer_expired = FALSE; } DBGOUT(2, "EVTouch: %s btn = %d action = %d\n", __FUNCTION__, btn, priv->btn_actions[btn].action); xf86PostButtonEvent (local->dev, TRUE, btn, priv->btn_actions[btn].action, 0, 2, priv->cur_x, priv->cur_y); priv->btn_actions[btn].do_it = 0; priv->btn_actions[btn].action = 0; } } } static void SetBtnAction(EVTouchPrivatePtr priv, int btn, int action) { DBGOUT(2, "EVTouch: %s btn = %d action = %d\n", __FUNCTION__, btn, action); if (btn < priv->btn_count) { priv->btn_actions[btn].do_it = 1; priv->btn_actions[btn].action = action; } } void EVTouchProcessAbs(EVTouchPrivatePtr priv) { struct input_event *ev; /* packet being/just read */ int pos_changed = 0; ev = &priv->ev; if ( (ev->code == ABS_X) || (ev->code == ABS_Z) ) { priv->raw_x = ev->value; pos_changed = 1; } if ( (ev->code == ABS_Y) || (ev->code == ABS_RX) ) { priv->raw_y = ev->value; pos_changed = 1; } if (pos_changed == 1) { #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 2 ConvertProc(priv->local, 0, 2, priv->raw_x, priv->raw_y, 0, 0, 0, 0, &priv->cur_x, &priv->cur_y); #endif libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y); return; } if (ev->code == ABS_WHEEL) { LocalDevicePtr local = priv->local; if (ev->value > 0) { for (; ev->value > 0; ev->value--) { xf86PostButtonEvent (local->dev, TRUE, 4, 1, 0, 2, priv->cur_x, priv->cur_y); xf86PostButtonEvent (local->dev, TRUE, 4, 0, 0, 2, priv->cur_x, priv->cur_y); } } else if (ev->value < 0) { for (ev->value = -ev->value; ev->value > 0; ev->value--) { xf86PostButtonEvent (local->dev, TRUE, 5, 1, 0, 2, priv->cur_x, priv->cur_y); xf86PostButtonEvent (local->dev, TRUE, 5, 0, 0, 2, priv->cur_x, priv->cur_y); } } } } void EVTouchProcessRel(EVTouchPrivatePtr priv) { struct input_event *ev; /* packet being/just read */ int dummy; ev = &priv->ev; if ( ev->code == REL_X ) { priv->raw_x += ev->value; if (priv->raw_x > priv->max_x) priv->raw_x = priv->max_x; if (priv->raw_x < priv->min_x) priv->raw_x = priv->min_x; } if ( ev->code == REL_Y ) { priv->raw_y += ev->value; if (priv->raw_y > priv->max_y) priv->raw_y = priv->max_y; if (priv->raw_y < priv->min_y) priv->raw_y = priv->min_y; } #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 2 ConvertProc(priv->local, 0, 2, priv->raw_x, priv->raw_y, 0, 0, 0, 0, &priv->cur_x, &priv->cur_y); #endif libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y); } void EVTouchLBRBEvent(EVTouchPrivatePtr priv) { struct input_event *ev; /* packet being/just read */ LocalDevicePtr local = priv->local; ev = &priv->ev; DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); if (priv->emulate3) { if ( (ev->value==1) && (priv->emulate3_timer==NULL) ) priv->emulate3_timer = TimerSet(priv->emulate3_timer, 0, priv->emulate3_timeout, emulate3Timer, local); if ( (ev->value == 1) && (ev->code == BTN_LEFT) ) { priv->touch_flags |= LB_STAT; } if ( (ev->value == 1) && (ev->code == BTN_RIGHT) ) { priv->touch_flags |= RB_STAT; } if ( (ev->value == 0) && (priv->touch_flags & RB_STAT) && (priv->touch_flags & LB_STAT) ) { DBGOUT(2, "EVTouch: Middle Release\n"); priv->touch_flags &= ~LB_STAT; priv->touch_flags &= ~RB_STAT; SetBtnAction(priv, 2, BTN_RELEASE); } else if ( (ev->value == 0) && (ev->code == BTN_LEFT) && (priv->touch_flags & LB_STAT) ) { DBGOUT(2, "EVTouch: Left Release\n"); priv->touch_flags &= ~LB_STAT; SetBtnAction(priv, 1, BTN_RELEASE); } else if ( (ev->value == 0) && (ev->code == BTN_RIGHT) && (priv->touch_flags & RB_STAT) ) { DBGOUT(2, "EVTouch: Right Release\n"); priv->touch_flags &= ~RB_STAT; SetBtnAction(priv, 3, BTN_RELEASE); } } else { if (ev->code == BTN_LEFT) { SetBtnAction(priv, 1, ev->value); } if (ev->code == BTN_MIDDLE) { SetBtnAction(priv, 2, ev->value); } if (ev->code == BTN_RIGHT) { SetBtnAction(priv, 3, ev->value); } } } void EVTouchProcessKey(EVTouchPrivatePtr priv) { struct input_event *ev; /* packet being/just read */ DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); ev = &priv->ev; if ( (ev->code == BTN_LEFT) || (ev->code == BTN_RIGHT) || (ev->code == BTN_MIDDLE) ) { /* give lb and rb-events some special treatment (emulate3 or not, ...) */ EVTouchLBRBEvent(priv); return; } #ifdef _0_ switch (ev->code) { case BTN_SIDE: break; case BTN_EXTRA: break; case BTN_FORWARD: break; case BTN_BACK: break; case BTN_TASK: break; default: return; } xf86PostButtonEvent(local->dev, TRUE, btn, ev->value, 0, 2, priv->cur_x, priv->cur_y); #endif return; } static Bool QueryHardware (LocalDevicePtr local) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); return Success; } static Bool DeviceOn (DeviceIntPtr dev) { LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate; EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); local->fd = xf86OpenSerial(local->options); DBGOUT(2, "EVTouch: %s\n", __FUNCTION__ ); if (local->fd == -1) { xf86Msg(X_WARNING, "%s: cannot open input device\n", local->name); return (!Success); } priv->buffer = XisbNew(local->fd, 64); DBG (9, XisbTrace (priv->buffer, 1)); if (!priv->buffer) { xf86CloseSerial(local->fd); local->fd = -1; return (!Success); } if (QueryHardware(local) != Success) { ErrorF ("Unable to query/initialize EVTouch hardware.\n"); return (!Success); } xf86FlushInput(local->fd); if (ioctl(local->fd, EVIOCGRAB, (void *)1)) xf86Msg(X_ERROR, "%s: Unable to grab device (%s).\n", local->name, strerror(errno)); #ifndef XFREE86_V4 xf86AddEnabledDevice(local); #else AddEnabledDevice(local->fd); #endif dev->public.on = TRUE; return (Success); } static Bool DeviceOff (DeviceIntPtr dev) { LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate; EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); DBGOUT(2, "EVTouch: %s\n", __FUNCTION__ ); if (local->fd != -1) { ioctl(local->fd, EVIOCGRAB, (void *)0); xf86RemoveEnabledDevice (local); if (priv->buffer) { XisbFree(priv->buffer); priv->buffer = NULL; } xf86CloseSerial(local->fd); local->fd = -1; } dev->public.on = FALSE; if ( (priv->calibrate) && (priv->fifo>0) ){ close (priv->fifo); } return (Success); } static Bool DeviceInit (DeviceIntPtr dev) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate; EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); unsigned char map[EV_MAX_BUTTONS]; int i; for (i = 0; i < EV_MAX_BUTTONS; i++) map[i] = i; priv->btn_count = EV_MAX_BUTTONS; /* * these have to be here instead of in the SetupProc, because when the * SetupProc is run at server startup, screenInfo is not setup yet */ ScrnInfoPtr pScrn = xf86Screens[priv->screen_num]; priv->screen_width = pScrn->virtualX; /* It's the virtual screen size ! */ priv->screen_height = pScrn->virtualY; priv->pViewPort_X0 = &(pScrn->frameX0); /* initialize the pointers to the viewport coords */ if ( (priv->screen_width != priv->phys_width) || (priv->screen_height != priv->phys_height) ) priv->virtual = 1; else priv->virtual = 0; priv->pViewPort_Y0 = &(pScrn->frameY0); priv->pViewPort_X1 = &(pScrn->frameX1); priv->pViewPort_Y1 = &(pScrn->frameY1); DBGOUT(2, "EVTouch: Display X,Y: %d %d\n", priv->phys_width, priv->phys_height); DBGOUT(2, "EVTouch: Virtual X,Y: %d %d\n", priv->screen_width, priv->screen_height); DBGOUT(2, "EVTouch: DriverName, Rev.: %s %d\n", pScrn->driverName, pScrn->driverVersion); DBGOUT(2, "EVTouch: Viewport X0,Y0: %d %d\n", *priv->pViewPort_X0, *priv->pViewPort_Y0); DBGOUT(2, "EVTouch: Viewport X1,Y1: %d %d\n", *priv->pViewPort_X1, *priv->pViewPort_Y1); DBGOUT(2, "EVTouch: MaxValue H,V: %d %d\n", pScrn->maxHValue, pScrn->maxVValue); priv->screen_width = screenInfo.screens[priv->screen_num]->width; priv->screen_height = screenInfo.screens[priv->screen_num]->height; /* * Device reports button press for 5 buttons. */ if (InitButtonClassDeviceStruct (dev, EV_MAX_BUTTONS, map) == FALSE) { ErrorF("Unable to allocate EVTouch touchscreen ButtonClassDeviceStruct\n"); return BadAlloc; } DBGOUT(2, "EVTouch: %s btn_count=%d\n", __FUNCTION__, priv->btn_count); priv->btn_actions = xcalloc(priv->btn_count, sizeof(BtnAction)); memset(priv->btn_actions, 0, priv->btn_count * sizeof(BtnAction)); DBGOUT(2, "EVTouch: %s btn_count=%d\n", __FUNCTION__, priv->btn_count); if (InitFocusClassDeviceStruct(dev) == FALSE) { ErrorF("Unable to allocate EVTouch touchscreen FocusClassDeviceStruct\n"); return !Success; } /* * Device reports motions on 2 axes in absolute coordinates. * Axes min and max values are reported in raw coordinates. */ if (InitValuatorClassDeviceStruct(dev, 2, xf86GetMotionEvents, local->history_size, Absolute) == FALSE) { ErrorF ("Unable to allocate EVTouch touchscreen ValuatorClassDeviceStruct\n"); return !Success; } #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 2 xf86InitValuatorAxisStruct(dev, 0, 0, priv->screen_width, 1024, EV_AXIS_MIN_RES /* min_res */ , EV_AXIS_MAX_RES /* max_res */ ); xf86InitValuatorDefaults(dev, 0); xf86InitValuatorAxisStruct(dev, 1, 0, priv->screen_height, 1024, EV_AXIS_MIN_RES /* min_res */ , EV_AXIS_MAX_RES /* max_res */ ); xf86InitValuatorDefaults(dev, 1); #else xf86InitValuatorAxisStruct(dev, 0, priv->min_x, priv->max_x, xf86InitValuatorDefaults(dev, 1); #endif /* Initial position of pointer on screen: Centered */ priv->cur_x=(priv->max_x - priv->min_x)/2; priv->cur_y=(priv->max_y - priv->min_y)/2; priv->raw_x=priv->cur_x; priv->raw_y=priv->cur_y; libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y); if (InitProximityClassDeviceStruct (dev) == FALSE) { ErrorF ("Unable to allocate EVTouch touchscreen ProximityClassDeviceStruct\n"); return !Success; } if (InitPtrFeedbackClassDeviceStruct(dev, EVTouchPtrCtrl) == FALSE) { ErrorF ("unable to allocate EVTouch touchscreen PtrFeedbackClassDeviceStruct\n"); return !Success; } /* * Allocate the motion events buffer. */ xf86MotionHistoryAllocate (local); return (Success); } static Bool DeviceControl (DeviceIntPtr dev, int mode) { Bool RetValue; switch (mode) { case DEVICE_INIT: RetValue = DeviceInit(dev); break; case DEVICE_ON: RetValue = DeviceOn(dev); break; case DEVICE_OFF: case DEVICE_CLOSE: RetValue = DeviceOff(dev); break; default: RetValue = BadValue; } return( RetValue ); } static void EVTouchNewPacket (EVTouchPrivatePtr priv) { memset(&priv->ev, 0, sizeof(struct input_event)); priv->packeti = 0; priv->binary_pkt = FALSE; } static unsigned char EVTouchRead(EVTouchPrivatePtr priv) { unsigned char c; XisbBlockDuration (priv->buffer, EV_TIMEOUT); c = XisbRead(priv->buffer); return (c); } static Bool EVTouchGetPacket (EVTouchPrivatePtr priv) { static int count = 0; int c; CARD32 now; if (count==0) EVTouchNewPacket(priv); while ((c = XisbRead(priv->buffer)) >= 0) { if (count == 0) { now = GetTimeInMillis(); libtouchSetTime(priv->libtouch, now); } ((char *)&priv->ev)[count] = c; count ++; if (sizeof(priv->ev) == count) { count = 0; EVTouchDumpPacketToLog(priv); return Success; } } return (!Success); } static void ReadInput (LocalDevicePtr local) { struct input_event *ev; /* packet being/just read */ EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); /* * set blocking to -1 on the first call because we know there is data to * read. Xisb automatically clears it after one successful read so that * succeeding reads are preceeded buy a select with a 0 timeout to prevent * read from blocking infinately. */ XisbBlockDuration (priv->buffer, -1); while (EVTouchGetPacket (priv) == Success) { ev = &priv->ev; DBGOUT(2, "EVTouch: %s type:%0.2x code: 0x%0.4x value:%d\n", __FUNCTION__, ev->type, ev->code, ev->value); xf86XInputSetScreen(local, priv->screen_num, priv->cur_x, priv->cur_y); xf86PostProximityEvent(local->dev, 1, 0, 2, priv->cur_x, priv->cur_y); switch (ev->type) { case EV_ABS: EVTouchProcessAbs(priv); break; case EV_REL: EVTouchProcessRel(priv); break; case EV_KEY: xf86PostMotionEvent (local->dev, TRUE, 0, 2, priv->cur_x, priv->cur_y); if (priv->ev.code == BTN_TOUCH) { if (priv->ev.value == 1) { priv->touch_flags |= TOUCHED; DBGOUT(2, "EVTouch: TOUCHED\n"); } else { priv->touch_flags &= ~TOUCHED; DBGOUT(2, "EVTouch: UNTOUCHED\n"); } } EVTouchProcessKey(priv); break; case EV_SYN: xf86PostMotionEvent (local->dev, TRUE, 0, 2, priv->cur_x, priv->cur_y); if ( priv->touch_flags & TOUCHED ) libtouchTriggerSM(priv->libtouch, PEN_TOUCHED); else libtouchTriggerSM(priv->libtouch, PEN_UNTOUCHED); DoBtnAction(priv); break; } DBGOUT( 2, "EVTouch: setting (x/y)=(%d/%d)\n", priv->cur_x, priv->cur_y); } } static int ControlProc(LocalDevicePtr device, xDeviceCtl *ctrl) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); /* xDeviceTSCalibrationCtl *c = (xDeviceTSCalibrationCtl *) ctrl; */ /* EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); */ /* priv->min_x = c->min_x; */ /* priv->max_x = c->max_x; */ /* priv->min_y = c->min_y; */ /* priv->max_y = c->max_y; */ return (Success); } static void CloseProc (LocalDevicePtr local) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); } static int SwitchMode (ClientPtr client, DeviceIntPtr dev, int mode) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); 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 ) { DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); /* correction factors depending on current position of pointer */ float cx[3]; float cy[3]; float dx = 0, dy = 0; int max_x, max_y; int xc, yc; int screen_width = 0; int screen_height = 0; #ifdef EVDBG int i = 0; #endif EVTouchPrivatePtr priv = (EVTouchPrivatePtr) (local->private); ScrnInfoPtr pScrn = xf86Screens[priv->screen_num]; Rotation rotation = RRGetRotation(pScrn->pScreen); DBGOUT(2, "EVTouch: FIRST: v0=%d v1=%d\n", v0, v1); /*write raw coordinates to fifo for calibration programm*/ if ( (priv->fifo > 0) && (priv->calibrate) ){ DBGOUT(2, "EVTouch: writing to FIFO\n"); write (priv->fifo, &v0, sizeof(v0)); write (priv->fifo, &v1, sizeof(v1)); } /*correction of raw coordinates*/ if (!priv->calibrate) { DBGOUT(2, "EVTouch: Scaling coordinates\n"); xc = v0 - priv->min_x; yc = v1 - priv->min_y; max_x = priv->max_x - priv->min_x; max_y = priv->max_y - priv->min_y; if (priv->rotate == EV_ROTATE_NONE) { screen_width = pScrn->currentMode->HDisplay; screen_height = pScrn->currentMode->VDisplay; } else { screen_width = pScrn->currentMode->VDisplay; screen_height = pScrn->currentMode->HDisplay; } if ( rotation == RR_Rotate_90 || rotation == RR_Rotate_270 ) { int tmp = screen_width; screen_width = screen_height; screen_height = tmp; } if (xc < (max_x / 2)) { /* left */ if (yc>(max_y / 2)) { /* upper */ cx[1] = ((float) xc / (max_x / 2) ); cx[0] = (float) 1 - cx[1]; cy[0] = ((float) (yc-(max_y/2)) / (max_y/2) ); cy[1] = (float) 1 - cy[0]; dx = ((float) (cx[1] * cy[0] * priv->diff[1][0]) + (float)(cx[0] * cy[0] * priv->diff[0][0]) + (float)(cx[1] * cy[1] * priv->diff[4][0]) + (float)(cx[0] * cy[1] * priv->diff[3][0])); dy = ((float) (cx[1] * cy[0] * priv->diff[1][1]) + (float)(cx[0] * cy[0] * priv->diff[0][1]) + (float)(cx[1] * cy[1] * priv->diff[4][1]) + (float)(cx[0] * cy[1] * priv->diff[3][1])); } else { /* lower */ cx[1] = ((float) xc / (max_x/2) ); cx[0] = (float) 1 - cx[1]; cy[0] = ((float) yc / (max_y/2) ); cy[1] = (float) 1 - cy[0]; dx = ((float) (cx[1] * cy[0] * priv->diff[4][0]) + (float)(cx[0] * cy[0] * priv->diff[3][0]) + (float)(cx[1] * cy[1] * priv->diff[7][0]) + (float)(cx[0] * cy[1] * priv->diff[6][0])); dy = ((float) (cx[1] * cy[0] * priv->diff[4][1]) + (float)(cx[0] * cy[0] * priv->diff[3][1]) + (float)(cx[1] * cy[1] * priv->diff[7][1]) + (float)(cx[0] * cy[1] * priv->diff[6][1])); } } else { /* right */ if (yc>(max_y/2)) { /* upper */ cx[1] = ((float) (xc-(max_x/2)) / (max_x/2) ); cx[0] = (float)1 - cx[1]; cy[0] = ((float) (yc-(max_y/2)) / (max_y/2) ); cy[1] = (float)1 - cy[0]; dx = ((float) (cx[1] * cy[0] * priv->diff[2][0]) + (float)(cx[0] * cy[0] * priv->diff[1][0]) + (float)(cx[1] * cy[1] * priv->diff[5][0]) + (float)(cx[0] * cy[1] * priv->diff[4][0])); dy = ((float) (cx[1] * cy[0] * priv->diff[2][1]) + (float)(cx[0] * cy[0] * priv->diff[1][1]) + (float)(cx[1] * cy[1] * priv->diff[5][1]) + (float)(cx[0] * cy[1] * priv->diff[4][1])); } else { /* lower */ cx[1] = ((float) (xc-(max_x/2)) / (max_x/2) ); cx[0] = (float) 1 - cx[1]; cy[0] = ((float) yc / (max_y/2) ); cy[1] = (float) 1 - cy[0]; dx = ((float) (cx[1] * cy[0] * priv->diff[5][0]) + (float)(cx[0] * cy[0] * priv->diff[4][0]) + (float)(cx[1] * cy[1] * priv->diff[8][0]) + (float)(cx[0] * cy[1] * priv->diff[7][0])); dy = ((float) (cx[1] * cy[0] * priv->diff[5][1]) + (float)(cx[0] * cy[0] * priv->diff[4][1]) + (float)(cx[1] * cy[1] * priv->diff[8][1]) + (float)(cx[0] * cy[1] * priv->diff[7][1])); } } #ifdef EVDBG for (i=0; i<3; i++) xf86ErrorFVerb(2, "cx[%d]=%f cy[%d]=%f\n", i, cx[i] ,i, cy[i]); DBGOUT(2, "EVTouch: ViewPort_X0=%d ViewPort_Y0=%d\n", *(priv->pViewPort_X0), *(priv->pViewPort_Y0)); DBGOUT(2, "EVTouch: dx=%f dy=%f\n", dx, dy); #endif xc = ( ((float)xc / max_x) * screen_width ) + dx; yc = ( ((float)yc / max_y) * screen_height) + dy; if (priv->swap_y == TRUE) yc = screen_height - yc; /* ususally we DON'T swap x -- but if swap_x is 1 => go on and swap */ if (priv->swap_x == TRUE) xc = screen_width - xc; int tmp = 0; /* rotation mixes x and y up a bit */ if (priv->rotate == EV_ROTATE_CW) { tmp = xc; xc = yc; yc = screen_width - tmp; } else if (priv->rotate == EV_ROTATE_CCW) { tmp = xc; xc = screen_height - yc; yc = tmp; } else if (priv->rotate == EV_ROTATE_UD) { xc = screen_width - xc; yc = screen_height - yc; } switch (rotation) { case RR_Rotate_0: v0 = xc; v1 = yc; break; case RR_Rotate_180: v0 = screen_width - xc; v1 = screen_height - yc; break; case RR_Rotate_90: tmp = xc; v0 = screen_height - yc; v1 = tmp; break; case RR_Rotate_270: tmp = xc; v0 = yc; v1 = screen_width - tmp; break; default: break; } } DBGOUT(2, "EVTouch: FINAL: v0=%d v1=%d\n", v0, v1); *x = v0; *y = v1; return (TRUE); } static InputInfoPtr EVTouchPreInit(InputDriverPtr drv, IDevPtr dev, int flags) { /* LocalDevicePtr local; */ InputInfoPtr local; EVTouchPrivatePtr priv; ScrnInfoPtr pScrn; int i = 0; char *s; char tmp_str[8]; int timeo = 0; DBGOUT(2, "EVTouch: %s\n", __FUNCTION__); priv = xcalloc (1, sizeof (EVTouchPrivateRec)); if (!priv) return NULL; local = xf86AllocateInput(drv, 0); if (!local) { xfree(priv); return NULL; } local->name = xstrdup(dev->identifier); local->type_name = XI_TOUCHSCREEN; local->device_control = DeviceControl; local->read_input = ReadInput; local->control_proc = ControlProc; local->close_proc = CloseProc; local->switch_mode = SwitchMode; local->conversion_proc = ConvertProc; local->reverse_conversion_proc = NULL; local->fd = -1; local->dev = NULL; local->private = priv; priv->local = local; local->private_flags = 0; local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; local->conf_idev = dev; xf86CollectInputOptions(local, default_options, NULL); xf86OptionListReport(local->options); priv->libtouch = xcalloc(1, sizeof(LibTouchRec)); libtouchInit(priv->libtouch, local); priv->screen_num = xf86SetIntOption(local->options, "ScreenNumber", 0 ); priv->calibrate = xf86SetIntOption(local->options, "Calibrate", 0); pScrn = xf86Screens[priv->screen_num]; priv->phys_width = pScrn->currentMode->HDisplay; /* physical screen resolution */ priv->phys_height = pScrn->currentMode->VDisplay; priv->min_x = xf86SetIntOption(local->options, "MinX", 0 ); priv->max_x = xf86SetIntOption(local->options, "MaxX", priv->phys_width ); priv->min_y = xf86SetIntOption(local->options, "MinY", 0 ); priv->max_y = xf86SetIntOption(local->options, "MaxY", priv->phys_height ); priv->button_number = xf86SetIntOption(local->options, "ButtonNumber", 2 ); priv->emulate3 = xf86SetBoolOption(local->options, "Emulate3Buttons", TRUE); priv->emulate3_timeout = xf86SetIntOption(local->options, "Emulate3Timeout", 50); debug_level = xf86SetIntOption(local->options, "DebugLevel", 0); libtouchSetDebugLevel(debug_level); timeo = xf86SetIntOption(local->options, "TapTimer", 90); libtouchSetTapTimeo(priv->libtouch, timeo); timeo = xf86SetIntOption(local->options, "LongtouchTimer", 160); libtouchSetLongtouchTimeo(priv->libtouch, timeo); libtouchSetMoveLimit(priv->libtouch, xf86SetIntOption( local->options, "MoveLimit", 180 )); priv->rotate = EV_ROTATE_NONE; s = xf86FindOptionValue(local->options, "Rotate"); if (s) { if (xf86NameCmp(s, "CW") == 0) { priv->rotate = EV_ROTATE_CW; } else if (xf86NameCmp(s, "CCW") == 0 ) { priv->rotate = EV_ROTATE_CCW; } } if (priv->rotate == EV_ROTATE_NONE) { priv->max_rel_x = priv->max_x; priv->max_rel_y = priv->max_y; priv->min_rel_x = priv->min_x; priv->min_rel_y = priv->min_y; } else { priv->max_rel_x = priv->max_y; priv->max_rel_y = priv->max_x; priv->min_rel_x = priv->min_y; priv->min_rel_y = priv->min_x; } priv->swap_y = xf86SetBoolOption(local->options, "SwapY", FALSE); priv->swap_x = xf86SetBoolOption(local->options, "SwapX", FALSE); /* get calibration parameters from XF86Config */ for (i = 0; i < 9; i++){ sprintf(tmp_str, "x%d", i); priv->diff[i][0] = xf86SetIntOption( local->options, tmp_str, 0 ); sprintf(tmp_str, "y%d", i); priv->diff[i][1] = xf86SetIntOption( local->options, tmp_str, 0 ); DBGOUT(2, "(diff[%d][0]/diff[%d][1])=(%d/%d)\n", i, i, priv->diff[i][0], priv->diff[i][1]); } priv->touch_flags = 0; local->history_size = xf86SetIntOption( local->options, "HistorySize", 0 ); /* prepare to process touch packets */ EVTouchNewPacket (priv); /* if started in calibration-mode: - open named pipe */ if (priv->calibrate) { priv->fifo = open("/tmp/ev_calibrate", O_RDWR, 0); if (priv->fifo < 0) xf86ErrorFVerb(2, "open FIFO FAILED\n"); } /* this results in an xstrdup that must be freed later */ local->name = xf86SetStrOption( local->options, "DeviceName", "EVTouch TouchScreen" ); xf86ProcessCommonOptions(local, local->options); local->flags |= XI86_CONFIGURED; xf86CloseSerial(local->fd); local->fd = -1; return (local); } static void EVTouchPtrCtrl(DeviceIntPtr device, PtrCtrl *ctrl) { /* I have no clue what this does, except that registering it stops the X server segfaulting in ProcGetPointerMapping() Ho Hum. */ }