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

wcmUSB.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 "wcmFilter.h"

#ifdef LINUX_INPUT
static Bool usbDetect(LocalDevicePtr);
static Bool usbInit(LocalDevicePtr pDev);

static void usbInitProtocol5(WacomCommonPtr common, int fd, const char* id,
      float version);
static void usbInitProtocol4(WacomCommonPtr common, int fd, const char* id,
      float version);
static int usbGetRanges(WacomCommonPtr common, int fd);
static int usbParse(WacomCommonPtr common, const unsigned char* data);
static void usbParseEvent(WacomCommonPtr common,
      const struct input_event* event);
static void usbParseChannel(WacomCommonPtr common, int channel, int serial);

      WacomDeviceClass gWacomUSBDevice =
      {
            usbDetect,
            usbInit,
            xf86WcmReadPacket,
      };

      static WacomModel usbUnknown =
      {
            "Unknown USB",
            usbInitProtocol5,     /* assume the best */
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            NULL,                 /* input filtering not needed */
      };

      static WacomModel usbPenPartner =
      {
            "USB PenPartner",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterCoord,   /* input filtering */
      };

      static WacomModel usbGraphire =
      {
            "USB Graphire",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterCoord,   /* input filtering */
      };

      static WacomModel usbGraphire2 =
      {
            "USB Graphire2",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterCoord,   /* input filtering */
      };

      static WacomModel usbGraphire3 =
      {
            "USB Graphire3",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterCoord,   /* input filtering */
      };

      static WacomModel usbCintiq =
      {
            "USB Cintiq",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmHysteresisFilter,   /* input filtering */
      };

      static WacomModel usbCintiqPartner =
      {
            "USB CintiqPartner",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmHysteresisFilter,   /* input filtering */
      };

      static WacomModel usbIntuos =
      {
            "USB Intuos",
            usbInitProtocol5,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterIntuos,  /* input filtering recommended */
      };

      static WacomModel usbIntuos2 =
      {
            "USB Intuos2",
            usbInitProtocol5,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterIntuos,  /* input filtering recommended */
      };

      static WacomModel usbIntuos3 =
      {
            "USB Intuos3",
            usbInitProtocol5,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterIntuos,  /* input filtering recommended */
      };

      static WacomModel usbVolito =
      {
            "USB Volito",
            usbInitProtocol4,
            NULL,                 /* resolution not queried */
            usbGetRanges,
            NULL,                 /* reset not supported */
            NULL,                 /* tilt automatically enabled */
            NULL,                 /* suppress implemented in software */
            NULL,                 /* link speed unsupported */
            NULL,                 /* start not supported */
            usbParse,
            xf86WcmFilterCoord,   /* input filtering */
      };


/*****************************************************************************
 * usbDetect --
 *   Test if the attached device is USB.
 ****************************************************************************/

static Bool usbDetect(LocalDevicePtr local)
{
      int version;
      int err;

      DBG(1, ErrorF("usbDetect\n"));
    
      SYSCALL(err = ioctl(local->fd, EVIOCGVERSION, &version));
    
      if (!err)
      {
/*          ErrorF("%s Wacom Kernel Input driver version is %d.%d.%d\n",
                        XCONFIG_PROBED, version >> 16,
                        (version >> 8) & 0xff, version & 0xff);
*/          return 1;
      }

      return 0;
}

/*****************************************************************************
 * usbInit --
 ****************************************************************************/

