2 * Copyright © 2008 Richard Lemon
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
30 * Richard Lemon (richard@codelemon.com)
31 * Taken in large part from Peter Hutterer's (peter@cs.unisa.edu.au)
32 * Random example driver and Steven Lang's <tiger@tyger.org> summa
40 #include <X11/extensions/XI.h>
41 #include <X11/extensions/XIproto.h>
43 #include <xf86_OSlib.h>
44 #include <xf86Xinput.h>
46 /* hardware specific defines */
47 #define INEXIO_MIN_X 0x0000
48 #define INEXIO_MIN_Y 0x0000
49 #define INEXIO_MAX_X 0x3FFF
50 #define INEXIO_MAX_Y 0x3FFF
51 #define INEXIO_BUTTON_DOWN 0x81
52 #define INEXIO_BUTTON_UP 0x80
53 #define INEXIO_BODY_LEN 0x05
54 #define INEXIO_BUFFER_LEN 0x100
57 * This internal struct is used by our driver.
59 typedef struct _InexioDevice
{
60 char *device
; /* device filename */
62 Bool button_down
; /* is the "button" currently down */
63 int button_number
; /* which button to report */
67 int screen_num
; /* Screen associated with the device */
68 int screen_width
; /* Width of the associated X screen */
69 int screen_height
; /* Height of the screen */
71 int min_x
; /* Minimum x reported by calibration */
72 int max_x
; /* Maximum x */
73 int min_y
; /* Minimum y reported by calibration */
74 int max_y
; /* Maximum y */
76 unsigned char buffer
[INEXIO_BUFFER_LEN
];/* buffer being read */
77 int bufferi
; /* index into buffer */
78 unsigned char body
[16];/* packet just read */
80 int swap_axes
; /* swap x and y axis */
81 } InexioDeviceRec
, *InexioDevicePtr
;
84 static void InexioUnplug(pointer p
);
85 static pointer
InexioPlug(pointer module
,
91 static InputInfoPtr
InexioPreInit(InputDriverPtr drv
,
95 static void InexioUnInit(InputDriverPtr drv
,
99 static void InexioReadInput(InputInfoPtr pInfo
);
101 static int InexioControl(DeviceIntPtr device
,
104 static Bool
InexioConvertProc(LocalDevicePtr local
,
117 static int _inexio_init_buttons(DeviceIntPtr device
);
118 static int _inexio_init_axes(DeviceIntPtr device
);
119 static int _inexio_read_packet(InexioDevicePtr priv
);
122 * Driver Rec, fields are used when device is initialised/removed.
124 _X_EXPORT InputDriverRec INEXIO
= {
135 * Module versioning information.
137 static XF86ModuleVersionInfo InexioVersionRec
=
143 XORG_VERSION_CURRENT
,
144 PACKAGE_VERSION_MAJOR
,
145 PACKAGE_VERSION_MINOR
,
146 PACKAGE_VERSION_PATCHLEVEL
,
155 * Module control. Fields are used when module is loaded/unloaded.
157 _X_EXPORT XF86ModuleData inexioModuleData
=
164 /***************************************************************************
166 ***************************************************************************/
169 * Called when module is unloaded.
172 InexioUnplug(pointer p
)
177 * Called when module is loaded.
180 InexioPlug(pointer module
,
185 xf86AddInputDriver(&INEXIO
, module
, 0);
189 /***************************************************************************
191 ***************************************************************************/
194 * Called each time a new device is to be initialized.
195 * Init your structs, sockets, whatever else you need to do.
197 static InputInfoPtr
InexioPreInit(InputDriverPtr drv
,
202 InexioDevicePtr pInexio
;
204 if (!(pInfo
= xf86AllocateInput(drv
, 0)))
207 pInexio
= xcalloc(1, sizeof(InexioDeviceRec
));
210 pInfo
->private = NULL
;
211 xf86DeleteInput(pInfo
, 0);
215 pInfo
->type_name
= XI_TOUCHSCREEN
; /* see XI.h */
216 pInfo
->device_control
= InexioControl
; /* enable/disable dev */
217 pInfo
->read_input
= InexioReadInput
; /* new data avl */
218 pInfo
->conversion_proc
= InexioConvertProc
; /* convert coords */
220 pInfo
->private = pInexio
;
221 pInfo
->private_flags
= 0;
222 pInfo
->flags
= XI86_POINTER_CAPABLE
| XI86_SEND_DRAG_EVENTS
;
223 pInfo
->conf_idev
= dev
;
225 pInfo
->name
= xstrdup(dev
->identifier
);
226 pInfo
->history_size
= 0;
228 /* process driver specific options */
229 pInexio
->device
= xf86CheckStrOption(dev
->commonOptions
,
232 xf86Msg(X_INFO
, "%s: Using device %s.\n", pInfo
->name
, pInexio
->device
);
234 pInexio
->max_x
= xf86CheckIntOption(dev
->commonOptions
,
236 INEXIO_MAX_X
); /* calibration x max */
237 pInexio
->min_x
= xf86CheckIntOption(dev
->commonOptions
,
239 INEXIO_MIN_X
); /* calibration x min */
240 pInexio
->max_y
= xf86CheckIntOption(dev
->commonOptions
,
242 INEXIO_MAX_Y
); /*calibration y max */
243 pInexio
->min_y
= xf86CheckIntOption(dev
->commonOptions
,
245 INEXIO_MIN_Y
); /* calibration y min */
247 pInexio
->screen_num
= xf86CheckIntOption(dev
->commonOptions
,
249 0); /* screen we are attached to */
251 pInexio
->button_number
= xf86CheckIntOption(dev
->commonOptions
,
253 1); /* button for touch */
255 /* TODO need to add rotate option */
256 pInexio
->swap_axes
= 0;
258 /* process generic options */
259 xf86CollectInputOptions(pInfo
, NULL
, NULL
);
260 xf86ProcessCommonOptions(pInfo
, pInfo
->options
);
262 /* Open sockets, init device files, etc. */
263 SYSCALL(pInfo
->fd
= open(pInexio
->device
, O_RDWR
| O_NONBLOCK
));
266 xf86Msg(X_ERROR
, "%s: failed to open %s.\n",
267 pInfo
->name
, pInexio
->device
);
268 pInfo
->private = NULL
;
270 xf86DeleteInput(pInfo
, 0);
274 /* do more initialization */
275 pInexio
->button_down
= FALSE
;
278 pInexio
->bufferi
= 0;
280 /* close file again */
284 /* set the required flags */
285 pInfo
->flags
|= XI86_OPEN_ON_INIT
;
286 pInfo
->flags
|= XI86_CONFIGURED
;
292 * Called each time a device is to be removed.
293 * Clean up your mess here.
295 static void InexioUnInit(InputDriverPtr drv
,
299 InexioDevicePtr pInexio
= pInfo
->private;
303 xfree(pInexio
->device
);
304 pInexio
->device
= NULL
;
308 xf86DeleteInput(pInfo
, 0);
312 * Called when data is available on the socket.
314 static void InexioReadInput(InputInfoPtr pInfo
)
317 * format of 5 bytes per packet
318 * format touch down 0x81 XH XL YH YL
319 * format touch up 0x80 XH XL YH YL
320 * where where XL,XH,YL,YH 7bit
321 * X Coord = XL + XH<<7;
322 * Y Coord = YL + YH<<7;
323 * X max = Y max = 0x3FFF (16383)
326 InexioDevicePtr pInexio
= pInfo
->private;
328 unsigned char data
[4], button_data
= 0, is_down
= FALSE
;
329 int x
= 0, y
= 0, len
= -1;
330 int is_absolute
= TRUE
, num_ax
= 2;
332 while(xf86WaitForInput(pInfo
->fd
, 0) > 0)
334 if (!(INEXIO_BODY_LEN
- pInexio
->bufferi
< 0))
335 SYSCALL(pInexio
->bufferi
= read(pInfo
->fd
,
336 &pInexio
->buffer
[pInexio
->bufferi
],
337 INEXIO_BODY_LEN
- pInexio
->bufferi
));
338 /*xf86Msg(X_INFO, "%s: read[%i] chars.\n", pInfo->name, pInexio->bufferi);*/
340 if (_inexio_read_packet(pInexio
) == Success
)
342 is_down
= (pInexio
->body
[0] & 1);
343 /*xf86Msg(X_INFO, "%s: button down[%x].\n", pInfo->name, button_data&1);*/
345 /* now we need to normalize the data */
346 x
= pInexio
->body
[2] + (pInexio
->body
[1]<<7);
347 y
= pInexio
->body
[4] + (pInexio
->body
[3]<<7);
349 { /* if the button is down report position */
354 { /* if the button is up keep last position */
358 /* now we can send the event on */
359 xf86PostMotionEvent(pInfo
->dev
,
360 is_absolute
, /* is_absolute */
361 0, /* first_valuator*/
362 num_ax
, /* number of axis*/
365 /*xf86Msg(X_INFO, "%s: posted the motion event\n", pInfo->name);*/
367 /* button changed code*/
368 if (pInexio
->button_down
!= is_down
)
371 pInexio
->button_down
= is_down
; /* set old to new state */
372 xf86PostButtonEvent(pInfo
->dev
, is_absolute
, pInexio
->button_number
,
373 is_down
, 0, num_ax
, x
, y
);
374 /*xf86Msg(X_INFO, "%s: posted the button event\n", pInfo->name);*/
377 /* The following is a USB ack string that is sent to the
378 * device by the windows driver, doesn't seem to be required
380 /* pInexio->body[0] = 0xaa; pInexio->body[1] = 0x02;
381 SYSCALL(write(pInfo->fd, pInexio->body, 2));
388 * Called when the device is started
389 * @return Success or X error code.
391 static int DeviceOn(DeviceIntPtr dev
)
393 InputInfoPtr pInfo
= dev
->public.devicePrivate
;
394 InexioDevicePtr pInexio
= pInfo
->private;
399 return Success
; /* already on */
401 SYSCALL(pInfo
->fd
= open(pInexio
->device
, O_RDONLY
| O_NONBLOCK
));
404 xf86Msg(X_ERROR
, "%s: cannot open device.\n", pInfo
->name
);
408 /* Set speed to 19200bps ( copied from gpm code ) */
409 tcgetattr(pInfo
->fd
, &tty
);
410 tty
.c_iflag
= IGNBRK
| IGNPAR
;
416 tty
.c_cflag
= B19200
|CS8
|CREAD
|CLOCAL
|HUPCL
;
417 err
= tcsetattr(pInfo
->fd
, TCSAFLUSH
, &tty
);
420 xf86Msg(X_ERROR
, "%s: cannot set tty attributes for device.\n",
425 /* The following is a USB init string that is sent to the device by the
426 * windows driver, doesn't seem to be required */
427 /* pInexio->body[0] = 0x82; pInexio->body[1] = 0x04;
428 pInexio->body[2] = 0x0a; pInexio->body[3] = 0x0f;
429 SYSCALL(write(pInfo->fd, pInexio->body, 4));
431 pInexio->body[0] = 0x83; pInexio->body[1] = 0x06;
432 pInexio->body[2] = 0x35; pInexio->body[3] = 0x2e;
433 pInexio->body[4] = 0x30; pInexio->body[5] = 0x32;
434 SYSCALL(write(pInfo->fd, pInexio->body, 6));
436 xf86FlushInput(pInfo
->fd
);
437 xf86AddEnabledDevice(pInfo
);
438 dev
->public.on
= TRUE
;
443 * Called when the device is to be enabled/disabled, etc.
444 * @return Success or X error code.
446 static int InexioControl(DeviceIntPtr device
,
449 InputInfoPtr pInfo
= device
->public.devicePrivate
;
450 InexioDevicePtr pInexio
= pInfo
->private;
455 _inexio_init_buttons(device
);
456 _inexio_init_axes(device
);
458 /* Switch device on. Establish socket, start event delivery. */
460 xf86Msg(X_INFO
, "%s: On.\n", pInfo
->name
);
461 return DeviceOn(device
);
467 xf86Msg(X_INFO
, "%s: Off.\n", pInfo
->name
);
468 if (!device
->public.on
)
470 xf86RemoveEnabledDevice(pInfo
);
472 device
->public.on
= FALSE
;
475 /* free what we have to free */
482 * Called to convert the device coordinates.
483 * @return Success or X error code.
485 static Bool
InexioConvertProc(LocalDevicePtr local
,
497 InexioDevicePtr pInexio
= local
->private;
499 *x
= xf86ScaleAxis(v0
, 0, pInexio
->screen_width
, pInexio
->min_x
,
501 *y
= xf86ScaleAxis(v1
, 0, pInexio
->screen_height
, pInexio
->min_y
,
503 /*xf86Msg(X_INFO, "inexio: transform coordinates v0[%i] v1[%i] ==> x[%i] y[%i]\n",
508 /***************************************************************************
510 ***************************************************************************/
513 * Init the button map for the random device.
514 * @return Success or X error code on failure.
516 static int _inexio_init_buttons(DeviceIntPtr device
)
518 InputInfoPtr pInfo
= device
->public.devicePrivate
;
521 const int num_buttons
= 1;
524 map
= xcalloc(num_buttons
, sizeof(CARD8
));
526 for (i
= 0; i
< num_buttons
; i
++)
529 if (!InitButtonClassDeviceStruct(device
, num_buttons
, map
)) {
530 xf86Msg(X_ERROR
, "%s: Failed to register buttons.\n", pInfo
->name
);
540 * Init the valuators for the random device.
541 * Only absolute mode is supported.
542 * @return Success or X error code on failure.
544 static int _inexio_init_axes(DeviceIntPtr device
)
546 InputInfoPtr pInfo
= device
->public.devicePrivate
;
547 InexioDevicePtr pInexio
= pInfo
->private;
549 const int num_axes
= 2;
551 pInexio
->screen_width
= screenInfo
.screens
[pInexio
->screen_num
]->width
;
552 pInexio
->screen_height
= screenInfo
.screens
[pInexio
->screen_num
]->height
;
554 if (!InitValuatorClassDeviceStruct(device
,
556 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
564 xf86InitValuatorAxisStruct(device
, 0, pInexio
->min_x
, pInexio
->max_x
,
565 INEXIO_MAX_X
, 0, INEXIO_MAX_X
);
566 xf86InitValuatorAxisStruct(device
, 1, pInexio
->min_y
, pInexio
->max_y
,
567 INEXIO_MAX_Y
, 0, INEXIO_MAX_Y
);
569 /* Allocate the motion events buffer. */
570 xf86MotionHistoryAllocate(pInfo
);
576 * Init the valuators for the random device.
577 * Only absolute mode is supported.
578 * @return Success or X error code on failure.
580 static int _inexio_read_packet(InexioDevicePtr priv
)
583 * format of 5 bytes per packet
584 * format touch down 0x81 XH XL YH YL
585 * format touch up 0x80 XH XL YH YL
586 * where where XL,XH,YL,YH 7bit
587 * X Coord = XL + XH<<7;
588 * Y Coord = YL + YH<<7;
589 * X max = Y max = 0x3FFF (16383)
592 int count
= 0, buffi
= priv
->bufferi
;
594 int retval
= !Success
;
595 while (count
< priv
->bufferi
)
597 c
= priv
->buffer
[count
];
598 if (!(c
& INEXIO_BUTTON_UP
))
600 /*xf86Msg(X_INFO, "inexio: c[%x] not &0x80, count[%i], bufferi[%i]\n",
601 c, count, priv->bufferi);*/
605 /*xf86Msg(X_INFO, "inexio: c[%x], count[%i], bufferi[%i]\n",
606 c, count, priv->bufferi);*/
608 if ((priv
->bufferi
- count
) >= INEXIO_BODY_LEN
)
610 memcpy(priv
->body
, &priv
->buffer
[count
], INEXIO_BODY_LEN
);
611 memmove(priv
->buffer
, &priv
->buffer
[count
+ INEXIO_BODY_LEN
],
612 priv
->bufferi
- count
-INEXIO_BODY_LEN
);
613 priv
->bufferi
-= count
+ INEXIO_BODY_LEN
;
621 if (priv
->bufferi
- count
> 0)
622 memmove(priv
->buffer
, &priv
->buffer
[count
], priv
->bufferi
- count
);
623 priv
->bufferi
-= count
;
624 if (priv
->bufferi
< 0)
625 priv
->bufferi
= 0; /* shouldn't be possible */