Hello,
    I'm supplying the following file to be put into the inputdrivers. It
works perfectly for my situation as is. However try as I might, I
couldn't get the dfb_config parts to work. They always crashed my
system, I left in the parts that weren't working all commented out. This
was all created against 0.9.22, but I don't think anything it does is
any different than the others. I've also provided a calibration program
to get it all setup. It needs to run without the device running as
disabling/re-enabling input devices isn't supported.

   I don't mind working on it to improve it, however I no longer have
the hardware as all my tests passed and I sent it off to my client.

   Thanks for DirectFB, it was wonderful to work with and learn, I hope
to add more to it as time goes on.

-- 
Nathanael D. Noblet
Gnat Solutions
http://www.gnat.ca/
T 250.385.4613
C 250.893.4613
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <errno.h>
#include <fcntl.h>
#include <termios.h>

#include <math.h>
#include <directfb.h>

static IDirectFB *dfb = NULL;
static IDirectFBSurface *primary = NULL;
static IDirectFBEventBuffer *buffer = NULL;
static IDirectFBInputDevice *mouse = NULL;
static IDirectFBFont *gara_reg_12 = NULL;

static int screen_width  = 0;
static int screen_height = 0;

#define DFBCHECK(x...)                                       \
{                                                            \
   DFBResult err = x;                                        \
                                                             \
   if (err != DFB_OK)                                        \
   {                                                         \
      fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \
      DirectFBErrorFatal( #x, err );                         \
   }                                                         \
}


#define BUFFER_SIZE         64          /* size of reception buffer */
#define GUNZE_MAXPHYSCOORD  1023
#define GUNZE_MAXCOORD      (64*1024-1) /* oversampled, synthetic value */
#define FLAG_TAPPING        1
#define FLAG_WAS_UP         2
#define BAUDRATE            B9600
static const char *default_options[] =
{
	"BaudRate", "9600",
	"StopBits", "1",
	"DataBits", "8",
	"Parity", "None",
	"Vmin", "1",
	"Vtime", "10",
	"FlowControl", "None",
	NULL
};

typedef struct 
{
    char	*gunDevice;	/* device file name */
    int		flags;		/* various flags */
    int		gunType;        /* TYPE_SERIAL, etc */
    int		gunBaud;	/* 9600 or 19200 */
    int		gunDlen;	/* data length (3 or 11) */
    int		gunAvgX;	/* previous X position */
    int		gunAvgY;	/* previous Y position */
    int		gunSmooth;	/* how smooth the motion is */
    int		gunTapping;	/* move-and-tap (or press-only) */
    int		gunPrevButton;	/* previous button state */
    int		gunBytes;	/* number of bytes read */
    unsigned char gunData[16];	/* data read on the device */
    struct timeval *gunTv;      /* release time */
    char	*gunConfig;     /* filename for configuration */
    int     fd;
} GunzeDevice, *GunzeDevicePtr;

enum devicetypeitems {
    TYPE_UNKNOWN = 0,
    TYPE_SERIAL = 1,
    TYPE_PS2,
    TYPE_USB
};

#define GUNZE_SERIAL_DLEN 11
#define GUNZE_PS2_DLEN     3

#define GUNZE_SECTION_NAME    "GunzeTS"
#define GUNZE_DEFAULT_CFGFILE "/etc/gunzets.calib"


#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
struct axis_coord {
    int x;
    int y;
} coords;

static void GetCalibData(GunzeDevicePtr priv)
{
    unsigned char *pkt = priv->gunData;
    int len, loop;
    int x, y;
    coords.x = 0;
    coords.y = 0;
    unsigned char buffer[BUFFER_SIZE];

    while ((len = read( priv->fd, buffer, BUFFER_SIZE)) >= 0 || errno == EINTR)
    {
        if (len <= 0) 
        {
            fprintf(stderr,"error reading Gunze touch screen device %d %d\n",errno,priv->fd);
            perror(NULL);
            return;
        }

        for(loop=0; loop<len; loop++) 
        {
            // if first byte, ensure that the packet is syncronized
            if (priv->gunBytes == 0) 
            {
                int error  = 0;
                if (priv->gunDlen == GUNZE_SERIAL_DLEN) 
                {
                    // First byte is 'R' (0x52) or 'T' (0x54)
                    if ((buffer[loop] != 'R') && (buffer[loop] != 'T'))
                        error = 1;
                }
                else // PS/2 
                {
                    if ( !(buffer[loop] & 0x80) || (len > loop+1 && !(buffer[loop+1] & 0x80)) || (len > loop+2 && (buffer[loop+2]  & 0x80)))
                        error = 1;
                }
                if (error) 
                {
                    fprintf(stderr,"GunzeReadInput: bad first byte 0x%x %c\n",buffer[loop],buffer[loop]);
                    continue;
                }
            }

            pkt[priv->gunBytes++] = buffer[loop];

            // Hack: sometimes a serial packet gets corrupted. If so, drop it
            if (buffer[loop] == 0x0d && priv->gunBytes != priv->gunDlen && priv->gunDlen == GUNZE_SERIAL_DLEN) 
            {
                pkt[priv->gunBytes-1] = '\0';
                fprintf(stderr,"Bad packet \"%s\", dropping it\n", pkt);
                priv->gunBytes = 0; // for next time
                continue;
            }

            // if whole packet collected, decode it
            if (priv->gunBytes == priv->gunDlen)
            {
                priv->gunBytes = 0; // for next time
                if (priv->gunDlen == GUNZE_SERIAL_DLEN) 
                {
                    x = atoi((char *)pkt+1);
                    y = atoi((char *)pkt+6);
                }

                if (x>1023 || x<0 || y>1023 || y<0) 
                {
                    fprintf(stderr,"Bad packet \"%s\" -> %i,%i\n", pkt, x, y);
                    priv->gunBytes = 0; // for next time 
                    continue;
                }

                if (pkt[0] == 'R')
                {
                    printf ("Returning %c %d %d\n",pkt[0],x,y);
                    coords.x = x;
                    coords.y = y;
                    return;
                }
                printf ("Continuing %c %d %d\n",pkt[0],x,y);

                priv->gunAvgX = x;
                priv->gunAvgY = y;
            }
        }
    }
}


static int GunzeOpen(GunzeDevicePtr priv)
{
    struct termios  newtio,termios_tty;
    int err;

    // Is it a serial port or something else? 
    priv->gunType = TYPE_SERIAL;
    priv->gunDlen = GUNZE_SERIAL_DLEN;

    SYSCALL(priv->fd = open(priv->gunDevice, O_RDWR | O_NOCTTY));
    if (priv->fd == -1) 
    {
        fprintf(stderr,"Error opening device %s\n",priv->gunDevice);
        return -1;
    }

    SYSCALL(err = tcgetattr(priv->fd, &newtio));

    if (err == -1) {
        fprintf(stderr,"Gunze touch screen tcgetattr\n");
        return -1;
    }

    memset(&newtio,0, sizeof(newtio)); /* clear struct for new port settings */

/*
    BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    CRTSCTS : output hardware flow control (only used if the cable has
            all necessary lines. See sect. 7 of Serial-HOWTO)
    CS8     : 8n1 (8bit,no parity,1 stopbit)
    CLOCAL  : local connection, no modem contol
    CREAD   : enable receiving characters
*/
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
/*
    IGNPAR  : ignore bytes with parity errors
    ICRNL   : map CR to NL (otherwise a CR input on the other computer will not terminate input)
    otherwise make device raw (no other input processing)
*/
    newtio.c_iflag = IGNPAR | ICRNL;
//  Raw output
    newtio.c_oflag = 0;
/*
    ICANON  : enable canonical input
    disable all echo functionality, and don't send signals to calling program
*/
    newtio.c_lflag = ICANON;

/*
    initialize all control characters 
    default values can be found in /usr/include/termios.h, and are given
    in the comments, but we don't need them here
*/
    newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
    newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
    newtio.c_cc[VERASE]   = 0;     /* del */
    newtio.c_cc[VKILL]    = 0;     /* @ */
    newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
    newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
    newtio.c_cc[VSWTC]    = 0;     /* '\0' */
    newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
    newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
    newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
    newtio.c_cc[VEOL]     = 0;     /* '\0' */
    newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
    newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
    newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
    newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
    newtio.c_cc[VEOL2]    = 0;     /* '\0' */

    //now clean the modem line and activate the settings for the port

    tcflush(priv->fd, TCIFLUSH);
    err = tcsetattr(priv->fd, TCSANOW, &newtio);
    if (err == -1) {
        fprintf(stderr,"Gunze touch screen tcsetattr TCSANOW\n");
        return -1;
    }

/*
    DBG(2, fprintf(stderr,"%s opened as fd %d\n", priv->gunDevice, priv->fd));
    DBG(1, fprintf(stderr,"initializing Gunze touch screen\n"));
*/
    // Hmm... close it, so it doens't say anything before we're ready
    // FIX ME

    // Clear any pending input
    tcflush(priv->fd, TCIFLUSH);
    // FIX ME: is there something to write-and-read here?

    return 0;
}

static GunzeDevicePtr GunzeAllocate()
{
    GunzeDevicePtr priv = (GunzeDevicePtr)malloc(sizeof(GunzeDevice));

    priv->gunDevice = "/dev/ttyS0";         /* device file name */
    priv->gunConfig = GUNZE_DEFAULT_CFGFILE;
    priv->gunDlen = 0;            /* unknown */
    priv->gunType = TYPE_SERIAL;
    priv->gunBaud = 9600;
    priv->gunTapping = 0;         /* default */
    priv->gunSmooth = 9;          /* quite smooth */
    priv->gunAvgX = -1;           /* previous (avg) X position */
    priv->gunAvgY = -1;           /* previous (avg) Y position */
    priv->gunPrevButton = 0;      /* previous buttons state */
    priv->flags = FLAG_WAS_UP;    /* first event is button-down */
    priv->gunBytes = 0;           /* number of bytes read */
    priv->fd = -1;

    return priv;
}

//-----------------------------------------------------------------------------------------------
void SetupFonts()
{
    DFBFontDescription font_dsc;
    font_dsc.flags = DFDESC_HEIGHT;
    font_dsc.height=25;
    DFBCHECK(dfb->CreateFont(dfb,"/usr/local/gnatfb/GARA.TTF",&font_dsc,&gara_reg_12));
}

//-----------------------------------------------------------------------------------------------
void ReleaseFonts()
{
    DFBCHECK(gara_reg_12->Release(gara_reg_12));
}

void DrawRects(char *input)
{
    int wid = screen_width; //[winfo screenwidth .]
    int hei = screen_height; //[winfo screenheight .]

    int x = screen_width/8;//[expr $wid/8]
    int y = screen_height/8;//[expr $hei/8]
    int LX = wid-x;//[expr $wid - $x]
    int LY = hei-y;//[expr $hei - $y]
    int hx = screen_width/2;//[expr $wid/2]
    int hy = screen_height/2;//[expr $hei/2]
    int cwid = 2*x;//[expr 2*$x]
    int chei = 2*y;//[expr 2*$y]

    DFBCHECK(primary->Clear(primary,55,18,5,0));
    DFBCHECK(primary->Flip(primary,NULL,DSFLIP_NONE));
    DFBCHECK(primary->Clear(primary,55,18,5,0));
    DFBCHECK(primary->SetFont(primary,gara_reg_12));

    DFBCHECK(primary->SetColor(primary,0xFF,0xEF,0xB5,0));
    //Bottom Rectangle
    DFBCHECK(primary->DrawRectangle(primary,50,hei-chei,cwid,chei));
    // Top Rectangle
    DFBCHECK(primary->DrawRectangle(primary,wid-cwid-50,0,cwid,chei));

    // Draw Two Cross Hairs
    DFBCHECK(primary->DrawLine(primary,50,hei-chei+50,150,hei-chei+50));
    DFBCHECK(primary->DrawLine(primary,100,hei-chei,100,hei-chei+100));

    DFBCHECK(primary->DrawLine(primary,wid-(cwid/2), 0 ,wid-(cwid/2), 100));
    DFBCHECK(primary->DrawLine(primary,wid-(cwid/2)-50, 50 ,wid-(cwid/2)+50, 50));
    DFBCHECK(primary->DrawString(primary,input,-1,screen_width/2,screen_height/2,DSTF_CENTER));
    DFBCHECK(primary->Flip(primary,NULL,DSFLIP_NONE));
    sleep(1);
}

//-----------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    int quit = 0;

    DFBSurfaceDescription dsc;
    DFBCHECK (DirectFBInit (&argc, &argv));
    DFBCHECK (DirectFBCreate (&dfb));

    DFBCHECK (dfb->SetCooperativeLevel (dfb,DFSCL_EXCLUSIVE));// DFSCL_FULLSCREEN));
    DFBCHECK (dfb->SetVideoMode(dfb,1024,768,16));
    dsc.flags = DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT;
    dsc.caps = DSCAPS_PRIMARY | DSCAPS_FLIPPING;
    dsc.width = 1024;
    dsc.height = 768;

    // Surface Creation
    DFBCHECK (dfb->CreateSurface(dfb, &dsc, &primary));
    DFBCHECK (primary->GetSize(primary, &screen_width, &screen_height));
    DFBCHECK (primary->SetBlittingFlags(primary,DSBLIT_BLEND_ALPHACHANNEL));

    // Event Handlers
    DFBCHECK(dfb->CreateInputEventBuffer(dfb,DICAPS_ALL,DFB_FALSE,&buffer));
    //Cursor

    SetupFonts();

    GunzeDevice *priv = GunzeAllocate();
    if(GunzeOpen(priv) != 0){
        fprintf(stderr,"Error Opening device!\n");
        return -1;
    }

    //The offset variables account for window manager borders etc

    //DFBCHECK(primary->DrawLine(primary,wid-cwid-50, 0 ,wid-cwid+50, 50));
    DrawRects("Touch Left Cross");

    GetCalibData(priv);
    int x1 = coords.x;
    int y1 = coords.y;
    DrawRects("Touch Right Cross");

    GetCalibData(priv);
    int x2 = coords.x;
    int y2 = coords.y;

    DrawRects("Done");
    char tmp[100];
    memset(tmp,0,100);
    sprintf(tmp,"X1:%d Y1:%d X2:%d Y2:%d",x1,y1,x2,y2);
    DFBCHECK(primary->DrawString(primary,tmp,-1,screen_width/2,(screen_height/2)-150,DSTF_CENTER));
    DFBCHECK(primary->Flip(primary,NULL,DSFLIP_NONE));
    memset(tmp,0,100);
    sprintf(tmp,"# Calibration coordinates for Gunze Device\n%d %d %d %d",x1,y1,x2,y2);
    int fd = 0;
    SYSCALL(fd = open(priv->gunConfig, O_RDWR | O_TRUNC | O_CREAT));
    SYSCALL(write(fd,tmp,strlen(tmp)));
    close(fd);

    DFBInputEvent event;

    while(!quit)
    {
        buffer->WaitForEvent(buffer);
        while ( buffer->GetEvent(buffer, DFB_EVENT(&event)) == DFB_OK)
        {
            if(event.type == DIET_KEYPRESS)
            {
                if(event.key_id == DIKI_ESCAPE || event.key_id == DIKI_Q)
                {
                    printf("Q||ESC KEY pressed event\n");
                    fflush(NULL);

                    quit = 1;
                }
            }
        }
    }

    close(priv->fd);
    free(priv);

    ReleaseFonts();
    if(mouse != NULL)
        mouse->Release(mouse);

    buffer->Release(buffer);
    primary->Release(primary);
    dfb->Release(dfb);
    return 0;
}
/*
   (c) Copyright 2005  Gnat Solutions, Inc.

   All rights reserved.

   Written by Nathanael D. Noblet <[EMAIL PROTECTED]>

   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 gunze driver provided in XFree86. 
   Using the MuTouch driver as a skeleton.

 */

