/* xf86-input-utouch (c) Volker Werth, 2008 $Id: utouch.c 2090 2009-09-03 12:24:23Z volker $ */ static char __FILEINFO[] = "$Id$"; /* * 2do: * do device tasting for serial (v.24) devices * - close file handle if device doesn't taste well * fix signal handler to really destroy actual working parameters * (hint: real pointer to device in use needed) * fix calibration interface and make the calibration app useable */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xf86Module.h" #define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) #define BEEP() ; /*XBell(NULL,100)*/ #define POSTPIPE(pipe,fmt,...) { if (pipe > 0) { \ write(pipe, stemp, \ sprintf(stemp, fmt, ## __VA_ARGS__ )); } }; #define DBGPIPE(lvl,pipe,fmt,...) \ { if (lvl<=debug_level) POSTPIPE(pipe, "###" fmt, ## __VA_ARGS__); } #define NAXES 2 /* X and Y axes only */ #define NBUTTONS 2 /* max theoretical buttons */ #define DFLTBUTTONS 1 /* default number of buttons */ /*#define NUMEVENTS 16*/ /* max # of device events to read at once */ #define UTOUCH_CLIPVAL 0xffff #define UTOUCH_IGNORE_CLIP 1 #define _UT_SIGNATURE1 't' #define _UT_SIGNATURE2 'S' #define _UT_VERSION 020 #define _UT_ABSOLUTE 0x0001 /* calibration */ #define UTOUCH_CALMASK 0x100 #define UTOUCH_CALX 0x1 #define UTOUCH_CALY 0x2 #define UTOUCH_CALAXIS (UTOUCH_CALX|UTOUCH_CALY) #define MAXCALPOINTS 16 #define CAL_LOCK 0x00 /* calibration mode locked */ #define CAL_LEARN 0x01 /* driver self learning mode enabled */ #define CAL_PRECAL 0x02 /* self learn if no pre-calibration available */ #define CAL_POINTS 0x04 /* manual calibration mode enabled */ typedef enum { IF_UTOUCH, IF_ATOUCH } touch_if_t; typedef struct utouch_coord { u_int16_t x; u_int16_t y; u_int16_t pressure; } utouch_coord_t; typedef struct utouch_proto { char sig[2]; u_int8_t version; u_int8_t ssize; u_int16_t mode; utouch_coord_t coord; u_int8_t buttons; char res[1]; } utouch_proto_t; typedef struct UTouchDevice { char *identifier; touch_if_t interfacetype; char *devName; /* device name */ char *confFile; /* configuration file holding dynamic values */ short useConfFile; short enableCal; int confFd; unsigned int buttons; /* # of buttons */ unsigned int lastbuttons; /* last state of buttons */ int x, y; /* current abs coordinates */ int pressure, lastpressure; unsigned short touchcounter; int min_x, max_x, min_y, max_y; /* always phys coord !! */ int num_axes; int swap_axes; int inv_x, inv_y; /* any axis values reversed ? */ int screen_width, screen_height; int logical_width, logical_heigth; int screen_no; int num, den, threshold; /* relative accel params */ int filter_limit; /* filter near movement - value = n/1000 */ int filter_limit_far; /* filter far movement - value = n/1000 */ int filter_1stpress; int filter_release; pointer buffer; int negativeZ, positiveZ; /* mappings for Z axis */ short beepenable; /* enable beeps on error */ char *livemonitor; int monitorhandle; } UTouchDeviceRec, *UTouchDevicePtr; typedef struct UTouchPointMatch { int scr_x; int scr_y; int touch_x; int touch_y; } UTouchPointMatch_t; typedef struct { short points; UTouchPointMatch_t coord[MAXCALPOINTS]; } UTouchCal_t; static pointer utouchLoad(pointer module, pointer options, int *errmaj, int *errmin); static void utouchUnload(pointer); static const OptionInfoRec *utouchAvailableOptions(void *); static InputInfoPtr utouchSetup(InputDriverPtr, IDevPtr, int); static int utouchProc(DeviceIntPtr, int); static void utouchReadUtouch(InputInfoPtr); static void utouchReadAtouch(InputInfoPtr pInfo); static void utouchProcessInput(InputInfoPtr pInfo, utouch_proto_t * proto); static void utouchSendButtons(InputInfoPtr, int); static Bool utouchOpen(InputInfoPtr); static void utouchClose(InputInfoPtr); static Bool utouchConvert(InputInfoPtr, int, int, int, int, int, int, int, int, int *, int *); static void utouchPtrFeedbackCtrl(DeviceIntPtr , PtrCtrl *); /*static int utouchScaleAxis(int point, int inverted, int screenmax, int scalemax);*/ static void utouchCoordLog2Scr(int scrmaxx, int scrmaxy, int lmaxx, int lmaxy, int swap_axes, int lx, int ly, int *scrx, int *scry); static void utouchCoordPhys2Log(int phymaxx, int phymaxy, int phyminx, int phyminy, int inv_x, int inv_y, int px, int py, int *lx, int *ly); static int UtouchConfFileRead(UTouchDevicePtr devPtr); static int UtouchConfFileWrite(UTouchDevicePtr devPtr); void sigtouch(int sig); UTouchCal_t UTouchCal; InputInfoPtr putouchDrvInfo = NULL; static char stemp[255]={0}; static XF86ModuleVersionInfo VersionRec = { "utouch", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, 0, 2, 0, ABI_CLASS_XINPUT, ABI_XINPUT_VERSION, MOD_CLASS_XINPUT, {0, 0, 0, 0} }; XF86ModuleData utouchModuleData = {&VersionRec, utouchLoad, utouchUnload}; _X_EXPORT InputDriverRec UTouchDrvRec = { _UT_VERSION, "utouch", NULL, /* identify */ utouchSetup, /* probe, attach */ NULL, /* detach */ NULL, 0 }; ModuleInfoRec utouchInfo = { 1, "UTouch", NULL, 0, utouchAvailableOptions, }; typedef enum { UTOPT_DEVICE, UTOPT_INTERFACE, UTOPT_DEBUG_LEVEL, UTOPT_MINX, UTOPT_MAXX, UTOPT_MINY, UTOPT_MAXY, UTOPT_ROTATE, UTOPT_SWAPXY, UTOPT_SCREENNO, UTOPT_INVERTX, UTOPT_INVERTY, UTOPT_THRESH, /* pressure threshold value */ UTOPT_FILTERNEAR, /* filter out movements too near */ UTOPT_FILTERFAR, /* filter out movements too far */ UTOPT_FILTERFIRST, /* filter out first press event */ UTOPT_FILTERRELEASE, /* filter out phantom releases */ UTOPT_CONFIG, /* name of the configuration (calibration) file */ UTOPT_CALMAGIC, /* magic calibration enabled? */ UTOPT_LIVEMON, UTOPT_BAUDRATE, UTOPT_DATABIT, UTOPT_STOPBIT, UTOPT_PARITY } UTouchOpts; static const OptionInfoRec UTouchOptions[] = { { UTOPT_DEVICE, "device", OPTV_STRING, {0}, FALSE }, { UTOPT_INTERFACE, "Interface", OPTV_STRING, {0}, FALSE }, { UTOPT_DEBUG_LEVEL, "debugLevel", OPTV_INTEGER, {0}, FALSE }, { UTOPT_MINX, "minX", OPTV_INTEGER, {0}, FALSE }, { UTOPT_MAXX, "maxX", OPTV_INTEGER, {0}, FALSE }, { UTOPT_MINY, "minY", OPTV_INTEGER, {0}, FALSE }, { UTOPT_MAXY, "maxY", OPTV_INTEGER, {0}, FALSE }, { UTOPT_ROTATE, "rotate", OPTV_STRING, {0}, FALSE }, { UTOPT_SWAPXY, "swapxy", OPTV_BOOLEAN, {0}, FALSE }, { UTOPT_SCREENNO, "ScreenNo", OPTV_INTEGER, {0}, FALSE }, { UTOPT_INVERTX, "invertX", OPTV_BOOLEAN, {0}, FALSE }, { UTOPT_INVERTY, "invertY", OPTV_BOOLEAN, {0}, FALSE }, { UTOPT_THRESH, "ThresHold", OPTV_INTEGER, {0}, FALSE }, { UTOPT_FILTERNEAR, "FilterNear", OPTV_INTEGER, {0}, FALSE }, { UTOPT_FILTERFAR, "FilterFar", OPTV_INTEGER, {0}, FALSE }, { UTOPT_FILTERFIRST, "FilterFirstPress", OPTV_INTEGER, {0}, FALSE }, { UTOPT_FILTERRELEASE, "FilterRelease", OPTV_BOOLEAN, {0}, FALSE }, { UTOPT_CONFIG, "ConfigFile", OPTV_STRING, {0}, FALSE }, { UTOPT_CALMAGIC, "CalibrateOpen", OPTV_INTEGER, {0}, TRUE }, { UTOPT_LIVEMON, "LiveMonitor", OPTV_STRING, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; /* #undef DEBUG */ #define DEBUG #undef DBG static int debug_level = 0; #ifdef DEBUG # define DBG(lvl, f) { if ((lvl) <= debug_level) f;} #else # define DBG(lvl, f) #endif /* * PreInit */ static InputInfoPtr utouchSetup(InputDriverPtr drv, IDevPtr dev, int flags) { InputInfoPtr pInfo = NULL; UTouchDeviceRec *priv = NULL; MessageType buttons_from = X_CONFIG; char *s; xf86Msg(X_INFO, "%s: %s\n", dev->identifier, __FILEINFO); pInfo = xf86AllocateInput(drv, 0); if (pInfo == NULL) { return NULL; } priv = (UTouchDeviceRec*)xcalloc(1, sizeof(UTouchDeviceRec)); if (priv == NULL) goto fail; priv->identifier = dev->identifier; putouchDrvInfo = pInfo; pInfo->name = dev->identifier; pInfo->type_name = XI_TOUCHSCREEN; pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; pInfo->private = priv; pInfo->conf_idev = dev; pInfo->fd = -1; pInfo->old_x = -1; pInfo->old_y = -1; priv->num_axes = NAXES; pInfo->device_control = utouchProc; pInfo->read_input = utouchReadUtouch; /*pInfo->control_proc = utouchChangeControl;*/ pInfo->switch_mode = NULL; pInfo->conversion_proc = utouchConvert; pInfo->reverse_conversion_proc = NULL; #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 pInfo->motion_history_proc = xf86GetMotionEvents; pInfo->history_size = 0; #endif xf86CollectInputOptions(pInfo, NULL, NULL); xf86ProcessCommonOptions(pInfo, pInfo->options); debug_level = xf86SetIntOption(pInfo->options, "DebugLevel", 0); xf86Msg(X_CONFIG, "%s: DebugLevel %d\n", dev->identifier, debug_level); priv->devName = xf86FindOptionValue(pInfo->options, "Device"); if (priv->devName == NULL) { xf86Msg(X_ERROR, "%s: No Device specified.\n", dev->identifier); goto fail; } /* --> priv->flags |= ABSOLUTE_FLAG;*/ priv->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0); if (priv->buttons == 0) { priv->buttons = DFLTBUTTONS; buttons_from = X_DEFAULT; } priv->negativeZ = priv->positiveZ = 0; priv->screen_no = xf86SetIntOption(pInfo->options, "ScreenNo", 0); xf86Msg(X_CONFIG, "%s: screen: %d (%dx%d) (max: %d)\n", dev->identifier, priv->screen_no, screenInfo.screens[priv->screen_no]->width, screenInfo.screens[priv->screen_no]->height, screenInfo.numScreens); if (priv->screen_no >= screenInfo.numScreens || priv->screen_no < 0) { priv->screen_no = 0; } priv->min_x = xf86SetIntOption(pInfo->options, "MinX", screenInfo.screens[priv->screen_no]->width - 1); priv->min_y = xf86SetIntOption(pInfo->options, "MinY", screenInfo.screens[priv->screen_no]->height - 1); priv->max_x = xf86SetIntOption(pInfo->options, "MaxX", screenInfo.screens[priv->screen_no]->width - 1); priv->max_y = xf86SetIntOption(pInfo->options, "MaxY", screenInfo.screens[priv->screen_no]->height - 1); priv->threshold = xf86SetIntOption(pInfo->options, "Threshold", 1); /* next line can be trashed some day - compatibility only */ priv->filter_limit = xf86SetIntOption(pInfo->options, "FilterLimit", 0); priv->filter_limit = xf86SetIntOption(pInfo->options, "FilterNear", 0); priv->filter_limit_far = xf86SetIntOption(pInfo->options, "FilterFar", 0); priv->filter_1stpress = xf86SetIntOption(pInfo->options, "FilterFirstPress", 0); priv->filter_release = xf86SetBoolOption(pInfo->options, "FilterRelease", 0); priv->enableCal = xf86SetIntOption(pInfo->options, "CalibrateOpen", CAL_PRECAL); if (priv->filter_limit_far && priv->filter_limit_far <= priv->filter_limit) { xf86Msg(X_WARNING, "%s FilterFar too short (%d <= %d) " "disabling FilterFar\n", dev->identifier, priv->filter_limit_far, priv->filter_limit); priv->filter_limit_far = 0; } xf86Msg(X_CONFIG, "%s min / max x position: %d - %d\n", dev->identifier, priv->min_x, priv->max_x); xf86Msg(X_CONFIG, "%s min / max y position: %d - %d\n", dev->identifier, priv->min_y, priv->max_y); xf86Msg(X_CONFIG, "%s threshold value: %d %s\n", dev->identifier, priv->threshold, priv->threshold >= 32 ? "(too high)" : ""); xf86Msg(X_CONFIG, "%s near filter value: %d\n", dev->identifier, priv->filter_limit); xf86Msg(X_CONFIG, "%s far filter value: %d\n", dev->identifier, priv->filter_limit_far); xf86Msg(X_CONFIG, "%s press filter value: %d %s\n", dev->identifier, priv->filter_1stpress, priv->filter_1stpress ? "(not recommended)" : ""); xf86Msg(X_CONFIG, "%s release filter %s\n", dev->identifier, priv->filter_release ? "enabled" : "disabled"); priv->useConfFile = 0; priv->confFd = -1; if ((priv->confFile = xf86FindOptionValue(pInfo->options, "ConfigFile")) != NULL) { if (access(priv->confFile, R_OK|W_OK) == 0) { xf86Msg(X_CONFIG, "%s: config file %s\n", dev->identifier, priv->confFile); priv->useConfFile = 1; if (!UtouchConfFileRead(priv) && priv->enableCal & CAL_PRECAL) { priv->enableCal = CAL_LEARN; /* conf read error, enable self learning */ xf86Msg(X_INFO, "%s: config read error, enable self learning mode\n", dev->identifier); } else { if (priv->enableCal & CAL_PRECAL) priv->enableCal = CAL_LOCK; } } else { if (priv->enableCal & CAL_PRECAL) priv->enableCal = CAL_LEARN; if ((priv->confFd = open(priv->confFile, O_RDWR|O_CREAT, 0644))) { xf86Msg(X_WARNING, "%s: config file created %s\n", dev->identifier, priv->confFile); priv->useConfFile = 1; close(priv->confFd); priv->confFd = -1; } else { xf86Msg(X_ERROR, "%s: unable to create config file %s\n", dev->identifier, priv->confFile); } } } else { priv->confFile = "/usr/local/etc/utouch.conf"; xf86Msg(X_WARNING, "%s: missing config filename, defaulting to %s\n", dev->identifier, priv->confFile); } priv->monitorhandle = 0; if ((priv->livemonitor = xf86FindOptionValue(pInfo->options, "LiveMonitor")) != NULL) { } else { priv->livemonitor = NULL; } if ((priv->inv_x = xf86SetBoolOption(pInfo->options, "Invert X", 0))) xf86Msg(X_CONFIG,"%s: inverting x-axis\n", pInfo->name ); if ((priv->inv_y = xf86SetBoolOption(pInfo->options, "Invert Y", 0))) xf86Msg(X_CONFIG,"%s: inverting y-axis\n", pInfo->name ); priv->swap_axes = 0; s = xf86FindOptionValue(pInfo->options, "Rotate"); if (s) { if (xf86NameCmp(s, "right") == 0) { priv->swap_axes = 1; } else if (xf86NameCmp(s, "left") == 0) { priv->swap_axes = -1; } else if (xf86NameCmp(s, "inverted") == 0) { priv->swap_axes = 2; } else if (xf86NameCmp(s, "normal") == 0 || xf86NameCmp(s, "regular") == 0) { priv->swap_axes = 0; } else { xf86Msg(X_ERROR, "%s: Option Rotate: \"%s\" invalid value\n", dev->identifier, s); xf86Msg(X_ERROR, "use: \"right\", \"left\"\n"); } xf86Msg(X_CONFIG, "%s: Rotate: %s\n", dev->identifier, priv->swap_axes == 1 ? "right" : priv->swap_axes == -1 ? "left" : "inverted"); } xf86Msg(buttons_from, "%s: Buttons: %d\n", pInfo->name, priv->buttons); priv->interfacetype = IF_UTOUCH; /* default to UTOUCH interface */ s = xf86FindOptionValue(pInfo->options, "Interface"); if (s) { if (xf86NameCmp(s, "atouch") == 0) { priv->interfacetype = IF_ATOUCH; } } switch (priv->interfacetype) { case IF_ATOUCH: pInfo->read_input = utouchReadAtouch; break; case IF_UTOUCH: break; default: /* */ xf86Msg(X_ERROR, "%s: unsupported interface type\n", dev->identifier); goto fail; break; } //pInfo->use = IsXExtensionDevice; /* grab signals */ //signal(SIGUSR1, sigtouch); signal(SIGUSR2, sigtouch); signal(SIGUSR2+1, sigtouch); /* mark the device configured */ pInfo->flags |= XI86_CONFIGURED | XI86_OPEN_ON_INIT; return pInfo; fail: if (priv != NULL) xfree(priv); if (pInfo != NULL) xfree(pInfo); return NULL; } /* utouchSetup */ static int utouchProc(DeviceIntPtr pUTouch, int what) { InputInfoPtr pInfo = (InputInfoPtr)pUTouch->public.devicePrivate; UTouchDevicePtr priv = (UTouchDevicePtr)XI_PRIVATE(pUTouch); unsigned char map[NBUTTONS + 1] = {0}; int i; switch (what) { case DEVICE_INIT: xf86Msg(X_INFO, "%s UTouch INIT\n", pInfo->name); xf86Msg(X_CONFIG, "%s: screen: %d (%dx%d) (max: %d)\n", pInfo->name, priv->screen_no, screenInfo.screens[priv->screen_no]->width, screenInfo.screens[priv->screen_no]->height, screenInfo.numScreens); priv->screen_width = screenInfo.screens[priv->screen_no]->width; priv->screen_height = screenInfo.screens[priv->screen_no]->height; priv->logical_width = screenInfo.screens[priv->screen_no]->width; priv->logical_heigth = screenInfo.screens[priv->screen_no]->height; xf86Msg(X_INFO, "%s Xinput ver %d.%d\n", pInfo->name, GET_ABI_MAJOR(ABI_XINPUT_VERSION), GET_ABI_MINOR(ABI_XINPUT_VERSION)); for (i = 0; i < NBUTTONS; i++) map[i] = i; InitPointerDeviceStruct((DevicePtr)pUTouch, map, min(priv->buttons, NBUTTONS), #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 miPointerGetMotionEvents, utouchPtrFeedbackCtrl, miPointerGetMotionBufferSize() #else GetMotionHistory, utouchPtrFeedbackCtrl, GetMotionHistorySize(), NAXES #endif ); InitAbsoluteClassDeviceStruct(pUTouch); InitValuatorClassDeviceStruct(pUTouch, priv->num_axes, xf86GetMotionEvents, 0, Absolute); xf86InitValuatorAxisStruct(pUTouch, 0, 0, -1, 1, 0, 1); //xf86InitValuatorAxisStruct(pUTouch, 0, -1, -1, 1, 0, 1); xf86InitValuatorDefaults(pUTouch, 0); xf86InitValuatorAxisStruct(pUTouch, 1, 0, -1, 1, 0, 1); //xf86InitValuatorAxisStruct(pUTouch, 1, -1, -1, 1, 0, 1); xf86InitValuatorDefaults(pUTouch, 1); /* create a 2nd ptr feedback for calibration purposes */ //InitPtrFeedbackClassDeviceStruct(pUTouch, utouchPtrFeedbackCtrl); xf86MotionHistoryAllocate(pInfo); AssignTypeAndName(pUTouch, pInfo->atom, pInfo->name); pUTouch->public.on = FALSE; priv->x = priv->min_x; priv->y = priv->min_y; priv->pressure = priv->lastpressure = 0; priv->touchcounter = 0; break; case DEVICE_ON: xf86Msg(X_INFO, "%s On\n", pInfo->name); if (! pUTouch->public.on) { if ((pInfo->fd < 0) && (utouchOpen(pInfo) != Success)) { xf86Msg(X_ERROR, "%s: opening %s failed %s\n", pInfo->name, priv->devName, strerror(errno)); return !Success; } xf86AddEnabledDevice(pInfo); pUTouch->public.on = TRUE; if (priv->livemonitor != NULL && priv->monitorhandle <= 0) { if ((!access(priv->livemonitor, R_OK|W_OK) || !mkfifo(priv->livemonitor, ACCESSPERMS)) && (priv->monitorhandle = open(priv->livemonitor, O_RDWR|O_NONBLOCK))) { xf86Msg(X_CONFIG, "%s: live monitor %s (h=%d/%x)\n", pInfo->name, priv->livemonitor, priv->monitorhandle, errno); if (priv->monitorhandle == -1) priv->monitorhandle = 0; } } } else xf86Msg(X_WARNING, "%s: DEVICE_ON: %s already open!\n", pInfo->name, priv->devName); POSTPIPE(priv->monitorhandle, "# %s DEVICE_ON (dbg: %d)\n", pInfo->name, debug_level); break; case DEVICE_CLOSE: xf86Msg(X_INFO, "%s closing\n", pInfo->name); case DEVICE_OFF: POSTPIPE(priv->monitorhandle, "# %s DEVICE_OFF\n", pInfo->name); xf86Msg(X_INFO, "%s Off\n", pInfo->name); if (pInfo->fd >= 0) { xf86RemoveEnabledDevice(pInfo); xf86FlushInput(pInfo->fd); utouchClose(pInfo); pInfo->fd = -1; /* if (priv->monitorhandle) { close(priv->monitorhandle); priv->monitorhandle = 0; } */ } pUTouch->public.on = FALSE; break; default: xf86Msg(X_ERROR, "%s: unknown command %d\n", pInfo->name, what); return !Success; } /* switch */ return Success; } /* utouchProc */ static void utouchReadUtouch(InputInfoPtr pInfo) { utouch_proto_t proto; UTouchDevicePtr priv; static int irc; static int scrx, scry; static int filterthis; priv = (UTouchDevicePtr)pInfo->private; while (xf86WaitForInput(pInfo->fd, 0) > 0) { scrx = scry = filterthis = 0; irc = read(pInfo->fd, &proto, sizeof(utouch_proto_t)); if (irc >= sizeof(utouch_proto_t) && proto.ssize == sizeof(utouch_proto_t)) { utouchProcessInput(pInfo, &proto); } else { DBGPIPE(1, priv->monitorhandle, "%s: protocol error %c%c[%d] %d/%d (%d) %s\n", pInfo->name, proto.sig[0], proto.sig[1], proto.version, proto.ssize, sizeof(utouch_proto_t), irc, strerror(errno)); xf86Msg(X_WARNING, "%s: protocol error %c%c[%d] %d/%d (%d) %s\n", pInfo->name, proto.sig[0], proto.sig[1], proto.version, proto.ssize, sizeof(utouch_proto_t), irc, strerror(errno)); } } /* XisbBlockDuration(priv->buffer, -1); */ return; } /* utouchReadUtouch*/ static void utouchReadAtouch(InputInfoPtr pInfo) { utouch_proto_t proto; UTouchDevicePtr priv; static int irc; static int scrx, scry; static int filterthis; unsigned char buf[128]; priv = (UTouchDevicePtr)pInfo->private; while (xf86WaitForInput(pInfo->fd, 0) > 0) { scrx = scry = filterthis = 0; irc = read(pInfo->fd, buf, sizeof(buf)); if (irc >= 5 && buf[0] & 0x80) { /* we've received a touch packet */ /* convert it to a utouch packet and let it process */ proto.sig[0] = _UT_SIGNATURE1; proto.sig[1] = _UT_SIGNATURE2; proto.ssize = sizeof(utouch_proto_t); proto.mode = 1; proto.version = 0; proto.buttons = 1; proto.coord.x = buf[1] << 7 | buf[2]; proto.coord.y = buf[3] << 7 | buf[4]; if (buf[0] & 0x1) proto.coord.pressure = priv->threshold; else proto.coord.pressure = 0; DBG(2, ErrorF("%s sertouch: %02x %02x %02x %02x %02x (%d)\n", pInfo->name, (char)buf[0], buf[1], buf[2], buf[3], buf[4], irc)); utouchProcessInput(pInfo, &proto); } else { xf86Msg(X_WARNING, "%s: protocol error %d %s\n", pInfo->name, irc, strerror(errno)); } } /* XisbBlockDuration(priv->buffer, -1); */ return; } /* utouchReadAtouch */ static void utouchProcessInput(InputInfoPtr pInfo, utouch_proto_t * proto) { UTouchDevicePtr priv; static int scrx, scry; static int filterthis; priv = (UTouchDevicePtr)pInfo->private; scrx = scry = filterthis = 0; if (proto->sig[0] == _UT_SIGNATURE1 && proto->sig[1] == _UT_SIGNATURE2) { if (priv->pressure == proto->coord.pressure) { /* no button state change - evaluate filter */ if (priv->filter_limit_far && (abs(priv->x - proto->coord.x) > ((priv->max_x - priv->min_x) * priv->filter_limit_far)>>10) && (abs(priv->y - proto->coord.y) > ((priv->max_y - priv->min_y) * priv->filter_limit_far)>>10)) { /* far filter limit reached */ filterthis = 1; POSTPIPE(priv->monitorhandle, "#*far motion %d/%d -> %d/%d\n", priv->x, priv->y, proto->coord.x, proto->coord.y); DBG(2, ErrorF("%s far motion filtered: %d>%dX %d>%dY\n", pInfo->name, priv->x, proto->coord.x, priv->y, proto->coord.y)); if (priv->pressure == proto->coord.pressure) { /* no button change - we're done, no far movement */ DBG(2, ErrorF("%s: far button filtered\n", pInfo->name)); ++priv->touchcounter; return; } } /* far filter */ if (priv->filter_limit && (abs(priv->x - proto->coord.x) <= ((priv->max_x - priv->min_x) * priv->filter_limit) >> 10) && (abs(priv->y - proto->coord.y) <= ((priv->max_y - priv->min_y) * priv->filter_limit) >> 10)) { /* check near filter limit reached */ POSTPIPE(priv->monitorhandle, "#*near motion %d/%d -> %d/%d\n", priv->x, priv->y, proto->coord.x, proto->coord.y); DBG(2, ErrorF("%s: near motion filtered: %d>%dX %d>%dY\n", pInfo->name, priv->x, proto->coord.x, priv->y, proto->coord.y)); /* revert to original position and continue */ filterthis = 1; } /* near filter */ } /* no button change */ if (priv->filter_release && priv->pressure && !proto->coord.pressure && (priv->touchcounter <= priv->filter_1stpress)) { /* button release event but no prior press event */ DBG(2, ErrorF("%s: button release filtered\n", pInfo->name)); priv->touchcounter = 0; priv->lastpressure = 0; priv->pressure = 0; return; } if (!filterthis) { priv->x = proto->coord.x; priv->y = proto->coord.y; } priv->pressure = proto->coord.pressure; priv->buttons = proto->buttons; POSTPIPE(priv->monitorhandle, "# motion %d/%d:%d\n", priv->x, priv->y, priv->pressure); if (utouchConvert(pInfo, 0, 2, priv->x, priv->y, 0, 0, 0, 0, &scrx, &scry)) { xf86PostMotionEvent(pInfo->dev, 1 /* is_absolute */, 0 /* first_valuator */, 2 /* num_valuators */, scrx, scry ); POSTPIPE(priv->monitorhandle, " %d/%d:%d (%d/%d:%d)\n", scrx, scry, priv->pressure, priv->x, priv->y, priv->pressure); } else { DBG(1, ErrorF("%s: utouchConvert failed - posting blind\n", pInfo->name)); xf86PostMotionEvent(pInfo->dev, 1 /* is_absolute */, 0 /* first_valuator */, 2 /* num_valuators */, priv->x, priv->y ); POSTPIPE(priv->monitorhandle, "?!%d/%d:%d (%d/%d:%d)\n", scrx, scry, priv->pressure, priv->x, priv->y, priv->pressure); } if (priv->pressure) { priv->touchcounter += 1; if (priv->touchcounter >= 65534) priv->touchcounter = priv->filter_1stpress + 1; } if (!priv->filter_1stpress || (priv->touchcounter > priv->filter_1stpress)) { utouchSendButtons(pInfo, priv->buttons); } else { DBG(2, ErrorF("%s: button %s 1st filtered %d\n", pInfo->name, priv->pressure? "press":"release", priv->touchcounter)); } if (!priv->pressure) { /* button release */ priv->touchcounter = 0; } } return; } /* utouchProcessInput */ static void utouchSendButtons(InputInfoPtr pInfo, int buttons) { UTouchDevicePtr priv = (UTouchDevicePtr)pInfo->private; int scrx, scry; if (priv->buttons != priv->lastbuttons) { if (utouchConvert(pInfo, 0, 2, priv->x, priv->y, 0, 0, 0, 0, &scrx, &scry)) { if (priv->pressure >= priv->threshold && ((priv->pressure != UTOUCH_CLIPVAL) || UTOUCH_IGNORE_CLIP)) { xf86PostButtonEvent(pInfo->dev, TRUE , 1 , TRUE , 0, 2, scrx, scry); /* experimental: post relative positions for buttons */ //xf86PostButtonEvent(pInfo->dev, FALSE, 1 , TRUE , 0, 2, 0, 0); POSTPIPE(priv->monitorhandle, "O%d/%d:%d (%d/%d:%d)\n", scrx, scry, priv->pressure, priv->x, priv->y, priv->pressure); DBG(9, ErrorF("post button DOWN %d #%d event %d at %d/%d " "(%d/%d)\n", buttons, priv->touchcounter, priv->pressure, priv->x, priv->y, scrx, scry)); priv->lastbuttons = buttons; priv->lastpressure = priv->pressure; } if (priv->pressure == 0 && (priv->pressure != priv->lastpressure)) { xf86PostButtonEvent(pInfo->dev, TRUE, 1, FALSE, 0, 2, scrx, scry); /* experimental: post relative positions for buttons */ //xf86PostButtonEvent(pInfo->dev, FALSE, 1, FALSE, 0, 2, 0, 0); POSTPIPE(priv->monitorhandle, "o%d/%d:%d (%d/%d:%d)\n", scrx, scry, priv->pressure, priv->x, priv->y, priv->pressure); DBG(9, ErrorF("post button UP %d #%d event at %d/%d (%d/%d)\n", buttons, priv->touchcounter, priv->x, priv->y, scrx, scry)); priv->lastbuttons = buttons; priv->lastpressure = priv->pressure; } } /* utouchConvert() */ } /* priv->buttons != priv->lastbuttons */ } /* utouchSendButtons */ static Bool utouchOpen(InputInfoPtr pInfo) { UTouchDevicePtr priv = (UTouchDevicePtr)pInfo->private; int rc=0; DBG(1, ErrorF("%s: UTouch open %s\n", pInfo->name, priv->devName)); SYSCALL(rc = access(priv->devName, W_OK|R_OK)); /*SYSCALL( pInfo->fd = open(priv->devName, O_RDWR | O_NONBLOCK));*/ if (rc < 0) pInfo->fd = -1; else pInfo->fd = xf86OpenSerial( pInfo->options ); if (pInfo->fd == -1) { xf86Msg(X_WARNING, "%s: unable to open input device: %s\n", pInfo->name, strerror(errno)); return !Success; } else { xf86Msg(X_INFO, "%s: device %s opened (%d)\n", pInfo->name, priv->devName, pInfo->fd ); xf86FlushInput(pInfo->fd); POSTPIPE(priv->monitorhandle,"# device: %s\n", priv->devName); } xf86SetSerial(pInfo->fd, pInfo->options); priv->touchcounter = 0; priv->buttons = priv->lastbuttons = 0; priv->pressure = priv->lastpressure = 0; return Success; } /* utouchOpen */ static void utouchClose(InputInfoPtr pInfo) { UTouchDevicePtr priv = (UTouchDevicePtr)pInfo->private; SYSCALL( close(pInfo->fd)); xf86Msg(X_INFO, "%s: device %s closed\n", pInfo->name, priv->devName); pInfo->fd = -1; } static Bool utouchConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2, int v3, int v4, int v5, int *x, int *y) { UTouchDevicePtr priv = (UTouchDevicePtr) pInfo->private; Bool raisedminmax = FALSE; int new_x, new_y; int vx, vy; if (first != 0 || num != 2) { xf86Msg(X_INFO, "%s: %s first!=0, num!=2\n", pInfo->name, __FUNCTION__); return FALSE; } vx = v0; vy = v1; if (priv->enableCal & CAL_POINTS) { /* * we're in calibration mode * set pointer to expected calibration point on screen */ UTouchCal.coord[UTouchCal.points].touch_x = vx; UTouchCal.coord[UTouchCal.points].touch_y = vy; POSTPIPE(priv->monitorhandle, "c%d/%d (%d/%d) [%d]\n", UTouchCal.coord[UTouchCal.points].scr_x, UTouchCal.coord[UTouchCal.points].scr_y, vx, vy, UTouchCal.points); xf86Msg(X_INFO, "%s: calibration touch %d (%d/%d) screen (%d/%d)\n", pInfo->name, UTouchCal.points, vx, vy, UTouchCal.coord[UTouchCal.points].scr_x, UTouchCal.coord[UTouchCal.points].scr_y); *x = UTouchCal.coord[UTouchCal.points].scr_x; *y = UTouchCal.coord[UTouchCal.points].scr_y; } else { if (priv->max_x < vx) { if (priv->enableCal & CAL_LEARN) { priv->max_x = vx; raisedminmax = TRUE; } else { POSTPIPE(priv->monitorhandle, "#!X %d exceeds %d\n", vx, priv->max_x); xf86Msg(X_INFO, "%s: X point %d exceeds maximum %d\n", pInfo->name, vx, priv->max_x); vx = priv->max_x; } } if (priv->max_y < vy) { if (priv->enableCal & CAL_LEARN) { priv->max_y = vy; raisedminmax = TRUE; } else { POSTPIPE(priv->monitorhandle, "#!Y %d exceeds %d\n", vy, priv->max_y); xf86Msg(X_INFO, "%s: Y point %d exceeds maximum %d\n", pInfo->name, vy, priv->max_y); vy = priv->max_y; } } if (priv->min_x > vx) { if (priv->enableCal & CAL_LEARN) { priv->min_x = vx; raisedminmax = TRUE; } else { POSTPIPE(priv->monitorhandle, "#!X %d underruns %d\n", vx, priv->min_x); xf86Msg(X_INFO, "%s: X point %d exceeds minimum %d\n", pInfo->name, vx, priv->min_x); vx = priv->min_x; } } if (priv->min_y > vy) { if (priv->enableCal & CAL_LEARN) { priv->min_y = vy; raisedminmax = TRUE; } else { POSTPIPE(priv->monitorhandle, "#!Y %d underruns %d\n", vy, priv->min_y); xf86Msg(X_INFO, "%s: Y point %d exceeds minimum %d\n", pInfo->name, vy, priv->min_y); vy = priv->min_y; } } if (raisedminmax && priv->enableCal & CAL_LEARN) { POSTPIPE(priv->monitorhandle, "# new DIM %d/%d : %d/%d\n", priv->min_x, priv->min_y, priv->max_x, priv->max_y); xf86Msg(X_INFO, "%s: new DIM min X/Y: %d/%d max X/Y: %d/%d\n", pInfo->name, priv->min_x, priv->min_y, priv->max_x, priv->max_y); UtouchConfFileWrite(priv); /*xf86InitValuatorAxisStruct(pInfo->conf_idev, 0, priv->min_x, priv->max_x, -1, -1, -1);*/ /*xf86InitValuatorAxisStruct(pInfo->conf_idev, 1, priv->min_y, priv->max_y, -1, -1, -1);*/ } /* physical to logical */ utouchCoordPhys2Log(priv->max_x, priv->max_y, priv->min_x, priv->min_y, priv->inv_x, priv->inv_y, vx, vy, &new_x, &new_y); DBGPIPE(8, priv->monitorhandle, "UTConvert: phy X %d Y %d max(%d/%d) " "log X %d Y %d max(%d/%d)\n", vx, vy, priv->max_x, priv->max_y, new_x, new_y, priv->max_x-priv->min_x, priv->max_y-priv->min_y); vx = new_x; vy = new_y; /* logical to screen */ if (priv->screen_width == 0 || priv->max_x-priv->min_x == 0 || priv->screen_height == 0 || priv->max_y-priv->min_y == 0) { /* we're about to cause a divide by zero fault */ POSTPIPE(priv->monitorhandle, "#!ZDIV %dx/%dy screen %dx/%dy log %dx/%dy\n", vx, vy, priv->screen_width, priv->screen_height, priv->max_x-priv->min_x, priv->max_y-priv->min_y); BEEP(); } utouchCoordLog2Scr(priv->screen_width, priv->screen_height, priv->max_x-priv->min_x, priv->max_y-priv->min_y, priv->swap_axes, vx, vy, &new_x, &new_y); DBGPIPE(8, priv->monitorhandle, "UTConvert: scaled log X %d->%d, Y %d->%d max(%d/%d)\n", vx, new_x, vy, new_y, priv->screen_width, priv->screen_height); *x = new_x; *y = new_y; } /* * Need to check if still on the correct screen. * This call is here so that this work can be done after * calib and before posting the event. */ xf86XInputSetScreen(pInfo, priv->screen_no, *x, *y); return TRUE; } /* utouchConvert */ /* * utouchPtrFeedbackCtrl - PtrFeedback handler * this handler is used to receive calibration information from an application * the app will signal screen coordinates where it has set a calibration point * it's our responsibility to get a physical touch point in sync with * the point on screen */ static void utouchPtrFeedbackCtrl(DeviceIntPtr device, PtrCtrl *ctrl) { InputInfoPtr pInfo = device->public.devicePrivate; UTouchDevicePtr priv = (UTouchDevicePtr)pInfo->private; UTouchPointMatch_t ptmax, ptmin; int pt, axis_scr, axis_tch; float scale; POSTPIPE(priv->monitorhandle, "# feedback 0x%x (thr %d num %d den %d)\n", ctrl->id, ctrl->threshold, ctrl->num, ctrl->den); xf86Msg(X_INFO, "%s: ptr feedback 0x%x (thr %d num %d den %d)\n", pInfo->name, ctrl->id, ctrl->threshold, ctrl->num, ctrl->den); if (ctrl->id == 1 || (ctrl->id == 0 && ctrl->den & 512)) { /* * we're looking for id = 1 for our calibration interface * den enables calibration mode if bit 8 (2^8) is set * num tells us which axis we're getting * threshold gives us the expected point position (on screen) */ if (ctrl->den & UTOUCH_CALMASK) { /* enable calibration mode */ if (!(priv->enableCal & CAL_POINTS)) { priv->enableCal = CAL_POINTS; xf86Msg(X_INFO, "%s: calibration mode enabled\n", pInfo->name); /* clear old calibration point structure */ for (UTouchCal.points = MAXCALPOINTS; UTouchCal.points >= 0; -- UTouchCal.points) { UTouchCal.coord[UTouchCal.points].scr_x = UTouchCal.coord[UTouchCal.points].scr_y = UTouchCal.coord[UTouchCal.points].touch_x = UTouchCal.coord[UTouchCal.points].touch_y = 0; } UTouchCal.points = 0; } if ((ctrl->num & UTOUCH_CALAXIS) & UTOUCH_CALX) { if(UTouchCal.coord[UTouchCal.points].touch_x > 0) { UTouchCal.points += 1; xf86Msg(X_INFO, "%s: setting next coordinate %d\n", pInfo->name, UTouchCal.points); } UTouchCal.coord[UTouchCal.points].scr_x = ctrl->threshold; } if ((ctrl->num & UTOUCH_CALAXIS) & UTOUCH_CALY) { UTouchCal.coord[UTouchCal.points].scr_y = ctrl->threshold; } if (UTouchCal.points >= MAXCALPOINTS-1) { xf86Msg(X_INFO, "%s: maximum calibration points exhausted! aborting\n", pInfo->name); priv->enableCal = 0; return; } } else { /* disable calibration mode */ if (priv->enableCal & CAL_POINTS) { xf86Msg(X_INFO, "%s: calibration end requested, at %d points\n", pInfo->name, UTouchCal.points); for (pt=0; pt <= UTouchCal.points; ++pt) { xf86Msg(X_INFO, "%s endcal %d: touch %d %d screen %d %d\n", pInfo->name, pt, UTouchCal.coord[pt].touch_x, UTouchCal.coord[pt].touch_y, UTouchCal.coord[pt].scr_x, UTouchCal.coord[pt].scr_y); } /* recalculate using calibration data */ if ((UTouchCal.points % 2) == 1 || (UTouchCal.points > 1 && UTouchCal.coord[UTouchCal.points].touch_x)) { /* check touchpoint tolerance by in-line comparison */ /* calculate relation of touch to screen */ ptmin.scr_x = ptmin.scr_y = ptmin.touch_x = ptmin.touch_y = -1; ptmax.scr_x = ptmax.scr_y = ptmax.touch_x = ptmax.touch_y = 0; /* iterate over calibration data to find min/max points */ for (pt=0; pt < MAXCALPOINTS; ++pt) { if (UTouchCal.coord[pt].scr_y > 0 || UTouchCal.coord[pt].touch_y > 0 || UTouchCal.coord[pt].scr_x > 0 || UTouchCal.coord[pt].touch_x > 0) { /* looking like valid coordinates, check min/max */ if (UTouchCal.coord[pt].scr_x < ptmin.scr_x || ptmin.scr_x == -1) { ptmin.scr_x = UTouchCal.coord[pt].scr_x; ptmin.touch_x = UTouchCal.coord[pt].touch_x; } if (UTouchCal.coord[pt].scr_x > ptmax.scr_x || ptmax.scr_x == -1) { ptmax.scr_x = UTouchCal.coord[pt].scr_x; ptmax.touch_x = UTouchCal.coord[pt].touch_x; } if (UTouchCal.coord[pt].scr_y < ptmin.scr_y || ptmin.scr_y == -1) { ptmin.scr_y = UTouchCal.coord[pt].scr_y; ptmin.touch_y = UTouchCal.coord[pt].touch_y; } if (UTouchCal.coord[pt].scr_y > ptmax.scr_y || ptmax.scr_y == -1) { ptmax.scr_y = UTouchCal.coord[pt].scr_y; ptmax.touch_y = UTouchCal.coord[pt].touch_y; } } } /* we should have the lowest and highest values right now */ /* scale screen coordinates to touch coordinates */ xf86Msg(X_INFO, "%s: final points: screen X %d-%d Y %d-%d " "touch X %d-%d Y %d-%d\n", pInfo->name, ptmin.scr_x, ptmax.scr_x, ptmin.scr_y, ptmax.scr_y, ptmin.touch_x, ptmax.touch_x, ptmin.touch_y, ptmax.touch_y); axis_scr = ptmax.scr_x - ptmin.scr_x; axis_tch = ptmax.touch_x - ptmin.touch_x; if (axis_scr == -1 || axis_tch == -1) { xf86Msg(X_INFO, "%s: X scaling invalid (s%d/t%d)\n", pInfo->name, axis_scr, axis_tch); } else { scale = (float)(axis_scr / (float)axis_tch); if (scale == 0) scale = 1; xf86Msg(X_INFO, "%s: scaling X (%ds = (%d - %d)/%dt = (%d - %d)) %f\n", pInfo->name, axis_scr, ptmax.scr_x, ptmin.scr_x, axis_tch, ptmax.touch_x, ptmin.touch_x, scale); /* calculate screen point zero on touch */ priv->min_x = (int)(ptmin.touch_x - (ptmin.scr_x * scale)); /* calculate max screen point on touch */ priv->max_x = (int)(ptmax.touch_x + (priv->screen_width - ptmax.scr_x) * scale); xf86Msg(X_INFO, "%s: calculated X axis %d .. %d scales to %d .. %d\n", pInfo->name, priv->min_x, priv->max_x, 0, priv->screen_width); } axis_scr = (ptmax.scr_y - ptmin.scr_y); if (priv->inv_y) { axis_tch = (ptmin.touch_y - ptmax.touch_y); } else { axis_tch = (ptmax.touch_y - ptmin.touch_y); } if (axis_scr == -1 || axis_tch == -1) { xf86Msg(X_INFO, "%s: Y scaling invalid (s%d/t%d)\n", pInfo->name, axis_scr, axis_tch); } else { scale = (float)(axis_scr / (float)axis_tch); xf86Msg(X_INFO, "%s: scaling Y (%ds = (%d - %d)/%dt = (%d - %d))" "= factor %f \n", pInfo->name, axis_scr, ptmax.scr_y, ptmin.scr_y, axis_tch, ptmax.touch_y, ptmin.touch_y, scale); if (priv->inv_y) { priv->min_y = (int)(ptmax.touch_y - ptmin.scr_y * scale); priv->max_y = (int)(ptmin.touch_y + (priv->screen_height - ptmax.scr_y) * scale); } else { priv->min_y = (int)(ptmin.touch_y - ptmin.scr_y * scale); priv->max_y = (int)(ptmax.touch_y + (priv->screen_height - ptmax.scr_y) * scale); } xf86Msg(X_INFO, "%s: calculated Y axis %d .. %d scales to %d .. %d\n", pInfo->name, priv->min_y, priv->max_y, 0, priv->screen_height); } xf86Msg(X_INFO, "%s: calibration data screen %d %d - %d %d\n", pInfo->name, 0, priv->screen_width, 0, priv->screen_height); xf86Msg(X_INFO, "%s: calibration data touch %d %d - %d %d\n", pInfo->name, priv->min_x, priv->max_x, priv->min_y, priv->max_y); /* store calibration data */ } else { xf86Msg(X_INFO, "%s: invalid calibration (points are odd %d)\n", pInfo->name, UTouchCal.points); } xf86Msg(X_INFO, "%s: calibration mode disabled\n", pInfo->name); priv->enableCal = CAL_LOCK; } } } } static pointer utouchLoad(pointer module, pointer options, int *errmaj, int *errmin) { static Bool Initialised = FALSE; if (!Initialised) { if (xf86LoaderCheckSymbol("xf86AddModuleInfo")) xf86AddModuleInfo(&utouchInfo, module); xf86AddInputDriver(&UTouchDrvRec, module, 0); Initialised = TRUE; /*xf86Msg(X_INFO, "%s: %s\n", dev->identifier, __FILEINFO);*/ } return module; } /* utouchLoad */ static void utouchUnload(pointer p) { } /* utouchUnload */ static const OptionInfoRec * utouchAvailableOptions(void *unused) { return UTouchOptions; } /* utouchAvailableOptions */ /* * utouchCoordPhys2Log * convert physical coordinates to logical coordinates */ static void utouchCoordPhys2Log(int phymaxx, int phymaxy, int phyminx, int phyminy, int inv_x, int inv_y, int px, int py, int *lx, int *ly) { if (inv_x) *lx = phymaxx - px + phyminx; else *lx = px; if (inv_y) *ly = phymaxy - py + phyminy; else *ly = py; *lx = *lx - phyminx; *ly = *ly - phyminy; DBG(18, ErrorF("Phys2Log: x %d -> %d y %d -> %d\n", px, *lx, py, *ly)); } /* utouchCoordPhys2Log */ /* * utouchCoordLog2Scr * convert logical coordinates to screen coordinates */ static void utouchCoordLog2Scr(int scrmaxx, int scrmaxy, int lmaxx, int lmaxy, int swap_axes, int lx, int ly, int *scrx, int *scry) { switch (swap_axes) { case -1: /* turn left - counter-clockwise */ *scrx = xf86ScaleAxis(ly, 0, scrmaxx, lmaxy, 0); *scry = xf86ScaleAxis(lx, 0, scrmaxy, 0, lmaxx); break; case 1: /* turn right - clockwise */ *scrx = xf86ScaleAxis(ly, 0, scrmaxx, 0, lmaxy); *scry = xf86ScaleAxis(lx, 0, scrmaxy, lmaxx, 0); break; case 2: /* fully invert */ *scrx = xf86ScaleAxis(lx, 0, scrmaxx, lmaxx, 0); *scry = xf86ScaleAxis(ly, 0, scrmaxy, lmaxy, 0); break; default: *scrx = xf86ScaleAxis(lx, 0, scrmaxx, 0, lmaxx); *scry = xf86ScaleAxis(ly, 0, scrmaxy, 0, lmaxy); break; } /* DBG(8, ErrorF("Log2Scr: x %d -> %d y %d -> %d\n", lx, *scrx, ly, *scry)); */ } /* utouchCoordLog2Scr */ static int UtouchConfFileRead(UTouchDevicePtr devPtr) { FILE * fConfFd; char setting[128] = {0}; char ident[128] = {0}; int value = 0; int iNumSettings=0; xf86Msg(X_INFO, "UtouchConfFileRead: reading %s (%s)\n", devPtr->confFile, devPtr->identifier); if ((fConfFd = fopen(devPtr->confFile, "r")) != NULL) { SYSCALL(fseek(fConfFd, 0L, SEEK_SET)); /// check for identifier while (fscanf(fConfFd, "%s %s = %d\n", ident, setting, &value) != EOF) { if (strcasecmp(ident, devPtr->identifier) == 0) { DBGPIPE(1, devPtr->monitorhandle, " config: setting %s = value %d\n", setting, value); xf86Msg(X_INFO, "ConfFileRead: setting %s = value %d\n", setting, value); if (*setting != '#') { if (strcasecmp(setting, "minX") == 0) { devPtr->min_x = value; ++iNumSettings; } if (strcasecmp(setting, "maxX") == 0) { devPtr->max_x = value; ++iNumSettings; } if (strcasecmp(setting, "minY") == 0) { devPtr->min_y = value; ++iNumSettings; } if (strcasecmp(setting, "maxY") == 0) { devPtr->max_y = value; ++iNumSettings; } } } } fclose(fConfFd); if (iNumSettings > 0) { xf86Msg(X_INFO, "ReadConfig %s: X %d/%d Y %d/%d\n", devPtr->identifier, devPtr->min_x, devPtr->max_x, devPtr->min_y, devPtr->max_y); } return iNumSettings; } xf86Msg(X_ERROR, "unable to open config file %s (%s)\n", devPtr->confFile, strerror(errno)); return 0; } static int UtouchConfFileWrite(UTouchDevicePtr devPtr) { FILE * fConfFd; int i, bufptr; long confsize; char * confbuffer = NULL; char line[1024]; char setting[128] = {0}; char ident[128] = {0}; int value = 0; if ((fConfFd = fopen(devPtr->confFile, "rw+")) != NULL) { // get file size fseek(fConfFd, 0L, SEEK_END); // EOF confsize = ftell(fConfFd); // read file size fseek(fConfFd, 0L, SEEK_SET); // BOF DBGPIPE(1, devPtr->monitorhandle, "%s size %ld byte\n", devPtr->confFile, confsize); // allocate buffer if ((confbuffer = (char *)malloc(confsize)) != NULL) { bufptr = 0; while (fgets(line, 1023, fConfFd) != NULL) { // check for identifier if(sscanf(line, "%s %s = %d", ident, setting, &value) > 0 && strcasecmp(ident, devPtr->identifier) != 0) { DBGPIPE(1, devPtr->monitorhandle, "retain: ident %s setting %s value %d\n", ident, setting, value); // append line to buffer memcpy(confbuffer+bufptr, line, strlen(line)); bufptr += strlen(line); } } fclose(fConfFd); if ((fConfFd = fopen(devPtr->confFile, "w")) != NULL) { // write filtered buffer to file fseek(fConfFd, 0L, SEEK_SET); fwrite(confbuffer, bufptr, 1, fConfFd); } free(confbuffer); } fclose(fConfFd); } else { DBGPIPE(0, devPtr->monitorhandle, " unable to open file %s for writing, rc=%d\n", devPtr->confFile, errno); } if ((fConfFd = fopen(devPtr->confFile, "a+")) != NULL) { fseek(fConfFd, 0L, SEEK_END); fprintf(fConfFd, "%s %s = %d\n%s %s = %d\n%s %s = %d\n%s %s = %d\n", devPtr->identifier, "minX", devPtr->min_x, devPtr->identifier, "maxX", devPtr->max_x, devPtr->identifier, "minY", devPtr->min_y, devPtr->identifier, "maxY", devPtr->max_y); /* write calibration data, if available */ if (UTouchCal.points > 0) { for (i=0; i < UTouchCal.points; ++i) { /*fprintf(fConfFd, "%s%d = %d\n", );*/ } } fclose(fConfFd); DBGPIPE(1, devPtr->monitorhandle, "file %s written (%d/%d, %d/%d)\n", devPtr->confFile, devPtr->min_x, devPtr->max_x, devPtr->min_y, devPtr->max_y); xf86Msg(X_INFO, "file %s written (%d/%d, %d/%d)\n", devPtr->confFile, devPtr->min_x, devPtr->max_x, devPtr->min_y, devPtr->max_y); return 1; } xf86Msg(X_ERROR, "UtouchConfFileWrite: %s error %s\n", devPtr->confFile, strerror(errno)); return 0; } void sigtouch(int sig) { UTouchDevicePtr priv; xf86Msg(X_INFO, "caught sig %d\n", sig); if(putouchDrvInfo != NULL) { priv = (UTouchDevicePtr)putouchDrvInfo->private; switch(sig) { case SIGUSR2: /* restore to default calibration */ xf86Msg(X_INFO, "decalibrating\n"); if(access(priv->confFile, R_OK|W_OK) == 0) { unlink(priv->confFile); } priv->min_x = screenInfo.screens[priv->screen_no]->width - 1; priv->min_y = screenInfo.screens[priv->screen_no]->height - 1; priv->max_x = 0; priv->max_y = 0; priv->enableCal = CAL_LEARN; printf("touchscreen calibration reset\n"); break; case SIGUSR2+1: xf86Msg(X_INFO, "fixating calibration\n"); priv->enableCal = CAL_LOCK; break; break; default: xf86Msg(X_INFO, "signal unhandled\n"); break; } } }