Logo Search packages:      
Sourcecode: wacom-tools version File versions

wcmSerial.c

/*
 * Copyright 1995-2004 by Frederic Lepied, France. <Lepied@XFree86.org>
 *                                                                            
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is  hereby granted without fee, provided that
 * the  above copyright   notice appear  in   all  copies and  that both  that
 * copyright  notice   and   this  permission   notice  appear  in  supporting
 * documentation, and that   the  name of  Frederic   Lepied not  be  used  in
 * advertising or publicity pertaining to distribution of the software without
 * specific,  written      prior  permission.     Frederic  Lepied   makes  no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.                   
 *                                                                            
 * FREDERIC  LEPIED DISCLAIMS ALL   WARRANTIES WITH REGARD  TO  THIS SOFTWARE,
 * INCLUDING ALL IMPLIED   WARRANTIES OF MERCHANTABILITY  AND   FITNESS, IN NO
 * EVENT  SHALL FREDERIC  LEPIED BE   LIABLE   FOR ANY  SPECIAL, INDIRECT   OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA  OR PROFITS, WHETHER  IN  AN ACTION OF  CONTRACT,  NEGLIGENCE OR OTHER
 * TORTIOUS  ACTION, ARISING    OUT OF OR   IN  CONNECTION  WITH THE USE    OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "xf86Wacom.h"
#include "wcmSerial.h"
#include "wcmFilter.h"

/* Serial Support */
static Bool serialDetect(LocalDevicePtr pDev);
static Bool serialInit(LocalDevicePtr pDev);