#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( gunze )

#define BUFFER_SIZE         64          /* size of reception buffer */
#define GUNZE_MAXPHYSCOORD  1023
#define GUNZE_MAXCOORD      (64*1024-1) /* oversampled, synthetic value */
#define FLAG_TAPPING        1
#define FLAG_WAS_UP         2
#define BAUDRATE            B9600

#define GunzeT_PACKET_SIZE     10
#define GunzeT_SCREENWIDTH     1024
#define GunzeT_SCREENHEIGHT    768
#define GunzeT_MINX            0
#define GunzeT_MINY            0
#define GunzeT_DEFAULT_DEVICE   "/dev/ttyS0"

#define GUNZE_PANEL_TOUCH       T
#define GUNZE_PANEL_UNTOUCH     R

#define GUNZE_SERIAL_DLEN 11
#define GUNZE_PS2_DLEN     3

#define GUNZE_SECTION_NAME    "gunze"
#define GUNZE_DEFAULT_CFGFILE "/etc/gunzets.calib"

#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))

/*
* Serial protocol (11 b):  <T-or-R> <4-bytes-for-X> , <4-bytes-for-Y> 0x0d
*/
typedef struct __GunzeTData__
{
    char *gunDevice;	/* device file name */
    DirectThread *thread;
    CoreInputDevice *device;
    unsigned int x;
    unsigned int y;
    unsigned int screen_width;
    unsigned int screen_height;
    int     flags;                 /* various flags */
    int     gunType;               /* TYPE_SERIAL, etc */
    int     gunBaud;               /* 9600 or 19200 */
    int     gunDlen;               /* data length (3 or 11) */
    int     gunPrevX;              /* previous X position */
    int     gunPrevY;              /* previous Y position */
    int     gunSmooth;             /* how smooth the motion is */
    int     gunTapping;            /* move-and-tap (or press-only) not implemented */
    int     gunPrevButtonState;    /* previous button state */
    int     gunBytes;              /* number of bytes read */
    unsigned char gunData[16];     /* data read on the device */
    int         gunCalib[4];       /* calibration data */
    char	*gunConfig;            /* filename for configuration */
    int     fd;
} GunzeTData;