static Bool usbInit(LocalDevicePtr local)
{
      short sID[4];
      char id[BUFFER_SIZE];
      WacomModelPtr model = NULL;
      WacomDevicePtr priv = (WacomDevicePtr)local->private;
      WacomCommonPtr common = priv->common;

      DBG(1, ErrorF("initializing USB tablet\n"));    

      /* fetch vendor, product, and model name */
      ioctl(local->fd, EVIOCGID, sID);
      ioctl(local->fd, EVIOCGNAME(sizeof(id)), id);

      /* vendor is wacom */
      if (sID[1] == 0x056A)
      {
            /* switch on product */
            switch (sID[2])
            {
                  case 0x00: /* PenPartner */
                        model = &usbPenPartner; break;

                  case 0x10: /* Graphire */
                        model = &usbGraphire; break;

                  case 0x11: /* Graphire2 4x5 */
                  case 0x12: /* Graphire2 5x7 */
                        model = &usbGraphire2; break;

                  case 0x13: /* Graphire3 4x5 */
                  case 0x14: /* Graphire3 6x8 */
                        model = &usbGraphire3; break;

                  case 0x20: /* Intuos 4x5 */
                  case 0x21: /* Intuos 6x8 */
                  case 0x22: /* Intuos 9x12 */
                  case 0x23: /* Intuos 12x12 */
                  case 0x24: /* Intuos 12x18 */
                        model = &usbIntuos; break;

                  case 0x03: /* PTU600 */
                        model = &usbCintiqPartner; break;

                  case 0x30: /* PL400 */
                  case 0x31: /* PL500 */
                  case 0x32: /* PL600 */
                  case 0x33: /* PL600SX */
                  case 0x34: /* PL550 */
                  case 0x35: /* PL800 */
                        model = &usbCintiq; break;

                  case 0x41: /* Intuos2 4x5 */
                  case 0x42: /* Intuos2 6x8 */
                  case 0x43: /* Intuos2 9x12 */
                  case 0x44: /* Intuos2 12x12 */
                  case 0x45: /* Intuos2 12x18 */
                  case 0x47: /* Intuos2 6x8 (verified in the field) */
                        model = &usbIntuos2; break;

                  case 0x60: /* Volito */
                        model = &usbVolito; break;

                  case 0xB0: /* Intuos3 4x5 */
                  case 0xB1: /* Intuos3 6x8 */
                  case 0xB2: /* Intuos3 9x12 */
                        model = &usbIntuos3; break;
            }
      }

      if (!model)
            model = &usbUnknown;

      return xf86WcmInitTablet(common,model,local->fd,id,0.0);
}

static void usbInitProtocol5(WacomCommonPtr common, int fd, const char* id,
      float version)
{
      DBG(2, ErrorF("detected a protocol 5 model (%s)\n",id));
      common->wcmProtocolLevel = 5;
      if ( strstr(id, "Intuos3") )
      {
            common->wcmChannelCnt = 1;
            common->wcmResolX = common->wcmResolY = 5080;
      }
      else
      {
            common->wcmChannelCnt = 2;
            common->wcmResolX = common->wcmResolY = 2540;
      }
      common->wcmPktLength = sizeof(struct input_event);
}

static void usbInitProtocol4(WacomCommonPtr common, int fd, const char* id,
      float version)
{
      DBG(2, ErrorF("detected a protocol 4 model (%s)\n",id));
      common->wcmResolX = common->wcmResolY = 1016;
      common->wcmProtocolLevel = 4;
      common->wcmPktLength = sizeof(struct input_event);
}

#define BIT(x) (1<<(x))
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y))
#define OFF(x)   ((x)%BITS_PER_LONG)
#define LONG(x)  ((x)/BITS_PER_LONG)

static int usbGetRanges(WacomCommonPtr common, int fd)
{
      int nValues[5];
      unsigned long ev[NBITS(EV_MAX)];
      unsigned long abs[NBITS(ABS_MAX)];

      if (ioctl(fd, EVIOCGBIT(0 /*EV*/, sizeof(ev)), ev) < 0)
      {
            ErrorF("WACOM: unable to ioctl event bits.\n");
            return !Success;
      }

      /* absolute values */
      if (ISBITSET(ev,EV_ABS))
      {
            if (ioctl(fd, EVIOCGBIT(EV_ABS,sizeof(abs)),abs) < 0)
            {
                  ErrorF("WACOM: unable to ioctl abs bits.\n");
                  return !Success;
            }

            /* max x */
            if (common->wcmMaxX == 0)
            {
                  if (ioctl(fd, EVIOCGABS(ABS_X), nValues) < 0)
                  {
                        ErrorF("WACOM: unable to ioctl xmax value.\n");
                        return !Success;
                  }
                  common->wcmMaxX = nValues[2];
                  if (common->wcmMaxX <= 0)
                  {
                        ErrorF("WACOM: xmax value is wrong.\n");
                        return !Success;
                  }
            }

            /* max y */
            if (common->wcmMaxY == 0)
            {
                  if (ioctl(fd, EVIOCGABS(ABS_Y), nValues) < 0)
                  {
                        ErrorF("WACOM: unable to ioctl ymax value.\n");
                        return !Success;
                  }
                  common->wcmMaxY = nValues[2];
                  if (common->wcmMaxY <= 0)
                  {
                        ErrorF("WACOM: ymax value is wrong.\n");
                        return !Success;
                  }
            }

            /* max z cannot be configured */
            if (ioctl(fd, EVIOCGABS(ABS_PRESSURE), nValues) < 0)
            {
                  ErrorF("WACOM: unable to ioctl press max value.\n");
                  return !Success;
            }
            common->wcmMaxZ = nValues[2];
            if (common->wcmMaxZ <= 0)
            {
                  ErrorF("WACOM: press max value is wrong.\n");
                  return !Success;
            }
      }
      else
      {
            ErrorF("WACOM: unable to ioctl max values.\n");
            return !Success;
      }

      return Success;
}