static int serialInitTablet(WacomCommonPtr common, int fd);
static void serialInitIntuos(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialInitIntuos2(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialInitCintiq(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialInitPenPartner(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialInitGraphire(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialInitProtocol4(WacomCommonPtr common, int fd,
      const char* id, float version);
static void serialGetResolution(WacomCommonPtr common, int fd);
static int serialGetRanges(WacomCommonPtr common, int fd);
static int serialResetIntuos(WacomCommonPtr common, int fd);
static int serialResetCintiq(WacomCommonPtr common, int fd);
static int serialResetPenPartner(WacomCommonPtr common, int fd);
static int serialResetProtocol4(WacomCommonPtr common, int fd);
static int serialEnableTiltProtocol4(WacomCommonPtr common, int fd);
static int serialEnableSuppressProtocol4(WacomCommonPtr common, int fd);
static int serialSetLinkSpeedIntuos(WacomCommonPtr common, int fd);
static int serialSetLinkSpeedProtocol5(WacomCommonPtr common, int fd);
static int serialStartTablet(WacomCommonPtr common, int fd);
static int serialParseCintiq(WacomCommonPtr common,
      const unsigned char* data);
static int serialParseGraphire(WacomCommonPtr common,
      const unsigned char* data);
static int serialParseProtocol4(WacomCommonPtr common,
      const unsigned char* data);
static int serialParseProtocol5(WacomCommonPtr common,
      const unsigned char* data);
static void serialParseP4Common(WacomCommonPtr common,
      const unsigned char* data, WacomDeviceState* last,
      WacomDeviceState* ds);

/*****************************************************************************
 * Global Structures
 ****************************************************************************/

      WacomDeviceClass gWacomSerialDevice =
      {
            serialDetect,
            serialInit,
            xf86WcmReadPacket,
      };

/*****************************************************************************
 * Static Structures
 ****************************************************************************/

      static WacomModel serialIntuos =
      {
            "Serial Intuos",
            serialInitIntuos,
            NULL,           /* resolution not queried */
            serialGetRanges,
            serialResetIntuos,
            NULL,           /* tilt automatically enabled */
            NULL,           /* suppress implemented in software */
            serialSetLinkSpeedIntuos,
            serialStartTablet,
            serialParseProtocol5,
            xf86WcmFilterIntuos,
      };

      static WacomModel serialIntuos2 =
      {
            "Serial Intuos2",
            serialInitIntuos2,
            NULL,                 /* resolution not queried */
            serialGetRanges,
            serialResetIntuos,    /* same as Intuos */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            serialSetLinkSpeedProtocol5,
            serialStartTablet,
            serialParseProtocol5,
            xf86WcmFilterIntuos,
      };

      static WacomModel serialCintiq =
      {
            "Serial Cintiq",
            serialInitCintiq,
            serialGetResolution,
            serialGetRanges,
            serialResetCintiq,
            serialEnableTiltProtocol4,
            serialEnableSuppressProtocol4,
            NULL,               /* link speed cannot be changed */
            serialStartTablet,
            serialParseCintiq,
            xf86WcmHysteresisFilter,
      };

      static WacomModel serialPenPartner =
      {
            "Serial PenPartner",
            serialInitPenPartner,
            NULL,               /* resolution not queried */
            serialGetRanges,
            serialResetPenPartner,
            serialEnableTiltProtocol4,
            serialEnableSuppressProtocol4,
            NULL,              /* link speed cannot be changed */
            serialStartTablet,
            serialParseProtocol4,
            xf86WcmFilterCoord,
      };    

      static WacomModel serialGraphire =
      {
            "Serial Graphire",
            serialInitGraphire,
            NULL,                     /* resolution not queried */
            NULL,                     /* ranges not supported */
            serialResetPenPartner,    /* functionally very similar */
            serialEnableTiltProtocol4,
            serialEnableSuppressProtocol4,
            NULL,                    /* link speed cannot be changed */
            serialStartTablet,
            serialParseGraphire,
            xf86WcmFilterCoord,
      };

      static WacomModel serialProtocol4 =
      {
            "Serial UD",
            serialInitProtocol4,
            serialGetResolution,
            serialGetRanges,
            serialResetProtocol4,
            serialEnableTiltProtocol4,
            serialEnableSuppressProtocol4,
            NULL,               /* link speed cannot be changed */
            serialStartTablet,
            serialParseProtocol4,
            xf86WcmHysteresisFilter,
      };

/*****************************************************************************
 * Setup strings
 ****************************************************************************/

      static const char * setup_string = WC_MULTI WC_UPPER_ORIGIN
            WC_ALL_MACRO WC_NO_MACRO1 WC_RATE WC_NO_INCREMENT
            WC_STREAM_MODE WC_ZFILTER;
      static const char * pl_setup_string = WC_UPPER_ORIGIN WC_RATE
            WC_STREAM_MODE;
      static const char * penpartner_setup_string = WC_PRESSURE_MODE
            WC_START;
      static const char * intuos_setup_string = WC_V_MULTI WC_V_ID WC_RATE
            WC_START;

      /* PROTOCOL 4 */

      /* Format of 7 bytes data packet for Wacom Tablets
      Byte 1
      bit 7  Sync bit always 1
      bit 6  Pointing device detected
      bit 5  Cursor = 0 / Stylus = 1
      bit 4  Reserved
      bit 3  1 if a button on the pointing device has been pressed
      bit 2  Reserved
      bit 1  X15
      bit 0  X14

      Byte 2
      bit 7  Always 0
      bits 6-0 = X13 - X7

      Byte 3
      bit 7  Always 0
      bits 6-0 = X6 - X0

      Byte 4
      bit 7  Always 0
      bit 6  B3
      bit 5  B2
      bit 4  B1
      bit 3  B0
      bit 2  P0
      bit 1  Y15
      bit 0  Y14

      Byte 5
      bit 7  Always 0
      bits 6-0 = Y13 - Y7

      Byte 6
      bit 7  Always 0
      bits 6-0 = Y6 - Y0

      Byte 7
      bit 7 Always 0
      bit 6  Sign of pressure data
      bit 5  P6
      bit 4  P5
      bit 3  P4
      bit 2  P3
      bit 1  P2
      bit 0  P1

      byte 8 and 9 are optional and present only
      in tilt mode.

      Byte 8
      bit 7 Always 0
      bit 6 Sign of tilt X
      bit 5  Xt6
      bit 4  Xt5
      bit 3  Xt4
      bit 2  Xt3
      bit 1  Xt2
      bit 0  Xt1

      Byte 9
      bit 7 Always 0
      bit 6 Sign of tilt Y
      bit 5  Yt6
      bit 4  Yt5
      bit 3  Yt4
      bit 2  Yt3
      bit 1  Yt2
      bit 0  Yt1
      */

/*****************************************************************************
 * xf86WcmSendRequest --
 *   send a request and wait for the answer.
 *   the answer must begin with the first two chars of the request.
 *   The last character in the answer string is replaced by a \0.
 ****************************************************************************/

char* xf86WcmSendRequest(int fd, const char* request, char* answer, int maxlen)
{
      int len, nr;
      int maxtry = MAXTRY;

      if (maxlen < 3)
            return NULL;
  
      /* send request string */
      do
      {
            SYSCALL(len = xf86WcmWrite(fd, request, strlen(request)));
            if ((len == -1) && (errno != EAGAIN))
            {
                  ErrorF("Wacom xf86WcmWrite error : %s", strerror(errno));
                  return NULL;
            }
            maxtry--;
      } while ((len == -1) && maxtry);

      if (maxtry == 0)
      {
            ErrorF("Wacom unable to xf86WcmWrite request string '%s' "
                        "after %d tries\n", request, MAXTRY);
            return NULL;
      }
  
      do
      {
            maxtry = MAXTRY;
    
            /* Read the first byte of the answer which must
             * be equal to the first byte of the request.
             */
            do
            {
                  if ((nr = xf86WcmWaitForTablet(fd)) > 0)
                  {
                        SYSCALL(nr = xf86WcmRead(fd, answer, 1));
                        if ((nr == -1) && (errno != EAGAIN))
                        {
                              ErrorF("Wacom xf86WcmRead error : %s\n",
                                          strerror(errno));
                              return NULL;
                        }
                        DBG(10, ErrorF("%c err=%d [0]\n",
                              answer[0], nr));
                  }
                  maxtry--;  
            } while ((answer[0] != request[0]) && maxtry);

            if (maxtry == 0)
            {
                  ErrorF("Wacom unable to read first byte of "
                              "request '%c%c' answer after %d tries\n",
                              request[0], request[1], MAXTRY);
                  return NULL;
            }

            /* Read the second byte of the answer which must be equal
             * to the second byte of the request. */
            do
            {    
                  maxtry = MAXTRY;
                  do
                  {
                        if ((nr = xf86WcmWaitForTablet(fd)) > 0)
                        {
                              SYSCALL(nr = xf86WcmRead(fd, answer+1, 1));
                              if ((nr == -1) && (errno != EAGAIN))
                              {
                                    ErrorF("Wacom xf86WcmRead error : %s\n",
                                                strerror(errno));
                                    return NULL;
                              }
                              DBG(10, ErrorF("%c err=%d [1]\n",
                                          answer[1], nr));
                        }
                        maxtry--;  
                  } while ((nr <= 0) && maxtry);
            
                  if (maxtry == 0)
                  {
                        ErrorF("Wacom unable to read second byte of "
                              "request '%c%c' answer after %d "
                              "tries\n", request[0], request[1],
                              MAXTRY);
                        return NULL;
                  }

                  if (answer[1] != request[1])
                        answer[0] = answer[1];
            
            } while ((answer[0] == request[0]) && (answer[1] != request[1]));

      } while ((answer[0] != request[0]) && (answer[1] != request[1]));

      /* Read until we don't get anything or timeout. */

      len = 2;
      maxtry = MAXTRY;
      do
      { 
            do
            {
                  if ((nr = xf86WcmWaitForTablet(fd)) > 0)
                  {
                        SYSCALL(nr = xf86WcmRead(fd, answer+len, 1));
                        if ((nr == -1) && (errno != EAGAIN))
                        {
                              ErrorF("Wacom xf86WcmRead error : %s\n", strerror(errno));
                              return NULL;
                        }
                        DBG(10, ErrorF("%c err=%d [%d]\n", answer[len], nr, len));
                  }
                  else
                  {
                        if (len == 2)
                        {
                              DBG(10, ErrorF("timeout remains %d tries\n", maxtry));
                              maxtry--;
                        }
                  }
            } while ((nr <= 0) && len == 2 && maxtry);

            if (nr > 0)
            {
                  len += nr;
                  if (len >= (maxlen - 1))
                        return NULL;
            }

            if (maxtry == 0)
            {
                  ErrorF("Wacom unable to read last byte of request '%c%c' answer after %d tries\n",
                              request[0], request[1], MAXTRY);
                  break;
            }
      } while (nr > 0);

      if (len <= 3)
            return NULL;
    
      answer[len-1] = '\0';
  
      return answer;
}

static Bool serialDetect(LocalDevicePtr pDev)
{
      return 1;
}

static Bool serialInit(LocalDevicePtr local)
{
      int err;
      WacomCommonPtr common = ((WacomDevicePtr)(local->private))->common;
    
      DBG(1, ErrorF("initializing serial tablet\n"));    

      /* Set the speed of the serial link to 38400 */
      if (xf86WcmSetSerialSpeed(local->fd, 38400) < 0)
            return !Success;
    
      /* Send reset to the tablet */
      SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD,
            strlen(WC_RESET_BAUD)));

      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }
    
      /* Wait 250 mSecs */
      if (xf86WcmWait(250))
            return !Success;

      /* Send reset to the tablet */
      SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }
    
      /* Wait 75 mSecs */
      if (xf86WcmWait(75))
            return !Success;

      /* Set the speed of the serial link to 19200 */
      if (xf86WcmSetSerialSpeed(local->fd, 19200) < 0)
            return !Success;
    
      /* Send reset to the tablet */
      SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD,
            strlen(WC_RESET_BAUD)));

      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }
    
      /* Wait 250 mSecs */
      if (xf86WcmWait(250))
            return !Success;

      /* Send reset to the tablet */
      SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET, strlen(WC_RESET)));
      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }
    
      /* Wait 75 mSecs */
      if (xf86WcmWait(75))
            return !Success;

      /* Set the speed of the serial link to 9600 */
      if (xf86WcmSetSerialSpeed(local->fd, 9600) < 0)
            return !Success;
    
      /* Send reset to the tablet */
      SYSCALL(err = xf86WcmWrite(local->fd, WC_RESET_BAUD, strlen(WC_RESET_BAUD)));
      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }
    
      /* Wait 250 mSecs */
      if (xf86WcmWait(250))
            return !Success;

      SYSCALL(err = xf86WcmWrite(local->fd, WC_STOP, strlen(WC_STOP)));
      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }

      /* Wait 30 mSecs */
      if (xf86WcmWait(30))
            return !Success;

      xf86WcmFlushTablet(local->fd);

      if (serialInitTablet(common,local->fd) == !Success)
      {
            SYSCALL(xf86WcmClose(local->fd));
            local->fd = -1;
            return !Success;
      }

      return Success;
}