enum devicetypeitems {
    TYPE_UNKNOWN = 0,
    TYPE_SERIAL = 1,
    TYPE_PS2,
    TYPE_USB
};

static int GunzeReadCalib(GunzeTData *priv)
{
    int i=1;
    int err = 1;
    FILE *f;
    priv->gunCalib[0]=priv->gunCalib[1]=priv->gunCalib[2]=priv->gunCalib[3]=0;
    f = fopen(priv->gunConfig, "r");
    if (f)
    {
        char s[80];
        fgets(s, 80, f); /* discard the comment */
        if (fscanf(f, "%d %d %d %d", priv->gunCalib, priv->gunCalib+1, priv->gunCalib+2, priv->gunCalib+3) == 4)
        {
            D_PERROR("DirectFB/gunze: Calibration invalid 0 i:%d gunCalib[0]:%d \n",i,priv->gunCalib[0]);
            err = 0;
        }

        for (i=0; i<4; i++) 
        {
            if (priv->gunCalib[i] & ~1023)
            {
                D_PERROR("DirectFB/gunze: Calibration invalid 0 i:%d gunCalib[i]:%d \n",i,priv->gunCalib[i]);
                err++;
            }
            if (abs(priv->gunCalib[0] - priv->gunCalib[2]) < 100)
            {
                D_PERROR("DirectFB/gunze: Calibration invalid 1 0:%d 2:%d abs(%d)\n",priv->gunCalib[0],priv->gunCalib[2],abs(priv->gunCalib[0] - priv->gunCalib[2]));
                err++;
            }
            if (abs(priv->gunCalib[1] - priv->gunCalib[3]) < 100)
            {
                D_PERROR("DirectFB/gunze: Calibration invalid 2 1:%d 3:%d abs(%d)\n",priv->gunCalib[1],priv->gunCalib[3],abs(priv->gunCalib[1] - priv->gunCalib[3]));
                err++;
            }
            fclose(f);
        }
    }
    if (err)
    {
      D_PERROR("DirectFB/gunze: Calibration data absent or invalid, using defaults\n");
      priv->gunCalib[0] = priv->gunCalib[1] = 128; /* 1/8 */
      priv->gunCalib[2] = priv->gunCalib[3] = 896; /* 7/8 */
    }
    return 0;
}