static int usbParse(WacomCommonPtr common, const unsigned char* data)
{
      usbParseEvent(common,(const struct input_event*)data);
      return common->wcmPktLength;
}

static void usbParseEvent(WacomCommonPtr common,
      const struct input_event* event)
{
      int i, serial, channel;

      /* store events until we receive the MSC_SERIAL containing
       * the serial number; without it we cannot determine the
       * correct channel. */

      /* space left? bail if not. */
      if (common->wcmEventCnt >=
            (sizeof(common->wcmEvents)/sizeof(*common->wcmEvents)))
      {
            DBG(1, ErrorF("usbParse: Exceeded event queue (%d)\n",
                        common->wcmEventCnt));
            common->wcmEventCnt = 0;
            return;
      }

      /* save it for later */
      common->wcmEvents[common->wcmEventCnt++] = *event;

      /* packet terminated by MSC_SERIAL on kernel 2.4 and SYN_REPORT on kernel 2.6 */
      if ((event->type != EV_MSC) || (event->code != MSC_SERIAL))
      {
#ifdef EV_SYN
            /* none serial number tools fall here */
            if ((event->type == EV_SYN) && (event->code == SYN_REPORT) 
                  && (common->wcmChannelCnt == 1))
            {
                  usbParseChannel(common,0,0);
                  common->wcmEventCnt = 0;
            }
#endif
            return;
      }
      /* serial number is key for channel */
      serial = event->value;
      channel = -1;

      /* one channel only? */
      if (common->wcmChannelCnt == 1)
      {
            /* Intuos3 Pad */
            if (serial == 0xffffffff)
            {
                  channel = 1;
                  (&common->wcmChannel[channel].work)->device_type = PAD_ID;
                  (&common->wcmChannel[channel].work)->proximity = 1;
            }
            else   /* must be it. */
            {
                  channel = 0;
                  if (common->wcmChannel[0].work.proximity == 0)
                  {
                        memset(&common->wcmChannel[0],0,
                                    sizeof(WacomChannel));
                  }
            }
      }

      /* otherwise, find the channel */
      else
      {
            /* clear out channels */
            for (i=0; i<common->wcmChannelCnt; ++i)
            {
                  if (common->wcmChannel[i].work.proximity == 0)
                  {
                        memset(&common->wcmChannel[i],0,
                                    sizeof(WacomChannel));
                  }
            }
            /* find existing channel */
            for (i=0; i<common->wcmChannelCnt; ++i)
            {
                  if (common->wcmChannel[i].work.serial_num == serial)
                  {
                        channel = i;
                        break;
                  }
            }

            /* find an empty channel */
            if (channel < 0)
            {
                  for (i=0; i<common->wcmChannelCnt; ++i)
                  {
                        if (common->wcmChannel[i].work.proximity == 0)
                        {
                              channel = i;
                              /* the in-prox event was missing */
                              common->wcmChannel[i].work.proximity = 1;
                              break;
                        }
                  }
            }

            /* fresh out of channels */
            if (channel < 0)
            {
                  /* this should never happen in normal use */
                  DBG(1, ErrorF("usbParse: Exceeded channel count; "
                        "ignoring.\n"));
                  return;
            }
      }

      usbParseChannel(common,channel,serial);

      common->wcmEventCnt = 0;
}