/*****************************************************************************
 * serialInitTablet --
 *   Initialize the tablet
 ****************************************************************************/


static int serialInitTablet(WacomCommonPtr common, int fd)
{
      int loop, idx;
      char id[BUFFER_SIZE];
      float version;

      WacomModelPtr model = NULL;

      /* if model is forced, initialize */
      if (model != NULL)
      {
            id[0] = '\0';
            version = 0.0F;
      }

      /* otherwise, query and initialize */
      else
      {
            DBG(2, ErrorF("reading model\n"));
            if (!xf86WcmSendRequest(fd, WC_MODEL, id, sizeof(id)))
                  return !Success;

            DBG(2, ErrorF("%s\n", id));
  
            if (xf86Verbose)
                  ErrorF("%s Wacom tablet model : %s\n",
                              XCONFIG_PROBED, id+2);
    
            /* Answer is in the form ~#Tablet-Model VRom_Version 
             * look for the first V from the end of the string
             * this seems to be the better way to find the version
             * of the ROM */
            for(loop=strlen(id); loop>=0 && *(id+loop) != 'V'; loop--);
            for(idx=loop; idx<strlen(id) && *(id+idx) != '-'; idx++);
            *(id+idx) = '\0';

            /* Extract version numbers */
            sscanf(id+loop+1, "%f", &version);

            /* Detect tablet model based on identifier */
            if (id[2] == 'G' && id[3] == 'D')
                  model = &serialIntuos;
            else if (id[2] == 'X' && id[3] == 'D')
                  model = &serialIntuos2;
            else if (id[2] == 'P' && id[3] == 'L')
                  model = &serialCintiq;
            else if (id[2] == 'C' && id[3] == 'T')
                  model = &serialPenPartner;
            else if (id[2] == 'E' && id[3] == 'T')
                  model = &serialGraphire;
            else
                  model = &serialProtocol4;

      }

      return xf86WcmInitTablet(common,model,fd,id,version);
}