static int GunzeSetToOptimalCTRL(int file)
{
    struct termios  newtio;
    int err;

    SYSCALL(err = tcgetattr(file, &newtio));

    if (err == -1) {
        D_PERROR("DirectFB/gunze: Gunze touch screen tcgetattr failed\n");
        return 0;
    }

    memset(&newtio,0, sizeof(newtio)); /* clear struct for new port settings */
/*
    BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    CRTSCTS : output hardware flow control (only used if the cable has
            all necessary lines. See sect. 7 of Serial-HOWTO)
    CS8     : 8n1 (8bit,no parity,1 stopbit)
    CLOCAL  : local connection, no modem contol
    CREAD   : enable receiving characters
*/
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
/*
    IGNPAR  : ignore bytes with parity errors
    ICRNL   : map CR to NL (otherwise a CR input on the other computer will not terminate input)
    otherwise make device raw (no other input processing)
*/
    newtio.c_iflag = IGNPAR | ICRNL;
/*  Raw output */
    newtio.c_oflag = 0;
/*
    ICANON  : enable canonical input
    disable all echo functionality, and don't send signals to calling program
*/
    newtio.c_lflag = ICANON;

/*
    initialize all control characters 
    default values can be found in /usr/include/termios.h, and are given
    in the comments, but we don't need them here
*/
    newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
    newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
    newtio.c_cc[VERASE]   = 0;     /* del */
    newtio.c_cc[VKILL]    = 0;     /* @ */
    newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
    newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
    newtio.c_cc[VSWTC]    = 0;     /* '\0' */
    newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
    newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
    newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
    newtio.c_cc[VEOL]     = 0;     /* '\0' */
    newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
    newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
    newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
    newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
    newtio.c_cc[VEOL2]    = 0;     /* '\0' */

    /* now clean the modem line and activate the settings for the port */

    tcflush(file, TCIFLUSH);
    err = tcsetattr(file, TCSANOW, &newtio);
    if (err == -1) {
        D_PERROR("DirectFB/gunze: Gunze touch screen tcsetattr TCSANOW failed\n");
        return 0;
    }

    return 1;
}