static void usbParseChannel(WacomCommonPtr common, int channel, int serial)
{
      int i, shift;
      WacomDeviceState* ds;
      struct input_event* event;

      #define MOD_BUTTONS(bit, value) do { \
            shift = 1<<bit; \
            ds->buttons = (((value) != 0) ? \
            (ds->buttons | (shift)) : (ds->buttons & ~(shift))); \
            } while (0)

      /* all USB data operates from previous context except relative values*/
      ds = &common->wcmChannel[channel].work;
      ds->relwheel = 0;
      ds->serial_num = serial;

      /* loop through all events in group */
      for (i=0; i<common->wcmEventCnt; ++i)
      {
            event = common->wcmEvents + i;
            DBG(11, ErrorF("usbParseChannel event[%d]->type=%d "
                  "code=%d value=%d\n", i, event->type,
                  event->code, event->value));

            /* absolute events */
            if (event->type == EV_ABS)
            {
                  if (event->code == ABS_X)
                        ds->x = event->value;
                  else if (event->code == ABS_Y)
                        ds->y = event->value;
                  else if (event->code == ABS_RX)
                        ds->stripx = event->value; 
                  else if (event->code == ABS_RY)
                        ds->stripy = event->value;
                  else if (event->code == ABS_RZ)
                        ds->rotation = event->value;
                  else if (event->code == ABS_TILT_X)
                        ds->tiltx = event->value - 64;
                  else if (event->code ==  ABS_TILT_Y)
                        ds->tilty = event->value - 64;
                  else if (event->code == ABS_PRESSURE)
                        ds->pressure = event->value;
                  else if (event->code == ABS_DISTANCE)
                        ds->distance = event->value;
                  else if (event->code == ABS_WHEEL)
                        ds->abswheel = event->value;
                  else if (event->code == ABS_THROTTLE)
                        ds->throttle = event->value;
            }
            else if (event->type == EV_REL)
            {
                  if (event->code == REL_WHEEL)
                        ds->relwheel = event->value;
                  else
                        ErrorF("wacom: rel event recv'd (%d)!\n", event->code);
            }

            else if (event->type == EV_KEY)
            {
                  if ((event->code == BTN_TOOL_PEN) ||
                        (event->code == BTN_TOOL_PENCIL) ||
                        (event->code == BTN_TOOL_BRUSH) ||
                        (event->code == BTN_TOOL_AIRBRUSH))
                  {
                        ds->device_type = STYLUS_ID;
                        ds->proximity = (event->value != 0);
                        DBG(6, ErrorF("USB stylus detected %x\n",
                              event->code));
                  }
                  else if (event->code == BTN_TOOL_RUBBER)
                  {
                        ds->device_type = ERASER_ID;
                        ds->proximity = (event->value != 0);
                        if (ds->proximity) 
                              ds->proximity = ERASER_PROX;
                        DBG(6, ErrorF("USB eraser detected %x\n",
                              event->code));
                  }
                  else if ((event->code == BTN_TOOL_MOUSE) ||
                        (event->code == BTN_TOOL_LENS))
                  {
                        DBG(6, ErrorF("USB mouse detected %x\n",
                              event->code));
                        ds->device_type = CURSOR_ID;
                        ds->proximity = (event->value != 0);
                  }
                  else if (event->code == BTN_TOOL_FINGER)
                  {
                        DBG(6, ErrorF("USB Intuos3 Pad detected %x\n",
                              event->code));
                        ds->device_type = PAD_ID;
                        ds->proximity = (event->value != 0);
                  }
                  else if (event->code == BTN_TOUCH)
                  {
                        /* we use the pressure to determine the button 1 */
                  }
                  else if ((event->code == BTN_STYLUS) ||
                        (event->code == BTN_MIDDLE))
                  {
                        MOD_BUTTONS (1, event->value);
                  }
                  else if ((event->code == BTN_STYLUS2) ||
                        (event->code == BTN_RIGHT))
                  {
                        MOD_BUTTONS (2, event->value);
                  }
                  else if (event->code == BTN_LEFT)
                        MOD_BUTTONS (0, event->value);
                  else if (event->code == BTN_SIDE)
                        MOD_BUTTONS (3, event->value);
                  else if (event->code == BTN_EXTRA)
                        MOD_BUTTONS (4, event->value);
                  else if (event->code == BTN_0)
                        MOD_BUTTONS (8, event->value);
                  else if (event->code == BTN_1)
                        MOD_BUTTONS (9, event->value);
                  else if (event->code == BTN_2)
                        MOD_BUTTONS (10, event->value);
                  else if (event->code == BTN_3)
                        MOD_BUTTONS (11, event->value);
                  else if (event->code == BTN_4)
                        MOD_BUTTONS (12, event->value);
                  else if (event->code == BTN_5)
                        MOD_BUTTONS (13, event->value);
                  else if (event->code == BTN_6)
                        MOD_BUTTONS (14, event->value);
                  else if (event->code == BTN_7)
                        MOD_BUTTONS (15, event->value);
            }
      } /* next event */      

      /* dispatch event */
      xf86WcmEvent(common, channel, ds);
}

#endif /* LINUX_INPUT */

Generated by  Doxygen 1.6.0   Back to index