static int serialParseGraphire(WacomCommonPtr common,
      const unsigned char* data)
{
      int n;
      WacomDeviceState* last = &common->wcmChannel[0].valid.state;
      WacomDeviceState* ds;

      /* positive value is skip */
      if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;

      /* pick up where we left off, minus relative values */
      ds = &common->wcmChannel[0].work;
      RESET_RELATIVE(*ds);

      /* get pressure */
      ds->pressure = ((data[6]&ZAXIS_BITS) << 2 ) +
            ((data[3]&ZAXIS_BIT) >> 1) +
            ((data[3]&PROXIMITY_BIT) >> 6) +
            ((data[6]&ZAXIS_SIGN_BIT) ? 0 : 0x100);

      /* get buttons */
      ds->buttons = (data[3] & 0x38) >> 3;

      /* requires button info, so it goes down here. */
      serialParseP4Common(common,data,last,ds);

      /* handle relative wheel for non-stylus device */
      if (ds->device_type == CURSOR_ID)
      {
            ds->relwheel = (data[6] & 0x30) >> 4;
            if (data[6] & 0x40)
                  ds->relwheel = -ds->relwheel;

      }

      xf86WcmEvent(common,0,ds);
      return common->wcmPktLength;
}

static int serialParseCintiq(WacomCommonPtr common,
      const unsigned char* data)
{
      int n;
      WacomDeviceState* last = &common->wcmChannel[0].valid.state;
      WacomDeviceState* ds;

      /* positive value is skip */
      if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;

      /* pick up where we left off, minus relative values */
      ds = &common->wcmChannel[0].work;
      RESET_RELATIVE(*ds);

      /* get pressure */
      if (common->wcmMaxZ == 255)
      {
            ds->pressure = ((data[6] & ZAXIS_BITS) << 1 ) |
                  ((data[3] & ZAXIS_BIT) >> 2) |
                  ((data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x80);
      }
      else
      {
            /* which tablets use this? */
            /* PL550, PL800, and Graphire apparently */
            ds->pressure = ((data[6]&ZAXIS_BITS) << 2 ) +
                  ((data[3]&ZAXIS_BIT) >> 1) +
                  ((data[3]&PROXIMITY_BIT) >> 6) +
                  ((data[6]&ZAXIS_SIGN_BIT) ? 0 : 0x100);
      }

      /* get buttons */
      ds->buttons = (data[3] & 0x38) >> 3;

      /* requires button info, so it goes down here. */
      serialParseP4Common(common,data,last,ds);

      xf86WcmEvent(common,0,ds);
      return common->wcmPktLength;
}

static int serialParseProtocol4(WacomCommonPtr common,
      const unsigned char* data)
{
      int n;
      WacomDeviceState* last = &common->wcmChannel[0].valid.state;
      WacomDeviceState* ds;

      /* positive value is skip */
      if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;

      /* pick up where we left off, minus relative values */
      ds = &common->wcmChannel[0].work;
      RESET_RELATIVE(*ds);

      /* get pressure */
      if (common->wcmMaxZ == 255)
            ds->pressure = ((data[6] & ZAXIS_BITS) << 1 ) |
                  ((data[3] & ZAXIS_BIT) >> 2) |
                  ((data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x80);

      else
            ds->pressure = (data[6] & ZAXIS_BITS) |
                  (data[6] & ZAXIS_SIGN_BIT) ? 0 : 0x40;

      /* get button state */
      ds->buttons = (data[3] & BUTTONS_BITS) >> 3;

      /* requires button info, so it goes down here. */
      serialParseP4Common(common,data,last,ds);

      xf86WcmEvent(common,0,ds);
      return common->wcmPktLength;
}

static int serialParseProtocol5(WacomCommonPtr common,
      const unsigned char* data)
{
      int n;
      int have_data=0;
      int channel;
      WacomDeviceState* ds;

      /* positive value is skip */
      if ((n = xf86WcmSerialValidate(common,data)) > 0) return n;

      /* Protocol 5 devices support 2 data channels */
      channel = data[0] & 0x01;

      /* pick up where we left off, minus relative values */
      ds = &common->wcmChannel[channel].work;
      RESET_RELATIVE(*ds);

      DBG(7, ErrorF("packet header = %x\n", data[0]));
     
      /* Device ID packet */
      if ((data[0] & 0xfc) == 0xc0)
      {
            /* start from scratch */
            memset(ds, 0, sizeof(*ds));

            ds->proximity = 1;
            ds->device_id = (((data[1] & 0x7f) << 5) |
                        ((data[2] & 0x7c) >> 2));
            ds->serial_num = (((data[2] & 0x03) << 30) |
                        ((data[3] & 0x7f) << 23) |
                        ((data[4] & 0x7f) << 16) |
                        ((data[5] & 0x7f) << 9) |
                        ((data[6] & 0x7f) << 2) |
                        ((data[7] & 0x60) >> 5));

            if ((ds->device_id & 0xf06) != 0x802)
                  ds->discard_first = 1;

            if (STYLUS_TOOL(ds))
                  ds->device_type = STYLUS_ID;
            else if (CURSOR_TOOL(ds))
                  ds->device_type = CURSOR_ID;
            else
                  ds->device_type = ERASER_ID;
  
            DBG(6, ErrorF("device_id=%x serial_num=%u type=%s\n",
                  ds->device_id, ds->serial_num,
                  (ds->device_type == STYLUS_ID) ? "stylus" :
                  (ds->device_type == CURSOR_ID) ? "cursor" :
                  "eraser"));
      }

      /* Out of proximity packet */
      else if ((data[0] & 0xfe) == 0x80)
      {
            ds->proximity = 0;
            have_data = 1;
      }

      /* General pen packet or eraser packet or airbrush first packet
       * airbrush second packet */
      else if (((data[0] & 0xb8) == 0xa0) ||
                  ((data[0] & 0xbe) == 0xb4))
      {
            ds->x = (((data[1] & 0x7f) << 9) |
                        ((data[2] & 0x7f) << 2) |
                        ((data[3] & 0x60) >> 5));
            ds->y = (((data[3] & 0x1f) << 11) |
                        ((data[4] & 0x7f) << 4) |
                        ((data[5] & 0x78) >> 3));
            if ((data[0] & 0xb8) == 0xa0)
            {
                  ds->pressure = (((data[5] & 0x07) << 7) |
                        (data[6] & 0x7f));
                  ds->buttons = (data[0] & 0x06);
            }
            else
            {
                  /* 10 bits for absolute wheel position */
                  ds->abswheel = (((data[5] & 0x07) << 7) |
                        (data[6] & 0x7f));
            }
            ds->tiltx = (data[7] & TILT_BITS);
            ds->tilty = (data[8] & TILT_BITS);
            if (data[7] & TILT_SIGN_BIT)
                  ds->tiltx -= (TILT_BITS + 1);
            if (data[8] & TILT_SIGN_BIT)
                  ds->tilty -= (TILT_BITS + 1);
            ds->proximity = (data[0] & PROXIMITY_BIT);
            have_data = 1;
      } /* end pen packet */

      /* 4D mouse 1st packet or Lens cursor packet or 2D mouse packet*/
      else if (((data[0] & 0xbe) == 0xa8) ||
                  ((data[0] & 0xbe) == 0xb0))
      {
            ds->x = (((data[1] & 0x7f) << 9) |
                        ((data[2] & 0x7f) << 2) |
                        ((data[3] & 0x60) >> 5));
            ds->y = (((data[3] & 0x1f) << 11) |
                        ((data[4] & 0x7f) << 4) |
                        ((data[5] & 0x78) >> 3));
            ds->tilty = 0;

            /* 4D mouse */
            if (MOUSE_4D(ds))
            {
                  ds->throttle = (((data[5] & 0x07) << 7) |
                        (data[6] & 0x7f));
                  if (data[8] & 0x08)
                        ds->throttle = -ds->throttle;
                  ds->buttons = (((data[8] & 0x70) >> 1) |
                        (data[8] & 0x07));
                  have_data = !ds->discard_first;
            }

            /* Lens cursor */
            else if (LENS_CURSOR(ds))
            {
                  ds->buttons = data[8];
                  have_data = 1;
            }

            /* 2D mouse */
            else if (MOUSE_2D(ds))
            {
                  ds->buttons = (data[8] & 0x1C) >> 2;
                  ds->relwheel = - (data[8] & 1) +
                              ((data[8] & 2) >> 1);
                  have_data = 1; /* must send since relwheel is reset */
            }

            ds->proximity = (data[0] & PROXIMITY_BIT);
      } /* end 4D mouse 1st packet */

      /* 4D mouse 2nd packet */
      else if ((data[0] & 0xbe) == 0xaa)
      {
            ds->x = (((data[1] & 0x7f) << 9) |
                  ((data[2] & 0x7f) << 2) |
                  ((data[3] & 0x60) >> 5));
            ds->y = (((data[3] & 0x1f) << 11) |
                  ((data[4] & 0x7f) << 4) |
                  ((data[5] & 0x78) >> 3));
            ds->rotation = (((data[6] & 0x0f) << 7) |
                  (data[7] & 0x7f));
            if (ds->rotation < 900) ds->rotation = -ds->rotation;
            else ds->rotation = 1799 - ds->rotation;
            ds->proximity = (data[0] & PROXIMITY_BIT);
            have_data = 1;
            ds->discard_first = 0;
      }
      else
      {
            DBG(10, ErrorF("unknown wacom V packet %x\n",data[0]));
      }

      /* if new data is available, send it */
      if (have_data)
      {
                  xf86WcmEvent(common,channel,ds);
      }

      /* otherwise, initialize channel and wait for next packet */
      else
      {
            common->wcmChannel[channel].pDev = NULL;
      }
      return common->wcmPktLength;
}

/*****************************************************************************
 * Model-specific functions
 ****************************************************************************/

static void serialInitIntuos(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected an Intuos model\n"));

      common->wcmProtocolLevel = 5;
      common->wcmVersion = version;

      common->wcmMaxZ = 1023;   /* max Z value */
      common->wcmResolX = 2540; /* tablet X resolution in points/inch */
      common->wcmResolY = 2540; /* tablet Y resolution in points/inch */
      common->wcmPktLength = 9; /* length of a packet */
      common->wcmFlags |= TILT_ENABLED_FLAG;
}

static void serialInitIntuos2(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected an Intuos2 model\n"));

      common->wcmProtocolLevel = 5;
      common->wcmVersion = version;

      common->wcmMaxZ = 1023;       /* max Z value */
      common->wcmResolX = 2540;     /* tablet X resolution in points/inch */
      common->wcmResolY = 2540;     /* tablet Y resolution in points/inch */
      common->wcmPktLength = 9;     /* length of a packet */
      common->wcmFlags |= TILT_ENABLED_FLAG;
}

static void serialInitCintiq(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected a Cintiq model\n"));

      common->wcmProtocolLevel = 4;
      common->wcmPktLength = 7;
      common->wcmVersion = version;

      if (id[5] == '2')
      {
            /* PL-250  */
            if ( id[6] == '5' )
            {
                  common->wcmMaxZ = 255;
            }
            /* PL-270  */
            else
            {
                  common->wcmMaxZ = 255;
            }
      }
      else if (id[5] == '3')
      {
            /* PL-300  */
            common->wcmMaxZ = 255;
      }
      else if (id[5] == '4')
      {
            /* PL-400  */
            common->wcmMaxZ = 255;
      }
      else if (id[5] == '5')
      {
            /* PL-550  */
            if ( id[6] == '5' )
            {
                  common->wcmMaxZ = 511;
            }
            /* PL-500  */
            else
            {
                  common->wcmMaxZ = 255;
            }
      }
      else if (id[5] == '6')
      {
            /* PL-600SX  */
            if ( id[8] == 'S' )
            {
                  common->wcmMaxZ = 255;
            }
            /* PL-600  */
            else
            {
                  common->wcmMaxZ = 255;
            }
      }
      else if (id[5] == '8')
      {
            /* PL-800  */
            common->wcmMaxZ = 511;
      }

      common->wcmResolX = 508; /* tablet X resolution in points/inch */
      common->wcmResolY = 508; /* tablet Y resolution in points/inch */
}

static void serialInitPenPartner(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected a PenPartner model\n"));

      common->wcmProtocolLevel = 4;
      common->wcmPktLength = 7;
      common->wcmVersion = version;

      common->wcmMaxZ = 256;
      common->wcmResolX = 1000; /* tablet X resolution in points/inch */
      common->wcmResolY = 1000; /* tablet Y resolution in points/inch */
}

static void serialInitGraphire(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected a Graphire model\n"));

      common->wcmProtocolLevel = 4;
      common->wcmPktLength = 7;
      common->wcmVersion = version;

      /* Graphire models don't answer WC_COORD requests */
      common->wcmMaxX = 5103;
      common->wcmMaxY = 3711;
      common->wcmMaxZ = 512;
      common->wcmResolX = 1000; /* tablet X resolution in points/inch */
      common->wcmResolY = 1000; /* tablet Y resolution in points/inch */
}

static void serialInitProtocol4(WacomCommonPtr common, int fd,
      const char* id, float version)
{
      DBG(2, ErrorF("detected a Protocol4 model\n"));

      common->wcmProtocolLevel = 4;
      common->wcmPktLength = 7;
      common->wcmVersion = version;

      /* If no maxZ is set, determine from version */
      if (!common->wcmMaxZ)
      {
            /* the rom version determines the max z */
            if (version >= (float)1.2)
                  common->wcmMaxZ = 255;
            else
                  common->wcmMaxZ = 120;
      }
}

static void serialGetResolution(WacomCommonPtr common, int fd)
{
      int a, b;
      char buffer[BUFFER_SIZE], header[BUFFER_SIZE];

      if (!(common->wcmResolX && common->wcmResolY))
      {
            DBG(2, ErrorF("Requesting resolution from device\n"));
            if (xf86WcmSendRequest(fd, WC_CONFIG, buffer,
                  sizeof(buffer)))
            {
                  DBG(2, ErrorF("%s\n", buffer));
                  /* The header string is simply a place to put the
                   * unwanted config header don't use buffer+xx because
                   * the header size varies on different tablets */

                  if (sscanf(buffer, "%[^,],%d,%d,%d,%d", header,
                         &a, &b, &common->wcmResolX,
                         &common->wcmResolY) == 5)
                  {
                        DBG(6, ErrorF("WC_CONFIG Header = %s\n",
                              header));
                  }
                  else
                  {
                        ErrorF("WACOM: unable to parse resolution. "
                              "Using default.\n");
                        common->wcmResolX = common->wcmResolY = 1270;
                  }
            }
            else
            {
                  ErrorF("WACOM: unable to read resolution. "
                        "Using default.\n");
                  common->wcmResolX = common->wcmResolY = 1270;
            }
      }

      DBG(2, ErrorF("serialGetResolution: ResolX=%d ResolY=%d\n",
            common->wcmResolX, common->wcmResolY));
}

static int serialGetRanges(WacomCommonPtr common, int fd)
{
      char buffer[BUFFER_SIZE];

      if (!(common->wcmMaxX && common->wcmMaxY))
      {
            DBG(2, ErrorF("Requesting max coordinates\n"));
            if (!xf86WcmSendRequest(fd, WC_COORD, buffer,
                  sizeof(buffer)))
            {
                  ErrorF("WACOM: unable to read max coordinates. "
                        "Use the MaxX and MaxY options.\n");
                  return !Success;
            }
            DBG(2, ErrorF("%s\n", buffer));
            if (sscanf(buffer+2, "%d,%d", &common->wcmMaxX,
                  &common->wcmMaxY) != 2)
            {
                  ErrorF("WACOM: unable to parse max coordinates. "
                        "Use the MaxX and MaxY options.\n");
                  return !Success;
            }
      }

      DBG(2, ErrorF("serialGetRanges: maxX=%d maxY=%d (%g,%g in)\n",
            common->wcmMaxX, common->wcmMaxY,
            (double)common->wcmMaxX / common->wcmResolX,
            (double)common->wcmMaxY / common->wcmResolY));

      return Success;
}

static int serialResetIntuos(WacomCommonPtr common, int fd)
{
      int err;
      SYSCALL(err = xf86WcmWrite(fd, intuos_setup_string,
            strlen(intuos_setup_string)));
      return (err == -1) ? !Success : Success;
}

static int serialResetCintiq(WacomCommonPtr common, int fd)
{
      int err;

      SYSCALL(err = xf86WcmWrite(fd, WC_RESET, strlen(WC_RESET)));
  
      if (xf86WcmWait(75)) return !Success;

      SYSCALL(err = xf86WcmWrite(fd, pl_setup_string,
            strlen(pl_setup_string)));
      if (err == -1) return !Success;

      SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
            strlen(penpartner_setup_string)));

      return (err == -1) ? !Success : Success;
}

