2 * Copyright 2013 Stephan Aßmus <superstippi@gmx.de>
3 * Copyright 2010-2011 Enrique Medina Gremaldos <quiqueiii@gmail.com>
4 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
5 * Distributed under the terms of the MIT license.
9 //! Driver for USB Human Interface Devices.
13 #include "TabletProtocolHandler.h"
15 #include "HIDCollection.h"
16 #include "HIDDevice.h"
17 #include "HIDReport.h"
18 #include "HIDReportItem.h"
22 #include <usb/USB_hid.h>
24 #include <keyboard_mouse_driver.h>
27 TabletProtocolHandler::TabletProtocolHandler(HIDReport
&report
,
28 HIDReportItem
&xAxis
, HIDReportItem
&yAxis
)
30 ProtocolHandler(report
.Device(), "input/tablet/usb/", 0),
50 uint32 buttonCount
= 0;
51 for (uint32 i
= 0; i
< report
.CountItems(); i
++) {
52 HIDReportItem
*item
= report
.ItemAt(i
);
56 if (item
->UsagePage() == B_HID_USAGE_PAGE_BUTTON
57 && item
->UsageID() - 1 < B_MAX_MOUSE_BUTTONS
) {
58 fButtons
[buttonCount
++] = item
;
62 fButtons
[buttonCount
] = NULL
;
64 fWheel
= report
.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP
,
67 fPressure
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
68 B_HID_UID_DIG_TIP_PRESSURE
);
70 fRange
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
71 B_HID_UID_DIG_IN_RANGE
);
73 fTip
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
74 B_HID_UID_DIG_TIP_SWITCH
);
76 fBarrelSwitch
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
77 B_HID_UID_DIG_BARREL_SWITCH
);
79 fEraser
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
80 B_HID_UID_DIG_ERASER
);
82 fXTilt
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
83 B_HID_UID_DIG_X_TILT
);
85 fYTilt
= report
.FindItem(B_HID_USAGE_PAGE_DIGITIZER
,
86 B_HID_UID_DIG_Y_TILT
);
88 TRACE("tablet device with %lu buttons, %stip, %seraser, "
89 "%spressure, and %stilt\n",
91 fTip
== NULL
? "no " : "",
92 fEraser
== NULL
? "no " : "",
93 fPressure
== NULL
? "no " : "",
94 fXTilt
== NULL
&& fYTilt
== NULL
? "no " : "");
96 TRACE("report id: %u\n", report
.ID());
101 TabletProtocolHandler::AddHandlers(HIDDevice
&device
, HIDCollection
&collection
,
102 ProtocolHandler
*&handlerList
)
104 bool supported
= false;
105 switch (collection
.UsagePage()) {
106 case B_HID_USAGE_PAGE_GENERIC_DESKTOP
:
108 switch (collection
.UsageID()) {
109 case B_HID_UID_GD_MOUSE
:
110 case B_HID_UID_GD_POINTER
:
111 // NOTE: Maybe it is supported if X-axis and Y-axis are
112 // absolute. This is determined below by scanning the
113 // report items for absolute X and Y axis.
121 case B_HID_USAGE_PAGE_DIGITIZER
:
123 switch (collection
.UsageID()) {
124 case B_HID_UID_DIG_DIGITIZER
:
125 case B_HID_UID_DIG_PEN
:
126 case B_HID_UID_DIG_LIGHT_PEN
:
127 case B_HID_UID_DIG_TOUCH_SCREEN
:
128 case B_HID_UID_DIG_TOUCH_PAD
:
129 case B_HID_UID_DIG_WHITE_BOARD
:
130 TRACE("found tablet/digitizer\n");
140 TRACE("collection not a tablet/digitizer\n");
144 HIDParser
&parser
= device
.Parser();
145 uint32 maxReportCount
= parser
.CountReports(HID_REPORT_TYPE_INPUT
);
146 if (maxReportCount
== 0)
149 uint32 inputReportCount
= 0;
150 HIDReport
*inputReports
[maxReportCount
];
151 collection
.BuildReportList(HID_REPORT_TYPE_INPUT
, inputReports
,
154 for (uint32 i
= 0; i
< inputReportCount
; i
++) {
155 HIDReport
*inputReport
= inputReports
[i
];
157 // try to find at least an absolute x and y axis
158 HIDReportItem
*xAxis
= inputReport
->FindItem(
159 B_HID_USAGE_PAGE_GENERIC_DESKTOP
, B_HID_UID_GD_X
);
160 if (xAxis
== NULL
|| xAxis
->Relative())
163 HIDReportItem
*yAxis
= inputReport
->FindItem(
164 B_HID_USAGE_PAGE_GENERIC_DESKTOP
, B_HID_UID_GD_Y
);
165 if (yAxis
== NULL
|| yAxis
->Relative())
168 ProtocolHandler
*newHandler
= new(std::nothrow
) TabletProtocolHandler(
169 *inputReport
, *xAxis
, *yAxis
);
170 if (newHandler
== NULL
) {
171 TRACE("failed to allocated tablet protocol handler\n");
175 newHandler
->SetNextHandler(handlerList
);
176 handlerList
= newHandler
;
182 TabletProtocolHandler::Control(uint32
*cookie
, uint32 op
, void *buffer
,
188 if (length
< sizeof(tablet_movement
))
189 return B_BUFFER_OVERFLOW
;
192 status_t result
= _ReadReport(buffer
, cookie
);
193 if (result
!= B_INTERRUPTED
)
200 if (fReport
.Device()->IsRemoved())
201 return B_DEV_NOT_READY
;
203 // we are always on demand, so 0 queued events
207 case MS_SET_CLICKSPEED
:
209 return user_memcpy(&fClickSpeed
, buffer
, sizeof(bigtime_t
));
211 fClickSpeed
= *(bigtime_t
*)buffer
;
221 TabletProtocolHandler::_ReadReport(void *buffer
, uint32
*cookie
)
223 status_t result
= fReport
.WaitForReport(B_INFINITE_TIMEOUT
);
224 if (result
!= B_OK
) {
225 if (fReport
.Device()->IsRemoved()) {
226 TRACE("device has been removed\n");
227 return B_DEV_NOT_READY
;
230 if ((*cookie
& PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED
) != 0)
233 if (result
!= B_INTERRUPTED
) {
234 // interrupts happen when other reports come in on the same
236 TRACE_ALWAYS("error waiting for report: %s\n", strerror(result
));
239 // signal that we simply want to try again
240 return B_INTERRUPTED
;
243 float axisAbsoluteData
[2];
244 axisAbsoluteData
[0] = 0.0f
;
245 axisAbsoluteData
[1] = 0.0f
;
247 if (fXAxis
.Extract() == B_OK
&& fXAxis
.Valid())
248 axisAbsoluteData
[0] = fXAxis
.ScaledFloatData();
250 if (fYAxis
.Extract() == B_OK
&& fYAxis
.Valid())
251 axisAbsoluteData
[1] = fYAxis
.ScaledFloatData();
253 uint32 wheelData
= 0;
254 if (fWheel
!= NULL
&& fWheel
->Extract() == B_OK
&& fWheel
->Valid())
255 wheelData
= fWheel
->Data();
258 for (uint32 i
= 0; i
< B_MAX_MOUSE_BUTTONS
; i
++) {
259 HIDReportItem
*button
= fButtons
[i
];
263 if (button
->Extract() == B_OK
&& button
->Valid())
264 buttons
|= (button
->Data() & 1) << (button
->UsageID() - 1);
267 float pressure
= 1.0f
;
268 if (fPressure
!= NULL
&& fPressure
->Extract() == B_OK
269 && fPressure
->Valid()) {
270 pressure
= fPressure
->ScaledFloatData();
274 if (fXTilt
!= NULL
&& fXTilt
->Extract() == B_OK
&& fXTilt
->Valid())
275 xTilt
= fXTilt
->ScaledFloatData();
278 if (fYTilt
!= NULL
&& fYTilt
->Extract() == B_OK
&& fYTilt
->Valid())
279 yTilt
= fYTilt
->ScaledFloatData();
283 inRange
= fRange
->Extract() == B_OK
&& fRange
->Valid();
286 if (fEraser
!= NULL
&& fEraser
->Extract() == B_OK
&& fEraser
->Valid())
287 eraser
= (fEraser
->Data() & 1) != 0;
289 fReport
.DoneProcessing();
290 TRACE("got tablet report\n");
293 bigtime_t timestamp
= system_time();
295 if (fLastButtons
== 0) {
296 if (fLastClickTime
+ fClickSpeed
> timestamp
)
302 fLastClickTime
= timestamp
;
303 clicks
= fClickCount
;
306 fLastButtons
= buttons
;
308 tablet_movement
*info
= (tablet_movement
*)buffer
;
309 memset(info
, 0, sizeof(tablet_movement
));
311 info
->xpos
= axisAbsoluteData
[0];
312 info
->ypos
= axisAbsoluteData
[1];
313 info
->has_contact
= inRange
;
314 info
->pressure
= pressure
;
315 info
->eraser
= eraser
;
316 info
->tilt_x
= xTilt
;
317 info
->tilt_y
= yTilt
;
319 info
->buttons
= buttons
;
320 info
->clicks
= clicks
;
321 info
->timestamp
= timestamp
;
322 info
->wheel_ydelta
= -wheelData
;