BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / input / usb_hid / TabletProtocolHandler.cpp
blob18496fef3d78485a940810dccb016f992c63ce63
1 /*
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.
6 */
9 //! Driver for USB Human Interface Devices.
12 #include "Driver.h"
13 #include "TabletProtocolHandler.h"
15 #include "HIDCollection.h"
16 #include "HIDDevice.h"
17 #include "HIDReport.h"
18 #include "HIDReportItem.h"
20 #include <new>
21 #include <string.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),
31 fReport(report),
33 fXAxis(xAxis),
34 fYAxis(yAxis),
35 fWheel(NULL),
37 fPressure(NULL),
38 fRange(NULL),
39 fTip(NULL),
40 fBarrelSwitch(NULL),
41 fEraser(NULL),
42 fXTilt(NULL),
43 fYTilt(NULL),
45 fLastButtons(0),
46 fClickCount(0),
47 fLastClickTime(0),
48 fClickSpeed(250000)
50 uint32 buttonCount = 0;
51 for (uint32 i = 0; i < report.CountItems(); i++) {
52 HIDReportItem *item = report.ItemAt(i);
53 if (!item->HasData())
54 continue;
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,
65 B_HID_UID_GD_WHEEL);
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",
90 buttonCount,
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());
100 void
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.
114 supported = true;
115 break;
118 break;
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");
131 supported = true;
132 break;
135 break;
139 if (!supported) {
140 TRACE("collection not a tablet/digitizer\n");
141 return;
144 HIDParser &parser = device.Parser();
145 uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT);
146 if (maxReportCount == 0)
147 return;
149 uint32 inputReportCount = 0;
150 HIDReport *inputReports[maxReportCount];
151 collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports,
152 inputReportCount);
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())
161 continue;
163 HIDReportItem *yAxis = inputReport->FindItem(
164 B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
165 if (yAxis == NULL || yAxis->Relative())
166 continue;
168 ProtocolHandler *newHandler = new(std::nothrow) TabletProtocolHandler(
169 *inputReport, *xAxis, *yAxis);
170 if (newHandler == NULL) {
171 TRACE("failed to allocated tablet protocol handler\n");
172 continue;
175 newHandler->SetNextHandler(handlerList);
176 handlerList = newHandler;
181 status_t
182 TabletProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
183 size_t length)
185 switch (op) {
186 case MS_READ:
188 if (length < sizeof(tablet_movement))
189 return B_BUFFER_OVERFLOW;
191 while (true) {
192 status_t result = _ReadReport(buffer, cookie);
193 if (result != B_INTERRUPTED)
194 return result;
198 case MS_NUM_EVENTS:
200 if (fReport.Device()->IsRemoved())
201 return B_DEV_NOT_READY;
203 // we are always on demand, so 0 queued events
204 return 0;
207 case MS_SET_CLICKSPEED:
208 #ifdef __HAIKU__
209 return user_memcpy(&fClickSpeed, buffer, sizeof(bigtime_t));
210 #else
211 fClickSpeed = *(bigtime_t *)buffer;
212 return B_OK;
213 #endif
216 return B_ERROR;
220 status_t
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)
231 return B_CANCELED;
233 if (result != B_INTERRUPTED) {
234 // interrupts happen when other reports come in on the same
235 // input as ours
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();
257 uint32 buttons = 0;
258 for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) {
259 HIDReportItem *button = fButtons[i];
260 if (button == NULL)
261 break;
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();
273 float xTilt = 0.0f;
274 if (fXTilt != NULL && fXTilt->Extract() == B_OK && fXTilt->Valid())
275 xTilt = fXTilt->ScaledFloatData();
277 float yTilt = 0.0f;
278 if (fYTilt != NULL && fYTilt->Extract() == B_OK && fYTilt->Valid())
279 yTilt = fYTilt->ScaledFloatData();
281 bool inRange = true;
282 if (fRange != NULL)
283 inRange = fRange->Extract() == B_OK && fRange->Valid();
285 bool eraser = false;
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");
292 int32 clicks = 0;
293 bigtime_t timestamp = system_time();
294 if (buttons != 0) {
295 if (fLastButtons == 0) {
296 if (fLastClickTime + fClickSpeed > timestamp)
297 fClickCount++;
298 else
299 fClickCount = 1;
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;
324 return B_OK;