static int GunzeOpenDevice(char *device)
{
    int fd;
    int res;

    /* opens device */
    SYSCALL(fd = open(device, O_RDWR | O_NOCTTY));
    if (fd == -1)
    {
        D_PERROR("DirectFB/gunze: Error opening device %s\n",device);
        return fd;
    }

    /* setup termios settings for communication */
    if((res = GunzeSetToOptimalCTRL(fd)) == 0)
    {
        close(fd);
        return res;
    }

    return fd;
}

/* The main routine for GunzeTouch */
static void *GunzeTouchEventThread(DirectThread *thread, void *driver_data)
{
    GunzeTData *priv = (GunzeTData *) driver_data;
    unsigned char *pkt = priv->gunData;
    int len, loop;
    int x =0;
    int y =0;
    int button =0;
    int *calib = priv->gunCalib;
    unsigned char buffer[BUFFER_SIZE];

    while ((len = read( priv->fd, buffer, BUFFER_SIZE)) >= 0 || errno == EINTR)
    {

        if (len <= 0) 
        {
            D_PERROR("DirectFB/gunze: error reading Gunze touch screen device %d %d\n",errno,priv->fd);
            perror(NULL);
            return NULL;
        }

        for(loop=0; loop<len; loop++) 
        {
            /* if first byte, ensure that the packet is syncronized */
            if (priv->gunBytes == 0) 
            {
                int error  = 0;
                if (priv->gunDlen == GUNZE_SERIAL_DLEN) 
                {
                    /* First byte is 'R' (0x52) or 'T' (0x54) */
                    if ((buffer[loop] != 'R') && (buffer[loop] != 'T'))
                        error = 1;
                }
                /* PS/2 / USB Unsupported for now (basically I don't have one, and didn't test adding support will be trivial
                else  
                {
                    if ( !(buffer[loop] & 0x80) || (len > loop+1 && !(buffer[loop+1] & 0x80)) || (len > loop+2 && (buffer[loop+2]  & 0x80)))
                        error = 1;
                }
                */
                if (error)
                {
                    D_PERROR("DirectFB/gunze: GunzeReadInput: bad first byte 0x%x %c\n",buffer[loop],buffer[loop]);
                    continue;
                }
            }

            pkt[priv->gunBytes++] = buffer[loop];

            /* Hack: sometimes a serial packet gets corrupted. If so, drop it */
            if (buffer[loop] == 0x0d && priv->gunBytes != priv->gunDlen && priv->gunDlen == GUNZE_SERIAL_DLEN) 
            {
                pkt[priv->gunBytes-1] = '\0';
                D_PERROR("DirectFB/gunze: Bad packet \"%s\" dropping it\n", pkt);
                priv->gunBytes = 0;
                continue;
            }

            /* if whole packet collected, decode it */
            if (priv->gunBytes == priv->gunDlen) 
            {
                priv->gunBytes = 0;
                if (priv->gunDlen == GUNZE_SERIAL_DLEN) 
                {
                    /* if T button == true */
                    button = (pkt[0] == 'T');
                    x = atoi((char *)pkt+1);
                    y = atoi((char *)pkt+6);
                }
                /* USB version which I haven't added support for 
                else
                {
                    button = (pkt[2] & 0x40);
                    x = ((pkt[0] & 0x7f) << 3) | ((pkt[1] & 0x70) >> 4);
                    y = ((pkt[1] & 0x0f) << 6) | ((pkt[2] & 0x3f));
                }
                */

                if (x>1023 || x<0 || y>1023 || y<0) 
                {
                    D_PERROR("DirectFB/gunze: Bad packet \"%s\" -> %i,%i\n", pkt, x, y);

                    priv->gunBytes = 0;
                    continue;
                }

                /*
                Ok, now that we have raw data, turn it to real data
                according to calibration, smoothness, tapping and debouncing
                calibrate and rescale (by multiplying by 64) 

                I don't fully understand this, came from xf86Gunze.c
                x = 64*128 + 64*768 * (x - calib[0])/(calib[2]-calib[0]);
                y = 64*128 + 64*768 * (y - calib[1])/(calib[3]-calib[1]);
                */

                x = 8192 + 49152 * (x - calib[0])/(calib[2]-calib[0]);
                y = 8192 + 49152 * (y - calib[1])/(calib[3]-calib[1]);
                y = GUNZE_MAXCOORD - y;
                /* smooth it down, unless first touch */
                if (!(priv->flags & FLAG_WAS_UP)) 
                {
                    x = (priv->gunPrevX * priv->gunSmooth + x)/(priv->gunSmooth+1);
                    y = (priv->gunPrevY * priv->gunSmooth + y)/(priv->gunSmooth+1);
                }

                /* convert gunze x/y to screen dimensions */
                x = x * priv->screen_width  / (GUNZE_MAXCOORD);
                y = y * priv->screen_height / (GUNZE_MAXCOORD);
                if (x < 0) x = 0;
                if (y < 0) y = 0;
                if (x > priv->screen_width)  x = priv->screen_width;
                if (y > priv->screen_height) y = priv->screen_height;

                if (!button)
                    priv->flags |= FLAG_WAS_UP;
                else
                    priv->flags &= ~FLAG_WAS_UP;

                /* Now send events */
                DFBInputEvent evt;

                /* only post new x/y if different from previous tap */
                if ( (priv->gunPrevX != x) || (priv->gunPrevY != y) )
                {
                    direct_thread_testcancel (thread);
                    /* Dispatch axis */
                    evt.type    = DIET_AXISMOTION;
                    evt.flags   = DIEF_AXISABS;
                    evt.axis    = DIAI_X;
                    evt.axisabs = x;
                    dfb_input_dispatch (priv->device, &evt);

                    evt.type    = DIET_AXISMOTION;
                    evt.flags   = DIEF_AXISABS;
                    evt.axis    = DIAI_Y;
                    evt.axisabs = y;
                    dfb_input_dispatch (priv->device, &evt);
                    direct_thread_testcancel (thread);
                    /*printf("dispatched motion x %d y %d\n",x,y);*/
                }
                /* post button state change at x/y */
                if (priv->gunPrevButtonState != button)
                {
                    direct_thread_testcancel (thread);

                    /* Dispatch axis */
                    evt.type    = DIET_AXISMOTION;
                    evt.flags   = DIEF_AXISABS;
                    evt.axis    = DIAI_X;
                    evt.axisabs = x;
                    dfb_input_dispatch (priv->device, &evt);

                    evt.type    = DIET_AXISMOTION;
                    evt.flags   = DIEF_AXISABS;
                    evt.axis    = DIAI_Y;
                    evt.axisabs = y;
                    dfb_input_dispatch (priv->device, &evt);

                    /* Dispatch touch event */
                    evt.type = (button) ? DIET_BUTTONPRESS:DIET_BUTTONRELEASE;
                    evt.flags  = DIEF_NONE;
                    evt.button = DIBI_LEFT;

                    dfb_input_dispatch (priv->device, &evt);
                    direct_thread_testcancel (thread);
                    /* printf("dispatched button x %d y %d\n",x,y); */
                }

                /* remember data */
                priv->gunPrevButtonState = button;
                priv->gunPrevX = x;
                priv->gunPrevY = y;

            }
        }
    }

    return NULL;
}

