xref: /haiku/src/add-ons/input_server/devices/wacom/TabletDevice.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
1  /*
2   * Copyright 2003-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3   * Distributed under the terms of the MIT license.
4   *
5   * Copyright 2000-2002  Olaf van Es. All Rights Reserved.
6   * Distributed under the terms of the MIT license.
7   *
8   * These people have added and tested device ids:
9   *
10   *		Frans van Nispen	<frans@xentronix.com>
11   *		Stefan Werner		<stefan@keindesign.de>
12   *		Hiroyuki Tsutsumi	<???>
13   *		Jeroen Oortwijn		<oortwijn@gmail.com>
14   */
15  
16  #include <stdio.h>
17  #include <stdlib.h>
18  #include <string.h>
19  
20  #include <File.h>
21  #include <InterfaceDefs.h>
22  #include <Screen.h>
23  #include <View.h>
24  
25  #include "DeviceReader.h"
26  #include "MasterServerDevice.h"
27  
28  #include "TabletDevice.h"
29  
30  #define SNOOZE_AMOUNT 2500
31  #define JITTER_X .0007
32  #define JITTER_Y .0007
33  #define ACCELERATION_KICK_IN 2.3
34  
35  // constructor
36  TabletDevice::TabletDevice(MasterServerDevice* parent, DeviceReader* reader)
37  	: PointingDevice(parent, reader),
38  	  fThreadID(B_ERROR),
39  	  fDeviceMode(DEVICE_UNKOWN),
40  	  fMaxX(1.0),
41  	  fMaxY(1.0),
42  	  fPosX(0.5),
43  	  fPosY(0.5),
44  	  fFakeMouseX(0.5),
45  	  fFakeMouseY(0.5),
46  	  fButtons(0),
47  	  fPressure(0.0),
48  	  fModifiers(0),
49  	  fEraser(0),
50  	  fTiltX(0.0),
51  	  fTiltY(0.0),
52  	  fClicks(0),
53  	  fHasContact(false)
54  {
55  }
56  
57  // destructor
58  TabletDevice::~TabletDevice()
59  {
60  	// cleanup
61  	Stop();
62  }
63  
64  // InitCheck
65  status_t
66  TabletDevice::InitCheck()
67  {
68  	status_t status = PointingDevice::InitCheck();
69  	if (status >= B_OK)
70  		status = DetectDevice(fReader);
71  	return status;
72  }
73  
74  // Start
75  status_t
76  TabletDevice::Start()
77  {
78  	status_t status = B_NO_INIT;
79  	if (fReader) {
80  		fActive = true;
81  		// get a nice name for our polling thread
82  		const char* name;
83  		_GetName(fReader->ProductID(), &name);
84  		// start generating events
85  		fThreadID = spawn_thread(poll_usb_device, name, 104, this);
86  		if (fThreadID >= B_OK) {
87  			resume_thread(fThreadID);
88  			status = B_OK;
89  		} else
90  			status = fThreadID;
91  	}
92  	return status;
93  }
94  
95  // Stop
96  status_t
97  TabletDevice::Stop()
98  {
99  	status_t err = B_OK;
100  
101  	fActive = false;
102  	if (fThreadID >= B_OK)
103  		wait_for_thread(fThreadID, &err);
104  	fThreadID = B_ERROR;
105  
106  	return err;
107  }
108  
109  // DetectDevice
110  status_t
111  TabletDevice::DetectDevice(const DeviceReader* reader)
112  {
113  	status_t status = B_OK;
114  	switch (reader->ProductID()) {
115  		case 0x00:
116  			SetDevice(5040.0, 3780.0, DEVICE_PENPARTNER);
117  			break;
118  		case 0x03:
119  			SetDevice(2048.0, 15360.0, DEVICE_PL500);
120  			break;
121  		case 0x10:
122  		case 0x11:
123  		case 0x13:
124  			SetDevice(10206.0, 7422.0, DEVICE_GRAPHIRE);
125  			break;
126  		case 0x12:	// Graphire 3 4x5
127  			SetDevice(13918.0, 10206.0, DEVICE_GRAPHIRE);
128  			break;
129  		case 0x14:	// Graphire 3 6x8
130  			SetDevice(16704.0, 12064.0, DEVICE_GRAPHIRE);
131  			break;
132  		case 0x15:	// Graphire 4 4x5 (tested)
133  			SetDevice(10208.0, 7024.0, DEVICE_GRAPHIRE);
134  			break;
135  		case 0x16:	// Graphire 4 6x8 (tested)
136  			SetDevice(16704.0, 12064.0, DEVICE_GRAPHIRE);
137  			break;
138  		case 0x17:	// BambooFun 4x5 (from Linux Wacom Project)
139  			SetDevice(14760.0, 9225.0, DEVICE_BAMBOO);
140  			break;
141  		case 0x18:	// BambooFun 6x8 (from Linux Wacom Project)
142  			SetDevice(21648.0, 13530.0, DEVICE_BAMBOO);
143  			break;
144  		case 0x20:
145  			SetDevice(12700.0, 10600.0, DEVICE_INTUOS);
146  			break;
147  		case 0x21:
148  			SetDevice(20320.0, 16240.0);
149  			break;
150  		case 0x22:
151  			SetDevice(30480.0, 24060.0);
152  			break;
153  		case 0x23:
154  			SetDevice(30480.0, 31680.0);
155  			break;
156  		case 0x24:
157  			SetDevice(45720.0, 31680.0);
158  			break;
159  		case 0x30:
160  			SetDevice(5408.0, 4056.0, DEVICE_PL500);
161  			break;
162  		case 0x31:
163  			SetDevice(6144.0, 4608.0, DEVICE_PL500);
164  			break;
165  		case 0x32:
166  			SetDevice(6126.0, 4604.0, DEVICE_PL500);
167  			break;
168  		case 0x33:
169  			SetDevice(6260.0, 5016.0, DEVICE_PL500);
170  			break;
171  		case 0x34:
172  			SetDevice(6144.0, 4608.0, DEVICE_PL500);
173  			break;
174  		case 0x35:
175  			SetDevice(7220.0, 5780.0, DEVICE_PL500);
176  			break;
177  		case 0x3F:
178  			SetDevice(87200.0, 65600.0, DEVICE_CINTIQ);
179  			break;
180  		case 0x41:
181  			SetDevice(12700.0, 10600.0);
182  			break;
183  		case 0x42:
184  			SetDevice(20320.0, 16240.0);
185  			break;
186  		case 0x43:
187  			SetDevice(30480.0, 24060.0);
188  			break;
189  		case 0x44:
190  			SetDevice(30480.0, 31680.0);
191  			break;
192  		case 0x45:
193  			SetDevice(45720.0, 31680.0);
194  			break;
195  		case 0x47:	// some I2 6x8 report as 0x47
196  			SetDevice(20320.0, 16240.0);
197  			break;
198  		case 0x60:
199  			SetDevice(5104.0, 3712.0, DEVICE_GRAPHIRE);
200  			break;
201  		case 0x61: // PenStation
202  //			SetDevice(3403.0, 2475.0, DEVICE_GRAPHIRE); // this version was untested
203  			SetDevice(3248.0, 2320.0, DEVICE_PENSTATION); // this version came from "beer"
204  			break;
205  		case 0x62: // Volito
206  			SetDevice(5040.0, 3712.0, DEVICE_VOLITO);
207  			break;
208  		case 0x64:	// PenPartner.1
209  //			SetDevice(3450.0, 2100.0, DEVICE_PENSTATION);
210  			SetDevice(3248.0, 2320.0, DEVICE_PENSTATION);
211  			break;
212  		case 0x65:	// Bamboo (from Linux Wacom Project)
213  			SetDevice(14760.0, 9225.0, DEVICE_BAMBOO);
214  			break;
215  		case 0x69:	// Bamboo1 (from Linux Wacom Project)
216  			SetDevice(5104.0,  3712.0, DEVICE_BAMBOO);
217  			break;
218  		case 0xB0:
219  			SetDevice(25400.0, 20320.0, DEVICE_INTUOS3);
220  			break;
221  		case 0xB1:
222  			SetDevice(40640.0, 30480.0, DEVICE_INTUOS3);
223  			break;
224  		case 0xB2:
225  			SetDevice(60960.0, 45720.0, DEVICE_INTUOS3);
226  			break;
227  		case 0xD0:	// Wacom Bamboo 2FG (from Linux Wacom Project)
228  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
229  			break;
230  		case 0xD1:	// Wacom BambooFun 2FG 4x5 (from Linux Wacom Project)
231  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
232  			break;
233  		case 0xD2:	// Wacom Bamboo Craft (from Linux Wacom Project)
234  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
235  			break;
236  		case 0xD3:	// Wacom BambooFun 2FG 6x8 (from Linux Wacom Project)
237  			SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
238  			break;
239  		case 0xD4:	// Wacom Bamboo 4x5 (from Linux Wacom Project)
240  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
241  			break;
242  		case 0xD6:	// Wacom Bamboo CTH-460/K (from Linux Wacom Project)
243  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
244  			break;
245  		case 0xD7:	// Wacom Bamboo CTH-461/S (from Linux Wacom Project)
246  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
247  			break;
248  		case 0xD8:	// Wacom Bamboo CTH-661/S1 (from Linux Wacom Project)
249  			SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
250  			break;
251  		case 0xDA:	// Wacom Bamboo CTH-461/L (from Linux Wacom Project)
252  			SetDevice(14720.0, 9200.0, DEVICE_BAMBOO_PT);
253  			break;
254  		case 0xDB:	// Wacom Bamboo CTH-661 (from Linux Wacom Project)
255  			SetDevice(21648.0, 13530.0, DEVICE_BAMBOO_PT);
256  			break;
257  		default:
258  			status = B_BAD_VALUE;
259  			break;
260  	}
261  	return status;
262  }
263  
264  // SetDevice
265  void
266  TabletDevice::SetDevice(float maxX, float maxY, uint32 mode)
267  {
268  	fDeviceMode = mode;
269  	fMaxX = maxX;
270  	fMaxY = maxY;
271  	fJitterX = JITTER_X;
272  	fJitterY = JITTER_Y;
273  }
274  
275  // ReadData
276  void
277  TabletDevice::ReadData(const uchar* data, int dataBytes, bool& hasContact,
278  	uint32& mode, uint32& buttons, float& x, float& y, float& pressure,
279  	int32& clicks, int32& eraser, float& wheelX, float& wheelY,
280  	float& tiltX, float& tiltY) const
281  {
282  	hasContact = false;
283  	buttons = 0;
284  	mode = MODE_PEN;
285  	bool firstButton = false;
286  	bool secondButton = false;
287  	bool thirdButton = false;
288  	uint16 xPos = 0;
289  	uint16 yPos = 0;
290  
291  	switch (fDeviceMode) {
292  		case DEVICE_PENPARTNER: {
293  			xPos = data[2] << 8 | data[1];
294  			yPos = data[4] << 8 | data[3];
295  
296  			eraser = (data[5] & 0x20);
297  
298  			int8 pressureData = data[6];
299  			pressure = (float)(pressureData + 120) / 240.0;
300  
301  			firstButton = ((pressureData > -80) && !(data[5] & 0x20));
302  			secondButton = (data[5] & 0x40);
303  
304  			hasContact = true;
305  			break;
306  		}
307  		case DEVICE_GRAPHIRE:
308  		case DEVICE_BAMBOO:
309  		{
310  			xPos = data[3] << 8 | data[2];
311  			yPos = data[5] << 8 | data[4];
312  
313  			hasContact = (data[1] & 0x80);
314  
315  			uint16 pressureData = data[7] << 8 | data[6];
316  			pressure = (float)pressureData / 511.0;
317  			eraser = (data[1] & 0x20);
318  
319  			// mouse wheel support
320  			if (data[1] & 0x40) {	// mouse is on tablet!
321  				wheelY = (float)(int8)data[6];
322  				mode = MODE_MOUSE;
323  				// override contact to loose it as soon as possible
324  				// when mouse is lifted from tablet
325  				hasContact = (uint8)data[7] >= 30;
326  				pressure = 0.0;
327  				eraser = 0;
328  			}
329  
330  			firstButton = pressure > 0.0 ? true : (data[1] & 0x01);
331  			secondButton = (data[1] & 0x02);
332  			thirdButton = (data[1] & 0x04);
333  
334  			break;
335  		}
336  		case DEVICE_BAMBOO_PT:
337  		{
338  			if (dataBytes < 20) {	// ignore touch-packets
339  				xPos = data[3] << 8 | data[2];
340  				yPos = data[5] << 8 | data[4];
341  
342  				hasContact = (data[1] & 0x20);
343  
344  				uint16 pressureData = data[7] << 8 | data[6];
345  				pressure = (float)pressureData / 1023.0;
346  				eraser = (data[1] & 0x08);
347  
348  				firstButton = (data[1] & 0x01);
349  				secondButton = (data[1] & 0x02);
350  				thirdButton = (data[1] & 0x04);
351  
352  				break;
353  			}
354  		}
355  		case DEVICE_INTUOS:
356  		case DEVICE_INTUOS3:
357  		case DEVICE_CINTIQ:
358  			if ((data[0] == 0x02) && !(((data[1] >> 5) & 0x03) == 0x02)) {
359  				if (fDeviceMode == DEVICE_INTUOS3) {
360  					xPos = (data[2] << 9) | (data[3] << 1)
361  						| ((data[9] >> 1) & 1);
362  					yPos = (data[4] << 9) | (data[5] << 1) | (data[9] & 1);
363  				} else {
364  					xPos = (data[2] << 8) | data[3];
365  					yPos = (data[4] << 8) | data[5];
366  				}
367  				uint16 pressureData = data[6] << 2 | ((data[7] >> 6) & 0x03);
368  				pressure = (float)pressureData / 1023.0;
369  
370  				// mouse and wheel support
371  				if (data[1] == 0xf0) {	// mouse is on tablet!
372  					mode = MODE_MOUSE;
373  
374  					if (data[8] == 0x02)
375  						wheelY = 1.0;
376  					else if (data[8] == 0x01)
377  						wheelY = -1.0;
378  
379  					firstButton = (data[8] & 0x04);
380  					secondButton = (data[8] & 0x10);
381  					thirdButton = (data[8] & 0x08);
382  
383  					// override contact to loose it as soon as possible
384  					// when mouse is lifted from tablet
385  					hasContact = data[9] <= 0x68;
386  					pressure = 0.0;
387  					eraser = 0;
388  				} else {
389  //					eraser = (data[1] & 0x20); // eraser is een tool-id
390  //					firstButton = (pressureData > 0) && data[9] <= 0x68;// > 180);
391  //					firstButton = (pressureData > 180);
392  					firstButton = (data[6] > 0);
393  					secondButton = (data[1] & 0x02);
394  					thirdButton = (data[1] & 0x04);
395  					hasContact = (data[1] & 0x40);
396  					// convert tilt (-128 ... 127)
397  //					int8 tiltDataX = ((data[7] & 0x3f) << 2) | ((data[8] & 0x80) >> 6);
398  					int8 tiltDataX = ((data[7] & 0x3f) << 1) | ((data[8] & 0x80) >> 7);
399  					int8 tiltDataY = data[8] & 0x7f;
400  //					int8 tiltDataY = 0;
401  					// convert to floats
402  					tiltX = (float)(tiltDataX - 64) / 64.0;
403  					tiltY = (float)(tiltDataY - 64) / 64.0;
404  				}
405  			}
406  			break;
407  		case DEVICE_PL500: {
408  			hasContact = ( data[1] & 0x20);
409  			xPos = data[2] << 8 | data[3];
410  			yPos = data[5] << 8 | data[6];
411  			firstButton = (data[4] & 0x08);
412  			secondButton = (data[4] & 0x10);
413  			thirdButton = (data[4] & 0x20);
414  			uint16 pressureData = (data[4] & 0x04) >> 2 | (data[7] & 0x7f) << 1;
415  			pressure = (float)pressureData / 511.0;
416  			break;
417  		}
418  		case DEVICE_VOLITO: {
419  			eraser = 0;
420  			thirdButton = 0;
421  
422  			xPos = data[3] << 8 | data[2];
423  			yPos = data[5] << 8 | data[4];
424  
425  			hasContact = (data[1] & 0x80);
426  
427  			firstButton = (data[1] & 0x01) == 1;
428  			secondButton = data[1] & 0x04;
429  
430  			uint16 pressureData = data[7] << 8 | data[6];
431  			pressure = (float)pressureData / 511.0;
432  
433  			if (data[1] & 0x40) {	// mouse is on tablet
434  				wheelY = 0;
435  				mode = MODE_MOUSE;
436  				hasContact = (uint8)data[7] >= 30;
437  				pressure = 0.0;
438  				secondButton = data[1] & 0x02;
439  			}
440  
441  			break;
442  		}
443  		case DEVICE_PENSTATION: {
444  			xPos = data[3] << 8 | data[2];
445  			yPos = data[5] << 8 | data[4];
446  			hasContact = (data[1] & 0x10);
447  			uint16 pressureData = data[7] << 8 | data[6];
448  			pressure = (float)pressureData / 511.0;
449  			firstButton = (data[1] & 0x01);
450  			secondButton = (data[1] & 0x02);
451  			thirdButton = (data[1] & 0x04);
452  			break;
453  		}
454  	}
455  	if (pressure > 1.0)
456  		pressure = 1.0;
457  	else if (pressure < 0.0)
458  		pressure = 0.0;
459  	buttons = (firstButton ? B_PRIMARY_MOUSE_BUTTON : 0)
460  			   | (secondButton ? B_SECONDARY_MOUSE_BUTTON : 0)
461  			   | (thirdButton ? B_TERTIARY_MOUSE_BUTTON : 0);
462  	x = (float)xPos;
463  	y = (float)yPos;
464  }
465  
466  // SetStatus
467  void
468  TabletDevice::SetStatus(uint32 mode, uint32 buttons, float x, float y,
469  	float pressure, int32 clicks, uint32 modifiers, int32 eraser,
470  	float wheelX, float wheelY, float tiltX, float tiltY, const uchar* data)
471  {
472  	if (fActive) {
473  		uint32 what = B_MOUSE_MOVED;
474  		if (buttons > fButtons)
475  			what = B_MOUSE_DOWN;
476  		else if (buttons < fButtons)
477  			what = B_MOUSE_UP;
478  
479  
480  #if DEBUG
481  	float tabletX = x;
482  	float tabletY = y;
483  #endif
484  		x /= fMaxX;
485  		y /= fMaxY;
486  
487  		float deltaX = 0.0;
488  		float deltaY = 0.0;
489  
490  		float absDeltaX = 0.0;
491  		float absDeltaY = 0.0;
492  
493  		float unfilteredX = x;
494  		float unfilteredY = y;
495  
496  		if (fHasContact) {
497  			deltaX = x - fPosX;
498  			deltaY = y - fPosY;
499  
500  			absDeltaX = fabsf(deltaX);
501  			absDeltaY = fabsf(deltaY);
502  
503  #if 0 //DEBUG
504  fParent->LogString() << "x: " << x << ", y: " << y << ", pressure: " << pressure << "\n";
505  fParent->LogString() << "tilt x: " << tiltX << ", tilt y: " << tiltY << "\n\n";
506  #endif
507  			// apply a bit of filtering
508  			if (absDeltaX < fJitterX)
509  				x = fPosX;
510  			if (absDeltaY < fJitterY)
511  				y = fPosY;
512  		}
513  
514  		// only do send message if something changed
515  		if (x != fPosX || y != fPosY || fButtons != buttons || pressure != fPressure
516  			|| fEraser != eraser || fTiltX != tiltX || fTiltY != tiltY) {
517  
518  			bigtime_t now = system_time();
519  
520  			// common fields for any mouse message
521  			BMessage* event = new BMessage(what);
522  			event->AddInt64("when", now);
523  			event->AddInt32("buttons", buttons);
524  			if (mode == MODE_PEN) {
525  				event->AddFloat("x", x);
526  				event->AddFloat("y", y);
527  				event->AddFloat("be:tablet_x", unfilteredX);
528  				event->AddFloat("be:tablet_y", unfilteredY);
529  				event->AddFloat("be:tablet_pressure", pressure);
530  				event->AddInt32("be:tablet_eraser", eraser);
531  				if (_DeviceSupportsTilt()) {
532  					event->AddFloat("be:tablet_tilt_x", tiltX);
533  					event->AddFloat("be:tablet_tilt_y", tiltY);
534  				}
535  				// adjust mouse coordinates as well
536  				// to have the mouse appear at the pens
537  				// last position when switching
538  				fFakeMouseX = unfilteredX;
539  				fFakeMouseY = unfilteredY;
540  			} else if (mode == MODE_MOUSE) {
541  				// apply acceleration
542  				float accelerationX = fJitterX * ACCELERATION_KICK_IN;
543  //				if (absDeltaX > accelerationX)
544  					deltaX *= absDeltaX / accelerationX;
545  				float accelerationY = fJitterY * ACCELERATION_KICK_IN;
546  //				if (absDeltaY > accelerationY)
547  					deltaY *= absDeltaY / accelerationY;
548  				// calculate screen coordinates
549  				fFakeMouseX = min_c(1.0, max_c(0.0, fFakeMouseX + deltaX));
550  				fFakeMouseY = min_c(1.0, max_c(0.0, fFakeMouseY + deltaY));
551  				event->AddFloat("x", fFakeMouseX);
552  				event->AddFloat("y", fFakeMouseY);
553  				event->AddFloat("be:tablet_x", fFakeMouseX);
554  				event->AddFloat("be:tablet_y", fFakeMouseY);
555  			}
556  			event->AddInt32("modifiers", modifiers);
557  
558  #if DEBUG
559  if (data) {
560  	event->AddData("raw usb data", B_RAW_TYPE, data, 12);
561  }
562  event->AddFloat("tablet x", tabletX);
563  event->AddFloat("tablet y", tabletY);
564  #endif
565  			// additional fields for mouse down or up
566  			if (what == B_MOUSE_DOWN) {
567  				if (now - fLastClickTime < fParent->DoubleClickSpeed()) {
568  					fClicks++;
569  					if (fClicks > 3)
570  						fClicks = 1;
571  				} else {
572  					fClicks = 1;
573  				}
574  				fLastClickTime = now;
575  				event->AddInt32("clicks", fClicks);
576  			} else if (what == B_MOUSE_UP)
577  				event->AddInt32("clicks", 0);
578  
579  			status_t ret = fParent->EnqueueMessage(event);
580  			if (ret < B_OK)
581  				PRINT(("EnqueueMessage(): %s\n", strerror(ret)));
582  
583  			// apply values to members
584  			fPosX = x;
585  			fPosY = y;
586  			fButtons = buttons;
587  			fPressure = pressure;
588  			fModifiers = modifiers;
589  			fEraser = eraser;
590  			fTiltX = tiltX;
591  			fTiltY = tiltY;
592  		}
593  
594  		// separate wheel changed message
595  		if (fWheelX != wheelX || fWheelY != wheelY) {
596  			BMessage* event = new BMessage(B_MOUSE_WHEEL_CHANGED);
597  			event->AddInt64("when", system_time());
598  			event->AddFloat("be:wheel_delta_x", wheelX);
599  			event->AddFloat("be:wheel_delta_y", wheelY);
600  			fParent->EnqueueMessage(event);
601  
602  			// apply values to members
603  			fWheelX = wheelX;
604  			fWheelY = wheelY;
605  		}
606  	}
607  }
608  
609  // SetContact
610  void
611  TabletDevice::SetContact(bool contact)
612  {
613  	fHasContact = contact;
614  }
615  
616  // poll_usb_device
617  int32
618  TabletDevice::poll_usb_device(void* arg)
619  {
620  	TabletDevice* tabletDevice = (TabletDevice*)arg;
621  	DeviceReader* reader = tabletDevice->fReader;
622  
623  	if (!reader || reader->InitCheck() < B_OK)
624  		return B_BAD_VALUE;
625  
626  	int dataBytes = reader->MaxPacketSize();
627  	if (dataBytes > 128)
628  		return B_BAD_VALUE;
629  
630  	uchar data[max_c(12, dataBytes)];
631  
632  	while (tabletDevice->IsActive()) {
633  
634  		status_t ret = reader->ReadData(data, dataBytes);
635  
636  		if (ret == dataBytes) {
637  			// data we read from the wacom device
638  			uint32 mode;
639  			bool hasContact = false;
640  			uint32 buttons = 0;
641  			float x = 0.0;
642  			float y = 0.0;
643  			float pressure = 0.0;
644  			int32 clicks = 0;
645  			int32 eraser = 0;
646  			float wheelX = 0.0;
647  			float wheelY = 0.0;
648  			float tiltX = 0.0;
649  			float tiltY = 0.0;
650  			// let the device extract all information from the data
651  			tabletDevice->ReadData(data, dataBytes, hasContact, mode, buttons,
652  								   x, y, pressure, clicks, eraser,
653  								   wheelX, wheelY, tiltX, tiltY);
654  			if (hasContact) {
655  				// apply the changes to the device
656  				tabletDevice->SetStatus(mode, buttons, x, y, pressure,
657  										clicks, modifiers(), eraser,
658  										wheelX, wheelY, tiltX, tiltY, data);
659  			} else
660  				PRINT(("device has no contact\n"));
661  			tabletDevice->SetContact(hasContact);
662  		} else {
663  			PRINT(("failed to read %ld bytes, read: %ld or %s\n",
664  				dataBytes, ret, strerror(ret)));
665  
666  			if (ret < B_OK) {
667  				if (ret == B_TIMED_OUT)
668  					snooze(SNOOZE_AMOUNT);
669  				else if (ret == B_INTERRUPTED)
670  					snooze(SNOOZE_AMOUNT);
671  				else {
672  					return ret;
673  				}
674  			}
675  		}
676  	}
677  
678  	return B_OK;
679  }
680  
681  // _DeviceSupportsTilt
682  bool
683  TabletDevice::_DeviceSupportsTilt() const
684  {
685  	bool tilt = false;
686  	switch (fDeviceMode) {
687  		case DEVICE_INTUOS:
688  		case DEVICE_INTUOS3:
689  		case DEVICE_CINTIQ:
690  			tilt = true;
691  			break;
692  	}
693  	return tilt;
694  }
695  
696  // _GetName
697  void
698  TabletDevice::_GetName(uint16 productID, const char** name) const
699  {
700  	switch (productID) {
701  		case 0x00:
702  			*name = "Wacom USB";
703  			break;
704  		case 0x03:	// driver does not support this yet
705  			*name = "Wacom Cintiq Partner USB";
706  			break;
707  		case 0x10:
708  			*name = "Wacom Graphire USB";
709  			break;
710  		case 0x11:
711  			*name = "Wacom Graphire2 4x5\" USB";
712  			break;
713  		case 0x12:
714  			*name = "Wacom Graphire2 5x7\" USB";
715  			break;
716  		case 0x13:
717  			*name = "Wacom Graphire3 4x5\" USB";
718  			break;
719  		case 0x14:
720  			*name = "Wacom Graphire3 6x8\" USB";
721  			break;
722  		case 0x15:
723  			*name = "Wacom Graphire4 4x5\" USB";
724  			break;
725  		case 0x16:
726  			*name = "Wacom Graphire4 6x8\" USB";
727  			break;
728  		case 0x17:
729  			*name = "Wacom BambooFun 4x5\" USB";
730  			break;
731  		case 0x18:
732  			*name = "Wacom BambooFun 6x8\" USB";
733  			break;
734  		case 0x20:
735  			*name = "Wacom Intuos 4x5\" USB";
736  			break;
737  		case 0x21:
738  			*name = "Wacom Intuos 6x8\" USB";
739  			break;
740  		case 0x22:
741  			*name = "Wacom Intuos 9x12\" USB";
742  			break;
743  		case 0x23:
744  			*name = "Wacom Intuos 12x12\" USB";
745  			break;
746  		case 0x24:
747  			*name = "Wacom Intuos 12x18\" USB";
748  			break;
749  		case 0x30:
750  			*name = "Wacom PL400 USB";
751  			break;
752  		case 0x31:
753  			*name = "Wacom PL500 USB";
754  			break;
755  		case 0x32:
756  			*name = "Wacom PL600 USB";
757  			break;
758  		case 0x33:
759  			*name = "Wacom PL600SX USB";
760  			break;
761  		case 0x34:
762  			*name = "Wacom PL550 USB";
763  			break;
764  		case 0x35:
765  			*name = "Wacom PL800 USB";
766  			break;
767  
768  		case 0x3F:
769  			*name = "Wacom Cintiq 21UX USB";
770  			break;
771  
772  		case 0x41:
773  			*name = "Wacom Intuos2 4x5\" USB";
774  			break;
775  		case 0x42:
776  			*name = "Wacom Intuos2 6x8\" USB";
777  			break;
778  		case 0x43:
779  			*name = "Wacom Intuos2 9x12\" USB";
780  			break;
781  		case 0x44:
782  			*name = "Wacom Intuos2 12x12\" USB";
783  			break;
784  		case 0x45:
785  			*name = "Wacom Intuos2 12x18\" USB";
786  			break;
787  		case 0x47:	// some I2 6x8s seem to report as 0x47
788  			*name = "Wacom Intuos2 6x8\" USB";
789  			break;
790  
791  		case 0x60:
792  			*name = "Wacom Volito USB";
793  			break;
794  		case 0x61:
795  			*name = "Wacom PenStation USB";
796  			break;
797  		case 0x62:
798  			*name = "Wacom Volito2 USB";
799  			break;
800  		case 0x64:
801  			*name = "Wacom PenPartner.1 USB";
802  			break;
803  		case 0x65:
804  			*name = "Wacom Bamboo USB";
805  			break;
806  		case 0x69:
807  			*name = "Wacom Bamboo1 USB";
808  			break;
809  
810  		case 0xB0:
811  			*name = "Wacom Intuos3 4x5 USB";
812  			break;
813  		case 0xB1:
814  			*name = "Wacom Intuos3 6x8 USB";
815  			break;
816  		case 0xB2:
817  			*name = "Wacom Intuos3 9x12 USB";
818  			break;
819  
820  		case 0xD0:
821  			*name = "Wacom Bamboo 2FG USB";
822  			break;
823  		case 0xD1:
824  			*name = "Wacom BambooFun 2FG 4x5\" USB";
825  			break;
826  		case 0xD2:
827  			*name = "Wacom Bamboo Craft USB";
828  			break;
829  		case 0xD3:
830  			*name = "Wacom BambooFun 2FG 6x8\" USB";
831  			break;
832  		case 0xD4:
833  			*name = "Wacom Bamboo 4x5\" USB";
834  			break;
835  		case 0xD6:
836  			*name = "Wacom Bamboo (CTH-460/K)";
837  			break;
838  		case 0xD7:
839  			*name = "Wacom Bamboo (CTH-461/S)";
840  			break;
841  		case 0xD8:
842  			*name = "Wacom Bamboo (CTH-661/S1)";
843  			break;
844  		case 0xDA:
845  			*name = "Wacom Bamboo (CTH-461/L)";
846  			break;
847  		case 0xDB:
848  			*name = "Wacom Bamboo (CTH-661)";
849  			break;
850  
851  		default:
852  			*name = "<unkown wacom tablet>";
853  			break;
854  	}
855  }
856  
857