BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / input / usb_hid / MouseProtocolHandler.cpp
blobdaf5c3edc0d242338849894494df6727bcb8282b
1 /*
2 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
3 * Distributed under the terms of the MIT license.
4 */
7 //! Driver for USB Human Interface Devices.
10 #include "Driver.h"
11 #include "MouseProtocolHandler.h"
13 #include "HIDCollection.h"
14 #include "HIDDevice.h"
15 #include "HIDReport.h"
16 #include "HIDReportItem.h"
18 #include <new>
19 #include <string.h>
20 #include <usb/USB_hid.h>
22 #include <keyboard_mouse_driver.h>
25 MouseProtocolHandler::MouseProtocolHandler(HIDReport &report,
26 HIDReportItem &xAxis, HIDReportItem &yAxis)
28 ProtocolHandler(report.Device(), "input/mouse/usb/", 0),
29 fReport(report),
31 fXAxis(xAxis),
32 fYAxis(yAxis),
33 fWheel(NULL),
35 fLastButtons(0),
36 fClickCount(0),
37 fLastClickTime(0),
38 fClickSpeed(250000)
40 uint32 buttonCount = 0;
41 for (uint32 i = 0; i < report.CountItems(); i++) {
42 HIDReportItem *item = report.ItemAt(i);
43 if (!item->HasData())
44 continue;
46 if (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON
47 && item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) {
48 fButtons[buttonCount++] = item;
52 fButtons[buttonCount] = NULL;
54 fWheel = report.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP,
55 B_HID_UID_GD_WHEEL);
57 TRACE("mouse device with %lu buttons and %swheel\n", buttonCount,
58 fWheel == NULL ? "no " : "");
59 TRACE("report id: %u\n", report.ID());
63 void
64 MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
65 ProtocolHandler *&handlerList)
67 bool supported = false;
68 switch (collection.UsagePage()) {
69 case B_HID_USAGE_PAGE_GENERIC_DESKTOP:
71 switch (collection.UsageID()) {
72 case B_HID_UID_GD_MOUSE:
73 case B_HID_UID_GD_POINTER:
74 supported = true;
75 break;
78 break;
82 if (!supported) {
83 TRACE("collection not a mouse\n");
84 return;
87 HIDParser &parser = device.Parser();
88 uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT);
89 if (maxReportCount == 0)
90 return;
92 uint32 inputReportCount = 0;
93 HIDReport *inputReports[maxReportCount];
94 collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports,
95 inputReportCount);
97 for (uint32 i = 0; i < inputReportCount; i++) {
98 HIDReport *inputReport = inputReports[i];
100 // try to find at least an absolute x and y axis
101 HIDReportItem *xAxis = inputReport->FindItem(
102 B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
103 if (xAxis == NULL || !xAxis->Relative())
104 continue;
106 HIDReportItem *yAxis = inputReport->FindItem(
107 B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
108 if (yAxis == NULL || !yAxis->Relative())
109 continue;
111 ProtocolHandler *newHandler = new(std::nothrow) MouseProtocolHandler(
112 *inputReport, *xAxis, *yAxis);
113 if (newHandler == NULL) {
114 TRACE("failed to allocated mouse protocol handler\n");
115 continue;
118 newHandler->SetNextHandler(handlerList);
119 handlerList = newHandler;
124 status_t
125 MouseProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer,
126 size_t length)
128 switch (op) {
129 case MS_READ:
131 if (length < sizeof(mouse_movement))
132 return B_BUFFER_OVERFLOW;
134 while (true) {
135 status_t result = _ReadReport(buffer, cookie);
136 if (result != B_INTERRUPTED)
137 return result;
141 case MS_NUM_EVENTS:
143 if (fReport.Device()->IsRemoved())
144 return B_DEV_NOT_READY;
146 // we are always on demand, so 0 queued events
147 return 0;
150 case MS_SET_CLICKSPEED:
151 #ifdef __HAIKU__
152 return user_memcpy(&fClickSpeed, buffer, sizeof(bigtime_t));
153 #else
154 fClickSpeed = *(bigtime_t *)buffer;
155 return B_OK;
156 #endif
159 return B_ERROR;
163 status_t
164 MouseProtocolHandler::_ReadReport(void *buffer, uint32 *cookie)
166 status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
167 if (result != B_OK) {
168 if (fReport.Device()->IsRemoved()) {
169 TRACE("device has been removed\n");
170 return B_DEV_NOT_READY;
173 if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
174 return B_CANCELED;
176 if (result != B_INTERRUPTED) {
177 // interrupts happen when other reports come in on the same
178 // input as ours
179 TRACE_ALWAYS("error waiting for report: %s\n", strerror(result));
182 // signal that we simply want to try again
183 return B_INTERRUPTED;
186 uint32 axisRelativeData[2];
187 axisRelativeData[0] = 0;
188 axisRelativeData[1] = 0;
190 if (fXAxis.Extract() == B_OK && fXAxis.Valid())
191 axisRelativeData[0] = fXAxis.Data();
193 if (fYAxis.Extract() == B_OK && fYAxis.Valid())
194 axisRelativeData[1] = fYAxis.Data();
196 uint32 wheelData = 0;
197 if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
198 wheelData = fWheel->Data();
200 uint32 buttons = 0;
201 for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) {
202 HIDReportItem *button = fButtons[i];
203 if (button == NULL)
204 break;
206 if (button->Extract() == B_OK && button->Valid())
207 buttons |= (button->Data() & 1) << (button->UsageID() - 1);
210 fReport.DoneProcessing();
211 TRACE("got mouse report\n");
213 int32 clicks = 0;
214 bigtime_t timestamp = system_time();
215 if (buttons != 0) {
216 if (fLastButtons == 0) {
217 if (fLastClickTime + fClickSpeed > timestamp)
218 fClickCount++;
219 else
220 fClickCount = 1;
223 fLastClickTime = timestamp;
224 clicks = fClickCount;
227 fLastButtons = buttons;
229 mouse_movement *info = (mouse_movement *)buffer;
230 memset(info, 0, sizeof(mouse_movement));
232 info->buttons = buttons;
233 info->xdelta = axisRelativeData[0];
234 info->ydelta = -axisRelativeData[1];
235 info->clicks = clicks;
236 info->timestamp = timestamp;
237 info->wheel_ydelta = -wheelData;
239 return B_OK;