f17e3e31d86d12bcfb7d6bc7303ab4eeadde61ae
[xf86-input-inexio.git] / src / xf86inexio.c
1 /*
2 * Copyright © 2008 Richard Lemon
3 *
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.
13 *
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.
23 *
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.
28 *
29 * Authors:
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
33 * tablet driver.
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <X11/extensions/XI.h>
41 #include <X11/extensions/XIproto.h>
42 #include <xf86.h>
43 #include <xf86_OSlib.h>
44 #include <xf86Xinput.h>
45
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
55
56 /**
57 * This internal struct is used by our driver.
58 */
59 typedef struct _InexioDevice {
60 char *device; /* device filename */
61
62 Bool button_down; /* is the "button" currently down */
63 int button_number; /* which button to report */
64 int last_x;
65 int last_y;
66
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 */
70
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 */
75
76 unsigned char buffer[INEXIO_BUFFER_LEN];/* buffer being read */
77 int bufferi; /* index into buffer */
78 unsigned char body[16];/* packet just read */
79
80 int swap_axes; /* swap x and y axis */
81 } InexioDeviceRec, *InexioDevicePtr;
82
83 /* module */
84 static void InexioUnplug(pointer p);
85 static pointer InexioPlug(pointer module,
86 pointer options,
87 int *errmaj,
88 int *errmin);
89
90 /* driver */
91 static InputInfoPtr InexioPreInit(InputDriverPtr drv,
92 IDevPtr dev,
93 int flags);
94
95 static void InexioUnInit(InputDriverPtr drv,
96 InputInfoPtr pInfo,
97 int flags);
98
99 static void InexioReadInput(InputInfoPtr pInfo);
100
101 static int InexioControl(DeviceIntPtr device,
102 int what);
103
104 static Bool InexioConvertProc(LocalDevicePtr local,
105 int first,
106 int num,
107 int v0,
108 int v1,
109 int v2,
110 int v3,
111 int v4,
112 int v5,
113 int *x,
114 int *y);
115
116 /* internal */
117 static int _inexio_init_buttons(DeviceIntPtr device);
118 static int _inexio_init_axes(DeviceIntPtr device);
119 static int _inexio_read_packet(InexioDevicePtr priv);
120
121 /**
122 * Driver Rec, fields are used when device is initialised/removed.
123 */
124 _X_EXPORT InputDriverRec INEXIO = {
125 1,
126 "inexio",
127 NULL,
128 InexioPreInit,
129 InexioUnInit,
130 NULL,
131 0
132 };
133
134 /**
135 * Module versioning information.
136 */
137 static XF86ModuleVersionInfo InexioVersionRec =
138 {
139 "inexio",
140 MODULEVENDORSTRING,
141 MODINFOSTRING1,
142 MODINFOSTRING2,
143 XORG_VERSION_CURRENT,
144 PACKAGE_VERSION_MAJOR,
145 PACKAGE_VERSION_MINOR,
146 PACKAGE_VERSION_PATCHLEVEL,
147 ABI_CLASS_XINPUT,
148 ABI_XINPUT_VERSION,
149 MOD_CLASS_XINPUT,
150 {0, 0, 0, 0}
151 };
152
153
154 /**
155 * Module control. Fields are used when module is loaded/unloaded.
156 */
157 _X_EXPORT XF86ModuleData inexioModuleData =
158 {
159 &InexioVersionRec,
160 InexioPlug,
161 InexioUnplug
162 };
163
164 /***************************************************************************
165 * Module procs *
166 ***************************************************************************/
167
168 /**
169 * Called when module is unloaded.
170 */
171 static void
172 InexioUnplug(pointer p)
173 {
174 }
175
176 /**
177 * Called when module is loaded.
178 */
179 static pointer
180 InexioPlug(pointer module,
181 pointer options,
182 int *errmaj,
183 int *errmin)
184 {
185 xf86AddInputDriver(&INEXIO, module, 0);
186 return module;
187 }
188
189 /***************************************************************************
190 * Driver procs *
191 ***************************************************************************/
192
193 /**
194 * Called each time a new device is to be initialized.
195 * Init your structs, sockets, whatever else you need to do.
196 */
197 static InputInfoPtr InexioPreInit(InputDriverPtr drv,
198 IDevPtr dev,
199 int flags)
200 {
201 InputInfoPtr pInfo;
202 InexioDevicePtr pInexio;
203
204 if (!(pInfo = xf86AllocateInput(drv, 0)))
205 return NULL;
206
207 pInexio = xcalloc(1, sizeof(InexioDeviceRec));
208 if (!pInexio)
209 {
210 pInfo->private = NULL;
211 xf86DeleteInput(pInfo, 0);
212 return NULL;
213 }
214
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 */
219 pInfo->dev = NULL;
220 pInfo->private = pInexio;
221 pInfo->private_flags = 0;
222 pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
223 pInfo->conf_idev = dev;
224
225 pInfo->name = xstrdup(dev->identifier);
226 pInfo->history_size = 0;
227
228 /* process driver specific options */
229 pInexio->device = xf86CheckStrOption(dev->commonOptions,
230 "Device",
231 "/dev/ttyS0");
232 xf86Msg(X_INFO, "%s: Using device %s.\n", pInfo->name, pInexio->device);
233
234 pInexio->max_x = xf86CheckIntOption(dev->commonOptions,
235 "MaxX",
236 INEXIO_MAX_X); /* calibration x max */
237 pInexio->min_x = xf86CheckIntOption(dev->commonOptions,
238 "MinX",
239 INEXIO_MIN_X); /* calibration x min */
240 pInexio->max_y = xf86CheckIntOption(dev->commonOptions,
241 "MaxY",
242 INEXIO_MAX_Y); /*calibration y max */
243 pInexio->min_y = xf86CheckIntOption(dev->commonOptions,
244 "MinY",
245 INEXIO_MIN_Y); /* calibration y min */
246
247 pInexio->screen_num = xf86CheckIntOption(dev->commonOptions,
248 "ScreenNumber",
249 0); /* screen we are attached to */
250
251 pInexio->button_number = xf86CheckIntOption(dev->commonOptions,
252 "ButtonNumber",
253 1); /* button for touch */
254
255 /* TODO need to add rotate option */
256 pInexio->swap_axes = 0;
257
258 /* process generic options */
259 xf86CollectInputOptions(pInfo, NULL, NULL);
260 xf86ProcessCommonOptions(pInfo, pInfo->options);
261
262 /* Open sockets, init device files, etc. */
263 SYSCALL(pInfo->fd = open(pInexio->device, O_RDWR | O_NONBLOCK));
264 if (pInfo->fd == -1)
265 {
266 xf86Msg(X_ERROR, "%s: failed to open %s.\n",
267 pInfo->name, pInexio->device);
268 pInfo->private = NULL;
269 xfree(pInexio);
270 xf86DeleteInput(pInfo, 0);
271 return NULL;
272 }
273
274 /* do more initialization */
275 pInexio->button_down = FALSE;
276 pInexio->last_x = 0;
277 pInexio->last_y = 0;
278 pInexio->bufferi = 0;
279
280 /* close file again */
281 close (pInfo->fd);
282 pInfo->fd = -1;
283
284 /* set the required flags */
285 pInfo->flags |= XI86_OPEN_ON_INIT;
286 pInfo->flags |= XI86_CONFIGURED;
287
288 return pInfo;
289 }
290
291 /**
292 * Called each time a device is to be removed.
293 * Clean up your mess here.
294 */
295 static void InexioUnInit(InputDriverPtr drv,
296 InputInfoPtr pInfo,
297 int flags)
298 {
299 InexioDevicePtr pInexio = pInfo->private;
300
301 if (pInexio->device)
302 {
303 xfree(pInexio->device);
304 pInexio->device = NULL;
305 }
306
307 xfree(pInexio);
308 xf86DeleteInput(pInfo, 0);
309 }
310
311 /**
312 * Called when data is available on the socket.
313 */
314 static void InexioReadInput(InputInfoPtr pInfo)
315 {
316 /*
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)
324 */
325
326 InexioDevicePtr pInexio = pInfo->private;
327
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;
331
332 while(xf86WaitForInput(pInfo->fd, 0) > 0)
333 {
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);*/
339
340 if (_inexio_read_packet(pInexio) == Success)
341 {
342 is_down = (pInexio->body[0] & 1);
343 /*xf86Msg(X_INFO, "%s: button down[%x].\n", pInfo->name, button_data&1);*/
344
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);
348 if (is_down)
349 { /* if the button is down report position */
350 pInexio->last_x = x;
351 pInexio->last_y = y;
352 }
353 else
354 { /* if the button is up keep last position */
355 x = pInexio->last_x;
356 y = pInexio->last_y;
357 }
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*/
363 x,y); /* the data */
364
365 /*xf86Msg(X_INFO, "%s: posted the motion event\n", pInfo->name);*/
366
367 /* button changed code*/
368 if (pInexio->button_down != is_down)
369 {
370
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);*/
375 }
376
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
379 * ack the packet */
380 /* pInexio->body[0] = 0xaa; pInexio->body[1] = 0x02;
381 SYSCALL(write(pInfo->fd, pInexio->body, 2));
382 */
383 }
384 }
385 }
386
387 /**
388 * Called when the device is started
389 * @return Success or X error code.
390 */
391 static int DeviceOn(DeviceIntPtr dev)
392 {
393 InputInfoPtr pInfo = dev->public.devicePrivate;
394 InexioDevicePtr pInexio = pInfo->private;
395 struct termios tty;
396 int err;
397
398 if (dev->public.on)
399 return Success; /* already on */
400
401 SYSCALL(pInfo->fd = open(pInexio->device, O_RDONLY | O_NONBLOCK));
402 if (pInfo->fd < 0)
403 {
404 xf86Msg(X_ERROR, "%s: cannot open device.\n", pInfo->name);
405 return BadRequest;
406 }
407
408 /* Set speed to 19200bps ( copied from gpm code ) */
409 tcgetattr(pInfo->fd, &tty);
410 tty.c_iflag = IGNBRK | IGNPAR;
411 tty.c_oflag = 0;
412 tty.c_lflag = 0;
413 tty.c_line = 0;
414 tty.c_cc[VTIME] = 0;
415 tty.c_cc[VMIN] = 1;
416 tty.c_cflag = B19200|CS8|CREAD|CLOCAL|HUPCL;
417 err = tcsetattr(pInfo->fd, TCSAFLUSH, &tty);
418 if (err < 0)
419 {
420 xf86Msg(X_ERROR, "%s: cannot set tty attributes for device.\n",
421 pInfo->name);
422 return !Success;
423 }
424
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));
430
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));
435 */
436 xf86FlushInput(pInfo->fd);
437 xf86AddEnabledDevice(pInfo);
438 dev->public.on = TRUE;
439 return Success;
440 }
441
442 /**
443 * Called when the device is to be enabled/disabled, etc.
444 * @return Success or X error code.
445 */
446 static int InexioControl(DeviceIntPtr device,
447 int what)
448 {
449 InputInfoPtr pInfo = device->public.devicePrivate;
450 InexioDevicePtr pInexio = pInfo->private;
451
452 switch(what)
453 {
454 case DEVICE_INIT:
455 _inexio_init_buttons(device);
456 _inexio_init_axes(device);
457 break;
458 /* Switch device on. Establish socket, start event delivery. */
459 case DEVICE_ON:
460 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
461 return DeviceOn(device);
462 break;
463 /**
464 * Shut down device.
465 */
466 case DEVICE_OFF:
467 xf86Msg(X_INFO, "%s: Off.\n", pInfo->name);
468 if (!device->public.on)
469 break;
470 xf86RemoveEnabledDevice(pInfo);
471 pInfo->fd = -1;
472 device->public.on = FALSE;
473 break;
474 case DEVICE_CLOSE:
475 /* free what we have to free */
476 break;
477 }
478 return Success;
479 }
480
481 /**
482 * Called to convert the device coordinates.
483 * @return Success or X error code.
484 */
485 static Bool InexioConvertProc(LocalDevicePtr local,
486 int first,
487 int num,
488 int v0,
489 int v1,
490 int v2,
491 int v3,
492 int v4,
493 int v5,
494 int *x,
495 int *y)
496 {
497 InexioDevicePtr pInexio = local->private;
498
499 *x = xf86ScaleAxis(v0, 0, pInexio->screen_width, pInexio->min_x,
500 pInexio->max_x);
501 *y = xf86ScaleAxis(v1, 0, pInexio->screen_height, pInexio->min_y,
502 pInexio->max_y);
503 /*xf86Msg(X_INFO, "inexio: transform coordinates v0[%i] v1[%i] ==> x[%i] y[%i]\n",
504 v0,v1,*x, *y); */
505 return TRUE;
506 }
507
508 /***************************************************************************
509 * internal procs *
510 ***************************************************************************/
511
512 /**
513 * Init the button map for the random device.
514 * @return Success or X error code on failure.
515 */
516 static int _inexio_init_buttons(DeviceIntPtr device)
517 {
518 InputInfoPtr pInfo = device->public.devicePrivate;
519 CARD8 *map;
520 int i;
521 const int num_buttons = 1;
522 int ret = Success;
523
524 map = xcalloc(num_buttons, sizeof(CARD8));
525
526 for (i = 0; i < num_buttons; i++)
527 map[i] = i;
528
529 if (!InitButtonClassDeviceStruct(device, num_buttons, map)) {
530 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
531 ret = BadAlloc;
532 }
533
534 xfree(map);
535 return ret;
536 }
537
538
539 /**
540 * Init the valuators for the random device.
541 * Only absolute mode is supported.
542 * @return Success or X error code on failure.
543 */
544 static int _inexio_init_axes(DeviceIntPtr device)
545 {
546 InputInfoPtr pInfo = device->public.devicePrivate;
547 InexioDevicePtr pInexio = pInfo->private;
548 int i;
549 const int num_axes = 2;
550
551 pInexio->screen_width = screenInfo.screens[pInexio->screen_num]->width;
552 pInexio->screen_height = screenInfo.screens[pInexio->screen_num]->height;
553
554 if (!InitValuatorClassDeviceStruct(device,
555 num_axes,
556 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
557 xf86GetMotionEvents,
558 #endif
559 pInfo->history_size,
560 Absolute))
561 return BadAlloc;
562
563
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);
568
569 /* Allocate the motion events buffer. */
570 xf86MotionHistoryAllocate(pInfo);
571
572 return Success;
573 }
574
575 /**
576 * Init the valuators for the random device.
577 * Only absolute mode is supported.
578 * @return Success or X error code on failure.
579 */
580 static int _inexio_read_packet(InexioDevicePtr priv)
581 {
582 /*
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)
590 */
591
592 int count = 0, buffi = priv->bufferi;
593 int c;
594 int retval = !Success;
595 while (count < priv->bufferi)
596 {
597 c = priv->buffer[count];
598 if (!(c & INEXIO_BUTTON_UP))
599 {
600 /*xf86Msg(X_INFO, "inexio: c[%x] not &0x80, count[%i], bufferi[%i]\n",
601 c, count, priv->bufferi);*/
602 count++;
603 continue;
604 }
605 /*xf86Msg(X_INFO, "inexio: c[%x], count[%i], bufferi[%i]\n",
606 c, count, priv->bufferi);*/
607
608 if ((priv->bufferi - count) >= INEXIO_BODY_LEN)
609 {
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;
614 retval = Success;
615 count = 0;
616 continue;
617 }
618 break;
619 };
620
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 */
626 return retval;
627 }
628