static int serialResetPenPartner(WacomCommonPtr common, int fd)
{
      int err;
      SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
            strlen(penpartner_setup_string)));
      return (err == -1) ? !Success : Success;
}

static int serialResetProtocol4(WacomCommonPtr common, int fd)
{
      int err;

      SYSCALL(err = xf86WcmWrite(fd, WC_RESET, strlen(WC_RESET)));
  
      if (xf86WcmWait(75)) return !Success;

      SYSCALL(err = xf86WcmWrite(fd, setup_string,
            strlen(setup_string)));
      if (err == -1) return !Success;

      SYSCALL(err = xf86WcmWrite(fd, penpartner_setup_string,
            strlen(penpartner_setup_string)));
      return (err == -1) ? !Success : Success;
}

static int serialEnableTiltProtocol4(WacomCommonPtr common, int fd)
{
      return Success;
}

static int serialEnableSuppressProtocol4(WacomCommonPtr common, int fd)
{
      char buf[20];
      int err;

      sprintf(buf, "%s%d\r", WC_SUPPRESS, common->wcmSuppress);
      SYSCALL(err = xf86WcmWrite(fd, buf, strlen(buf)));

      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n",
                  strerror(errno));
            return !Success;
      }
      return Success;
}

static int serialSetLinkSpeedIntuos(WacomCommonPtr common, int fd)
{
      if ((common->wcmLinkSpeed == 38400) &&
            (common->wcmVersion < 2.0F))
      {
            ErrorF("Wacom: 38400 speed not supported with this Intuos "
                  "firmware (%f)\n", common->wcmVersion);
            ErrorF("Switching to 19200\n");
            common->wcmLinkSpeed = 19200;
      }
      return serialSetLinkSpeedProtocol5(common,fd);
}