/* exported symbols */

static int driver_get_available( void )
{
    int fd;
    /*
    if (!dfb_config->gunze_device){
        D_PERROR("DirectFB/GunzeTouch: Missing Gunze device file using default %s!\n",GunzeT_DEFAULT_DEVICE);
        fflush(NULL);
    }*/

/*    
    if (!dfb_config->gunze_device)
        return 0;
    */
    /* TODO gotta clean this up... seems odd to open & close it like this... */
     //fd = GunzeOpenDevice (dfb_config->gunze_device);
    fd = GunzeOpenDevice(GunzeT_DEFAULT_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,"gunze" );
     snprintf(info->vendor, DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH,"Gunze" );

     info->version.major = 0;
     info->version.minor = 1;
}

static DFBResult driver_open_device(CoreInputDevice *device,
                                    unsigned int number,
                                    InputDeviceInfo *info,
                                    void **driver_data)
{
    int fd;
    GunzeTData *data = NULL;


    if (!dfb_config->gunze_device)
        D_PERROR("DirectFB/GunzeTouch: Missing Gunze device file using default %s!\n",GunzeT_DEFAULT_DEVICE);


    /* open device */
    fd = GunzeOpenDevice (GunzeT_DEFAULT_DEVICE);

    if (fd < 0) {
        D_PERROR("DirectFB/GunzeTouch: Error opening '%s'!\n", dfb_config->gunze_device);
        return DFB_INIT;
    }

    data = D_CALLOC (1, sizeof(GunzeTData));

    data->fd = fd;
    data->device = device;
    data->gunDevice= (!dfb_config->gunze_device) ? GunzeT_DEFAULT_DEVICE:dfb_config->gunze_device;
    /* hard coded... */
    data->gunType = TYPE_SERIAL;
    data->gunDlen = GUNZE_SERIAL_DLEN;
    /* Must define the correct resolution of screen */
    data->screen_width  = GunzeT_SCREENWIDTH;
    data->screen_height = GunzeT_SCREENHEIGHT;
    data->gunConfig = GUNZE_DEFAULT_CFGFILE;//(!dfb_config->gunze_calibration_file)?GUNZE_DEFAULT_CFGFILE:dfb_config->gunze_calibration_file;

    /* The following variable are defined to adjust the orientation of
    * the touchscreen. Variables are either max screen height/width or 0.
    * don't know how to use this as it was taken from mutouch likely not needed...

    data->min_x = GunzeT_MINX;
    data->min_y = GunzeT_MINY;
*/
    /* grab calibration data */
    GunzeReadCalib(data);

    /* fill device info structure */
    snprintf(info->desc.name, DFB_INPUT_DEVICE_DESC_NAME_LENGTH,"gunze");
    snprintf(info->desc.vendor, DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH,"Gunze");

    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, GunzeTouchEventThread, data, "GunzeTouch 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)
{
     GunzeTData *data = (GunzeTData *)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);
}

_______________________________________________
directfb-dev mailing list
[email protected]
http://mail.directfb.org/cgi-bin/mailman/listinfo/directfb-dev

Reply via email to