xf86Elo.c revision dd0822ca
1/*
2 * Copyright 1995, 1999 by Patrick Lecoanet, France. <lecoanet@cena.dgac.fr>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is  hereby granted without fee, provided that
6 * the  above copyright   notice appear  in   all  copies and  that both  that
7 * copyright  notice   and   this  permission   notice  appear  in  supporting
8 * documentation, and that   the  name of  Patrick  Lecoanet not  be  used  in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific,  written      prior  permission.     Patrick Lecoanet   makes  no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * PATRICK LECOANET DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT  SHALL PATRICK LECOANET BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA  OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS  ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 */
23
24/*
25 *******************************************************************************
26 *******************************************************************************
27 *
28 * This driver is able to deal with Elographics SmartSet serial controllers.
29 * It uses only a subset of the functions provided through the protocol.
30 *
31 * SUPPORT FOR E281-2310 and compatible controllers added with help of:
32 *   1996/01/17 Juergen P. Meier (jpm@mailserv.rz.fh-muenchen.de) and
33 *   1998/03/25 G.Felkel@edelmann.de
34 *
35 *   The E281-2310 is a somewhat lobotomized 2210.
36 *   It does not support the c,g,h,k,l,p,q,s and t commands.
37 *   Especially the P command, which is used to check the baud rate.
38 *   The E281-2310 however semms to use always 9600bps, 8bit, 1stop
39 *   no parity, Hardwarehandshake (RTS-CTS) (which are the drivers
40 *   default values)
41 *
42 *******************************************************************************
43 *******************************************************************************
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include "xorgVersion.h"
51
52
53#include "misc.h"
54#include "xf86.h"
55#include "xf86_OSproc.h"
56#include "xf86Xinput.h"
57#include "exevents.h"
58
59#include "xf86Module.h"
60
61/**
62 * models to be treated specially.
63 */
64#define MODEL_UNKNOWN  -1
65#define MODEL_SUNIT_D  1
66
67typedef struct {
68    int         type;
69    char        *name;
70} Model;
71
72static Model SupportedModels[] =
73{
74    {MODEL_SUNIT_D, "Sunit dSeries"}, /* sunit dSeries models don't reply to queries */
75    {MODEL_UNKNOWN, NULL}
76};
77/*
78 ***************************************************************************
79 *
80 * Default constants.
81 *
82 ***************************************************************************
83 */
84#define ELO_MAX_TRIALS	3		/* Number of timeouts waiting for a	*/
85					/* pending reply.			*/
86#define ELO_MAX_WAIT		100000	/* Max wait time for a reply (microsec)	*/
87#define ELO_UNTOUCH_DELAY	5	/* 100 ms				*/
88#define ELO_REPORT_DELAY	1	/* 40 ms or 25 motion reports/s		*/
89#define ELO_LINK_SPEED		B9600	/* 9600 Bauds				*/
90#define ELO_PORT		"/dev/ttyS1"
91
92#define DEFAULT_MAX_X		3000
93#define DEFAULT_MIN_X		600
94#define DEFAULT_MAX_Y		3000
95#define DEFAULT_MIN_Y		600
96
97
98/*
99 ***************************************************************************
100 *
101 * Protocol constants.
102 *
103 ***************************************************************************
104 */
105#define ELO_PACKET_SIZE		10
106
107#define ELO_SYNC_BYTE		'U'	/* Sync byte. First of a packet.	*/
108#define ELO_TOUCH		'T'	/* Report of touchs and motions. Not	*
109					 * used by 2310.			*/
110#define ELO_OWNER		'O'	/* Report vendor name.			*/
111#define ELO_ID			'I'	/* Report of type and features.		*/
112#define ELO_MODE		'M'	/* Set current operating mode.		*/
113#define ELO_PARAMETER		'P'	/* Set the serial parameters.		*/
114#define ELO_REPORT		'B'	/* Set touch reports timings.		*/
115#define ELO_ACK			'A'	/* Acknowledge packet			*/
116
117#define ELO_INIT_CHECKSUM	0xAA	/* Initial value of checksum.		*/
118
119#define	ELO_PRESS		0x01	/* Flags in ELO_TOUCH status byte	*/
120#define	ELO_STREAM		0x02
121#define ELO_RELEASE		0x04
122
123#define ELO_TOUCH_MODE		0x01	/* Flags in ELO_MODE command		*/
124#define ELO_STREAM_MODE		0x02
125#define ELO_UNTOUCH_MODE	0x04
126#define ELO_RANGE_CHECK_MODE	0x40
127#define ELO_TRIM_MODE		0x02
128#define ELO_CALIB_MODE		0x04
129#define ELO_SCALING_MODE	0x08
130#define ELO_TRACKING_MODE	0x40
131
132#define ELO_SERIAL_SPEED	0x06	/* Flags for high speed serial (19200)	*/
133#define ELO_SERIAL_MASK		0xF8
134
135#define ELO_SERIAL_IO		'0'	/* Indicator byte for PARAMETER command */
136
137
138/*
139 ***************************************************************************
140 *
141 * Usefull macros.
142 *
143 ***************************************************************************
144 */
145#define WORD_ASSEMBLY(byte1, byte2)	(((byte2) << 8) | (byte1))
146#define SYSCALL(call)			while(((call) == -1) && (errno == EINTR))
147
148/* This one is handy, thanx Fred ! */
149#ifdef DBG
150#undef DBG
151#endif
152#ifdef DEBUG
153#undef DEBUG
154#endif
155
156static int      debug_level = 0;
157#define DEBUG 1
158#if DEBUG
159#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
160#else
161#define DBG(lvl, f)
162#endif
163
164#undef SYSCALL
165#undef read
166#undef write
167#undef close
168#define SYSCALL(call) call
169#define read(fd, ptr, num) xf86ReadSerial(fd, ptr, num)
170#define write(fd, ptr, num) xf86WriteSerial(fd, ptr, num)
171#define close(fd) xf86CloseSerial(fd)
172
173
174/*
175 ***************************************************************************
176 *
177 * Device private records.
178 *
179 ***************************************************************************
180 */
181typedef struct _EloPrivateRec {
182  char		*input_dev;		/* The touchscreen input tty			*/
183  int		min_x;			/* Minimum x reported by calibration		*/
184  int		max_x;			/* Maximum x					*/
185  int		min_y;			/* Minimum y reported by calibration		*/
186  int		max_y;			/* Maximum y					*/
187  int		untouch_delay;		/* Delay before reporting an untouch (in ms)    */
188  int		report_delay;		/* Delay between touch report packets		*/
189  int		screen_no;		/* Screen associated with the device		*/
190  int		screen_width;		/* Width of the associated X screen		*/
191  int		screen_height;		/* Height of the screen				*/
192  Bool		inited;			/* The controller has already been configured ?	*/
193  Bool		is_a_2310;		/* Set if the smartset is a 2310.		*/
194  int		checksum;		/* Current checksum of data in assembly buffer	*/
195  int		packet_buf_p;		/* Assembly buffer pointer			*/
196  int		swap_axes;		/* Swap X an Y axes if != 0 */
197  unsigned char	packet_buf[ELO_PACKET_SIZE]; /* Assembly buffer				*/
198  int		model;			/* one of MODEL_...				*/
199} EloPrivateRec, *EloPrivatePtr;
200
201/*
202 ***************************************************************************
203 *
204 * xf86EloGetPacket --
205 *	Read a packet from the port. Try to synchronize with start of
206 *	packet and compute checksum.
207 *      The packet structure read by this function is as follow:
208 *		Byte 0 : ELO_SYNC_BYTE
209 *		Byte 1
210 *		...
211 *		Byte 8 : packet data
212 *		Byte 9 : checksum of bytes 0 to 8
213 *
214 *	This function returns if a valid packet has been assembled in
215 *	buffer or if no more data is available.
216 *
217 *	Returns Success if a packet is successfully assembled including
218 *	testing checksum. If a packet checksum is incorrect, it is discarded.
219 *	Bytes preceding the ELO_SYNC_BYTE are also discarded.
220 *	Returns !Success if out of data while reading. The start of the
221 *	partially assembled packet is left in buffer, buffer_p and
222 *	checksum reflect the current state of assembly.
223 *
224 ***************************************************************************
225 */
226static Bool
227xf86EloGetPacket(unsigned char	*buffer,
228		 int		*buffer_p,
229		 int		*checksum,
230		 int		fd)
231{
232  int	num_bytes;
233  Bool	ok;
234
235  DBG(4, ErrorF("Entering xf86EloGetPacket with checksum == %d and buffer_p == %d\n",
236		*checksum, *buffer_p));
237
238  /*
239   * Try to read enough bytes to fill up the packet buffer.
240   */
241  DBG(4, ErrorF("buffer_p is %d, Trying to read %d bytes from link\n",
242		*buffer_p, ELO_PACKET_SIZE - *buffer_p));
243  SYSCALL(num_bytes = read(fd,
244			   (char *) (buffer + *buffer_p),
245			   ELO_PACKET_SIZE - *buffer_p));
246
247  /*
248   * Okay, give up.
249   */
250  if (num_bytes < 0) {
251    Error("System error while reading from Elographics touchscreen.");
252    return !Success;
253  }
254  DBG(4, ErrorF("Read %d bytes\n", num_bytes));
255
256  while (num_bytes) {
257    /*
258     * Sync with the start of a packet.
259     */
260    if ((*buffer_p == 0) && (buffer[0] != ELO_SYNC_BYTE)) {
261      /*
262       * No match, shift data one byte toward the start of the buffer.
263       */
264      ErrorF("Elographics: Dropping one byte in an attempt to synchronize: '%c' 0x%X\n",
265	     buffer[0], buffer[0]);
266      memcpy(&buffer[0], &buffer[1], num_bytes-1);
267    }
268    else {
269      /*
270       * Compute checksum in assembly buffer.
271       */
272      if (*buffer_p < ELO_PACKET_SIZE-1) {
273	*checksum = *checksum + buffer[*buffer_p];
274	*checksum = *checksum % 256;
275	DBG(4, ErrorF(" 0x%X-->0x%X ", buffer[*buffer_p], *checksum));
276      }
277      (*buffer_p)++;
278    }
279    num_bytes--;
280  }
281
282  if (*buffer_p == ELO_PACKET_SIZE) {
283    /*
284     * Got a packet, validate checksum and reset state.
285     */
286    ok = (*checksum == buffer[ELO_PACKET_SIZE-1]);
287    DBG(3, ErrorF("Expecting checksum %d, got %d\n", *checksum, buffer[ELO_PACKET_SIZE-1]));
288    *checksum = ELO_INIT_CHECKSUM;
289    *buffer_p = 0;
290
291    if (!ok) {
292      ErrorF("Checksum error on Elographics touchscreen link\n");
293      return !Success;
294    }
295
296    /*
297     * Valid packet received report it.
298     */
299    return Success;
300  }
301  else {
302    return !Success;
303  }
304}
305
306
307/*
308 ***************************************************************************
309 *
310 * xf86EloReadInput --
311 *	Read all pending report packets from the touchscreen and enqueue
312 *	them.
313 *	If a packet is not fully received it is deferred until the next
314 *	call to the function.
315 *	Packets recognized by this function comply with the format:
316 *
317 *		Byte 1 :  ELO_TOUCH
318 *		Byte 2 :  Packet type
319 *		  Bit 2 : Pen Up   (Release)
320 *		  Bit 1 : Position (Stream)
321 *		  Bit 0 : Pen Down (Press)
322 *		Byte 3 :  X coordinate (lower bits)
323 *		Byte 4 :  X coordinate (upper bits)
324 *		Byte 5 :  Y coordinate (lower bits)
325 *		Byte 6 :  Y coordinate (upper bits)
326 *		Byte 7 :  Z coordinate (lower bits)
327 *		Byte 8 :  Z coordinates (upper bits)
328 *
329 *
330 ***************************************************************************
331 */
332static void
333xf86EloReadInput(InputInfoPtr	pInfo)
334{
335  EloPrivatePtr			priv = (EloPrivatePtr)(pInfo->private);
336  int				cur_x, cur_y;
337  int				state;
338
339  DBG(4, ErrorF("Entering ReadInput\n"));
340
341  /*
342   * Read bytes until there's no data left. We may have more or less than
343   * one packet worth of data in the OS buffer.
344   */
345  do {
346      if(xf86EloGetPacket(priv->packet_buf,
347		       &priv->packet_buf_p,
348		       &priv->checksum,
349		       pInfo->fd) != Success)
350          continue;
351
352      /*
353       * Process only ELO_TOUCHs here.
354       */
355      if (priv->packet_buf[1] == ELO_TOUCH) {
356          /*
357           * First stick together the various pieces.
358           */
359          cur_x = WORD_ASSEMBLY(priv->packet_buf[3], priv->packet_buf[4]);
360          cur_y = WORD_ASSEMBLY(priv->packet_buf[5], priv->packet_buf[6]);
361          state = priv->packet_buf[2] & 0x07;
362
363          /*
364           * Send events.
365           *
366           * We *must* generate a motion before a button change if pointer
367           * location has changed as DIX assumes this. This is why we always
368           * emit a motion, regardless of the kind of packet processed.
369           */
370          xf86PostMotionEvent(pInfo->dev, TRUE, 0, 2, cur_x, cur_y);
371
372          /*
373           * Emit a button press or release.
374           */
375          if (state == ELO_PRESS || state == ELO_RELEASE) {
376              xf86PostButtonEvent(pInfo->dev, TRUE, 1, state == ELO_PRESS, 0, 2, cur_x, cur_y);
377          }
378
379          DBG(3, ErrorF("TouchScreen: x(%d), y(%d), %s\n",
380                      cur_x, cur_y,
381                      (state == ELO_PRESS) ? "Press" : ((state == ELO_RELEASE) ? "Release" : "Stream")));
382      }
383  }
384  while (xf86WaitForInput(pInfo->fd, 0) > 0);  /* don't wait, just check */
385}
386
387
388/*
389 ***************************************************************************
390 *
391 * xf86EloSendPacket --
392 *	Emit an height bytes packet to the controller.
393 *	The function expects a valid buffer containing the
394 *	command to be sent to the controller. It fills it with the
395 *	leading sync character an the trailing checksum byte.
396 *
397 ***************************************************************************
398 */
399static Bool
400xf86EloSendPacket(unsigned char	*packet,
401		  int		fd)
402{
403  int	i, result;
404  int	sum = ELO_INIT_CHECKSUM;
405
406  packet[0] = ELO_SYNC_BYTE;
407  for (i = 0; i < ELO_PACKET_SIZE-1; i++) {
408    sum += packet[i];
409    sum &= 0xFF;
410  }
411  packet[ELO_PACKET_SIZE-1] = sum;
412
413  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",
414		packet[0], packet[1], packet[2], packet[3], packet[4],
415		packet[5], packet[6], packet[7], packet[8], packet[9]));
416  SYSCALL(result = write(fd, packet, ELO_PACKET_SIZE));
417  if (result != ELO_PACKET_SIZE) {
418    DBG(5, ErrorF("System error while sending to Elographics touchscreen.\n"));
419    return !Success;
420  }
421  else {
422    return Success;
423  }
424}
425
426
427/*
428 ***************************************************************************
429 *
430 * xf86EloWaitReply --
431 *	It is assumed that the reply will be in the few next bytes
432 *	read and will be available very soon after the query post. if
433 *	these two asumptions are not met, there are chances that the server
434 *	will be stuck for a while.
435 *	The reply type need to match parameter 'type'.
436 *	The reply is left in reply. The function returns Success if the
437 *	reply is valid and !Success otherwise.
438 *
439 ***************************************************************************
440 */
441
442static Bool
443xf86EloWaitReply(unsigned char	type,
444		 unsigned char	*reply,
445		 int		fd)
446{
447  Bool			ok;
448  int			i, result;
449  int			reply_p = 0;
450  int			sum = ELO_INIT_CHECKSUM;
451
452  DBG(4, ErrorF("Waiting a '%c' reply\n", type));
453  i = ELO_MAX_TRIALS;
454  do {
455    ok = !Success;
456
457    /*
458     * Wait half a second for the reply. The fuse counts down each
459     * timeout and each wrong packet.
460     */
461    DBG(4, ErrorF("Waiting %d ms for data from port\n", ELO_MAX_WAIT / 1000));
462    result = xf86WaitForInput(fd, ELO_MAX_WAIT);
463    if (result > 0) {
464      ok = xf86EloGetPacket(reply, &reply_p, &sum, fd);
465      /*
466       * Do not report an error on a 'P' query as the controller
467       * might be a 2310.
468       */
469      if (ok == Success && reply[1] != type && type != ELO_PARAMETER) {
470	DBG(3, ErrorF("Wrong reply received\n"));
471	ok = !Success;
472      }
473    }
474    else {
475      DBG(3, ErrorF("No answer from link : %d\n", result));
476    }
477
478    if (result == 0) {
479      i--;
480    }
481  } while(ok != Success && i);
482
483  return ok;
484}
485
486
487/*
488 ***************************************************************************
489 *
490 * xf86EloWaitAck --
491 *	Wait for an acknowledge from the controller. Returns Success if
492 *	acknowledge received and reported no errors.
493 *
494  ***************************************************************************
495 */
496static Bool
497xf86EloWaitAck(int	fd)
498{
499  unsigned char	packet[ELO_PACKET_SIZE];
500  int		i, nb_errors;
501
502  if (xf86EloWaitReply(ELO_ACK, packet, fd) == Success) {
503    for (i = 0, nb_errors = 0; i < 4; i++) {
504      if (packet[2 + i] != '0') {
505	nb_errors++;
506      }
507    }
508    if (nb_errors != 0) {
509      DBG(2, ErrorF("Elographics acknowledge packet reports %d errors\n",
510		    nb_errors));
511    }
512    return Success;
513    /*    return (nb_errors < 4) ? Success : !Success;*/
514  }
515  else {
516    return !Success;
517  }
518}
519
520
521/*
522 ***************************************************************************
523 *
524 * xf86EloSendQuery --
525 *	Emit a query to the controller and blocks until the reply and
526 *	the acknowledge are read.
527 *
528 *	The reply is left in reply. The function returns Success if the
529 *	reply is valid and !Success otherwise.
530 *
531 ***************************************************************************
532 */
533static Bool
534xf86EloSendQuery(unsigned char	*request,
535		 unsigned char	*reply,
536		 int		fd)
537{
538  Bool			ok;
539
540  if (xf86EloSendPacket(request, fd) == Success) {
541    ok = xf86EloWaitReply(toupper(request[1]), reply, fd);
542    if (ok == Success) {
543      ok = xf86EloWaitAck(fd);
544    }
545    return ok;
546  }
547  else {
548    return !Success;
549  }
550}
551
552
553/*
554 ***************************************************************************
555 *
556 * xf86EloSendControl --
557 *	Emit a control command to the controller and wait for acknowledge.
558 *
559 *	Returns Success if acknowledge received and reported no error.
560 *
561 ***************************************************************************
562 */
563static Bool
564xf86EloSendControl(unsigned char	*control,
565		   int			fd)
566{
567  if (xf86EloSendPacket(control, fd) == Success) {
568    return xf86EloWaitAck(fd);
569  }
570  else {
571    return !Success;
572  }
573}
574
575
576/*
577 ***************************************************************************
578 *
579 * xf86EloPrintIdent --
580 *	Print type of touchscreen and features on controller board.
581 *
582 ***************************************************************************
583 */
584static void
585xf86EloPrintIdent(unsigned char	*packet,
586		  EloPrivatePtr	priv)
587{
588  xf86Msg(X_PROBED, "Elographics touchscreen is a ");
589  switch(packet[2]) {
590  case '0':
591    xf86Msg(X_NONE, "AccuTouch");
592    break;
593  case '1':
594    xf86Msg(X_NONE, "DuraTouch");
595    break;
596  case '2':
597    xf86Msg(X_NONE, "Intellitouch");
598    break;
599  }
600  xf86Msg(X_NONE, ", connected through a ");
601  switch(packet[3]) {
602  case '0':
603    xf86Msg(X_NONE, "serial link.\n");
604    break;
605  case '1':
606    xf86Msg(X_NONE, "PC-Bus port.\n");
607    break;
608  case '2':
609    xf86Msg(X_NONE, "Micro Channel port.\n");
610    break;
611  }
612  xf86Msg(X_PROBED, "The controller is a model ");
613  if (packet[8] & 1) {
614    if (priv->is_a_2310) {
615      xf86Msg(X_NONE, "E281-2310");
616    }
617    else {
618      xf86Msg(X_NONE, "E271-2210");
619    }
620  }
621  else {
622    xf86Msg(X_NONE, "E271-2200");
623  }
624  xf86Msg(X_NONE, ", firmware revision %d.%d.\n", packet[6], packet[5]);
625
626  if (packet[4]) {
627    xf86Msg(X_PROBED, " Additional features:\n");
628    if (packet[4] & 0x10) {
629      xf86Msg(X_PROBED, "	External A/D converter\n");
630    }
631    if (packet[4] & 0x20) {
632      xf86Msg(X_PROBED, "	32Ko RAM\n");
633    }
634    if (packet[4] & 0x40) {
635      xf86Msg(X_PROBED, "	RAM onboard\n");
636    }
637    if (packet[4] & 0x80) {
638      xf86Msg(X_PROBED, "	Z axis active\n");
639    }
640    xf86Msg(X_NONE, "\n");
641  }
642}
643
644
645/*
646 ***************************************************************************
647 *
648 * xf86EloPtrControl --
649 *
650 ***************************************************************************
651 */
652
653static void
654xf86EloPtrControl(DeviceIntPtr	dev,
655		  PtrCtrl	*ctrl)
656{
657}
658
659
660
661/*
662 ***************************************************************************
663 *
664 * xf86EloControl --
665 *
666 ***************************************************************************
667 */
668static Bool
669xf86EloControl(DeviceIntPtr	dev,
670	       int		mode)
671{
672  InputInfoPtr	pInfo = (InputInfoPtr) dev->public.devicePrivate;
673  EloPrivatePtr		priv = (EloPrivatePtr)(pInfo->private);
674  unsigned char		map[] = { 0, 1 };
675  unsigned char		req[ELO_PACKET_SIZE];
676  unsigned char		reply[ELO_PACKET_SIZE];
677  Atom btn_label;
678  Atom axis_labels[2] = { 0, 0 };
679
680  switch(mode) {
681
682  case DEVICE_INIT:
683    {
684      DBG(2, ErrorF("Elographics touchscreen init...\n"));
685
686      if (priv->screen_no >= screenInfo.numScreens ||
687	  priv->screen_no < 0) {
688	priv->screen_no = 0;
689      }
690      priv->screen_width = screenInfo.screens[priv->screen_no]->width;
691      priv->screen_height = screenInfo.screens[priv->screen_no]->height;
692
693      /*
694       * Device reports button press for up to 1 button.
695       */
696      if (InitButtonClassDeviceStruct(dev, 1, &btn_label, map) == FALSE) {
697	ErrorF("Unable to allocate Elographics touchscreen ButtonClassDeviceStruct\n");
698	return !Success;
699      }
700
701      if (InitFocusClassDeviceStruct(dev) == FALSE) {
702	ErrorF("Unable to allocate Elographics touchscreen FocusClassDeviceStruct\n");
703	return !Success;
704      }
705      if (InitPtrFeedbackClassDeviceStruct(dev, xf86EloPtrControl) == FALSE) {
706	  ErrorF("unable to init ptr feedback\n");
707	  return !Success;
708      }
709      /*
710       * Device reports motions on 2 axes in absolute coordinates.
711       * Axes min and max values are reported in raw coordinates.
712       * Resolution is computed roughly by the difference between
713       * max and min values scaled from the approximate size of the
714       * screen to fit one meter.
715       */
716      if (InitValuatorClassDeviceStruct(dev, 2, axis_labels,
717					GetMotionHistorySize(), Absolute) == FALSE) {
718	ErrorF("Unable to allocate Elographics touchscreen ValuatorClassDeviceStruct\n");
719	return !Success;
720      }
721      else {
722	/* I will map coordinates myself */
723	InitValuatorAxisStruct(dev, 0,
724			       axis_labels[0],
725			       -1, -1,
726			       9500,
727			       0     /* min_res */,
728			       9500  /* max_res */,
729			       Absolute);
730	InitValuatorAxisStruct(dev, 1,
731			       axis_labels[1],
732			       -1, -1,
733			       10500,
734			       0     /* min_res */,
735			       10500 /* max_res */,
736			       Absolute);
737      }
738
739      if (InitFocusClassDeviceStruct(dev) == FALSE) {
740	ErrorF("Unable to allocate Elographics touchscreen FocusClassDeviceStruct\n");
741      }
742
743      /*
744       * Allocate the motion events buffer.
745       */
746      xf86MotionHistoryAllocate(pInfo);
747
748
749      DBG(2, ErrorF("Done.\n"));
750      return Success;
751    }
752
753  case DEVICE_ON:
754    DBG(2, ErrorF("Elographics touchscreen on...\n"));
755
756    if (pInfo->fd < 0) {
757
758      DBG(2, ErrorF("Elographics touchscreen opening : %s\n", priv->input_dev));
759      pInfo->fd = xf86OpenSerial(pInfo->options);
760      if (pInfo->fd < 0) {
761	Error("Unable to open Elographics touchscreen device");
762	return !Success;
763      }
764
765      if (priv->model != MODEL_SUNIT_D)
766      {
767          /*
768           * Try to see if the link is at the specified rate and
769           * ask the controller to report various infos.
770           */
771          memset(req, 0, ELO_PACKET_SIZE);
772          req[1] = tolower(ELO_PARAMETER);
773          if (xf86EloSendQuery(req, reply, pInfo->fd) != Success) {
774              priv->is_a_2310 = 1;
775              ErrorF("Not at the specified rate or model 2310, will continue\n");
776          }
777
778          /*
779           * Ask the controller to report various infos.
780           */
781          memset(req, 0, ELO_PACKET_SIZE);
782          req[1] = tolower(ELO_ID);
783          if (xf86EloSendQuery(req, reply, pInfo->fd) == Success) {
784              xf86EloPrintIdent(reply, priv);
785          }
786          else {
787              DBG(2, ErrorF("Unable to ask Elographics touchscreen identification... Maybe it's GeneralTouch touchscreen...\n"));
788          }
789
790          /*
791           * Set the operating mode: Stream, no scaling, no calibration,
792           * no range checking, no trim, tracking enabled.
793           */
794          memset(req, 0, ELO_PACKET_SIZE);
795          req[1] = ELO_MODE;
796          req[3] = ELO_TOUCH_MODE | ELO_STREAM_MODE | ELO_UNTOUCH_MODE;
797          req[4] = ELO_TRACKING_MODE;
798          if (xf86EloSendControl(req, pInfo->fd) != Success) {
799              DBG(2, ErrorF("Unable to change Elographics touchscreen operating mode... Maybe it's GeneralTouch touchscreen...\n"));
800          }
801
802          /*
803           * Set the touch reports timings from configuration data.
804           */
805          memset(req, 0, ELO_PACKET_SIZE);
806          req[1] = ELO_REPORT;
807          req[2] = priv->untouch_delay;
808          req[3] = priv->report_delay;
809          if (xf86EloSendControl(req, pInfo->fd) != Success) {
810              DBG(2, ErrorF("Unable to change Elographics touchscreen reports timings... Maybe it's GeneralTouch touchscreen...\n"));
811          }
812      }
813      xf86AddEnabledDevice(pInfo);
814      dev->public.on = TRUE;
815    }
816
817    DBG(2, ErrorF("Done\n"));
818    return Success;
819
820    /*
821     * Deactivate the device. After this, the device will not emit
822     * events until a subsequent DEVICE_ON. Thus, we can momentarily
823     * close the port.
824     */
825  case DEVICE_OFF:
826    DBG(2, ErrorF("Elographics touchscreen off...\n"));
827    dev->public.on = FALSE;
828    if (pInfo->fd >= 0) {
829      xf86RemoveEnabledDevice(pInfo);
830    }
831    SYSCALL(close(pInfo->fd));
832    pInfo->fd = -1;
833    DBG(2, ErrorF("Done\n"));
834    return Success;
835
836    /*
837     * Final close before server exit. This is used during server shutdown.
838     * Close the port and free all the resources.
839     */
840  case DEVICE_CLOSE:
841    DBG(2, ErrorF("Elographics touchscreen close...\n"));
842    dev->public.on = FALSE;
843    if (pInfo->fd >= 0) {
844	xf86RemoveEnabledDevice(pInfo);
845    }
846    SYSCALL(close(pInfo->fd));
847    pInfo->fd = -1;
848    DBG(2, ErrorF("Done\n"));
849    return Success;
850
851  default:
852      ErrorF("unsupported mode=%d\n", mode);
853      return !Success;
854  }
855}
856
857/*
858 ***************************************************************************
859 *
860 * xf86EloAllocate --
861 *
862 ***************************************************************************
863 */
864static int
865xf86EloAllocate(InputDriverPtr drv, InputInfoPtr pInfo)
866{
867  EloPrivatePtr		priv;
868
869  priv = malloc(sizeof(EloPrivateRec));
870  if (!priv)
871    return BadAlloc;
872
873  priv->input_dev = strdup(ELO_PORT);
874  priv->min_x = 0;
875  priv->max_x = 3000;
876  priv->min_y = 0;
877  priv->max_y = 3000;
878  priv->untouch_delay = ELO_UNTOUCH_DELAY;
879  priv->report_delay = ELO_REPORT_DELAY;
880  priv->screen_no = 0;
881  priv->screen_width = -1;
882  priv->screen_height = -1;
883  priv->inited = 0;
884  priv->is_a_2310 = 0;
885  priv->checksum = ELO_INIT_CHECKSUM;
886  priv->packet_buf_p = 0;
887  priv->swap_axes = 0;
888
889  pInfo->flags = 0 /* XI86_NO_OPEN_ON_INIT */;
890  pInfo->device_control = xf86EloControl;
891  pInfo->read_input   = xf86EloReadInput;
892  pInfo->control_proc = NULL;
893  pInfo->switch_mode  = NULL;
894  pInfo->private      = priv;
895  pInfo->type_name    = "Elographics TouchScreen";
896
897  return Success;
898}
899
900
901static void
902xf86EloUninit(InputDriverPtr	drv,
903	      InputInfoPtr	pInfo,
904	      int flags)
905{
906  EloPrivatePtr		priv = (EloPrivatePtr) pInfo->private;
907
908  free(priv->input_dev);
909  free(priv);
910  pInfo->private = NULL;
911  xf86DeleteInput(pInfo, 0);
912}
913
914static char *default_options[] = {
915  "BaudRate", "9600",
916  "StopBits", "1",
917  "DataBits", "8",
918  "Parity", "None",
919  "FlowControl", "None",
920  NULL
921};
922
923static int
924xf86EloInit(InputDriverPtr	drv,
925	    InputInfoPtr	pInfo,
926	    int			flags)
927{
928  EloPrivatePtr		priv=NULL;
929  char			*str;
930  int			portrait = 0;
931  int			height, width;
932  char			*opt_model;
933  Model*		model;
934  int			rc;
935
936
937  rc = xf86EloAllocate(drv, pInfo);
938  if (rc != Success)
939    return rc;
940
941  priv = pInfo->private;
942
943  str = xf86FindOptionValue(pInfo->options, "Device");
944  if (!str) {
945    xf86Msg(X_ERROR, "%s: No Device specified in Elographics module config.\n",
946	    pInfo->name);
947    if (priv) {
948      if (priv->input_dev) {
949	free(priv->input_dev);
950      }
951      free(priv);
952    }
953    return BadValue;
954  }
955  priv->input_dev = strdup(str);
956
957  opt_model = xf86SetStrOption(pInfo->options, "Model", NULL);
958  model = SupportedModels;
959  priv->model = MODEL_UNKNOWN;
960  while(model->type != MODEL_UNKNOWN && opt_model)
961  {
962      if (!strcmp(model->name, opt_model))
963      {
964          priv->model = model->type;
965          break;
966      }
967      model++;
968  }
969
970  pInfo->name = xf86SetStrOption(pInfo->options, "DeviceName", XI_TOUCHSCREEN);
971  xf86Msg(X_CONFIG, "Elographics X device name: %s\n", pInfo->name);
972  priv->screen_no = xf86SetIntOption(pInfo->options, "ScreenNo", 0);
973  xf86Msg(X_CONFIG, "Elographics associated screen: %d\n", priv->screen_no);
974  priv->untouch_delay = xf86SetIntOption(pInfo->options, "UntouchDelay", ELO_UNTOUCH_DELAY);
975  xf86Msg(X_CONFIG, "Elographics untouch delay: %d ms\n", priv->untouch_delay*10);
976  priv->report_delay = xf86SetIntOption(pInfo->options, "ReportDelay", ELO_REPORT_DELAY);
977  xf86Msg(X_CONFIG, "Elographics report delay: %d ms\n", priv->report_delay*10);
978  priv->max_x = xf86SetIntOption(pInfo->options, "MaxX", 3000);
979  xf86Msg(X_CONFIG, "Elographics maximum x position: %d\n", priv->max_x);
980  priv->min_x = xf86SetIntOption(pInfo->options, "MinX", 0);
981  xf86Msg(X_CONFIG, "Elographics minimum x position: %d\n", priv->min_x);
982  priv->max_y = xf86SetIntOption(pInfo->options, "MaxY", 3000);
983  xf86Msg(X_CONFIG, "Elographics maximum y position: %d\n", priv->max_y);
984  priv->min_y = xf86SetIntOption(pInfo->options, "MinY", 0);
985  xf86Msg(X_CONFIG, "Elographics minimum y position: %d\n", priv->min_y);
986  priv->swap_axes = xf86SetBoolOption(pInfo->options, "SwapXY", 0);
987  if (priv->swap_axes) {
988    xf86Msg(X_CONFIG, "Elographics device will work with X and Y axes swapped\n");
989  }
990  debug_level = xf86SetIntOption(pInfo->options, "DebugLevel", 0);
991  if (debug_level) {
992#if DEBUG
993    xf86Msg(X_CONFIG, "Elographics debug level sets to %d\n", debug_level);
994#else
995    xf86Msg(X_INFO, "Elographics debug not available\n");
996#endif
997  }
998  str = xf86SetStrOption(pInfo->options, "PortraitMode", "Landscape");
999  if (strcmp(str, "Portrait") == 0) {
1000    portrait = 1;
1001  }
1002  else if (strcmp(str, "PortraitCCW") == 0) {
1003    portrait = -1;
1004  }
1005  else if (strcmp(str, "Landscape") != 0) {
1006    xf86Msg(X_ERROR, "Elographics portrait mode should be: Portrait, Landscape or PortraitCCW");
1007    str = "Landscape";
1008  }
1009  xf86Msg(X_CONFIG, "Elographics device will work in %s mode\n", str);
1010
1011  width = priv->max_x - priv->min_x;
1012  height = priv->max_y - priv->min_y;
1013  if (width == 0) {
1014    xf86Msg(X_ERROR, "Elographics: Cannot configure touchscreen with width 0\n");
1015    return BadValue;
1016  }
1017  else if (width < 0) {
1018    xf86Msg(X_INFO, "Elographics: reverse x mode (minimum x position >= maximum x position)\n");
1019  }
1020  if (height == 0) {
1021    xf86Msg(X_ERROR, "Elographics: Cannot configure touchscreen with height 0\n");
1022    return BadValue;
1023  }
1024  else if (height < 0) {
1025    xf86Msg(X_INFO, "Elographics: reverse y mode (minimum y position >= maximum y position)\n");
1026  }
1027
1028  if (portrait == 1) {
1029    /*
1030     * Portrait Clockwise: reverse Y axis and exchange X and Y.
1031     */
1032    int tmp;
1033    tmp = priv->min_y;
1034    priv->min_y = priv->max_y;
1035    priv->max_y = tmp;
1036    priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
1037  }
1038  else if (portrait == -1) {
1039    /*
1040     * Portrait Counter Clockwise: reverse X axis and exchange X and Y.
1041     */
1042    int tmp;
1043    tmp = priv->min_x;
1044    priv->min_x = priv->max_x;
1045    priv->max_x = tmp;
1046    priv->swap_axes = (priv->swap_axes==0) ? 1 : 0;
1047  }
1048
1049  return Success;
1050}
1051
1052_X_EXPORT InputDriverRec ELOGRAPHICS = {
1053    1,				/* driver version */
1054    "elographics",		/* driver name */
1055    NULL,			/* identify */
1056    xf86EloInit,		/* pre-init */
1057    xf86EloUninit,		/* un-init */
1058    NULL,			/* module */
1059    default_options
1060};
1061
1062static pointer
1063Plug(pointer	module,
1064     pointer	options,
1065     int	*errmaj,
1066     int	*errmin)
1067{
1068  xf86AddInputDriver(&ELOGRAPHICS, module, 0);
1069
1070  return module;
1071}
1072
1073static void
1074Unplug(pointer	p)
1075{
1076  DBG(1, ErrorF("EloUnplug\n"));
1077}
1078
1079static XF86ModuleVersionInfo version_rec = {
1080  "elographics",
1081  MODULEVENDORSTRING,
1082  MODINFOSTRING1,
1083  MODINFOSTRING2,
1084  XORG_VERSION_CURRENT,
1085  PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
1086  ABI_CLASS_XINPUT,
1087  ABI_XINPUT_VERSION,
1088  MOD_CLASS_XINPUT,
1089  { 0, 0, 0, 0 }
1090};
1091
1092/*
1093 * This is the entry point in the module. The name
1094 * is setup after the pattern <module_name>ModuleData.
1095 * Do not change it.
1096 */
1097_X_EXPORT XF86ModuleData elographicsModuleData = { &version_rec, Plug, Unplug };
1098
1099