diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:56 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 16:48:56 +0000 |
commit | 7d3ee7b318425801939c01c9ff8850d5821bc224 (patch) | |
tree | 6f8cb3251b41fc288accebc41570d9430daf58d4 |
Initial revisionXORG-RELEASE-1-BASEXEVIE-MERGEXEVIE-BASEXORG-STABLE
-rw-r--r-- | man/mutouch.man | 40 | ||||
-rw-r--r-- | src/xf86MuTouch.c | 1890 |
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 */ |