summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:56 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:56 +0000
commit7d3ee7b318425801939c01c9ff8850d5821bc224 (patch)
tree6f8cb3251b41fc288accebc41570d9430daf58d4
-rw-r--r--man/mutouch.man40
-rw-r--r--src/xf86MuTouch.c1890
2 files changed, 1930 insertions, 0 deletions
diff --git a/man/mutouch.man b/man/mutouch.man
new file mode 100644
index 0000000..9660d51
--- /dev/null
+++ b/man/mutouch.man
@@ -0,0 +1,40 @@
+.\" $XFree86: xc/programs/Xserver/hw/xfree86/input/mutouch/mutouch.man,v 1.2 2001/01/27 18:20:58 dawes Exp $
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH MUTOUCH __drivermansuffix__ __vendorversion__
+.SH NAME
+mutouch \- Microtouch input driver
+.SH SYNOPSIS
+.B "Section \*qInputDevice\*q"
+.br
+.BI " Identifier \*q" idevname \*q
+.br
+.B " Driver \*qmutouch\*q"
+.br
+.BI " Option \*qDevice\*q \*q" devpath \*q
+.br
+\ \ ...
+.br
+.B EndSection
+.SH DESCRIPTION
+.B mutouch
+is an XFree86 input driver for Microtouch devices...
+.PP
+The
+.B mutouch
+driver functions as a pointer input device, and may be used as the
+X server's core pointer.
+THIS MAN PAGE NEEDS TO BE FILLED IN.
+.SH SUPPORTED HARDWARE
+What is supported...
+.SH CONFIGURATION DETAILS
+Please refer to XF86Config(__filemansuffix__) for general configuration
+details and for options that can be used with all input drivers. This
+section only covers configuration details specific to this driver.
+.PP
+Config details...
+.SH "SEE ALSO"
+XFree86(1), XF86Config(__filemansuffix__), xf86config(1), Xserver(1), X(__miscmansuffix__).
+.SH AUTHORS
+Authors include...
+ Patrick Lecoanet
diff --git a/src/xf86MuTouch.c b/src/xf86MuTouch.c
new file mode 100644
index 0000000..6762034
--- /dev/null
+++ b/src/xf86MuTouch.c
@@ -0,0 +1,1890 @@
+/*
+ * Copyright 1996, 1999 by Patrick Lecoanet, France. <lecoanet@cena.dgac.fr>
+ *
+ * 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 name of Patrick Lecoanet not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Patrick Lecoanet makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * PATRICK LECOANET DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL PATRICK LECOANET 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.
+ *
+ */
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/input/mutouch/xf86MuTouch.c,v 1.14 2001/08/17 13:27:56 dawes Exp $ */
+
+/*
+ *******************************************************************************
+ *******************************************************************************
+ *
+ * This driver is able to deal with MicroTouch serial controllers using
+ * firmware set 2. This includes (but may not be limited to) Serial/SMT3
+ * and TouchPen controllers. The only data format supported is Mode Tablet
+ * as it is the only available with these controllers. Anyway this is not a big
+ * lost as it is the most efficient (by far) and is supported by all controllers.
+ *
+ * The code has been lifted from the Elographics driver in xf86Elo.c.
+ *
+ * ThruGlass specific addition 1999 by Andreas Micklei, Germany.
+ * <micklei@fokus.gmd.de>
+ *
+ *******************************************************************************
+ *******************************************************************************
+ */
+
+#include "xf86Version.h"
+#if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(3,9,0,0,0)
+#define XFREE86_V4
+#endif
+
+#ifdef XFREE86_V4
+#include "misc.h"
+#include "xf86.h"
+#if !defined(DGUX)
+#include "xf86_ansic.h"
+#endif
+#include "xf86_OSproc.h"
+#include "xf86Xinput.h"
+#include "exevents.h"
+
+#ifdef XFree86LOADER
+#include "xf86Module.h"
+#endif
+
+#else /* XFREE86_V4 */
+
+#include "Xos.h"
+#include <signal.h>
+#include <stdio.h>
+
+#define NEED_EVENTS
+#include "X.h"
+#include "Xproto.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "XI.h"
+#include "XIproto.h"
+
+#include "compiler.h"
+
+#include "xf86.h"
+#include "xf86Procs.h"
+#include "xf86_OSlib.h"
+#include "xf86_Config.h"
+#include "xf86Xinput.h"
+
+#include "os.h"
+#include "osdep.h"
+#include "exevents.h"
+
+#include "extnsionst.h"
+#include "extinit.h"
+
+#endif /* XFREE86_V4 */
+
+
+#ifndef XFREE86_V4
+/*
+ ***************************************************************************
+ *
+ * Configuration descriptor.
+ *
+ ***************************************************************************
+ */
+#define FINGER_SECTION_NAME "microtouchfinger"
+#define STYLUS_SECTION_NAME "microtouchstylus"
+
+#define PORT 1
+#define DEVICENAME 2
+#define SCREEN_NO 3
+#define MAXX 5
+#define MAXY 6
+#define MINX 7
+#define MINY 8
+#define DEBUG_LEVEL 9
+#define HISTORY_SIZE 10
+#define LINK_SPEED 11
+#define ALWAYS_CORE 12
+#define SWAP_AXES 13
+#define FREQUENCY 14
+#define PORTRAIT_MODE 15
+
+static SymTabRec MuTTab[] = {
+ { ENDSUBSECTION, "endsubsection" },
+ { PORT, "port" },
+ { DEVICENAME, "devicename" },
+ { SCREEN_NO, "screenno" },
+ { MAXX, "maximumxposition" },
+ { MAXY, "maximumyposition" },
+ { MINX, "minimumxposition" },
+ { MINY, "minimumyposition" },
+ { DEBUG_LEVEL, "debuglevel" },
+ { HISTORY_SIZE, "historysize" },
+ { LINK_SPEED, "linkspeed" },
+ { ALWAYS_CORE, "alwayscore" },
+ { SWAP_AXES, "swapxy" },
+ { FREQUENCY, "frequency" },
+ { PORTRAIT_MODE, "portraitmode" },
+ { -1, "" },
+};
+
+#define LS300 1
+#define LS1200 2
+#define LS2400 3
+#define LS9600 4
+#define LS19200 5
+
+static SymTabRec LinkSpeedTab[] = {
+ { LS300, "b300" },
+ { LS1200, "b1200" },
+ { LS2400, "b2400" },
+ { LS9600, "b9600" },
+ { LS19200, "b19200" }
+};
+
+
+typedef struct {
+ int speed;
+} LinkParameterStruct;
+
+static LinkParameterStruct LinkSpeedValues[] = {
+ { B300 },
+ { B1200 },
+ { B2400 },
+ { B9600 },
+ { B19200 }
+};
+#endif /* XFREE86_V4 */
+
+
+/*
+ ***************************************************************************
+ *
+ * Default constants.
+ *
+ ***************************************************************************
+ */
+#define MuT_MAX_TRIALS 5 /* Number of timeouts waiting for a */
+ /* pending reply. */
+#define MuT_MAX_WAIT 300000 /* Max wait time for a reply (microsec) */
+#define MuT_LINK_SPEED B9600 /* 9600 Bauds */
+#define MuT_PORT "/dev/ttyS1"
+
+#define DEFAULT_MAX_X 3000
+#define DEFAULT_MIN_X 600
+#define DEFAULT_MAX_Y 3000
+#define DEFAULT_MIN_Y 600
+
+#define XI_FINGER "FINGER" /* X device name for the finger device */
+#define XI_STYLUS "STYLUS" /* X device name for the stylus device */
+
+
+/*
+ ***************************************************************************
+ *
+ * Protocol constants.
+ *
+ ***************************************************************************
+ */
+#define MuT_REPORT_SIZE 5 /* Size of a report packet. */
+#define MuT_BUFFER_SIZE 256 /* Size of input buffer. */
+#define MuT_PACKET_SIZE 10 /* Maximum size of a command/reply *including* */
+ /* the leading and trailing bytes. */
+
+#define MuT_LEAD_BYTE 0x01 /* First byte of a command/reply packet. */
+#define MuT_TRAIL_BYTE 0x0D /* Last byte of a command/reply packet. */
+
+/*
+ * Commands.
+ */
+#define MuT_RESET "R" /* Reset the controller. */
+#define MuT_RESTORE_DEFAULTS "RD" /* Restore factory settings. */
+#define MuT_FORMAT_TABLET "FT" /* Report events using tablet format. */
+#define MuT_FORMAT_RAW "FR" /* Report events in raw mode (no corrections). */
+#define MuT_CALIBRATE_RAW "CR" /* Calibration in raw mode. */
+#define MuT_CALIBRATE_EXT "CX" /* Calibration in extended mode (cooked). */
+#define MuT_OUTPUT_IDENT "OI" /* Ask some infos about the firmware. */
+#define MuT_UNIT_TYPE "UT" /* Ask some more infos about the firmware. */
+#define MuT_FINGER_ONLY "FO" /* Send reports only if a finger is touching. */
+#define MuT_PEN_ONLY "PO" /* Send reports only if a pen is touching. */
+#define MuT_PEN_FINGER "PF" /* Always send reports. */
+#define MuT_MODE_STREAM "MS" /* Receive reports in stream mode (continuous). */
+
+/*
+ * Additional ThruGlass-Specific Commands
+ */
+#define MuT_MODE_NOISE "MN" /* Stream noise data packets. */
+#define MuT_MODE_EXTENDED "MX" /* Send firmware algorithm data on press. */
+#define MuT_SET_CREEP "SC" /* Set/show base update rates. */
+#define MuT_SET_SENSITIVITY "SS" /* Set/show touch algorithm parameters. */
+#define MuT_SET_FREQUENCY "SF" /* Set/show frequency. */
+#define MuT_SET_PHASE "SP" /* Set/show phase. */
+#define MuT_SET_TYPE "ST" /* Set/show controller & screen orientation. */
+#define MuT_SET_CORRECTION_X "SCX" /* Set/show X depth correction parameters. */
+#define MuT_SET_CORRECTION_Y "SCY" /* Set/show Y depth correction parameters. */
+#define MuT_FORMAT_RAW_ASCII "FRA" /* Show 16 sensor channel values. */
+#define MuT_FORMAT_BASE_ASCII "FBA" /* Show 16 base values. */
+#define MuT_FORMAT_DEPTH_ASCII "FZA" /* Show 16 press depth values. */
+#define MuT_NOISE_ASCII "NOA" /* Show noise data. */
+
+/*
+ * Command reply values.
+ */
+#define MuT_OK '0' /* Report success. */
+#define MuT_ERROR '1' /* Report error. */
+
+/*
+ * Offsets in status byte of touch and motion reports.
+ */
+#define MuT_SW1 0x01 /* State of switch 1 (TouchPen only). */
+#define MuT_SW2 0x02 /* State of switch 2 (TouchPen only). */
+#define MuT_WHICH_DEVICE 0x20 /* If report is from pen or from finger. */
+#define MuT_CONTACT 0x40 /* Report touch/untouch with touchscreen. */
+
+/*
+ * Identity and friends.
+ */
+#define MuT_TOUCH_PEN_IDENT "P5"
+#define MuT_SMT3_IDENT "Q1"
+#define MuT_THRU_GLASS_IDENT "T1"
+
+
+/*
+ ***************************************************************************
+ *
+ * Usefull macros.
+ *
+ ***************************************************************************
+ */
+#define WORD_ASSEMBLY(byte1, byte2) (((byte2) << 7) | (byte1))
+#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
+
+/* This one is handy, thanx Fred ! */
+#ifdef DBG
+#undef DBG
+#endif
+#ifdef DEBUG
+#undef DEBUG
+#endif
+
+static int debug_level = 0;
+#define DEBUG 1
+#if DEBUG
+#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
+#else
+#define DBG(lvl, f)
+#endif
+
+#ifdef XFREE86_V4
+#undef SYSCALL
+#undef read
+#undef write
+#undef close
+#define SYSCALL(call) call
+#define read(fd, ptr, num) xf86ReadSerial(fd, ptr, num)
+#define write(fd, ptr, num) xf86WriteSerial(fd, ptr, num)
+#define close(fd) xf86CloseSerial(fd)
+#endif
+
+
+/*
+ ***************************************************************************
+ *
+ * Device private records.
+ *
+ ***************************************************************************
+ */
+#define FINGER_ID 1
+#define STYLUS_ID 2
+#define DEVICE_ID(flags) ((flags) & 0x03)
+
+typedef struct _MuTPrivateRec {
+ char *input_dev; /* The touchscreen input tty */
+ int min_x; /* Minimum x reported by calibration */
+ int max_x; /* Maximum x */
+ int min_y; /* Minimum y reported by calibration */
+ int max_y; /* Maximum y */
+#ifndef XFREE86_V4
+ int link_speed; /* Speed of the RS232 link connecting the ts. */
+#endif
+ int frequency; /* Frequency for ThruGlass */
+ int screen_no; /* Screen associated with the device */
+ int screen_width; /* Width of the associated X screen */
+ int screen_height; /* Height of the screen */
+ Bool inited; /* The controller has already been configured ? */
+ char state; /* Current state of report flags. */
+ int num_old_bytes; /* Number of bytes left in receive buffer. */
+ LocalDevicePtr finger; /* Finger device ptr associated with the hw. */
+ LocalDevicePtr stylus; /* Stylus device ptr associated with the hw. */
+ int swap_axes; /* Swap X an Y axes if != 0 */
+ unsigned char rec_buf[MuT_BUFFER_SIZE]; /* Receive buffer. */
+} MuTPrivateRec, *MuTPrivatePtr;
+
+
+#ifndef XFREE86_V4
+/*
+ ***************************************************************************
+ *
+ * xf86MuTConfig --
+ * Configure the driver from the configuration data.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTConfig(LocalDevicePtr *array,
+ int inx,
+ int max,
+ LexPtr val)
+{
+ LocalDevicePtr local = array[inx];
+ MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
+ int token;
+ int portrait=0;
+
+ while ((token = xf86GetToken(MuTTab)) != ENDSUBSECTION) {
+ switch(token) {
+
+ case PORT:
+ if (xf86GetToken(NULL) != STRING)
+ xf86ConfigError("MicroTouch input port expected");
+ else {
+ /*
+ * See if another X device share the same physical
+ * device and set up the links so that they share
+ * the same private structure (the one that controls
+ * the physical device).
+ */
+ int i;
+ for (i = 0; i < max; i++) {
+ if (i == inx)
+ continue;
+ if (array[i]->device_config == xf86MuTConfig &&
+ (strcmp(((MuTPrivatePtr) array[i]->private)->input_dev,
+ val->str) == 0)) {
+ ErrorF("%s MicroTouch config detected a device share between %s and %s\n",
+ XCONFIG_GIVEN, local->name, array[i]->name);
+ xfree(priv);
+ priv = local->private = array[i]->private;
+ switch (DEVICE_ID(local->private_flags)) {
+ case FINGER_ID:
+ priv->finger = local;
+ break;
+ case STYLUS_ID:
+ priv->stylus = local;
+ break;
+ }
+ break;
+ }
+ }
+ if (i == max) {
+ priv->input_dev = strdup(val->str);
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s input port: %s\n",
+ XCONFIG_GIVEN, local->name, priv->input_dev);
+ }
+ }
+ break;
+
+ case DEVICENAME:
+ if (xf86GetToken(NULL) != STRING)
+ xf86ConfigError("MicroTouch device name expected");
+ local->name = strdup(val->str);
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s X device name: %s\n",
+ XCONFIG_GIVEN, local->name, local->name);
+ break;
+
+ case SCREEN_NO:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch screen number expected");
+ priv->screen_no = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s associated screen: %d\n",
+ XCONFIG_GIVEN, local->name, priv->screen_no);
+ break;
+
+ case LINK_SPEED:
+ {
+ int ltoken = xf86GetToken(LinkSpeedTab);
+ if (ltoken == EOF ||
+ ltoken == STRING ||
+ ltoken == NUMBER)
+ xf86ConfigError("MicroTouch link speed expected");
+ priv->link_speed = LinkSpeedValues[ltoken-1].speed;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s link speed: %s bps\n",
+ XCONFIG_GIVEN, local->name, (LinkSpeedTab[ltoken-1].name)+1);
+ }
+ break;
+
+ case MAXX:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch maximum x position expected");
+ priv->max_x = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s maximum x position: %d\n",
+ XCONFIG_GIVEN, local->name, priv->max_x);
+ break;
+
+ case MAXY:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch maximum y position expected");
+ priv->max_y = val->num;
+ if (xf86Verbose)
+ ErrorF("%s Microtouch %s maximum y position: %d\n",
+ XCONFIG_GIVEN, local->name, priv->max_y);
+ break;
+
+ case MINX:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch minimum x position expected");
+ priv->min_x = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s minimum x position: %d\n",
+ XCONFIG_GIVEN, local->name, priv->min_x);
+ break;
+
+ case MINY:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch minimum y position expected");
+ priv->min_y = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s minimum y position: %d\n",
+ XCONFIG_GIVEN, local->name, priv->min_y);
+ break;
+
+ case DEBUG_LEVEL:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch driver debug expected");
+ debug_level = val->num;
+ if (xf86Verbose) {
+#if DEBUG
+ ErrorF("%s MicroTouch %s debug level sets to %d\n", XCONFIG_GIVEN,
+ local->name, debug_level);
+#else
+ ErrorF("%s MicroTouch %s debug not available\n",
+ XCONFIG_GIVEN, local->name, debug_level);
+#endif
+ }
+ break;
+
+ case HISTORY_SIZE:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch motion history size expected");
+ local->history_size = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s motion history size is %d\n", XCONFIG_GIVEN,
+ local->name, local->history_size);
+ break;
+
+ case FREQUENCY:
+ if (xf86GetToken(NULL) != NUMBER)
+ xf86ConfigError("MicroTouch ThruGlass frequency expected");
+ priv->frequency = val->num;
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s frequency is %d\n", XCONFIG_GIVEN,
+ local->name, priv->frequency);
+ break;
+
+ case ALWAYS_CORE:
+ xf86AlwaysCore(local, TRUE);
+ if (xf86Verbose)
+ ErrorF("%s MicroTouch %s device will always stays core pointer\n",
+ XCONFIG_GIVEN, local->name);
+ break;
+
+ case SWAP_AXES:
+ priv->swap_axes = 1;
+ if (xf86Verbose) {
+ ErrorF("%s Microtouch %s device will work with X and Y axes swapped\n",
+ XCONFIG_GIVEN, local->name);
+ }
+ break;
+
+ case PORTRAIT_MODE:
+ if (xf86GetToken(NULL) != STRING) {
+ portrait_mode_err:
+ xf86ConfigError("Microtouch portrait mode should be: Portrait, Landscape or PortraitCCW");
+ }
+ if (strcmp(val->str, "portrait") == 0) {
+ portrait = 1;
+ }
+ else if (strcmp(val->str, "portraitccw") == 0) {
+ portrait = -1;
+ }
+ else if (strcmp(val->str, "landscape") != 0) {
+ goto portrait_mode_err;
+ }
+ if (xf86Verbose) {
+ ErrorF("%s Microtouch %s device will work in %s mode\n",
+ XCONFIG_GIVEN, local->name, val->str);
+ }
+ break;
+
+ case EOF:
+ FatalError("Unexpected EOF (missing EndSubSection)");
+ break;
+
+ default:
+ xf86ConfigError("MicroTouch subsection keyword expected");
+ break;
+ }
+ }
+
+ if (priv->max_x - priv->min_x <=0) {
+ ErrorF("%s MicroTouch: reverse x mode (minimum x position >= maximum x position)\n",
+ XCONFIG_GIVEN);
+ }
+ if (priv->max_y - priv->min_y <=0) {
+ ErrorF("%s MicroTouch: reverse y mode (minimum y position >= maximum y position)\n",
+ XCONFIG_GIVEN);
+ }
+
+ /*
+ * The portrait adjustments need to be done after axis reversing
+ * and axes swap. This way the driver can cope with deffective
+ * hardware and still do the correct processing depending on the
+ * actual display orientation.
+ */
+ if (portrait == 1) {
+ /*
+ * Portrait Clockwise: reverse Y axis and exchange X and Y.
+ */
+ int tmp;
+ tmp = priv->min_y;
+ priv->min_y = priv->max_y;
+ priv->max_y = tmp;
+ priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
+ }
+ else if (portrait == -1) {
+ /*
+ * Portrait Counter Clockwise: reverse X axis and exchange X and Y.
+ */
+ int tmp;
+ tmp = priv->min_x;
+ priv->min_x = priv->max_x;
+ priv->max_x = tmp;
+ priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
+ }
+
+ DBG(2, ErrorF("xf86MuTConfig port name=%s\n", priv->input_dev))
+
+ return Success;
+}
+#endif
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTConvert --
+ * Convert extended valuators to x and y suitable for core motion
+ * events. Return True if ok and False if the requested conversion
+ * can't be done for the specified valuators.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTConvert(LocalDevicePtr local,
+ int first,
+ int num,
+ int v0,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int v5,
+ int *x,
+ int *y)
+{
+ MuTPrivatePtr priv = (MuTPrivatePtr) local->private;
+ int width = priv->max_x - priv->min_x;
+ int height = priv->max_y - priv->min_y;
+ int input_x, input_y;
+
+ if (first != 0 || num != 2)
+ return FALSE;
+
+ if (priv->swap_axes) {
+ input_x = v1;
+ input_y = v0;
+ }
+ else {
+ input_x = v0;
+ input_y = v1;
+ }
+ *x = (priv->screen_width * (input_x - priv->min_x)) / width;
+ *y = (priv->screen_height -
+ (priv->screen_height * (input_y - priv->min_y)) / height);
+
+#ifdef XFREE86_V4
+ /*
+ * 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(local, priv->screen_no, *x, *y);
+#endif
+
+ return TRUE;
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTReadInput --
+ * Read a buffer full of input from the touchscreen and enqueue
+ * all report packets found in it.
+ * If a packet is not fully received it is deferred until the next
+ * call to the function.
+ * Packet recognized by this function comply with the format :
+ *
+ * Byte 1 : Status flags with MSB set to 1
+ * Byte 2 : X coordinate (lower bits)
+ * Byte 3 : X coordinate (upper bits)
+ * Byte 4 : Y coordinate (lower bits)
+ * Byte 5 : Y coordinate (upper bits)
+ *
+ * The routine can work with any of the two X device structs associated
+ * with the touchscreen. It is always possible to find the relevant
+ * informations and to emit the events for both devices if provided
+ * with one of the two structs. This point is relevant only if the
+ * two devices are actives at the same time.
+ *
+
+ ***************************************************************************
+ */
+static void
+xf86MuTReadInput(LocalDevicePtr local)
+{
+ MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
+ int cur_x, cur_y;
+ int state;
+ int num_bytes;
+ int bytes_in_packet;
+ unsigned char *ptr, *start_ptr;
+
+ DBG(4, ErrorF("Entering ReadInput\n"));
+
+ /*
+ * Try to get a buffer full of report packets.
+ */
+ DBG(4, ErrorF("num_old_bytes is %d, Trying to read %d bytes from port\n",
+ priv->num_old_bytes, MuT_BUFFER_SIZE - priv->num_old_bytes));
+ SYSCALL(num_bytes = read(local->fd,
+ (char *) (priv->rec_buf + priv->num_old_bytes),
+ MuT_BUFFER_SIZE - priv->num_old_bytes));
+ if (num_bytes < 0) {
+ Error("System error while reading from MicroTouch touchscreen.");
+ return;
+ }
+
+ DBG(4, ErrorF("Read %d bytes of reports\n", num_bytes));
+ num_bytes += priv->num_old_bytes;
+ ptr = priv->rec_buf;
+ bytes_in_packet = 0;
+ start_ptr = ptr;
+
+ while (num_bytes >= (MuT_REPORT_SIZE-bytes_in_packet)) {
+ /*
+ * Skip bytes until a status byte (MSB set to 1).
+ */
+ if (bytes_in_packet == 0) {
+ if ((ptr[0] & 0x80) == 0) {
+ DBG(3, ErrorF("Dropping a byte in an attempt to synchronize a report packet: 0x%X\n",
+ ptr[0]));
+ start_ptr++;
+ }
+ else {
+ bytes_in_packet++;
+ }
+ num_bytes--;
+ ptr++;
+ }
+ else if (bytes_in_packet != 5) {
+ if ((ptr[0] & 0x80) == 0) {
+ bytes_in_packet++;
+ }
+ else {
+ /*
+ * Reset the start of packet, we have most certainly
+ * lost some data.
+ */
+ DBG(3, ErrorF("Reseting start of report packet data has been lost\n"));
+ bytes_in_packet = 1;
+ start_ptr = ptr;
+ }
+ ptr++;
+ num_bytes--;
+ }
+
+ if (bytes_in_packet == 5) {
+ LocalDevicePtr local_to_use;
+
+ /*
+ * First stick together the various pieces.
+ */
+ state = start_ptr[0] & 0x7F;
+ cur_x = WORD_ASSEMBLY(start_ptr[1], start_ptr[2]);
+ cur_y = WORD_ASSEMBLY(start_ptr[3], start_ptr[4]);
+
+ DBG(3, ErrorF("Packet: 0x%X 0x%X 0x%X 0x%X 0x%X\n",
+ start_ptr[0], start_ptr[1], start_ptr[2], start_ptr[3], start_ptr[4]));
+ start_ptr = ptr;
+ bytes_in_packet = 0;
+
+ /*
+ * Send events.
+ *
+ * We *must* generate a motion before a button change if pointer
+ * location has changed as DIX assumes this. This is why we always
+ * emit a motion, regardless of the kind of packet processed.
+ *
+ * If local_to_use is NULL we have received a packet from a device
+ * (stylus or finger) which is not configured. Discard it. The first
+ * time a warning is emitted in case of misconfiguration. (Patch
+ * contributed by David Woodhouse). This probably happens
+ * with a touchscreen that reports finger touches only and the
+ * configured device is Stylus. On TouchPens the init procedure is
+ * smart enough to ask only for packets that match the configuration
+ * in XF86Config.
+ */
+ local_to_use = (state & MuT_WHICH_DEVICE) ? priv->stylus : priv->finger;
+ if (!local_to_use) {
+ /*
+ * We have received an event for a device which we don't care
+ * about. Drop it, but whinge first, just in case it's a
+ * misconfiguration.
+ */
+ static int whinged = 0;
+
+ if (!whinged) {
+ whinged++;
+ ErrorF("MicroTouch screen sent %s event, but that device is not configured.\n",
+ (state & MuT_WHICH_DEVICE)?"stylus":"finger");
+ ErrorF("You might want to consider altering your config accordingly.\n");
+ }
+ }
+ else {
+ /*
+ * Emit a motion. If in core pointer mode we need to calibrate
+ * or we will feed X with quite bogus event positions.
+ */
+ xf86PostMotionEvent(local_to_use->dev, TRUE, 0, 2, cur_x, cur_y);
+
+ /*
+ * Emit a button press or release.
+ */
+ if ((state & MuT_CONTACT) != (priv->state & MuT_CONTACT)) {
+ xf86PostButtonEvent(local_to_use->dev, TRUE, 1, state & MuT_CONTACT,
+ 0, 2, cur_x, cur_y);
+ }
+ }
+ DBG(3, ErrorF("TouchScreen %s: x(%d), y(%d), %s\n",
+ ((state & MuT_WHICH_DEVICE) ? "Stylus" : "Finger"),
+ cur_x, cur_y,
+ (((state & MuT_CONTACT) != (priv->state & MuT_CONTACT)) ?
+ ((state & MuT_CONTACT) ? "Press" : "Release") : "Stream")));
+ priv->state = state;
+ }
+ }
+
+ /*
+ * If some bytes are left in the buffer, pack them at the
+ * beginning for the next turn.
+ */
+ if (num_bytes != 0) {
+ memcpy(priv->rec_buf, ptr, num_bytes);
+ priv->num_old_bytes = num_bytes;
+ }
+ else {
+ priv->num_old_bytes = 0;
+ }
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTSendPacket --
+ * Emit a variable length packet to the controller.
+ * The function expects a valid buffer containing the
+ * command to be sent to the controller. The command
+ * size is in len
+ * The buffer is filled with the leading and trailing
+ * character before sending.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTSendPacket(unsigned char *packet,
+ int len,
+ int fd)
+{
+ int result;
+
+ packet[0] = MuT_LEAD_BYTE;
+ packet[len+1] = MuT_TRAIL_BYTE;
+
+ DBG(4, ErrorF("Sending packet : 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
+ packet[0], packet[1], packet[2], packet[3], packet[4],
+ packet[5], packet[6], packet[7], packet[8], packet[9]));
+ SYSCALL(result = write(fd, packet, len+2));
+ if (result != len+2) {
+ DBG(5, ErrorF("System error while sending to MicroTouch touchscreen.\n"));
+ return !Success;
+ }
+ else {
+ return Success;
+ }
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTGetReply --
+ * Read a reply packet from the port. Synchronize with start and stop
+ * of packet.
+ * The packet structure read by this function is as follow:
+ * Byte 0 : MuT_LEAD_BYTE
+ * Byte 1
+ * ...
+ * Byte n : packet data
+ * Byte n+1 : MuT_TRAIL_BYTE
+ *
+ * This function returns if a valid packet has been assembled in
+ * buffer or if no more data is available to do so.
+ *
+ * Returns Success if a packet is successfully assembled.
+ * Bytes preceding the MuT_LEAD_BYTE are discarded.
+ * Returns !Success if out of data while reading. The start of the
+ * partially assembled packet is left in buffer, buffer_p reflects
+ * the current state of assembly. Buffer should at least have room
+ * for MuT_BUFFER_SIZE bytes.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTGetReply(unsigned char *buffer,
+ int *buffer_p,
+ int fd)
+{
+ int num_bytes;
+
+ DBG(4, ErrorF("Entering xf86MuTGetReply with buffer_p == %d\n", *buffer_p));
+
+ /*
+ * Try to read enough bytes to fill up the packet buffer.
+ */
+ DBG(4, ErrorF("buffer_p is %d, Trying to read %d bytes from port\n",
+ *buffer_p, MuT_BUFFER_SIZE - *buffer_p));
+ SYSCALL(num_bytes = read(fd,
+ (char *) (buffer + *buffer_p),
+ MuT_BUFFER_SIZE - *buffer_p));
+
+ /*
+ * Okay, give up.
+ */
+ if (num_bytes < 0) {
+ Error("System error while reading from MicroTouch touchscreen.");
+ return !Success;
+ }
+ DBG(4, ErrorF("Read %d bytes of reply\n", num_bytes));
+
+ while (num_bytes) {
+ /*
+ * Sync with the start of a packet.
+ */
+ if ((*buffer_p == 0) && (buffer[0] != MuT_LEAD_BYTE)) {
+ /*
+ * No match, shift data one byte toward the start of the buffer.
+ */
+ DBG(4, ErrorF("Dropping one byte in an attempt to synchronize: '%c' 0x%X\n",
+ buffer[0], buffer[0]));
+ memcpy(&buffer[0], &buffer[1], num_bytes-1);
+ num_bytes--;
+ }
+ else if (buffer[*buffer_p] == MuT_TRAIL_BYTE) {
+ /*
+ * Got a packet, report it.
+ */
+ *buffer_p = 0;
+ return Success;
+ }
+ else {
+ num_bytes--;
+ (*buffer_p)++;
+ }
+ }
+
+ return !Success;
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTWaitReply --
+ * It is assumed that the reply will be in the few next bytes
+ * read and will be available very soon after the command post. if
+ * these two asumptions are not met, there are chances that the server
+ * will be stuck for a while.
+ * The reply is left in reply. The function returns Success if a valid
+ * reply was found and !Success otherwise. Reply should at least
+ * have room for MuT_BUFFER_SIZE bytes.
+ *
+ ***************************************************************************
+ */
+#ifndef XFREE86_V4
+static int
+xf86WaitForInput(int fd,
+ int timeout)
+{
+ fd_set readfds;
+ struct timeval to;
+ int r;
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ to.tv_sec = 0;
+ to.tv_usec = timeout;
+
+ SYSCALL(r = select(FD_SETSIZE, &readfds, NULL, NULL, &to));
+ return r;
+}
+#endif
+
+static Bool
+xf86MuTWaitReply(unsigned char *reply,
+ int fd)
+{
+ Bool ok;
+ int i, result;
+ int reply_p = 0;
+ unsigned char local_reply[3];
+
+ DBG(4, ErrorF("Waiting a reply\n"));
+ i = MuT_MAX_TRIALS;
+ do {
+ ok = !Success;
+
+ /*
+ * Wait half a second for the reply. The fuse counts down each
+ * timeout and each wrong packet.
+ */
+ DBG(4, ErrorF("Waiting %d ms for data from port\n", MuT_MAX_WAIT / 1000));
+ result = xf86WaitForInput(fd, MuT_MAX_WAIT);
+ if (result > 0) {
+ if (reply) {
+ ok = xf86MuTGetReply(reply, &reply_p, fd);
+ }
+ else {
+ ok = xf86MuTGetReply(local_reply, &reply_p, fd);
+ if (ok && local_reply[1] != MuT_OK) {
+ DBG(3, ErrorF("Error reported by firmware\n"));
+ ok = !Success;
+ }
+ }
+ }
+ else {
+ DBG(3, ErrorF("No answer from port : %d\n", result));
+ }
+
+ if (result == 0)
+ i--;
+ } while(ok != Success && i);
+
+ return ok;
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTSendCommand --
+ * Emit a command to the controller and blocks until the reply is
+ * read.
+ *
+ * The reply is left in reply. The function returns Success if the
+ * reply is valid and !Success otherwise. Reply should at least
+ * have room for MuT_BUFFER_SIZE bytes.
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTSendCommand(unsigned char *request,
+ int len,
+ unsigned char *reply,
+ int fd)
+{
+ Bool ok;
+
+ if (xf86MuTSendPacket(request, len, fd) == Success) {
+ ok = xf86MuTWaitReply(reply, fd);
+ return ok;
+ }
+ else {
+ return !Success;
+ }
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTPrintIdent --
+ * Print type of touchscreen and features on controller board.
+ *
+ ***************************************************************************
+ */
+static void
+xf86MuTPrintIdent(unsigned char *packet)
+{
+ int vers, rev;
+
+#ifdef XFREE86_V4
+ xf86Msg(X_PROBED, "MicroTouch touchscreen is a ");
+ if (strncmp((char *) &packet[1], MuT_TOUCH_PEN_IDENT, 2) == 0) {
+ xf86Msg(X_NONE, "TouchPen");
+ }
+ else if (strncmp((char *) &packet[1], MuT_SMT3_IDENT, 2) == 0) {
+ xf86Msg(X_NONE, "Serial/SMT3");
+ }
+ else if (strncmp((char *) &packet[1], MuT_THRU_GLASS_IDENT, 2) == 0) {
+ xf86Msg(X_NONE, "ThruGlass");
+ }
+ xf86Msg(X_NONE, ", connected through a serial port.\n");
+ sscanf((char *) &packet[3], "%2d%2d", &vers, &rev);
+ xf86Msg(X_PROBED, "MicroTouch controller firmware revision is %d.%d.\n", vers, rev);
+#else
+ ErrorF("%s MicroTouch touchscreen is a ", XCONFIG_PROBED);
+ if (strncmp((char *) &packet[1], MuT_TOUCH_PEN_IDENT, 2) == 0) {
+ ErrorF("TouchPen");
+ }
+ else if (strncmp((char *) &packet[1], MuT_SMT3_IDENT, 2) == 0) {
+ ErrorF("Serial/SMT3");
+ }
+ else if (strncmp((char *) &packet[1], MuT_THRU_GLASS_IDENT, 2) == 0) {
+ ErrorF("ThruGlass");
+ }
+ ErrorF(", connected through a serial port.\n");
+ sscanf((char *) &packet[3], "%2d%2d", &vers, &rev);
+ ErrorF("%s MicroTouch controller firmware revision is %d.%d.\n", XCONFIG_PROBED, vers, rev);
+#endif
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTPrintHwStatus --
+ * Print status of hardware. That is if the controller report errors,
+ * decode and display them.
+ *
+ ***************************************************************************
+ */
+static void
+xf86MuTPrintHwStatus(unsigned char *packet)
+{
+#ifdef XFREE86_V4
+ xf86Msg(X_PROBED, "MicroTouch status of errors: %c%c.\n", packet[7], packet[8]);
+#else
+ ErrorF("%s MicroTouch status of errors: %c%c.\n", XCONFIG_PROBED, packet[7], packet[8]);
+#endif
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTPtrControl --
+ *
+ ***************************************************************************
+ */
+#if 0
+static void
+xf86MuTPtrControl(DeviceIntPtr dev,
+ PtrCtrl *ctrl)
+{
+}
+#endif
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTControl --
+ *
+ ***************************************************************************
+ */
+static Bool
+xf86MuTControl(DeviceIntPtr dev,
+ int mode)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ MuTPrivatePtr priv = (MuTPrivatePtr)(local->private);
+ unsigned char map[] = { 0, 1 };
+ unsigned char req[MuT_PACKET_SIZE];
+ unsigned char reply[MuT_BUFFER_SIZE];
+ char *id_string = DEVICE_ID(local->private_flags) == FINGER_ID ? "finger" : "stylus";
+
+ switch(mode) {
+
+ case DEVICE_INIT:
+ {
+ DBG(2, ErrorF("MicroTouch %s init...\n", id_string));
+
+ if (priv->screen_no >= screenInfo.numScreens ||
+ priv->screen_no < 0) {
+ priv->screen_no = 0;
+ }
+ priv->screen_width = screenInfo.screens[priv->screen_no]->width;
+ priv->screen_height = screenInfo.screens[priv->screen_no]->height;
+
+ /*
+ * Device reports button press for up to 1 button.
+ */
+ if (InitButtonClassDeviceStruct(dev, 1, map) == FALSE) {
+ ErrorF("Unable to allocate ButtonClassDeviceStruct\n");
+ return !Success;
+ }
+
+ /*
+ * Device reports motions on 2 axes in absolute coordinates.
+ * Axes min and max values are reported in raw coordinates.
+ * Resolution is computed roughly by the difference between
+ * max and min values scaled from the approximate size of the
+ * screen to fit one meter.
+ */
+ if (InitValuatorClassDeviceStruct(dev, 2, xf86GetMotionEvents,
+ local->history_size, Absolute) == FALSE) {
+ ErrorF("Unable to allocate ValuatorClassDeviceStruct\n");
+ return !Success;
+ }
+ else {
+ InitValuatorAxisStruct(dev, 0, priv->min_x, priv->max_x,
+ 9500,
+ 0 /* min_res */,
+ 9500 /* max_res */);
+ InitValuatorAxisStruct(dev, 1, priv->min_y, priv->max_y,
+ 10500,
+ 0 /* min_res */,
+ 10500 /* max_res */);
+ }
+
+ if (InitFocusClassDeviceStruct(dev) == FALSE) {
+ ErrorF("Unable to allocate FocusClassDeviceStruct\n");
+ }
+
+ /*
+ * Allocate the motion events buffer.
+ */
+ xf86MotionHistoryAllocate(local);
+
+ /*
+ * This once has caused the server to crash after doing an xalloc & strcpy ??
+ */
+#ifndef XFREE86_V4
+ AssignTypeAndName(dev, local->atom, local->name);
+#endif
+
+ DBG(2, ErrorF("Done.\n"));
+ return Success;
+ }
+
+ case DEVICE_ON:
+ {
+ Bool already_open = FALSE;
+ char *report_what = "";
+
+ DBG(2, ErrorF("MicroTouch %s on...\n", id_string));
+
+ /*
+ * Try to see if the port has already been opened either
+ * for this device or for the other one.
+ */
+ if (local->fd >= 0) {
+ already_open = TRUE;
+ }
+ else {
+ switch (DEVICE_ID(local->private_flags)) {
+ case FINGER_ID:
+ if (priv->stylus && priv->stylus->fd >= 0) {
+ already_open = TRUE;
+ local->fd = priv->stylus->fd;
+ }
+ break;
+ case STYLUS_ID:
+ if (priv->finger && priv->finger->fd >= 0) {
+ already_open = TRUE;
+ local->fd = priv->finger->fd;
+ }
+ break;
+ }
+ }
+ if (!already_open) {
+#ifndef XFREE86_V4
+ struct termios termios_tty;
+ int result;
+#endif
+
+ DBG(2, ErrorF("MicroTouch touchscreen opening : %s\n", priv->input_dev));
+#ifdef XFREE86_V4
+ local->fd = xf86OpenSerial(local->options);
+ if (local->fd < 0) {
+ Error("Unable to open MicroTouch touchscreen device");
+ return !Success;
+ }
+#else
+ SYSCALL(local->fd = open(priv->input_dev, O_RDWR|O_NDELAY, 0));
+ if (local->fd < 0) {
+ Error("Unable to open MicroTouch touchscreen device");
+ return !Success;
+ }
+
+ /*
+ * Try to see if the link is at the specified rate and
+ * reset the controller. The wait time needed by the
+ * controller after reset should be compensated by the
+ * timeouts in the receive section.
+ */
+ DBG(3, ErrorF("Try to see if the link is at the specified rate\n"));
+ memset(&termios_tty, 0, sizeof(termios_tty));
+ termios_tty.c_cflag = priv->link_speed | CS8 | CREAD | CLOCAL;
+#ifdef CRTSCTS
+ termios_tty.c_cflag &= ~CRTSCTS;
+#endif
+ termios_tty.c_cc[VMIN] = 1;
+ SYSCALL(result = tcsetattr(local->fd, TCSANOW, &termios_tty));
+ if (result < 0) {
+ Error("Unable to configure MicroTouch touchscreen port");
+ goto not_success;
+ }
+#endif
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_RESET, strlen(MuT_RESET));
+ if (xf86MuTSendCommand(req, strlen(MuT_RESET), NULL, local->fd) != Success) {
+ DBG(3, ErrorF("Not at the specified rate, giving up\n"));
+ goto not_success;
+ }
+
+ /*
+ * ask the controller to report identity and status.
+ */
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_OUTPUT_IDENT, strlen(MuT_OUTPUT_IDENT));
+ if (xf86MuTSendCommand(req, strlen(MuT_OUTPUT_IDENT),
+ reply, local->fd) != Success) {
+ ErrorF("Unable to ask MicroTouch touchscreen identification\n");
+ goto not_success;
+ }
+ xf86MuTPrintIdent(reply);
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_UNIT_TYPE, strlen(MuT_UNIT_TYPE));
+ if (xf86MuTSendCommand(req, strlen(MuT_UNIT_TYPE),
+ reply, local->fd) != Success) {
+ ErrorF("Unable to ask MicroTouch touchscreen status\n");
+ goto not_success;
+ }
+ xf86MuTPrintHwStatus(reply);
+
+ /*
+ * Set the operating mode: Format Tablet, Mode stream, Pen.
+ */
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_FORMAT_TABLET, strlen(MuT_FORMAT_TABLET));
+ if (xf86MuTSendCommand(req, strlen(MuT_FORMAT_TABLET),
+ NULL, local->fd) != Success) {
+ ErrorF("Unable to switch MicroTouch touchscreen to Tablet Format\n");
+ goto not_success;
+ }
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_MODE_STREAM, strlen(MuT_MODE_STREAM));
+ if (xf86MuTSendCommand(req, strlen(MuT_MODE_STREAM),
+ NULL, local->fd) != Success) {
+ ErrorF("Unable to switch MicroTouch touchscreen to Stream Mode\n");
+ goto not_success;
+ }
+
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_PEN_ONLY, strlen(MuT_PEN_ONLY));
+ if (xf86MuTSendCommand(req, strlen(MuT_PEN_ONLY),
+ NULL, local->fd) != Success) {
+ ErrorF("Unable to change MicroTouch touchscreen to pen mode\n");
+ goto not_success;
+ }
+ /* goto not_success;*/
+#ifndef XFREE86_V4
+ xf86AddEnabledDevice(local);
+#else
+ AddEnabledDevice(local->fd);
+#endif
+ }
+
+ /*
+ * Select Pen / Finger reports depending on which devices are
+ * currently on.
+ */
+ switch (DEVICE_ID(local->private_flags)) {
+ case FINGER_ID:
+ if (priv->stylus && priv->stylus->dev->public.on) {
+ report_what = MuT_PEN_FINGER;
+ }
+ else {
+ report_what = MuT_FINGER_ONLY;
+ }
+ break;
+ case STYLUS_ID:
+ if (priv->finger && priv->finger->dev->public.on) {
+ report_what = MuT_PEN_FINGER;
+ }
+ else {
+ report_what = MuT_PEN_ONLY;
+ }
+ break;
+ }
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], report_what, strlen(report_what));
+ if (xf86MuTSendCommand(req, strlen(report_what), NULL, local->fd) != Success) {
+ ErrorF("Unable to change MicroTouch touchscreen to %s\n",
+ (strcmp(report_what, MuT_PEN_FINGER) == 0) ? "Pen & Finger" :
+ ((strcmp(report_what, MuT_PEN_ONLY) == 0) ? "Pen Only" : "Finger Only"));
+ goto not_success;
+ }
+ dev->public.on = TRUE;
+ /*
+ * Set frequency for ThruGlass
+ */
+ if (priv->frequency != 0) {
+ memset(req, 0, MuT_PACKET_SIZE);
+ strncpy((char *) &req[1], MuT_SET_FREQUENCY, strlen(MuT_SET_FREQUENCY));
+ req[1+strlen(MuT_SET_FREQUENCY)] = ' ';
+ req[2+strlen(MuT_SET_FREQUENCY)] = '0';
+ req[3+strlen(MuT_SET_FREQUENCY)] = (priv->frequency<=9?'0':'A'-10)+priv->frequency;
+ if (xf86MuTSendCommand(req, strlen((char *) &req[1]), NULL, local->fd) != Success) {
+ ErrorF("Unable to set MicroTouch ThruGlass frquency to %d\n", priv->frequency);
+ goto not_success;
+ }
+ }
+
+
+ DBG(2, ErrorF("Done\n"));
+ return Success;
+
+ not_success:
+ SYSCALL(close(local->fd));
+ local->fd = -1;
+ return !Success;
+ }
+
+ /*
+ * Deactivate the device.
+ */
+ case DEVICE_OFF:
+ DBG(2, ErrorF("MicroTouch %s off...\n", id_string));
+ dev->public.on = FALSE;
+ DBG(2, ErrorF("Done\n"));
+ return Success;
+
+ /*
+ * Final close before server exit. This is used during server shutdown.
+ * Close the port and free all the resources.
+ */
+ case DEVICE_CLOSE:
+ DBG(2, ErrorF("MicroTouch %s close...\n", id_string));
+ dev->public.on = FALSE;
+ if (local->fd >= 0) {
+#ifdef XFREE86_V4
+ xf86RemoveEnabledDevice(local);
+#else
+ RemoveEnabledDevice(local->fd);
+#endif
+ SYSCALL(close(local->fd));
+ local->fd = -1;
+ /*
+ * Need some care to close the port only once.
+ */
+ switch (DEVICE_ID(local->private_flags)) {
+ case FINGER_ID:
+ if (priv->stylus) {
+ priv->stylus->fd = -1;
+ }
+ break;
+ case STYLUS_ID:
+ if (priv->finger) {
+ priv->finger->fd = -1;
+ }
+ }
+ }
+ DBG(2, ErrorF("Done\n"));
+ return Success;
+
+ default:
+ ErrorF("unsupported mode=%d\n", mode);
+ return !Success;
+ }
+}
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTAllocate --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+#ifndef XFREE86_V4
+xf86MuTAllocate(char *name,
+ char *type_name,
+ int flag)
+#else
+xf86MuTAllocate(InputDriverPtr drv,
+ char *name,
+ char *type_name,
+ int flag)
+#endif
+{
+#ifndef XFREE86_V4
+ LocalDevicePtr local = (LocalDevicePtr) xalloc(sizeof(LocalDeviceRec));
+#else
+ LocalDevicePtr local = xf86AllocateInput(drv, 0);
+#endif
+ MuTPrivatePtr priv = (MuTPrivatePtr) xalloc(sizeof(MuTPrivateRec));
+
+ if (!local) {
+ if (priv) {
+ xfree(priv);
+ }
+ return NULL;
+ }
+ if (!priv) {
+ if (local) {
+ xfree(local);
+ }
+ return NULL;
+ }
+
+ priv->input_dev = strdup(MuT_PORT);
+#ifndef XFREE86_V4
+ priv->link_speed = MuT_LINK_SPEED;
+#endif
+ priv->min_x = 0;
+ priv->max_x = 0;
+ priv->min_y = 0;
+ priv->max_y = 0;
+ priv->screen_no = 0;
+ priv->screen_width = -1;
+ priv->screen_height = -1;
+ priv->inited = 0;
+ priv->state = 0;
+ priv->num_old_bytes = 0;
+ priv->stylus = NULL;
+ priv->finger = NULL;
+ priv->swap_axes = 0;
+ priv->frequency = 0;
+
+ local->name = name;
+ local->flags = 0 /* XI86_NO_OPEN_ON_INIT */;
+#ifndef XFREE86_V4
+ local->device_config = xf86MuTConfig;
+#endif
+ local->device_control = xf86MuTControl;
+ local->read_input = xf86MuTReadInput;
+ local->control_proc = NULL;
+ local->close_proc = NULL;
+ local->switch_mode = NULL;
+ local->conversion_proc = xf86MuTConvert;
+ local->reverse_conversion_proc = NULL;
+ local->fd = -1;
+ local->atom = 0;
+ local->dev = NULL;
+ local->private = priv;
+ local->private_flags = flag;
+ local->type_name = type_name;
+ local->history_size = 0;
+
+ return local;
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTAllocateFinger --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+#ifndef XFREE86_V4
+xf86MuTAllocateFinger(void)
+#else
+xf86MuTAllocateFinger(InputDriverPtr drv)
+#endif
+{
+#ifndef XFREE86_V4
+ LocalDevicePtr local = xf86MuTAllocate(XI_FINGER, "MicroTouch Finger", FINGER_ID);
+#else
+ LocalDevicePtr local = xf86MuTAllocate(drv, XI_FINGER, "MicroTouch Finger", FINGER_ID);
+#endif
+
+ if (local) {
+ ((MuTPrivatePtr) local->private)->finger = local;
+ }
+ return local;
+}
+
+
+/*
+ ***************************************************************************
+ *
+ * xf86MuTAllocateStylus --
+ *
+ ***************************************************************************
+ */
+static LocalDevicePtr
+#ifndef XFREE86_V4
+xf86MuTAllocateStylus(void)
+#else
+xf86MuTAllocateStylus(InputDriverPtr drv)
+#endif
+{
+#ifndef XFREE86_V4
+ LocalDevicePtr local = xf86MuTAllocate(XI_STYLUS, "MicroTouch Stylus", STYLUS_ID);
+#else
+ LocalDevicePtr local = xf86MuTAllocate(drv, XI_STYLUS, "MicroTouch Stylus", STYLUS_ID);
+#endif
+
+ if (local) {
+ ((MuTPrivatePtr) local->private)->stylus = local;
+ }
+ return local;
+}
+
+
+#ifndef XFREE86_V4
+/*
+ ***************************************************************************
+ *
+ * MicroTouch finger device association --
+ *
+ ***************************************************************************
+ */
+DeviceAssocRec MuT_finger_assoc =
+{
+ FINGER_SECTION_NAME, /* config_section_name */
+ xf86MuTAllocateFinger /* device_allocate */
+};
+
+/*
+ ***************************************************************************
+ *
+ * MicroTouch stylus device association --
+ *
+ ***************************************************************************
+ */
+DeviceAssocRec MuT_stylus_assoc =
+{
+ STYLUS_SECTION_NAME, /* config_section_name */
+ xf86MuTAllocateStylus /* device_allocate */
+};
+
+
+#ifdef DYNAMIC_MODULE
+/*
+ ***************************************************************************
+ *
+ * entry point of dynamic loading
+ *
+ ***************************************************************************
+ */
+int
+#ifndef DLSYM_BUG
+init_module(unsigned long server_version)
+#else
+init_xf86MuTouch(unsigned long server_version)
+#endif
+{
+ xf86AddDeviceAssoc(&MuT_finger_assoc);
+ xf86AddDeviceAssoc(&MuT_stylus_assoc);
+
+ if (server_version != XF86_VERSION_CURRENT) {
+ ErrorF("Warning: MicroTouch module compiled for version%s\n", XF86_VERSION);
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+#endif
+
+#else /* XFREE86_V4 */
+static void
+xf86MuTUninit(InputDriverPtr drv,
+ LocalDevicePtr local,
+ int flags)
+{
+ MuTPrivatePtr priv = (MuTPrivatePtr) local->private;
+
+ xf86MuTControl(local->dev, DEVICE_OFF);
+
+ if (priv) {
+ priv->stylus->private = NULL;
+ priv->finger->private = NULL;
+ xfree(priv->input_dev);
+ xfree(priv);
+ }
+ xfree(local->name);
+ xfree(local);
+
+ xf86DeleteInput(local, 0);
+}
+
+static const char *default_options[] = {
+ "BaudRate", "9600",
+ "StopBits", "1",
+ "DataBits", "8",
+ "Parity", "None",
+ "Vmin", "10",
+ "Vtime", "1",
+ "FlowControl", "None",
+ NULL
+};
+
+static InputInfoPtr
+xf86MuTInit(InputDriverPtr drv,
+ IDevPtr dev,
+ int flags)
+{
+ LocalDevicePtr local=NULL, fake_local=NULL, current;
+ MuTPrivatePtr priv=NULL;
+ char *str;
+ int portrait=0;
+
+ fake_local = (LocalDevicePtr) xcalloc(1, sizeof(LocalDeviceRec));
+ if (!fake_local) {
+ goto init_err;
+ }
+ fake_local->conf_idev = dev;
+
+ xf86CollectInputOptions(fake_local, default_options, NULL);
+
+ str = xf86FindOptionValue(fake_local->options, "Type");
+ if (str && (xf86NameCmp(str, "finger") == 0)) {
+ local = xf86MuTAllocateFinger(drv);
+ }
+ else if (str && (xf86NameCmp(str, "stylus") == 0)) {
+ local = xf86MuTAllocateStylus(drv);
+ }
+ else {
+ xf86Msg(X_ERROR, "%s: Type field missing in Microtouch module config,\n"
+ "Must be stylus or finger\n", dev->identifier);
+ goto init_err;
+ }
+ if (!local) {
+ goto init_err;
+ }
+ priv = local->private;
+ local->options = fake_local->options;
+ local->conf_idev = fake_local->conf_idev;
+ xfree(fake_local);
+ fake_local = NULL;
+
+ str = xf86FindOptionValue(local->options, "Device");
+ if (!str) {
+ xf86Msg(X_ERROR, "%s: No Device specified in Microtouch module config.\n",
+ dev->identifier);
+ goto init_err;
+ }
+ priv->input_dev = strdup(str);
+
+ /*
+ * See if another X device share the same physical
+ * device and set up the links so that they share
+ * the same private structure (the one that controls
+ * the physical device).
+ */
+ current = xf86FirstLocalDevice();
+ while (current) {
+ if ((local != current) &&
+ (current->device_control == xf86MuTControl) &&
+ (strcmp(((MuTPrivatePtr) (current->private))->input_dev, priv->input_dev) == 0)) {
+ xf86Msg(X_CONFIG, "MicroTouch config detected a device share between %s and %s\n",
+ local->name, current->name);
+ xfree(priv->input_dev);
+ xfree(priv);
+ priv = local->private = current->private;
+ switch (DEVICE_ID(local->private_flags)) {
+ case FINGER_ID:
+ priv->finger = local;
+ break;
+ case STYLUS_ID:
+ priv->stylus = local;
+ break;
+ }
+ break;
+ }
+ current = current->next;
+ }
+ if (!current) {
+ xf86Msg(X_CONFIG, "MicroTouch %s input device: %s\n", local->name, priv->input_dev);
+ }
+
+ /* Process the common options. */
+ xf86ProcessCommonOptions(local, local->options);
+
+ str = xf86FindOptionValue(local->options, "DeviceName");
+ if (str) {
+ local->name = strdup(str);
+ }
+ xf86Msg(X_CONFIG, "Microtouch X device name: %s\n", local->name);
+ priv->screen_no = xf86SetIntOption(local->options, "ScreenNo", 0);
+ xf86Msg(X_CONFIG, "Microtouch associated screen: %d\n", priv->screen_no);
+ priv->max_x = xf86SetIntOption(local->options, "MaxX", 3000);
+ xf86Msg(X_CONFIG, "Microtouch maximum x position: %d\n", priv->max_x);
+ priv->min_x = xf86SetIntOption(local->options, "MinX", 0);
+ xf86Msg(X_CONFIG, "Microtouch minimum x position: %d\n", priv->min_x);
+ priv->max_y = xf86SetIntOption(local->options, "MaxY", 3000);
+ xf86Msg(X_CONFIG, "Microtouch maximum y position: %d\n", priv->max_y);
+ priv->min_y = xf86SetIntOption(local->options, "MinY", 0);
+ xf86Msg(X_CONFIG, "Microtouch minimum y position: %d\n", priv->min_y);
+ priv->frequency = xf86SetIntOption(local->options, "Frequency", 0);
+ xf86Msg(X_CONFIG, "Microtouch ThruGlass frequency is: %d\n", priv->frequency);
+ priv->swap_axes = xf86SetBoolOption(local->options, "SwapXY", 0);
+ if (priv->swap_axes) {
+ xf86Msg(X_CONFIG, "Microtouch %s device will work with X and Y axes swapped\n",
+ local->name);
+ }
+ debug_level = xf86SetIntOption(local->options, "DebugLevel", 0);
+ if (debug_level) {
+#if DEBUG
+ xf86Msg(X_CONFIG, "Microtouch debug level sets to %d\n", debug_level);
+#else
+ xf86Msg(X_INFO, "Microtouch debug not available\n");
+#endif
+ }
+ str = xf86SetStrOption(local->options, "PortraitMode", "Landscape");
+ if (strcmp(str, "Portrait") == 0) {
+ portrait = 1;
+ }
+ else if (strcmp(str, "PortraitCCW") == 0) {
+ portrait = -1;
+ }
+ else if (strcmp(str, "Landscape") != 0) {
+ xf86Msg(X_ERROR, "Microtouch portrait mode should be: Portrait, Landscape or PortraitCCW");
+ str = "Landscape";
+ }
+ xf86Msg(X_CONFIG, "Microtouch device will work in %s mode\n", str);
+
+ if (priv->max_x - priv->min_x <= 0) {
+ xf86Msg(X_INFO, "MicroTouch: reverse x mode (minimum x position >= maximum x position)\n");
+ }
+ if (priv->max_y - priv->min_y <= 0) {
+ xf86Msg(X_INFO, "MicroTouch: reverse y mode (minimum y position >= maximum y position)\n");
+ }
+
+ if (portrait == 1) {
+ /*
+ * Portrait Clockwise: reverse Y axis and exchange X and Y.
+ */
+ int tmp;
+ tmp = priv->min_y;
+ priv->min_y = priv->max_y;
+ priv->max_y = tmp;
+ priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
+ }
+ else if (portrait == -1) {
+ /*
+ * Portrait Counter Clockwise: reverse X axis and exchange X and Y.
+ */
+ int tmp;
+ tmp = priv->min_x;
+ priv->min_x = priv->max_x;
+ priv->max_x = tmp;
+ priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
+ }
+
+ /* mark the device configured */
+ local->flags |= XI86_CONFIGURED;
+ return local;
+
+ init_err:
+ if (fake_local) {
+ xfree(fake_local);
+ }
+ if (priv) {
+ if (priv->input_dev) {
+ xfree(priv->input_dev);
+ }
+ xfree(priv);
+ }
+ if (local) {
+ xfree(local);
+ }
+ return NULL;
+}
+
+#ifdef XFree86LOADER
+static
+#endif
+InputDriverRec MUTOUCH = {
+ 1, /* driver version */
+ "mutouch", /* driver name */
+ NULL, /* identify */
+ xf86MuTInit, /* pre-init */
+ xf86MuTUninit, /* un-init */
+ NULL, /* module */
+ 0 /* ref count */
+};
+
+#ifdef XFree86LOADER
+static pointer
+Plug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ xf86AddInputDriver(&MUTOUCH, module, 0);
+
+ return module;
+}
+
+static void
+Unplug(pointer p)
+{
+ DBG(1, ErrorF("MuTUnplug\n"));
+}
+
+static XF86ModuleVersionInfo version_rec = {
+ "mutouch",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * This is the entry point in the module. The name
+ * is setup after the pattern <module_name>ModuleData.
+ * Do not change it.
+ */
+XF86ModuleData mutouchModuleData = { &version_rec, Plug, Unplug };
+#endif
+
+#endif /* XFREE86_V4 */