summaryrefslogtreecommitdiff
path: root/Source/DirectFB/inputdrivers/mutouch/mutouch.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/inputdrivers/mutouch/mutouch.c')
-rwxr-xr-xSource/DirectFB/inputdrivers/mutouch/mutouch.c615
1 files changed, 615 insertions, 0 deletions
diff --git a/Source/DirectFB/inputdrivers/mutouch/mutouch.c b/Source/DirectFB/inputdrivers/mutouch/mutouch.c
new file mode 100755
index 0000000..79c278f
--- /dev/null
+++ b/Source/DirectFB/inputdrivers/mutouch/mutouch.c
@@ -0,0 +1,615 @@
+/*
+ (c) Copyright 2000-2002 Fulgid Technology Co., Ltd.
+
+ All rights reserved.
+
+ Written by Simon Ueng <simon@ftech.com.tw>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ This driver is a re-write from the MuTouch driver provided in XFree86.
+ Extended options in the MuTouch firmware are not used as it wasn't
+ an issue during the writing of this driver.
+ Baudrate has also been rewritting to automatically adjust to 19200 if
+ its support else it uses 9600.
+
+ Feel free to change according to your needs, but changing both
+ MuT_MINX as well as MuT_MINY is required to adjust the orientation
+ of the touchscreen. We've had numerous occasions where the one
+ touchscreen was installed in a different orientation than others.
+ Also don't forget to adjust the MuT_SCREENWIDTH and MuT_SCREENHEIGHT
+ for the appropriate screen dimension.
+
+ Not much time has been spent writing this driver therefore expect errors.
+ Calibration process has also been omitted since there are applications
+ to do the calibration process.
+
+ Lastly, please don't email me regarding technical informations. I
+ don't work for 3M. But if you have any new ideas on improving this
+ driver, please don't hesitate to share it with me.
+ */
+/*
+ * Jacques Luder j.luder@laposte.net
+ * Baudrate adjust now realy working !
+ * version 0.3 10/09/2006 Jacques Luder j.luder@laposte.net
+ * Can now work also with a keyspan USB-Serial line.
+ * Can start OK even if someone touch the screen during probing.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <termios.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <linux/serial.h>
+
+#include <directfb.h>
+
+#include <core/coredefs.h>
+#include <core/coretypes.h>
+
+#include <core/input.h>
+#include <core/system.h>
+
+#include <misc/conf.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+#include <direct/memcpy.h>
+#include <direct/thread.h>
+
+#include <core/input_driver.h>
+
+
+DFB_INPUT_DRIVER( mutouch )
+
+
+#define BAUDRATE B9600
+#define OPTIMAL_BAUDRATE B19200
+#define MAX_TIMEOUT 5
+
+#define MuT_REPORT_SIZE 5
+#define MuT_PACKET_SIZE 10
+#define MuT_SCREENWIDTH 4096
+#define MuT_SCREENHEIGHT 4096
+#define MuT_MINX 0
+#define MuT_MINY 0
+
+#define MuT_LEAD_BYTE 0x01
+#define MuT_TRAIL_BYTE 0x0d
+
+
+#define ERROR_NOT_SUITABLE -1110 /* The touchpanel firmware is not
+ suitable for IMP2001 */
+#define ERROR_NOT_FOUND -1111 /* Touchpanel not found */
+#define ERROR_INIT -1112 /* Error occurred while initializing */
+
+#define MUT_PANEL_TOUCH 0x01
+#define MUT_PANEL_UNTOUCH 0x00
+
+
+/* Commands */
+#define MuT_RESET "R"
+#define MuT_AUTOBAUD_DISABLE "AD"
+#define MuT_RESTORE_DEFAULTS "RD"
+#define MuT_QUERY "Z"
+#define MuT_FORMAT_TABLET "FT"
+#define MuT_FORMAT_RAW "FR"
+#define MuT_CALIBRATE_RAW "CR"
+#define MuT_CALIBRATE_EXT "CX"
+#define MuT_OUTPUT_IDENT "OI"
+#define MuT_UNIT_TYPE "UT"
+#define MuT_FINGER_ONLY "FO"
+#define MuT_PEN_ONLY "PO"
+#define MuT_PEN_FINGER "PF"
+#define MuT_MODE_STREAM "MS"
+#define MuT_MODE_DOWN_UP "MDU"
+
+/* Command reply */
+#define MuT_OK '0'
+#define MuT_ERROR '1'
+
+/* Offsets in status byte of touch and motion reports */
+#define MuT_WHICH_DEVICE 0x20
+#define MuT_CONTACT 0x40
+
+/* Identity and friends */
+#define MuT_SMT3_IDENT "Q1"
+#define MuT_THRU_GLASS_IDENT "T1"
+
+/* Event mask */
+#define MuT_PANEL_TOUCH_MASK 0x40
+#define MuT_PANEL_SYNC_MASK 0x80
+
+typedef struct __MuTData__ {
+ int fd;
+ DirectThread *thread;
+ CoreInputDevice *device;
+ unsigned short x;
+ unsigned short y;
+ unsigned short screen_width;
+ unsigned short screen_height;
+ unsigned short min_x;
+ unsigned short min_y;
+ unsigned char action;
+} MuTData;
+
+/* Global Variables */
+static unsigned char packet[MuT_PACKET_SIZE];
+
+
+static inline void __mdelay(unsigned int msec)
+{
+ struct timespec delay;
+
+ delay.tv_sec = 0;
+ delay.tv_nsec = msec * 1000000;
+ nanosleep (&delay, NULL);
+}
+
+static inline void MuTSendPacket(int file, char *packet, unsigned char len)
+{
+ unsigned char tmp_packet[MuT_PACKET_SIZE];
+
+ direct_memcpy (&tmp_packet[1], packet, len);
+ *tmp_packet = MuT_LEAD_BYTE;
+ tmp_packet[len + 1] = MuT_TRAIL_BYTE;
+ write (file, tmp_packet, len + 2);
+}
+
+static inline void MuTReadPacket(int file, unsigned char *packet)
+{
+ int n = 0;
+
+ while ( n < MuT_REPORT_SIZE ) {
+ read( file, &packet[n], 1 );
+ if ( (packet[0] & MuT_PANEL_SYNC_MASK) != 0) {
+ n++;
+ }
+ }
+}
+
+static int MuTSetToOptimalCTRL(int file, unsigned long baud)
+{
+ unsigned char packet[3]={0,0,0};
+ struct termios options;
+ struct termios save_options;
+ /*
+ * We are now in a mode who "works" but may be not the good one !
+ * So we will make a test if a "good" mode works fine ...
+ */
+
+ tcgetattr(file, &options);
+ tcgetattr(file, &save_options); // Save mode who works.
+ /*
+ * Send a command to change to suitable mode.
+ */
+ switch (baud) {
+ case B19200:
+ MuTSendPacket (file, "PN811", 5);
+ break;
+ case B9600:
+ MuTSendPacket (file, "PN812", 5);
+ break;
+ }
+ // Note answer from driver will be lost ! there is no way to catch it with some
+ // USB-Serial device. we have only to wait !
+ __mdelay (20);
+
+ /*
+ * We can't work on CS7 mode messages format are not the same !
+ */
+ options.c_cflag = CS8 | CLOCAL | CREAD;
+ /*
+ * POSIX says speed is ONLY here !
+ */
+ cfsetospeed( &options, baud);
+ cfsetispeed( &options, 0); // Same as output.
+
+ tcsetattr (file, TCSANOW, &options);
+ __mdelay (100);
+ tcflush (file, TCIFLUSH);
+ /*
+ * With some USB-Serial device flush may occurs after sending message and answer from driver
+ * may be lost ! ... so we wait !
+ */
+ __mdelay (100);
+
+ switch (baud) {
+ case B19200:
+ MuTSendPacket (file, "PN811", 5);
+ break;
+ case B9600:
+ MuTSendPacket (file, "PN812", 5);
+ break;
+ }
+ /*
+ * note if someone touch screen, we have also to strip "touch" message by testing MuT_LEAD_BYTE.
+ */
+ __mdelay (100);
+ int n = 0;
+ while ( n <3 ) {
+ if (read( file, &packet[n], 1 ) <=0)
+ break;
+ if ( packet[n] == MuT_LEAD_BYTE ) { // new start
+ n = 0;
+ packet[0] = MuT_LEAD_BYTE;
+ }
+ if ( (n==1) && (packet[1] != MuT_OK)) {
+ n = 0;
+ packet[0]= 0;
+ }
+ if ( (n==2) && (packet[2] != MuT_TRAIL_BYTE) ) {
+ n = 0;
+ packet[0]= 0;
+ }
+ if ( packet[0] == MuT_LEAD_BYTE)
+ n++;
+ }
+
+ if ( n == 3 ) {
+ /* Unset O_NONBLOCK */
+ int flags;
+ flags = fcntl( file, F_GETFL );
+ flags &= ~O_NONBLOCK;
+ fcntl( file, F_SETFL, flags );
+ /* Unset VTIME */
+ options.c_cc[VMIN] = 1;
+ options.c_cc[VTIME] = 0;
+ tcsetattr (file, TCSANOW, &options);
+ __mdelay (100);
+
+ return 1; // OK
+ }
+ // KO return to old termios options.
+ tcsetattr (file, TCSANOW, &save_options);
+ __mdelay (100);
+ return 0;
+}
+
+
+static int MuTPollDevice(char *device)
+{
+ int file;
+ struct termios options;
+ unsigned char i, m;
+ unsigned char packet[MuT_PACKET_SIZE];
+ unsigned long baud[2] = {B9600, B19200};
+ unsigned long misc[2] = {CS8, CS7 | CSTOPB};
+
+ file = open (device, O_RDWR | O_NOCTTY);
+
+ /* Set O_NONBLOCK */
+ int flags;
+ flags = fcntl( file, F_GETFL );
+ flags |= O_NONBLOCK;
+ fcntl( file, F_SETFL, flags );
+
+
+ /* Make raw I/O */
+ memset (&options, 0, sizeof (struct termios));
+
+ /* cfmakeraw(&options) */
+ options.c_cc[VMIN] = 0;
+ options.c_cc[VTIME] = 10;
+
+ /* loop through the bauds */
+ for (i = 0; i < 2; i++) {
+ /* loop through the misc configs */
+ for (m = 0; m < 2; m++) {
+ options.c_cflag = misc[m] | CLOCAL | CREAD;
+ /*
+ * POSIX
+ */
+ cfsetospeed( &options, baud[i]);
+ cfsetispeed( &options, 0);
+ tcsetattr (file, TCSANOW, &options);
+ /* wait for some USB-Serial device */
+ __mdelay (100);
+ tcflush (file, TCIFLUSH);
+ __mdelay (100);
+
+ MuTSendPacket (file, MuT_QUERY, strlen (MuT_QUERY));
+ /* we are in O_NONBLOCK need wait before read */
+ __mdelay (100);
+
+ int n = 0;
+ while ( n <3 ) {
+ if (read( file, &packet[n], 1 ) <=0)
+ break;
+ if ( packet[n] == MuT_LEAD_BYTE ) { // new start
+ n = 0;
+ packet[0] = MuT_LEAD_BYTE;
+ }
+ if ( (n==1) && (packet[1] != MuT_OK)) { // false start
+ n = 0;
+ packet[0]= 0;
+ }
+ if ( (n==2) && (packet[2] != MuT_TRAIL_BYTE) ) { // false start
+ n = 0;
+ packet[0]= 0;
+ }
+ if ( packet[0] == MuT_LEAD_BYTE)
+ n++;
+ }
+
+ if ( n == 3 ) {
+
+
+ if (MuTSetToOptimalCTRL (file, B19200)) {
+ return file;
+ }
+ else if (MuTSetToOptimalCTRL (file, B9600)) {
+ return file;
+ }
+ else return ERROR_NOT_SUITABLE;
+ }
+ }
+ }
+ close(file);
+ return ERROR_NOT_FOUND;
+}
+
+static int MuTInitCmd(int file, char *cmd)
+{
+ unsigned char timeout = 0;
+ unsigned char packet[MuT_PACKET_SIZE];
+
+ do {
+ MuTSendPacket (file, cmd, strlen (cmd));
+
+ /*
+ * Strip out 'touch" message
+ */
+ int n = 0;
+ while ( n <3 ) {
+ if (read( file, &packet[n], 1 ) <=0)
+ break;
+ if ( packet[0] == MuT_LEAD_BYTE)
+ n++;
+ }
+
+ timeout++;
+ if (timeout >= MAX_TIMEOUT)
+ return ERROR_INIT;
+ } while (packet[1] != MuT_OK);
+
+ return 1;
+}
+
+static inline int MuTInitialize(int file)
+{
+ if (!MuTInitCmd (file, MuT_RESET))
+ return 0;
+ if (!MuTInitCmd (file, MuT_FINGER_ONLY))
+ return 0;
+ if (!MuTInitCmd (file, MuT_MODE_DOWN_UP))
+ return 0;
+ if (!MuTInitCmd (file, MuT_FORMAT_TABLET))
+ return 0;
+
+ return 1;
+}
+
+static int MuTOpenDevice(char *device)
+{
+ int fd;
+ int res;
+
+ fd = MuTPollDevice (device);
+ if ((res = MuTInitialize (fd)) == 0) {
+ close (fd);
+ return res;
+ }
+
+ return fd;
+}
+
+#define WORD_ASSEMBLY(byte1, byte2) (((byte2) << 7) | (byte1))
+static int MuTGetEvent(MuTData *event)
+{
+ MuTReadPacket(event->fd, packet);
+
+ /* Sync bit always must be set to 1 */
+ if ((*packet & MuT_PANEL_SYNC_MASK) == 0)
+ return 0;
+
+ if (*packet & MuT_PANEL_TOUCH_MASK)
+ event->action = MUT_PANEL_TOUCH;
+ else
+ event->action = MUT_PANEL_UNTOUCH;
+
+ event->x = (event->screen_width *
+ WORD_ASSEMBLY(packet[1], packet[2])) / 16383;
+ event->y = (event->screen_height *
+ WORD_ASSEMBLY(packet[3], packet[4])) / 16383;
+
+ if (event->min_x)
+ event->x = event->min_x - event->x;
+ if (event->min_y)
+ event->y = event->min_y - event->y;
+
+ return 1;
+}
+
+/* The main routine for MuTouch */
+static void *MuTouchEventThread(DirectThread *thread, void *driver_data)
+{
+ MuTData *data = (MuTData *) driver_data;
+
+ /* Read data */
+ while (1) {
+ DFBInputEvent evt;
+
+ if (!MuTGetEvent (data))
+ continue;
+ direct_thread_testcancel (thread);
+
+ /* Dispatch axis */
+ evt.type = DIET_AXISMOTION;
+ evt.flags = DIEF_AXISABS;
+ evt.axis = DIAI_X;
+ evt.axisabs = data->x;
+ dfb_input_dispatch (data->device, &evt);
+
+ evt.type = DIET_AXISMOTION;
+ evt.flags = DIEF_AXISABS;
+ evt.axis = DIAI_Y;
+ evt.axisabs = data->y;
+ dfb_input_dispatch (data->device, &evt);
+
+ /* Dispatch touch event */
+ switch (data->action) {
+ case MUT_PANEL_TOUCH:
+ evt.type = DIET_BUTTONPRESS;
+ break;
+ case MUT_PANEL_UNTOUCH:
+ evt.type = DIET_BUTTONRELEASE;
+ break;
+ }
+
+ evt.flags = DIEF_NONE;
+ evt.button = DIBI_LEFT;
+
+ dfb_input_dispatch (data->device, &evt);
+ direct_thread_testcancel (thread);
+ }
+
+ return NULL;
+}
+
+/* exported symbols */
+
+static int driver_get_available( void )
+{
+ int fd;
+
+ if (!dfb_config->mut_device)
+ return 0;
+
+ fd = MuTOpenDevice (dfb_config->mut_device);
+ if (fd < 0)
+ return 0;
+
+ close(fd);
+
+ return 1;
+}
+
+static void driver_get_info( InputDriverInfo *info )
+{
+ /* fill driver info structure */
+ snprintf(info->name, DFB_INPUT_DRIVER_INFO_NAME_LENGTH,
+ "MuTouch" );
+ snprintf(info->vendor, DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH,
+ "Microtouch" );
+
+ info->version.major = 0;
+ info->version.minor = 3;
+}
+
+static DFBResult driver_open_device(CoreInputDevice *device,
+ unsigned int number,
+ InputDeviceInfo *info,
+ void **driver_data)
+{
+ int fd;
+ MuTData *data;
+
+ /* open device */
+ fd = MuTOpenDevice (dfb_config->mut_device);
+ D_INFO("MuTouch:driver_open_device %s fd %d\n", dfb_config->mut_device,fd);
+
+ if (fd < 0) {
+ return DFB_INIT;
+ }
+
+ data = D_CALLOC (1, sizeof(MuTData));
+ if (!data) {
+ close (fd);
+ return D_OOM ();
+ }
+
+ data->fd = fd;
+ data->device = device;
+
+ /* Must define the correct resolution of screen */
+ data->screen_width = MuT_SCREENWIDTH;
+ data->screen_height = MuT_SCREENHEIGHT;
+
+ /* The following variable are defined to adjust the orientation of
+ * the touchscreen. Variables are either max screen height/width or 0.
+ */
+ data->min_x = MuT_MINX;
+ data->min_y = MuT_MINY;
+
+ /* fill device info structure */
+ snprintf(info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH,
+ "MuTouch");
+ snprintf(info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH,
+ "Microtouch");
+
+ info->prefered_id = DIDID_MOUSE;
+ info->desc.type = DIDTF_MOUSE;
+ info->desc.caps = DICAPS_AXES | DICAPS_BUTTONS;
+ info->desc.max_axis = DIAI_Y;
+ info->desc.max_button = DIBI_LEFT;
+
+ /* start input thread */
+ data->thread = direct_thread_create (DTT_INPUT, MuTouchEventThread, data, "MuTouch Input");
+
+ /* set private data pointer */
+ *driver_data = data;
+
+ return DFB_OK;
+}
+
+/*
+ * Fetch one entry from the device's keymap if supported.
+ */
+static DFBResult driver_get_keymap_entry(CoreInputDevice *device,
+ void *driver_data,
+ DFBInputDeviceKeymapEntry *entry)
+{
+ return DFB_UNSUPPORTED;
+}
+
+static void driver_close_device(void *driver_data)
+{
+ MuTData *data = (MuTData *)driver_data;
+
+ /* stop input thread */
+ direct_thread_cancel (data->thread);
+ direct_thread_join (data->thread);
+ direct_thread_destroy (data->thread);
+
+ /* close device */
+ close (data->fd);
+
+ /* free private data */
+ D_FREE (data);
+}
+