static int serialSetLinkSpeedProtocol5(WacomCommonPtr common, int fd)
{
      int err;
      char* speed_init_string;

      DBG(1, ErrorF("Switching serial link to %d\n",
            common->wcmLinkSpeed));

      /* set init string according to speed */
      speed_init_string = (common->wcmLinkSpeed == 38400) ?
            WC_V_38400 : WC_V_19200;

      /* Switch the tablet to the requested speed */
      SYSCALL(err = xf86WcmWrite(fd, speed_init_string,
            strlen(speed_init_string)));

      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }

      /* Wait 75 mSecs */
      if (xf86WcmWait(75))
            return !Success;

      /* Set speed of serial link to requested speed */
      if (xf86WcmSetSerialSpeed(fd, common->wcmLinkSpeed) < 0)
            return !Success;

      return Success;
}

static int serialStartTablet(WacomCommonPtr common, int fd)
{
      int err;

      /* Tell the tablet to start sending coordinates */
      SYSCALL(err = xf86WcmWrite(fd, WC_START, strlen(WC_START)));

      if (err == -1)
      {
            ErrorF("Wacom xf86WcmWrite error : %s\n", strerror(errno));
            return !Success;
      }

      return Success;
}

static void serialParseP4Common(WacomCommonPtr common,
      const unsigned char* data, WacomDeviceState* last,
      WacomDeviceState* ds)
{
      int is_stylus = (data[0] & POINTER_BIT);
      int cur_type = is_stylus ?
            ((ds->buttons & 4) ? ERASER_ID : STYLUS_ID) :
            CURSOR_ID;

      /* proximity bit */
      ds->proximity = (data[0] & PROXIMITY_BIT);

      /* x and y coordinates */
      ds->x = (((data[0] & 0x3) << 14) + (data[1] << 7) + data[2]);
      ds->y = (((data[3] & 0x3) << 14) + (data[4] << 7) + data[5]);

      /* first time into prox */
      if (!last->proximity && ds->proximity) 
            ds->device_type = cur_type;

      /* check on previous proximity */
      else if (is_stylus)
      {
            /* we were fooled by tip and second
             * sideswitch when it came into prox */
            if ((ds->device_type != cur_type) &&
                  (ds->device_type == ERASER_ID))
            {
                  /* send a prox-out for old device */
                  WacomDeviceState out = { 0 };
                  xf86WcmEvent(common,0,&out);
                  ds->device_type = cur_type;
            }
      }

      DBG(8, ErrorF("serialParseP4Common %s\n",
            ds->device_type == CURSOR_ID ? "CURSOR" :
            ds->device_type == ERASER_ID ? "ERASER " :
            ds->device_type == STYLUS_ID ? "STYLUS" : "NONE"));

      /* handle tilt values only for stylus */
      if (HANDLE_TILT(common) && is_stylus)
      {
            ds->tiltx = (data[7] & TILT_BITS);
            ds->tilty = (data[8] & TILT_BITS);
            if (data[7] & TILT_SIGN_BIT)
                  ds->tiltx -= 64;
            if (data[8] & TILT_SIGN_BIT)
                  ds->tilty -= 64;
      }
}

/*****************************************************************************
 * xf86WcmSerialValidate -- validates serial packet; returns 0 on success,
 *   positive number of bytes to skip on error.
 ****************************************************************************/

int xf86WcmSerialValidate(WacomCommonPtr common, const unsigned char* data)
{
      int i, bad = 0;

      /* check magic */
      for (i=0; i<common->wcmPktLength; ++i)
      {
            if ( ((i==0) && !(data[i] & HEADER_BIT)) || 
                        ((i!=0) && (data[i] & HEADER_BIT)) )
            {
                  bad = 1;
                  DBG(10, ErrorF("xf86WcmSerialValidate: bad magic at %d "
                        "v=%x l=%d\n", i, data[i], common->wcmPktLength));
                  if (i!=0 && (data[i] & HEADER_BIT)) return i;
            }
      }
      if (bad) return common->wcmPktLength;
      else return 0;
}


Generated by  Doxygen 1.6.0   Back to index