xref: /haiku/src/add-ons/input_server/devices/wacom/TabletDevice.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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