/* * Copyright 1996 by Steven Lang * * AceCad tablet support ported by Arpad Gereoffy * originally written by Shane Watts * and Fredrik Chabot * * 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 Steven Lang not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. Steven Lang makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * STEVEN LANG DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL STEVEN LANG 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 ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $XFree86: xc/programs/Xserver/hw/xfree86/input/summa/xf86Summa.c,v 1.16 2003/11/03 05:11:49 tsi Exp $ */ #if 0 static const char identification[] = "$Identification: 18 $"; #endif #include "xf86Version.h" #if XF86_VERSION_CURRENT >= XF86_VERSION_NUMERIC(3,9,0,0,0) #define XFREE86_V4 1 #endif #ifdef XFREE86_V4 /* post 3.9 headers */ #ifndef XFree86LOADER #include #include #endif #include "misc.h" #include "xf86.h" #define NEED_XF86_TYPES #if !defined(DGUX) #include "xf86_ansic.h" #include "xisb.h" #endif #include "xf86_OSproc.h" #include "xf86Xinput.h" #include "exevents.h" /* Needed for InitValuator/Proximity stuff */ #include "keysym.h" #include "mipointer.h" #ifdef XFree86LOADER #include "xf86Module.h" #endif #define wait_for_fd(fd) xf86WaitForInput((fd), 1000) #define tcflush(fd, n) xf86FlushInput((fd)) #undef read #define read(a,b,c) xf86ReadSerial((a),(b),(c)) #undef write #define write(a,b,c) xf86WriteSerial((a),(char*)(b),(c)) #undef close #define close(a) xf86CloseSerial((a)) #define XCONFIG_PROBED "(==)" #define XCONFIG_GIVEN "(**)" #define xf86Verbose 1 #undef PRIVATE #define PRIVATE(x) XI_PRIVATE(x) /* * Be sure to set vmin appropriately for your device's protocol. You want to * read a full packet before returning */ static const char *default_options[] = { "BaudRate", "9600", "DataBits", "8", "StopBits", "1", "Parity", "Odd", "FlowControl", "Xoff", "VTime", "10", "VMin", "1", NULL }; static InputDriverPtr sumDrv; #else /* pre 3.9 headers */ #define NEED_EVENTS #include "X.h" #include "Xproto.h" #include "misc.h" #include "inputstr.h" #include "scrnintstr.h" #include "XI.h" #include "XIproto.h" #if defined(sun) && !defined(i386) #define POSIX_TTY #include #include #include #include #include "extio.h" #else #include "compiler.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86_OSproc.h" #ifdef XFree86LOADER #include "xf86_ansic.h" #endif #include "xf86Config.h" #include "xf86Xinput.h" #include "atKeynames.h" #endif #if !defined(sun) || defined(i386) #include "osdep.h" #include "exevents.h" #include "extnsionst.h" #include "extinit.h" #endif #endif /* ** Debugging macros */ #ifdef DBG #undef DBG #endif #ifdef DEBUG #undef DEBUG #endif static int debug_level = 5; #define DEBUG 1 #if DEBUG #define DBG(lvl, f) {if ((lvl) <= debug_level) f;} #else #define DBG(lvl, f) #endif /* ** Device records (flag bits) */ #define ABSOLUTE_FLAG 1 /* default */ #define STYLUS_FLAG 2 /* not default */ #define COMPATIBLE_FLAG 4 /* not default */ #define H1217D_FLAG 8 /* not default */ #define Z_AXIS_FLAG 16 /* not default */ #define INITIALIZED 32 typedef struct { char *sumDevice; /* device file name */ int sumInc; /* increment between transmits */ int sumButTrans; /* button translation flags */ int sumOldX; /* previous X position */ int sumOldY; /* previous Y position */ int sumOldZ; /* previous Z position */ int sumOldProximity; /* previous proximity */ int sumOldButtons; /* previous buttons state */ int sumMaxX; /* max X value */ int sumMaxY; /* max Y value */ int sumXSize; /* active area X size */ int sumXOffset; /* active area X offset */ int sumYSize; /* active area Y size */ int sumYOffset; /* active area Y offset */ int sumRes; /* resolution in lines per inch */ int flags; /* various flags */ int sumIndex; /* number of bytes read */ unsigned char sumData[7]; /* data read on the device */ } SummaDeviceRec, *SummaDevicePtr; /* ** Configuration data */ #define SUMMA_SECTION_NAME "SummaSketch" #ifndef XFREE86_V4 #define PORT 1 #define DEVICENAME 2 #define THE_MODE 3 #define CURSOR 4 #define INCREMENT 5 #define BORDER 6 #define DEBUG_LEVEL 7 #define HISTORY_SIZE 8 #define ALWAYS_CORE 9 #define ACTIVE_AREA 10 #define ACTIVE_OFFSET 11 #define COMPATIBLE 12 #define RESOLUTION 13 #define HITACHI_1217D 14 #if !defined(sun) || defined(i386) static SymTabRec SumTab[] = { {ENDSUBSECTION, "endsubsection"}, {PORT, "port"}, {DEVICENAME, "devicename"}, {THE_MODE, "mode"}, {CURSOR, "cursor"}, {INCREMENT, "increment"}, {BORDER, "border"}, {DEBUG_LEVEL, "debuglevel"}, {HISTORY_SIZE, "historysize"}, {ALWAYS_CORE, "alwayscore"}, {ACTIVE_AREA, "activearea"}, {ACTIVE_OFFSET, "activeoffset"}, {COMPATIBLE, "compatible"}, {RESOLUTION, "resolution"}, {HITACHI_1217D, "hitachi_1217d"}, {-1, ""} }; #define RELATIVE 1 #define ABSOLUTE 2 static SymTabRec SumModeTabRec[] = { {RELATIVE, "relative"}, {ABSOLUTE, "absolute"}, {-1, ""} }; #define PUCK 1 #define STYLUS 2 static SymTabRec SumPointTabRec[] = { {PUCK, "puck"}, {STYLUS, "stylus"}, {-1, ""} }; #endif #endif /* Pre 3.9 headers */ /* ** Contants and macro */ #define BUFFER_SIZE 256 /* size of reception buffer */ #define XI_NAME "SUMMA" /* X device name for the stylus */ #define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) #define SS_TABID0 "0" /* Tablet ID 0 */ #define SS_FIRMID "z?" /* Request firmware ID string */ #define SS_CONFIG "a" /* Send configuration (max coords) */ #define SS_ABSOLUTE 'F' /* Absolute mode */ #define SS_RELATIVE 'E' /* Relative mode */ #define SS_UPPER_ORIGIN "b" /* Origin upper left */ #define SS_PROMPT_MODE "B" /* Prompt mode */ #define SS_STREAM_MODE "@" /* Stream mode */ #define SS_INCREMENT 'I' /* Set increment */ #define SS_BINARY_FMT "zb" /* Binary reporting */ #define SS_PROMPT "P" /* Prompt for current position */ static const char * ss_initstr = SS_TABID0 SS_UPPER_ORIGIN SS_BINARY_FMT SS_STREAM_MODE; #define PHASING_BIT 0x80 #define PROXIMITY_BIT 0x40 #define TABID_BIT 0x20 #define XSIGN_BIT 0x10 #define YSIGN_BIT 0x08 #define BUTTON_BITS 0x07 #define COORD_BITS 0x7f /* macro from counts/inch to counts/meter */ #define LPI2CPM(res) (res * 1000 / 25.4) /* ** External declarations */ #ifndef XFREE86_V4 #if defined(sun) && !defined(i386) #define ENQUEUE suneqEnqueue #else #define ENQUEUE xf86eqEnqueue extern void xf86eqEnqueue( xEventPtr /*e*/ ); #endif extern void miPointerDeltaCursor( int /*dx*/, int /*dy*/, unsigned long /*time*/ ); #endif #ifndef XFREE86_V4 #if !defined(sun) || defined(i386) /* ** xf86SumConfig ** Reads the SummaSketch section from the XF86Config file */ static Bool xf86SumConfig(LocalDevicePtr *array, int inx, int max, LexPtr val) { LocalDevicePtr dev = array[inx]; SummaDevicePtr priv = (SummaDevicePtr)(dev->private); int token; int mtoken; DBG(2, ErrorF("xf86SumConfig\n")); while ((token = xf86GetToken(SumTab)) != ENDSUBSECTION) { switch(token) { case DEVICENAME: if (xf86GetToken(NULL) != STRING) xf86ConfigError("Option string expected"); else { dev->name = strdup(val->str); if (xf86Verbose) ErrorF("%s SummaSketch X device name is %s\n", XCONFIG_GIVEN, dev->name); } break; case PORT: if (xf86GetToken(NULL) != STRING) xf86ConfigError("Option string expected"); else { priv->sumDevice = strdup(val->str); if (xf86Verbose) ErrorF("%s SummaSketch port is %s\n", XCONFIG_GIVEN, priv->sumDevice); } break; case THE_MODE: mtoken = xf86GetToken(SumModeTabRec); if ((mtoken == EOF) || (mtoken == STRING) || (mtoken == NUMBER)) xf86ConfigError("Mode type token expected"); else { switch (mtoken) { case ABSOLUTE: priv->flags |= ABSOLUTE_FLAG; break; case RELATIVE: priv->flags &= ~ABSOLUTE_FLAG; break; default: xf86ConfigError("Illegal Mode type"); break; } } break; case CURSOR: mtoken = xf86GetToken(SumPointTabRec); if ((mtoken == EOF) || (mtoken == STRING) || (mtoken == NUMBER)) xf86ConfigError("Cursor token expected"); else { switch (mtoken) { case STYLUS: priv->flags |= STYLUS_FLAG; break; case PUCK: priv->flags &= ~STYLUS_FLAG; break; default: xf86ConfigError("Illegal cursor type"); break; } } break; case INCREMENT: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumInc = val->num; if (xf86Verbose) ErrorF("%s SummaSketch increment value is %d\n", XCONFIG_GIVEN, priv->sumInc); break; case DEBUG_LEVEL: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); debug_level = val->num; if (xf86Verbose) { #if DEBUG ErrorF("%s SummaSketch debug level sets to %d\n", XCONFIG_GIVEN, debug_level); #else ErrorF("%s SummaSketch debug level not sets to %d because" " debugging is not compiled\n", XCONFIG_GIVEN, debug_level); #endif } break; case HISTORY_SIZE: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); dev->history_size = val->num; if (xf86Verbose) ErrorF("%s SummaSketch Motion history size is %d\n", XCONFIG_GIVEN, dev->history_size); break; case HITACHI_1217D: priv->flags |= H1217D_FLAG; priv->sumInc = 0; if(xf86Verbose) ErrorF("%s Hitach_1217D, compatible enforced.\n", XCONFIG_GIVEN); case COMPATIBLE: priv->flags |= COMPATIBLE_FLAG; if(xf86Verbose) ErrorF("%s SummaSketch compatible - will not query firmware ID\n", XCONFIG_GIVEN); break; case ALWAYS_CORE: xf86AlwaysCore(dev, TRUE); if (xf86Verbose) ErrorF("%s SummaSketch device always stays core pointer\n", XCONFIG_GIVEN); break; case ACTIVE_AREA: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumXSize = val->realnum * 100; if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumYSize = val->realnum * 100; if (xf86Verbose) ErrorF("%s SummaSketch active area: %d.%02dx%d.%02d" " inches\n", XCONFIG_GIVEN, priv->sumXSize / 100, priv->sumXSize % 100, priv->sumYSize / 100, priv->sumYSize % 100); break; case ACTIVE_OFFSET: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumXOffset = val->realnum * 100; if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumYOffset = val->realnum * 100; if (xf86Verbose) ErrorF("%s SummaSketch active offsets: %d.%02d %d.%02d" " inches\n", XCONFIG_GIVEN, priv->sumXOffset / 100, priv->sumXOffset % 100, priv->sumYOffset / 100, priv->sumYOffset % 100); break; case RESOLUTION: if (xf86GetToken(NULL) != NUMBER) xf86ConfigError("Option number expected"); priv->sumRes = val->num; if (xf86Verbose) ErrorF("%s SummaSketch resolution set to %d\n", XCONFIG_GIVEN, priv->sumRes); break; case EOF: FatalError("Unexpected EOF (missing EndSubSection)"); break; default: xf86ConfigError("SummaSketch subsection keyword expected"); break; } } DBG(2, ErrorF("xf86SumConfig name=%s\n", priv->sumDevice)); return Success; } #endif #endif /* ** xf86SumConvert ** Convert device valuator values to screen X and Y. */ static Bool xf86SumConvert(LocalDevicePtr local, int first, int num, int v0, int v1, int v2, int v3, int v4, int v5, int* x, int* y) { SummaDevicePtr priv = (SummaDevicePtr) local->private; if (first != 0 || num == 1) return FALSE; *x = (v0 * screenInfo.screens[0]->width) / priv->sumXSize; *y = (v1 * screenInfo.screens[0]->height) / priv->sumYSize; if (*x < 0) *x = 0; if (*y < 0) *y = 0; if (*x > screenInfo.screens[0]->width) *x = screenInfo.screens[0]->width; if (*y > screenInfo.screens[0]->height) *y = screenInfo.screens[0]->height; DBG(6, ErrorF("Adjusted coords x=%d y=%d\n", *x, *y)); return TRUE; } /* ** xf86SumReadInput ** Reads from the SummaSketch and posts any new events to the server. */ static void xf86SumReadInput(LocalDevicePtr local) { SummaDevicePtr priv = (SummaDevicePtr) local->private; int len, loop; int is_absolute, num_ax; int x, y, z, buttons, prox; DeviceIntPtr device; unsigned char buffer[BUFFER_SIZE]; DBG(7, ErrorF("xf86SumReadInput BEGIN device=%s fd=%d\n", priv->sumDevice, local->fd)); SYSCALL(len = read(local->fd, buffer, sizeof(buffer))); if (len <= 0) { Error("error reading SummaSketch device"); return; } for(loop=0; loopsumIndex == 0) && !(buffer[loop] & PHASING_BIT)) { /* magic bit is not OK */ DBG(6, ErrorF("xf86SumReadInput bad magic number 0x%x\n", buffer[loop]));; continue; } priv->sumData[priv->sumIndex++] = buffer[loop]; if (priv->sumIndex == ( (priv->flags & ABSOLUTE_FLAG) ? ((priv->flags & Z_AXIS_FLAG)?7:5) : 3)) { /* the packet is OK */ /* reset char count for next read */ priv->sumIndex = 0; prox = (priv->sumData[0] & PROXIMITY_BIT)? 0: 1; buttons = (priv->sumData[0] & BUTTON_BITS); if (priv->flags & ABSOLUTE_FLAG) { x = (int)priv->sumData[1] + ((int)priv->sumData[2] << 7); y = (int)priv->sumData[3] + ((int)priv->sumData[4] << 7); if(priv->flags & Z_AXIS_FLAG){ z = ((int)priv->sumData[5] << 2) | ((int)priv->sumData[6] & 0x01 << 1) | ((int)priv->sumData[6] & 0x10); buttons |= ((int)priv->sumData[6] & 0x02 << 2); } else z = 0; } else { x = priv->sumData[0] & XSIGN_BIT? priv->sumData[1]: -priv->sumData[1]; y = priv->sumData[0] & YSIGN_BIT? priv->sumData[2]: -priv->sumData[2]; z = 0; } /* adj x/y by user given offsets; z untouched */ x -= priv->sumXOffset; y -= priv->sumYOffset; if (x < 0) x = 0; if (y < 0) y = 0; if (x > priv->sumXSize) x = priv->sumXSize; if (y > priv->sumYSize) y = priv->sumYSize; device = local->dev; DBG(6, ErrorF("prox=%s\tx=%d\ty=%d\tz=%d\tbuttons=%d\n", prox ? "true" : "false", x, y, z, buttons)); is_absolute = (priv->flags & ABSOLUTE_FLAG); num_ax = (priv->flags & Z_AXIS_FLAG)? 3 : 2; /* coordinates are ready we can send events */ if (prox) { if (!(priv->sumOldProximity)) xf86PostProximityEvent(device, 1, 0, num_ax, x, y, z); if ((is_absolute && ((priv->sumOldX != x) || (priv->sumOldY != y) || (priv->sumOldZ != z))) || (!is_absolute && (x || y))) { if (is_absolute || priv->sumOldProximity) { xf86PostMotionEvent(device, is_absolute, 0, num_ax, x, y, z); } } if (priv->sumOldButtons != buttons) { int delta; int button; delta = buttons - priv->sumOldButtons; button = (delta > 0)? delta: ((delta == 0)? priv->sumOldButtons : -delta); if (priv->sumOldButtons != buttons) { DBG(6, ErrorF("xf86SumReadInput button=%d delta=%d\n", button, delta)); xf86PostButtonEvent(device, is_absolute, button, (delta > 0), 0, num_ax, x, y, z); } } priv->sumOldButtons = buttons; priv->sumOldX = x; priv->sumOldY = y; priv->sumOldZ = z; priv->sumOldProximity = prox; } else { /* !PROXIMITY */ /* Any changes in buttons are ignored when !proximity */ if (priv->sumOldProximity) xf86PostProximityEvent(device, 0, 0, num_ax, x, y, z); priv->sumOldProximity = 0; } } } DBG(7, ErrorF("xf86SumReadInput END device=%p priv=%p\n", (void *)local->dev, (void *)priv)); } /* ** xf86SumControlProc ** It really does do something. Honest! */ static void xf86SumControlProc(DeviceIntPtr device, PtrCtrl *ctrl) { DBG(2, ErrorF("xf86SumControlProc\n")); } /* ** xf86SumWriteAndRead ** Write data, and get the response. */ static char * xf86SumWriteAndRead(int fd, char *data, char *buffer, int len, int cr_term) { int err, numread = 0; #ifndef XFREE86_V4 fd_set readfds; struct timeval timeout; #endif SYSCALL(err = write(fd, data, strlen(data))); if (err == -1) { Error("SummaSketch write"); return NULL; } #ifndef XFREE86_V4 FD_ZERO(&readfds); FD_SET(fd, &readfds); #endif while (numread < len) { #ifndef XFREE86_V4 timeout.tv_sec = 0; timeout.tv_usec = 200000; SYSCALL(err = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout)); #else err = xf86WaitForInput(fd, 200000); #endif if (err == -1) { Error("SummaSketch select"); return NULL; } if (!err) { ErrorF("Timeout while reading SummaSketch tablet. No tablet connected ???\n"); return NULL; } SYSCALL(err = read(fd, buffer + numread++, 1)); if (err == -1) { Error("SummaSketch read"); return NULL; } if (!err) { --numread; break; } if (cr_term && buffer[numread - 1] == '\r') { buffer[numread - 1] = 0; break; } } buffer[numread] = 0; return buffer; } /* xf86SumSetResCode * Set Summa MM mode resolution code letter. */ static void xf86SumSetResCode (int *res, char *buffer, int index) { switch (*res) { case 1: buffer[index] = 'l'; break; case 2: buffer[index] = 'n'; break; case 4: buffer[index] = 'p'; break; case 100: buffer[index] = 'd'; break; case 200: buffer[index] = 'e'; break; case 10: /* 10 lpmm */ *res = 254; case 254: buffer[index] = 'f'; break; case 400: buffer[index] = 'g'; break; case 20: /* 20 lpmm */ *res = 508; case 508: buffer[index] = 'i'; break; case 1000: buffer[index] = 'j'; break; case 40: /* 40 lpmm */ *res = 1016; case 1016: buffer[index] = 'q'; break; case 2000: buffer[index] = 's'; break; case 2032: buffer[index] = 'u'; break; case 2540: /* note: for 12x12 tablet only */ buffer[index] = 'v'; break; default: /* default to 500 lpi */ *res = 500; buffer[index] = 'h'; break; } buffer[index+1] = 0; } /* ** xf86SumOpen ** Open and initialize the tablet, as well as probe for any needed data. */ static Bool xf86SumOpen(LocalDevicePtr local) { #ifndef XFREE86_V4 struct termios termios_tty; struct timeval timeout; #endif char buffer[256], dbuffer[4]; int err, idx; int res100; double sratio, tratio; SummaDevicePtr priv = (SummaDevicePtr)local->private; DBG(2, ErrorF("opening %s\n", priv->sumDevice)); #ifdef XFREE86_V4 local->fd = xf86OpenSerial(local->options); #else SYSCALL(local->fd = open(priv->sumDevice, O_RDWR|O_NDELAY, 0)); #endif if (local->fd == -1) { Error(priv->sumDevice); return !Success; } DBG(2, ErrorF("%s opened as fd %d\n", priv->sumDevice, local->fd)); #ifndef XFREE86_V4 #ifdef POSIX_TTY err = tcgetattr(local->fd, &termios_tty); if (err == -1) { Error("SummaSketch tcgetattr"); return !Success; } termios_tty.c_iflag = IXOFF; termios_tty.c_cflag = B9600|CS8|CREAD|CLOCAL|HUPCL|PARENB|PARODD; termios_tty.c_lflag = 0; /* prevent tty term discipline processing */ termios_tty.c_cc[VINTR] = 0; termios_tty.c_cc[VQUIT] = 0; termios_tty.c_cc[VERASE] = 0; #ifdef VWERASE termios_tty.c_cc[VWERASE] = 0; #endif #ifdef VREPRINT termios_tty.c_cc[VREPRINT] = 0; #endif termios_tty.c_cc[VKILL] = 0; termios_tty.c_cc[VEOF] = 0; termios_tty.c_cc[VEOL] = 0; #ifdef VEOL2 termios_tty.c_cc[VEOL2] = 0; #endif termios_tty.c_cc[VSUSP] = 0; #ifdef VDISCARD termios_tty.c_cc[VDISCARD] = 0; #endif #ifdef VLNEXT termios_tty.c_cc[VLNEXT] = 0; #endif termios_tty.c_cc[VMIN] = 1 ; termios_tty.c_cc[VTIME] = 10 ; err = tcsetattr(local->fd, TCSANOW, &termios_tty); if (err == -1) { Error("SummaSketch tcsetattr TCSANOW"); return !Success; } #else #error Code for someone else to write to handle OSs without POSIX tty functions #endif #endif /* xf_v4 */ DBG(2, ErrorF("initializing SummaSketch tablet\n")); /* send ASCII spaces in case tablet can auto-baud */ for (idx = 0; idx < 10; idx++) buffer[idx] = ' '; SYSCALL(err = write(local->fd, buffer, 10)); if (err == -1) { Error("SummaSketch write"); return !Success; } buffer[0] = 0; SYSCALL(err = write(local->fd, buffer, 1)); /* Wait 400 mSecs, just in case. 200 ms isn't enough for the Genius EasyPen. */ #ifndef XFREE86_V4 timeout.tv_sec = 0; timeout.tv_usec = 400000; SYSCALL(err = select(0, NULL, NULL, NULL, &timeout)); #else err = xf86WaitForInput(-1, 400000); #endif if (err == -1) { Error("SummaSketch select"); return !Success; } /* Put it in prompt mode so it doens't say anything before we're ready */ SYSCALL(err = write(local->fd, SS_PROMPT_MODE, strlen(SS_PROMPT_MODE))); if (err == -1) { Error("SummaSketch write"); return !Success; } #ifndef XFREE86_V4 /* Clear any pending input */ tcflush(local->fd, TCIFLUSH); #else xf86FlushInput(local->fd); #endif if ((priv->flags & COMPATIBLE_FLAG) == 0) { DBG(2, ErrorF("reading firmware ID\n")); if (!xf86SumWriteAndRead(local->fd, SS_FIRMID, buffer, 255, 1)) return !Success; DBG(2, ErrorF("%s\n", buffer)); if (xf86Verbose) ErrorF("%s %s firmware ID : %s\n", XCONFIG_PROBED, local->name, buffer); } DBG(2, ErrorF("setting up resolution\n")); xf86SumSetResCode (&priv->sumRes, dbuffer, 0); dbuffer[1] = 'a'; /* config cmd */ dbuffer[2] = 0; DBG(2, ErrorF("reading max coordinates\n")); if (!xf86SumWriteAndRead(local->fd, dbuffer, buffer, (priv->flags&Z_AXIS_FLAG)?7:5, 0)) return !Success; priv->sumMaxX = (buffer[1] & 0x7f) | (buffer[2] << 7); priv->sumMaxY = (buffer[3] & 0x7f) | (buffer[4] << 7); if (priv->flags & H1217D_FLAG) { /* the numbers below are from Hitachi 1217D spec sheet */ priv->sumMaxX = (432.4 / 25.4) * priv->sumRes; priv->sumMaxY = (297.6 / 25.4) * priv->sumRes; } if (xf86Verbose) ErrorF("%s %s: tablet size is %d.%02din. x %d.%02din., %dx%d " "lines of resolution\n", XCONFIG_PROBED, local->name, priv->sumMaxX / priv->sumRes, (priv->sumMaxX * 100 / priv->sumRes) % 100, priv->sumMaxY / priv->sumRes, (priv->sumMaxY * 100 / priv->sumRes) % 100, priv->sumMaxX, priv->sumMaxY); res100 = priv->sumRes / 100; if (priv->sumXOffset >= 0 && priv->sumYOffset >= 0) { priv->sumXOffset *= res100; priv->sumYOffset *= res100; priv->sumMaxX -= priv->sumXOffset; priv->sumMaxY -= priv->sumYOffset; } if (priv->sumXSize > 0 && priv->sumYSize > 0) { if ((priv->sumXSize * res100) <= priv->sumMaxX && (priv->sumYSize * res100) <= priv->sumMaxY) { priv->sumXSize *= res100; priv->sumYSize *= res100; } else { ErrorF("%s %s: active area bigger than tablet, " "assuming maximum\n", XCONFIG_PROBED, local->name); priv->sumXSize = priv->sumMaxX; priv->sumYSize = priv->sumMaxY; } } else { priv->sumXSize = priv->sumMaxX; priv->sumYSize = priv->sumMaxY; } /* map tablet area by screen aspect ratio */ sratio = (double)screenInfo.screens[0]->height / (double)screenInfo.screens[0]->width; tratio = (double)priv->sumMaxY / (double)priv->sumMaxX; if (tratio <= 1.0) { /* tablet horizontal > vertical */ priv->sumXSize = (double)priv->sumYSize / sratio; if (priv->sumXSize > priv->sumMaxX) priv->sumXSize = priv->sumMaxX; } else { priv->sumYSize = (double)priv->sumXSize / sratio; if (priv->sumYSize > priv->sumMaxY) priv->sumYSize = priv->sumMaxY; } ErrorF("%s %s: using tablet area %d by %d, at res %d lpi\n", XCONFIG_PROBED, local->name, priv->sumXSize, priv->sumYSize, priv->sumRes); if (priv->sumInc > 95) priv->sumInc = 95; if (priv->sumInc < 0) { /* increment not given by user */ /* Make a guess as to the best increment value given video mode */ if (priv->sumXSize / screenInfo.screens[0]->width < priv->sumYSize / screenInfo.screens[0]->height) priv->sumInc = priv->sumXSize / screenInfo.screens[0]->width; else priv->sumInc = priv->sumYSize / screenInfo.screens[0]->height; if (priv->sumInc < 1) priv->sumInc = 1; if (xf86Verbose) ErrorF("%s %s: Using increment value of %d\n", XCONFIG_PROBED, local->name, priv->sumInc); } /* Sets up the tablet mode to increment, stream, and such */ for (idx = 0; ss_initstr[idx]; idx++) { buffer[idx] = ss_initstr[idx]; } buffer[idx++] = SS_INCREMENT; buffer[idx++] = 32 + priv->sumInc; buffer[idx++] = (priv->flags & ABSOLUTE_FLAG)? SS_ABSOLUTE: SS_RELATIVE; buffer[idx] = 0; SYSCALL(err = write(local->fd, buffer, idx)); if (err == -1) { Error("SummaSketch write"); return !Success; } if (err <= 0) { SYSCALL(close(local->fd)); return !Success; } return Success; } /* ** xf86SumOpenDevice ** Opens and initializes the device driver stuff or sumpthin. */ static int xf86SumOpenDevice(DeviceIntPtr pSum) { LocalDevicePtr local = (LocalDevicePtr)pSum->public.devicePrivate; SummaDevicePtr priv = (SummaDevicePtr)XI_PRIVATE(pSum); if (xf86SumOpen(local) != Success) { if (local->fd >= 0) { SYSCALL(close(local->fd)); } local->fd = -1; } /* Set the real values */ InitValuatorAxisStruct(pSum, 0, 0, /* min val */ priv->sumXSize, /* max val in use */ LPI2CPM(priv->sumRes), /* resolution */ 0, /* min_res */ LPI2CPM(priv->sumRes)); /* max_res */ InitValuatorAxisStruct(pSum, 1, 0, /* min val */ priv->sumYSize, /* max val in use */ LPI2CPM(priv->sumRes), /* resolution */ 0, /* min_res */ LPI2CPM(priv->sumRes)); /* max_res */ if(priv->flags&Z_AXIS_FLAG) InitValuatorAxisStruct(pSum, 2, 0, /* min val */ 512, /* max val */ LPI2CPM(priv->sumRes), /* resolution */ 0, /* min_res */ LPI2CPM(priv->sumRes)); /* max_res */ return (local->fd != -1); } /* initialize start-up values */ static void xf86SumInitPrivate (SummaDevicePtr priv) { #if defined (sun) && !defined(i386) char *dev_name; #endif if (priv == NULL) return; #if defined(sun) && !defined(i386) if ((dev_name = getenv("SUMMASKETCH_DEV"))) { priv->sumDevice = xalloc(strlen(dev_name) + 1); strcpy(priv->sumDevice, dev_name); ErrorF("xf86SumOpen port changed to '%s'\n", priv->sumDevice); } else { priv->sumDevice = ""; } #else priv->sumDevice = ""; /* device file name */ #endif priv->sumRes = 500; /* default 500 lpi */ priv->sumInc = -1; /* event trigger delta moves thrshold */ priv->sumOldX = -1; /* previous X position */ priv->sumOldY = -1; /* previous Y position */ priv->sumOldProximity = 0; /* previous proximity */ priv->sumOldButtons = 0; /* previous buttons state */ priv->sumMaxX = -1; /* max X value */ priv->sumMaxY = -1; /* max Y value */ priv->sumXSize = 0; /* active area X size */ priv->sumXOffset = 0; /* active area X offset */ priv->sumYSize = 0; /* active area Y size */ priv->sumYOffset = 0; /* active area Y offset */ priv->sumIndex = 0; /* number of bytes read */ priv->flags = ABSOLUTE_FLAG; /* various flags -- default absolute */ } /* ** xf86SumProc ** Handle requests to do stuff to the driver. */ static int xf86SumProc(DeviceIntPtr pSum, int what) { CARD8 map[25]; int nbaxes; int nbbuttons; int loop; LocalDevicePtr local = (LocalDevicePtr)pSum->public.devicePrivate; SummaDevicePtr priv = (SummaDevicePtr)PRIVATE(pSum); DBG(2, ErrorF("BEGIN xf86SumProc dev=%p priv=%p what=%d\n", (void *)pSum, (void *)priv, what)); switch (what) { case DEVICE_INIT: DBG(2, ErrorF("xf86SumProc pSum=%p fd = %d, what=INIT\n", (void *)pSum, local->fd)); if (priv->flags & INITIALIZED) break; /* already done */ nbaxes = (priv->flags & Z_AXIS_FLAG)?3:2; /* X, Y [,Z] */ nbbuttons = (priv->flags & STYLUS_FLAG)? ((priv->flags & Z_AXIS_FLAG)?3:2): 4; for(loop=1; loop<=nbbuttons; loop++) map[loop] = loop; if (InitButtonClassDeviceStruct(pSum, nbbuttons, map) == FALSE) { ErrorF("unable to allocate Button class device\n"); return !Success; } if (InitFocusClassDeviceStruct(pSum) == FALSE) { ErrorF("unable to init Focus class device\n"); return !Success; } if (InitPtrFeedbackClassDeviceStruct(pSum, xf86SumControlProc) == FALSE) { ErrorF("unable to init ptr feedback\n"); return !Success; } if (InitProximityClassDeviceStruct(pSum) == FALSE) { ErrorF("unable to init proximity class device\n"); return !Success; } if (InitValuatorClassDeviceStruct(pSum, nbaxes, xf86GetMotionEvents, local->history_size, (priv->flags & ABSOLUTE_FLAG)? Absolute: Relative) == FALSE) { ErrorF("unable to allocate Valuator class device\n"); return !Success; } /* allocate the motion history buffer if needed */ xf86MotionHistoryAllocate(local); #ifndef XFREE86_V4 AssignTypeAndName(pSum, local->atom, local->name); #endif /* open the device to gather informations */ xf86SumOpenDevice(pSum); priv->flags |= INITIALIZED; break; case DEVICE_ON: DBG(2, ErrorF("xf86SumProc pSum=%p fd = %d, what=ON\n", (void *)pSum, local->fd)); if (pSum->public.on) break; /* already on */ if ((local->fd < 0) && (!xf86SumOpenDevice(pSum))) { return !Success; } /* send prompt character to start the reports */ SYSCALL(write(local->fd, SS_PROMPT, strlen(SS_PROMPT))); /* note: using xf86Add/Remove EnabledDevice() somehow causes the tablet * to stop responding after a VT switch, and cannot be restored w/o * cycling tablet power. until we figure out what's going on, do not * enagae signal handlers yet. -huver@amgraf.com mar/12/2001. */ #if 0 # ifdef XFREE86_V4 xf86AddEnabledDevice(local); # else AddEnabledDevice(local->fd); # endif #else AddEnabledDevice(local->fd); #endif pSum->public.on = TRUE; break; case DEVICE_OFF: DBG(2, ErrorF("xf86SumProc pSum=%p fd = %d, what=OFF\n", (void *)pSum, local->fd)); if (! pSum->public.on) break; /* already off */ if (local->fd >= 0) #if 0 # ifdef XFREE86_V4 xf86RemoveEnabledDevice(local); # else RemoveEnabledDevice(local->fd); # endif #else RemoveEnabledDevice(local->fd); #endif pSum->public.on = FALSE; break; case DEVICE_CLOSE: DBG(2, ErrorF("xf86SumProc pSum=%p fd = %d, what=CLOSE\n", (void *)pSum, local->fd)); if (local->fd != -1) { SYSCALL(close(local->fd)); local->fd = -1; } break; default: ErrorF("unsupported mode=%d\n", what); return !Success; break; } DBG(2, ErrorF("END xf86SumProc Success what=%d dev=%p priv=%p\n", what, (void *)pSum, (void *)priv)); return Success; } /* ** xf86SumClose ** It... Uh... Closes the physical device? */ static void xf86SumClose(LocalDevicePtr local) { DBG(2, ErrorF("xf86SumClose local = %p, ->fd = %d\n", (void *)local, local->fd)); if (local->fd >= 0) { #ifdef XFREE86_V4 xf86CloseSerial(local->fd); #else SYSCALL(close(local->fd)); #endif } local->fd = -1; xf86SumInitPrivate (local->private); } /* ** xf86SumChangeControl ** When I figure out what it does, it will do it. */ static int xf86SumChangeControl(LocalDevicePtr local, xDeviceCtl* control) { xDeviceResolutionCtl *res; res = (xDeviceResolutionCtl *)control; if ((res->control != DEVICE_RESOLUTION) || (res->num_valuators < 1)) return (BadMatch); return(Success); } /* ** xf86SumSwitchMode ** Switches the mode. For now just absolute or relative, hopefully ** more on the way. */ static int xf86SumSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) { LocalDevicePtr local = (LocalDevicePtr)dev->public.devicePrivate; SummaDevicePtr priv = (SummaDevicePtr)(local->private); char newmode; DBG(3, ErrorF("xf86SumSwitchMode dev=%p mode=%d\n", (void *)dev, mode)); switch(mode) { case Absolute: priv->flags |= ABSOLUTE_FLAG; newmode = SS_ABSOLUTE; break; case Relative: priv->flags &= ~ABSOLUTE_FLAG; newmode = SS_RELATIVE; break; default: DBG(2, ErrorF("xf86SumSwitchMode dev=%p invalid mode=%d\n", (void *)dev, mode)); return BadMatch; } SYSCALL(write(local->fd, &newmode, 1)); return Success; } /* ** xf86SumAllocate ** Allocates the device structures for the SummaSketch. */ static LocalDevicePtr xf86SumAllocate(void) { LocalDevicePtr local; SummaDevicePtr priv; priv = xalloc(sizeof(SummaDeviceRec)); if (!priv) return NULL; #ifdef XFREE86_V4 local = xf86AllocateInput(sumDrv, 0); #else local = xalloc(sizeof(LocalDeviceRec)); #endif if (!local) { xfree(priv); return NULL; } local->name = XI_NAME; local->type_name = "SummaSketch Tablet"; local->flags = 0; #ifndef XFREE86_V4 #if !defined(sun) || defined(i386) local->device_config = xf86SumConfig; #endif #endif local->device_control = xf86SumProc; local->read_input = xf86SumReadInput; local->control_proc = xf86SumChangeControl; local->close_proc = xf86SumClose; local->switch_mode = xf86SumSwitchMode; local->conversion_proc = xf86SumConvert; local->fd = -1; local->atom = 0; local->dev = NULL; local->private = priv; local->private_flags = 0; local->history_size = 0; local->old_x = -1; local->old_y = -1; xf86SumInitPrivate (priv); return local; } #ifndef XFREE86_V4 /* ** SummaSketch device association ** Device section name and allocation function. */ DeviceAssocRec summasketch_assoc = { SUMMA_SECTION_NAME, /* config_section_name */ xf86SumAllocate /* device_allocate */ }; #ifdef DYNAMIC_MODULE /* ** init_module ** Entry point for dynamic module. */ int #ifndef DLSYM_BUG init_module(unsigned long server_version) #else init_xf86Summa(unsigned long server_version) #endif { xf86AddDeviceAssoc(&summasketch_assoc); if (server_version != XF86_VERSION_CURRENT) { ErrorF("Warning: SummaKetch module compiled for version%s\n", XF86_VERSION); return 0; } else { return 1; } } #endif /* dynamic_module */ #else /* below for xfree86_v4 */ /* * xf86SumUninit -- * * called when the driver is unloaded. */ static void xf86SumUninit(InputDriverPtr drv, LocalDevicePtr local, int flags) { SummaDevicePtr priv = (SummaDevicePtr) local->private; DBG(2, ErrorF("xf86SumUninit\n")); xf86SumProc(local->dev, DEVICE_OFF); xfree (priv); xf86DeleteInput(local, 0); } /* * xf86SumInit -- * * called when the module subsection is found in XF86Config */ static InputInfoPtr xf86SumInit(InputDriverPtr drv, IDevPtr dev, int flags) { LocalDevicePtr local = NULL; SummaDevicePtr priv = NULL; char *s; sumDrv = drv; DBG(2, ErrorF("xf86SumInit allocating...\n")); local = xf86SumAllocate(); if (!local) return NULL; local->conf_idev = dev; DBG(2, ErrorF("xf86SumInit CollectInputOptions... ")); xf86CollectInputOptions(local, default_options, NULL); DBG(2, ErrorF("done.\n")); xf86OptionListReport( local->options ); priv = (SummaDevicePtr) local->private; local->name = dev->identifier; /* Serial Device name is mandatory */ priv->sumDevice = xf86FindOptionValue(local->options, "Device"); if (!priv->sumDevice) { xf86Msg (X_ERROR, "%s: No Device specified.\n", dev->identifier); goto SetupProc_fail; } /* Process the common options. */ xf86ProcessCommonOptions(local, local->options); /* Optional configuration */ xf86Msg(X_CONFIG, "%s: serial device is %s\n", dev->identifier, priv->sumDevice); debug_level = xf86SetIntOption(local->options, "DebugLevel", 0); if (debug_level > 0) { xf86Msg(X_CONFIG, "Summa: debug level set to %d\n", debug_level); } priv->sumInc = xf86SetIntOption(local->options, "Increment", -1); if (priv->sumInc >= 0) { xf86Msg(X_CONFIG, "%s: increment set to %d\n", local->name, priv->sumInc); } s = xf86FindOptionValue(local->options, "Resolution"); if (s) { priv->sumRes=atoi(s); xf86Msg(X_CONFIG, "%s: resolution given %d\n", local->name, priv->sumRes); } s = xf86FindOptionValue(local->options, "Mode"); if (s && (xf86NameCmp(s, "absolute") == 0)) { priv->flags = priv->flags | ABSOLUTE_FLAG; } else if (s && (xf86NameCmp(s, "relative") == 0)) { priv->flags = priv->flags & ~ABSOLUTE_FLAG; } else if (s) { xf86Msg(X_ERROR, "%s: invalid Mode (should be absolute or relative). " "Using default.\n", dev->identifier); } xf86Msg(X_CONFIG, "%s: set for %s mode\n", local->name, (priv->flags & ABSOLUTE_FLAG) ? "absolute" : "relative"); s = xf86FindOption(local->options, "Compatible"); if (s) { priv->flags|=COMPATIBLE_FLAG; } if (xf86FindOption(local->options, "Hitachi_1217D") != NULL) { priv->flags |= H1217D_FLAG | COMPATIBLE_FLAG; priv->sumInc = 0; /* this must be zero for Hitachi 1217D */ xf86Msg(X_CONFIG, "%s: Hitachi 1217D, Compatible mode and Increment 0 implied\n", local->name); } if (priv->flags & COMPATIBLE_FLAG) { xf86Msg(X_CONFIG, "%s: will not query firmware ID.\n", local->name); } s = xf86FindOptionValue(local->options, "ZAxis"); if(s){ priv->flags|=Z_AXIS_FLAG; xf86Msg(X_CONFIG, "Tablet has Z axis (AceCad Flair or compatible)\n"); } s = xf86FindOptionValue(local->options, "Cursor"); if (s && (xf86NameCmp(s, "stylus") == 0)) { priv->flags = priv->flags | STYLUS_FLAG; } else if (s && (xf86NameCmp(s, "puck") == 0)) { priv->flags = priv->flags & ~STYLUS_FLAG; } else if (s) { xf86Msg(X_ERROR, "%s: invalid Cursor (should be stylus or puck). " "Using default.\n", dev->identifier); } xf86Msg(X_CONFIG, "%s: cursor mode is %s\n", local->name, (priv->flags & STYLUS_FLAG) ? "cursor" : "puck"); priv->sumXSize = xf86SetRealOption(local->options, "XSize", 0.0) * 100; if (priv->sumXSize != 0) { xf86Msg(X_CONFIG, "%s: XSize = %d.%02din.\n", dev->identifier, priv->sumXSize/100, priv->sumXSize%100); } priv->sumYSize = xf86SetRealOption(local->options, "YSize", 0.0) * 100; if (priv->sumYSize != 0) { xf86Msg(X_CONFIG, "%s: YSize = %d.%02din.\n", dev->identifier, priv->sumYSize/100, priv->sumYSize%100); } priv->sumXOffset = xf86SetRealOption(local->options, "XOffset", 0.0) * 100; if (priv->sumXOffset != 0) { xf86Msg(X_CONFIG, "%s: XOffset = %d.%02din.\n", dev->identifier, priv->sumXOffset / 100, priv->sumXOffset % 100); } priv->sumYOffset = xf86SetRealOption(local->options, "YOffset", 0.0) * 100; if (priv->sumYOffset != 0) { xf86Msg(X_CONFIG, "%s: YOffset = %d.%02din.\n", dev->identifier, priv->sumYOffset / 100, priv->sumYOffset % 100); } /* mark the device configured */ local->flags |= XI86_POINTER_CAPABLE | XI86_CONFIGURED; /* return the LocalDevice */ return local; SetupProc_fail: if (priv) xfree(priv); return local; } #ifdef XFree86LOADER static #endif InputDriverRec SUMMA = { 1, /* driver version */ "summa", /* driver name */ NULL, /* identify */ xf86SumInit, /* pre-init */ xf86SumUninit, /* un-init */ NULL, /* module */ 0 /* ref count */ }; /* *************************************************************************** * * Dynamic loading functions * *************************************************************************** */ #ifdef XFree86LOADER /* * xf86SumUnplug -- * * called when the module subsection is found in XF86Config */ static void xf86SumUnplug(pointer p) { } /* * xf86SumPlug -- * * called when the module subsection is found in XF86Config */ static pointer xf86SumPlug(pointer module, pointer options, int *errmaj, int *errmin) { xf86AddInputDriver(&SUMMA, module, 0); return module; } static XF86ModuleVersionInfo xf86SumVersionRec = { "summa", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XORG_VERSION_CURRENT, 1, 0, 0, ABI_CLASS_XINPUT, ABI_XINPUT_VERSION, MOD_CLASS_XINPUT, {0, 0, 0, 0} /* signature, to be patched into the file by */ /* a tool */ }; XF86ModuleData summaModuleData = {&xf86SumVersionRec, xf86SumPlug, xf86SumUnplug}; #endif /* XFree86LOADER */ #endif /* XFREE86_V4 */ /* end of xf86Summa.c */