1*e16045dbSVladimir Serbinenko /*
2*e16045dbSVladimir Serbinenko * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
3*e16045dbSVladimir Serbinenko * Copyright 2008-2011, Michael Lotz <mmlr@mlotz.ch>
4*e16045dbSVladimir Serbinenko * Copyright 2020, 2022 Vladimir Kondratyev <wulf@FreeBSD.org>
5*e16045dbSVladimir Serbinenko * Copyright 2023 Vladimir Serbinenko <phcoder@gmail.com>
6*e16045dbSVladimir Serbinenko * Distributed under the terms of the MIT license.
7*e16045dbSVladimir Serbinenko */
8*e16045dbSVladimir Serbinenko
9*e16045dbSVladimir Serbinenko
10*e16045dbSVladimir Serbinenko //! Driver for I2C Elan Devices.
11*e16045dbSVladimir Serbinenko // Partially based on FreeBSD ietp driver
12*e16045dbSVladimir Serbinenko
13*e16045dbSVladimir Serbinenko
14*e16045dbSVladimir Serbinenko #include "Driver.h"
15*e16045dbSVladimir Serbinenko #include "ELANDevice.h"
16*e16045dbSVladimir Serbinenko #include "HIDReport.h"
17*e16045dbSVladimir Serbinenko #include <keyboard_mouse_driver.h>
18*e16045dbSVladimir Serbinenko #include <kernel.h>
19*e16045dbSVladimir Serbinenko
20*e16045dbSVladimir Serbinenko #include <stdlib.h>
21*e16045dbSVladimir Serbinenko #include <stdio.h>
22*e16045dbSVladimir Serbinenko #include <string.h>
23*e16045dbSVladimir Serbinenko #include <unistd.h>
24*e16045dbSVladimir Serbinenko #include <new>
25*e16045dbSVladimir Serbinenko
26*e16045dbSVladimir Serbinenko #define LO_ELAN_REPORT_SIZE 32
27*e16045dbSVladimir Serbinenko #define HI_ELAN_REPORT_SIZE 37
28*e16045dbSVladimir Serbinenko #define MIN_ELAN_REPORT 11
29*e16045dbSVladimir Serbinenko
30*e16045dbSVladimir Serbinenko #define IETP_MAX_X_AXIS 0x0106
31*e16045dbSVladimir Serbinenko #define IETP_MAX_Y_AXIS 0x0107
32*e16045dbSVladimir Serbinenko
33*e16045dbSVladimir Serbinenko #define IETP_CONTROL 0x0300
34*e16045dbSVladimir Serbinenko #define IETP_CTRL_ABSOLUTE 0x0001
35*e16045dbSVladimir Serbinenko #define IETP_CTRL_STANDARD 0x0000
36*e16045dbSVladimir Serbinenko
ELANDevice(device_node * parent,i2c_device_interface * i2c,i2c_device i2cCookie)37*e16045dbSVladimir Serbinenko ELANDevice::ELANDevice(device_node* parent, i2c_device_interface* i2c,
38*e16045dbSVladimir Serbinenko i2c_device i2cCookie)
39*e16045dbSVladimir Serbinenko : fStatus(B_NO_INIT),
40*e16045dbSVladimir Serbinenko fTransferLastschedule(0),
41*e16045dbSVladimir Serbinenko fTransferScheduled(0),
42*e16045dbSVladimir Serbinenko fOpenCount(0),
43*e16045dbSVladimir Serbinenko fRemoved(false),
44*e16045dbSVladimir Serbinenko fPublishPath(nullptr),
45*e16045dbSVladimir Serbinenko fReportID(0x5d),
46*e16045dbSVladimir Serbinenko fHighPrecision(false),
47*e16045dbSVladimir Serbinenko fParent(parent),
48*e16045dbSVladimir Serbinenko fI2C(i2c),
49*e16045dbSVladimir Serbinenko fI2CCookie(i2cCookie),
50*e16045dbSVladimir Serbinenko fLastButtons(0),
51*e16045dbSVladimir Serbinenko fClickCount(0),
52*e16045dbSVladimir Serbinenko fLastClickTime(0),
53*e16045dbSVladimir Serbinenko fClickSpeed(250000),
54*e16045dbSVladimir Serbinenko fReportStatus(B_NO_INIT),
55*e16045dbSVladimir Serbinenko fCurrentReportLength(0),
56*e16045dbSVladimir Serbinenko fBusyCount(0)
57*e16045dbSVladimir Serbinenko {
58*e16045dbSVladimir Serbinenko fConditionVariable.Init(this, "elan report");
59*e16045dbSVladimir Serbinenko
60*e16045dbSVladimir Serbinenko uint16 descriptorAddress = 1;
61*e16045dbSVladimir Serbinenko // fetch HID descriptor
62*e16045dbSVladimir Serbinenko CALLED();
63*e16045dbSVladimir Serbinenko fStatus = _FetchBuffer((uint8*)&descriptorAddress,
64*e16045dbSVladimir Serbinenko sizeof(descriptorAddress), &fDescriptor, sizeof(fDescriptor));
65*e16045dbSVladimir Serbinenko if (fStatus != B_OK) {
66*e16045dbSVladimir Serbinenko ERROR("failed to fetch HID descriptor\n");
67*e16045dbSVladimir Serbinenko return;
68*e16045dbSVladimir Serbinenko }
69*e16045dbSVladimir Serbinenko
70*e16045dbSVladimir Serbinenko if (_SetAbsoluteMode(true) != B_OK) {
71*e16045dbSVladimir Serbinenko TRACE_ALWAYS("failed to set absolute mode\n");
72*e16045dbSVladimir Serbinenko return;
73*e16045dbSVladimir Serbinenko }
74*e16045dbSVladimir Serbinenko
75*e16045dbSVladimir Serbinenko fHardwareSpecs.areaStartX = 0;
76*e16045dbSVladimir Serbinenko fHardwareSpecs.areaStartY = 0;
77*e16045dbSVladimir Serbinenko
78*e16045dbSVladimir Serbinenko uint16_t buf;
79*e16045dbSVladimir Serbinenko
80*e16045dbSVladimir Serbinenko if (_ReadRegister(IETP_MAX_X_AXIS, sizeof(buf), &buf) != B_OK) {
81*e16045dbSVladimir Serbinenko TRACE_ALWAYS("failed reading max x\n");
82*e16045dbSVladimir Serbinenko return;
83*e16045dbSVladimir Serbinenko }
84*e16045dbSVladimir Serbinenko fHardwareSpecs.areaEndX = buf;
85*e16045dbSVladimir Serbinenko
86*e16045dbSVladimir Serbinenko if (_ReadRegister(IETP_MAX_Y_AXIS, sizeof(buf), &buf) != B_OK) {
87*e16045dbSVladimir Serbinenko TRACE_ALWAYS("failed reading max y\n");
88*e16045dbSVladimir Serbinenko return;
89*e16045dbSVladimir Serbinenko }
90*e16045dbSVladimir Serbinenko fHardwareSpecs.areaEndY = buf;
91*e16045dbSVladimir Serbinenko
92*e16045dbSVladimir Serbinenko fHardwareSpecs.edgeMotionWidth = 55;
93*e16045dbSVladimir Serbinenko
94*e16045dbSVladimir Serbinenko fHardwareSpecs.minPressure = 0;
95*e16045dbSVladimir Serbinenko fHardwareSpecs.realMaxPressure = 50;
96*e16045dbSVladimir Serbinenko fHardwareSpecs.maxPressure = 255;
97*e16045dbSVladimir Serbinenko
98*e16045dbSVladimir Serbinenko TRACE("Dimensions %dx%d\n", fHardwareSpecs.areaEndX, fHardwareSpecs.areaEndY);
99*e16045dbSVladimir Serbinenko
100*e16045dbSVladimir Serbinenko fStatus = B_OK;
101*e16045dbSVladimir Serbinenko }
102*e16045dbSVladimir Serbinenko
103*e16045dbSVladimir Serbinenko
~ELANDevice()104*e16045dbSVladimir Serbinenko ELANDevice::~ELANDevice()
105*e16045dbSVladimir Serbinenko {
106*e16045dbSVladimir Serbinenko }
107*e16045dbSVladimir Serbinenko
108*e16045dbSVladimir Serbinenko
109*e16045dbSVladimir Serbinenko status_t
Open(uint32 flags)110*e16045dbSVladimir Serbinenko ELANDevice::Open(uint32 flags)
111*e16045dbSVladimir Serbinenko {
112*e16045dbSVladimir Serbinenko atomic_add(&fOpenCount, 1);
113*e16045dbSVladimir Serbinenko _Reset();
114*e16045dbSVladimir Serbinenko
115*e16045dbSVladimir Serbinenko return B_OK;
116*e16045dbSVladimir Serbinenko }
117*e16045dbSVladimir Serbinenko
118*e16045dbSVladimir Serbinenko
119*e16045dbSVladimir Serbinenko status_t
Close()120*e16045dbSVladimir Serbinenko ELANDevice::Close()
121*e16045dbSVladimir Serbinenko {
122*e16045dbSVladimir Serbinenko atomic_add(&fOpenCount, -1);
123*e16045dbSVladimir Serbinenko _SetPower(I2C_HID_POWER_OFF);
124*e16045dbSVladimir Serbinenko
125*e16045dbSVladimir Serbinenko return B_OK;
126*e16045dbSVladimir Serbinenko }
127*e16045dbSVladimir Serbinenko
128*e16045dbSVladimir Serbinenko
129*e16045dbSVladimir Serbinenko void
Removed()130*e16045dbSVladimir Serbinenko ELANDevice::Removed()
131*e16045dbSVladimir Serbinenko {
132*e16045dbSVladimir Serbinenko fRemoved = true;
133*e16045dbSVladimir Serbinenko }
134*e16045dbSVladimir Serbinenko
135*e16045dbSVladimir Serbinenko
136*e16045dbSVladimir Serbinenko status_t
_MaybeScheduleTransfer(int type,int id,int reportSize)137*e16045dbSVladimir Serbinenko ELANDevice::_MaybeScheduleTransfer(int type, int id, int reportSize)
138*e16045dbSVladimir Serbinenko {
139*e16045dbSVladimir Serbinenko if (fRemoved)
140*e16045dbSVladimir Serbinenko return ENODEV;
141*e16045dbSVladimir Serbinenko
142*e16045dbSVladimir Serbinenko if (atomic_get_and_set(&fTransferScheduled, 1) != 0) {
143*e16045dbSVladimir Serbinenko // someone else already caused a transfer to be scheduled
144*e16045dbSVladimir Serbinenko return B_OK;
145*e16045dbSVladimir Serbinenko }
146*e16045dbSVladimir Serbinenko
147*e16045dbSVladimir Serbinenko snooze_until(fTransferLastschedule, B_SYSTEM_TIMEBASE);
148*e16045dbSVladimir Serbinenko fTransferLastschedule = system_time() + 10000;
149*e16045dbSVladimir Serbinenko
150*e16045dbSVladimir Serbinenko TRACE("scheduling interrupt transfer of %u bytes\n",
151*e16045dbSVladimir Serbinenko reportSize);
152*e16045dbSVladimir Serbinenko return _FetchReport(type, id, reportSize);
153*e16045dbSVladimir Serbinenko }
154*e16045dbSVladimir Serbinenko
155*e16045dbSVladimir Serbinenko void
SetPublishPath(char * publishPath)156*e16045dbSVladimir Serbinenko ELANDevice::SetPublishPath(char *publishPath)
157*e16045dbSVladimir Serbinenko {
158*e16045dbSVladimir Serbinenko free(fPublishPath);
159*e16045dbSVladimir Serbinenko fPublishPath = publishPath;
160*e16045dbSVladimir Serbinenko }
161*e16045dbSVladimir Serbinenko
162*e16045dbSVladimir Serbinenko status_t
Control(uint32 op,void * buffer,size_t length)163*e16045dbSVladimir Serbinenko ELANDevice::Control(uint32 op, void *buffer,
164*e16045dbSVladimir Serbinenko size_t length)
165*e16045dbSVladimir Serbinenko {
166*e16045dbSVladimir Serbinenko switch (op) {
167*e16045dbSVladimir Serbinenko
168*e16045dbSVladimir Serbinenko case B_GET_DEVICE_NAME:
169*e16045dbSVladimir Serbinenko {
170*e16045dbSVladimir Serbinenko if (!IS_USER_ADDRESS(buffer))
171*e16045dbSVladimir Serbinenko return B_BAD_ADDRESS;
172*e16045dbSVladimir Serbinenko
173*e16045dbSVladimir Serbinenko if (user_strlcpy((char *)buffer, "Elantech I2C touchpad", length) > 0)
174*e16045dbSVladimir Serbinenko return B_OK;
175*e16045dbSVladimir Serbinenko
176*e16045dbSVladimir Serbinenko return B_ERROR;
177*e16045dbSVladimir Serbinenko }
178*e16045dbSVladimir Serbinenko
179*e16045dbSVladimir Serbinenko case MS_IS_TOUCHPAD:
180*e16045dbSVladimir Serbinenko TRACE("ELANTECH: MS_IS_TOUCHPAD\n");
181*e16045dbSVladimir Serbinenko if (buffer == NULL)
182*e16045dbSVladimir Serbinenko return B_OK;
183*e16045dbSVladimir Serbinenko return user_memcpy(buffer, &fHardwareSpecs, sizeof(fHardwareSpecs));
184*e16045dbSVladimir Serbinenko
185*e16045dbSVladimir Serbinenko case MS_READ_TOUCHPAD:
186*e16045dbSVladimir Serbinenko {
187*e16045dbSVladimir Serbinenko touchpad_read read;
188*e16045dbSVladimir Serbinenko int zero_report_count = 0;
189*e16045dbSVladimir Serbinenko if (length < sizeof(touchpad_read))
190*e16045dbSVladimir Serbinenko return B_BUFFER_OVERFLOW;
191*e16045dbSVladimir Serbinenko
192*e16045dbSVladimir Serbinenko if (user_memcpy(&read.timeout, &(((touchpad_read*)buffer)->timeout),
193*e16045dbSVladimir Serbinenko sizeof(bigtime_t)) != B_OK)
194*e16045dbSVladimir Serbinenko return B_BAD_ADDRESS;
195*e16045dbSVladimir Serbinenko
196*e16045dbSVladimir Serbinenko read.event = MS_READ_TOUCHPAD;
197*e16045dbSVladimir Serbinenko
198*e16045dbSVladimir Serbinenko while (true) {
199*e16045dbSVladimir Serbinenko status_t result = _ReadAndParseReport(
200*e16045dbSVladimir Serbinenko &read.u.touchpad, read.timeout,
201*e16045dbSVladimir Serbinenko zero_report_count);
202*e16045dbSVladimir Serbinenko if (result == B_INTERRUPTED)
203*e16045dbSVladimir Serbinenko continue;
204*e16045dbSVladimir Serbinenko
205*e16045dbSVladimir Serbinenko if (!IS_USER_ADDRESS(buffer)
206*e16045dbSVladimir Serbinenko || user_memcpy(buffer, &read, sizeof(read))
207*e16045dbSVladimir Serbinenko != B_OK) {
208*e16045dbSVladimir Serbinenko return B_BAD_ADDRESS;
209*e16045dbSVladimir Serbinenko }
210*e16045dbSVladimir Serbinenko
211*e16045dbSVladimir Serbinenko TRACE("Returning MS_READ_TOUCHPAD: %x\n", result);
212*e16045dbSVladimir Serbinenko
213*e16045dbSVladimir Serbinenko return result;
214*e16045dbSVladimir Serbinenko }
215*e16045dbSVladimir Serbinenko }
216*e16045dbSVladimir Serbinenko }
217*e16045dbSVladimir Serbinenko
218*e16045dbSVladimir Serbinenko return B_ERROR;
219*e16045dbSVladimir Serbinenko }
220*e16045dbSVladimir Serbinenko
221*e16045dbSVladimir Serbinenko
222*e16045dbSVladimir Serbinenko status_t
_SetAbsoluteMode(bool enable)223*e16045dbSVladimir Serbinenko ELANDevice::_SetAbsoluteMode(bool enable)
224*e16045dbSVladimir Serbinenko {
225*e16045dbSVladimir Serbinenko return _WriteRegister(IETP_CONTROL, enable ? IETP_CTRL_ABSOLUTE : IETP_CTRL_STANDARD);
226*e16045dbSVladimir Serbinenko }
227*e16045dbSVladimir Serbinenko
228*e16045dbSVladimir Serbinenko
229*e16045dbSVladimir Serbinenko status_t
_WaitForReport(bigtime_t timeout)230*e16045dbSVladimir Serbinenko ELANDevice::_WaitForReport(bigtime_t timeout)
231*e16045dbSVladimir Serbinenko {
232*e16045dbSVladimir Serbinenko CALLED();
233*e16045dbSVladimir Serbinenko while (atomic_get(&fBusyCount) != 0)
234*e16045dbSVladimir Serbinenko snooze(1000);
235*e16045dbSVladimir Serbinenko
236*e16045dbSVladimir Serbinenko ConditionVariableEntry conditionVariableEntry;
237*e16045dbSVladimir Serbinenko fConditionVariable.Add(&conditionVariableEntry);
238*e16045dbSVladimir Serbinenko TRACE("Starting report wait\n");
239*e16045dbSVladimir Serbinenko status_t result = _MaybeScheduleTransfer(
240*e16045dbSVladimir Serbinenko HID_REPORT_TYPE_INPUT, fReportID,
241*e16045dbSVladimir Serbinenko fHighPrecision ? HI_ELAN_REPORT_SIZE : LO_ELAN_REPORT_SIZE);
242*e16045dbSVladimir Serbinenko if (result != B_OK) {
243*e16045dbSVladimir Serbinenko TRACE_ALWAYS("scheduling transfer failed\n");
244*e16045dbSVladimir Serbinenko conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, 0);
245*e16045dbSVladimir Serbinenko return result;
246*e16045dbSVladimir Serbinenko }
247*e16045dbSVladimir Serbinenko
248*e16045dbSVladimir Serbinenko result = conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, timeout);
249*e16045dbSVladimir Serbinenko if (result != B_OK)
250*e16045dbSVladimir Serbinenko return result;
251*e16045dbSVladimir Serbinenko
252*e16045dbSVladimir Serbinenko if (fReportStatus != B_OK)
253*e16045dbSVladimir Serbinenko return fReportStatus;
254*e16045dbSVladimir Serbinenko
255*e16045dbSVladimir Serbinenko atomic_add(&fBusyCount, 1);
256*e16045dbSVladimir Serbinenko return B_OK;
257*e16045dbSVladimir Serbinenko }
258*e16045dbSVladimir Serbinenko
259*e16045dbSVladimir Serbinenko
260*e16045dbSVladimir Serbinenko status_t
_ReadAndParseReport(touchpad_movement * info,bigtime_t timeout,int & zero_report_count)261*e16045dbSVladimir Serbinenko ELANDevice::_ReadAndParseReport(touchpad_movement *info, bigtime_t timeout, int &zero_report_count)
262*e16045dbSVladimir Serbinenko {
263*e16045dbSVladimir Serbinenko CALLED();
264*e16045dbSVladimir Serbinenko status_t result = _WaitForReport(timeout);
265*e16045dbSVladimir Serbinenko if (result != B_OK) {
266*e16045dbSVladimir Serbinenko if (IsRemoved()) {
267*e16045dbSVladimir Serbinenko TRACE("device has been removed\n");
268*e16045dbSVladimir Serbinenko return B_DEV_NOT_READY;
269*e16045dbSVladimir Serbinenko }
270*e16045dbSVladimir Serbinenko
271*e16045dbSVladimir Serbinenko if (result != B_INTERRUPTED) {
272*e16045dbSVladimir Serbinenko // interrupts happen when other reports come in on the same
273*e16045dbSVladimir Serbinenko // input as ours
274*e16045dbSVladimir Serbinenko TRACE_ALWAYS("error waiting for report: %s\n", strerror(result));
275*e16045dbSVladimir Serbinenko }
276*e16045dbSVladimir Serbinenko
277*e16045dbSVladimir Serbinenko if (result == B_TIMED_OUT) {
278*e16045dbSVladimir Serbinenko return result;
279*e16045dbSVladimir Serbinenko }
280*e16045dbSVladimir Serbinenko
281*e16045dbSVladimir Serbinenko // signal that we simply want to try again
282*e16045dbSVladimir Serbinenko return B_INTERRUPTED;
283*e16045dbSVladimir Serbinenko }
284*e16045dbSVladimir Serbinenko
285*e16045dbSVladimir Serbinenko if (fCurrentReportLength == 0 && ++zero_report_count < 3) {
286*e16045dbSVladimir Serbinenko atomic_add(&fBusyCount, -1);
287*e16045dbSVladimir Serbinenko return B_INTERRUPTED;
288*e16045dbSVladimir Serbinenko }
289*e16045dbSVladimir Serbinenko
290*e16045dbSVladimir Serbinenko uint8 report_copy[TRANSFER_BUFFER_SIZE];
291*e16045dbSVladimir Serbinenko memset(report_copy, 0, TRANSFER_BUFFER_SIZE);
292*e16045dbSVladimir Serbinenko memcpy(report_copy, fCurrentReport, MIN(TRANSFER_BUFFER_SIZE, fCurrentReportLength));
293*e16045dbSVladimir Serbinenko atomic_add(&fBusyCount, -1);
294*e16045dbSVladimir Serbinenko
295*e16045dbSVladimir Serbinenko memset(info, 0, sizeof(*info));
296*e16045dbSVladimir Serbinenko
297*e16045dbSVladimir Serbinenko if (report_copy[0] == 0 || report_copy[0] == 0xff)
298*e16045dbSVladimir Serbinenko return B_OK;
299*e16045dbSVladimir Serbinenko
300*e16045dbSVladimir Serbinenko info->buttons = report_copy[0] & 0x7;
301*e16045dbSVladimir Serbinenko uint8 fingers = (report_copy[0] >> 3) & 0x1f;
302*e16045dbSVladimir Serbinenko info->fingers = fingers;
303*e16045dbSVladimir Serbinenko TRACE("buttons=%x, fingers=%x\n", info->buttons, fingers);
304*e16045dbSVladimir Serbinenko const uint8 *fingerData = fCurrentReport + 1;
305*e16045dbSVladimir Serbinenko int fingerCount = 0;
306*e16045dbSVladimir Serbinenko int sumx = 0, sumy = 0, sumz = 0, sumw = 0;
307*e16045dbSVladimir Serbinenko for (int finger = 0; finger < 5; finger++, fingerData += 5)
308*e16045dbSVladimir Serbinenko if (fingers & (1 << finger)) {
309*e16045dbSVladimir Serbinenko TRACE("finger %d:\n", finger);
310*e16045dbSVladimir Serbinenko uint8 wh;
311*e16045dbSVladimir Serbinenko int x, y, w;
312*e16045dbSVladimir Serbinenko if (fHighPrecision) {
313*e16045dbSVladimir Serbinenko x = fingerData[0] << 8 | fingerData[1];
314*e16045dbSVladimir Serbinenko y = fingerData[2] << 8 | fingerData[3];
315*e16045dbSVladimir Serbinenko wh = report_copy[30 + finger];
316*e16045dbSVladimir Serbinenko } else {
317*e16045dbSVladimir Serbinenko x = (fingerData[0] & 0xf0) << 4 | fingerData[1];
318*e16045dbSVladimir Serbinenko y = (fingerData[0] & 0x0f) << 8 | fingerData[2];
319*e16045dbSVladimir Serbinenko wh = fingerData[3];
320*e16045dbSVladimir Serbinenko }
321*e16045dbSVladimir Serbinenko
322*e16045dbSVladimir Serbinenko int z = fingerData[4];
323*e16045dbSVladimir Serbinenko
324*e16045dbSVladimir Serbinenko w = MAX((wh >> 4) & 0xf, wh & 0xf);
325*e16045dbSVladimir Serbinenko
326*e16045dbSVladimir Serbinenko sumw += w;
327*e16045dbSVladimir Serbinenko sumx += x;
328*e16045dbSVladimir Serbinenko sumy += y;
329*e16045dbSVladimir Serbinenko sumz += z;
330*e16045dbSVladimir Serbinenko
331*e16045dbSVladimir Serbinenko TRACE("x=%d, y=%d, z=%d, w=%d, wh=0x%x\n", x, y, z, w, wh);
332*e16045dbSVladimir Serbinenko
333*e16045dbSVladimir Serbinenko fingerCount++;
334*e16045dbSVladimir Serbinenko }
335*e16045dbSVladimir Serbinenko if (fingerCount > 0) {
336*e16045dbSVladimir Serbinenko info->xPosition = sumx / fingerCount;
337*e16045dbSVladimir Serbinenko info->yPosition = sumy / fingerCount;
338*e16045dbSVladimir Serbinenko info->zPressure = sumz / fingerCount;
339*e16045dbSVladimir Serbinenko info->fingerWidth = MIN(12, sumw / fingerCount);
340*e16045dbSVladimir Serbinenko }
341*e16045dbSVladimir Serbinenko
342*e16045dbSVladimir Serbinenko TRACE("Resulting position=[%d, %d, %d, %d]\n",
343*e16045dbSVladimir Serbinenko info->xPosition, info->yPosition, info->zPressure,
344*e16045dbSVladimir Serbinenko info->fingerWidth);
345*e16045dbSVladimir Serbinenko
346*e16045dbSVladimir Serbinenko return B_OK;
347*e16045dbSVladimir Serbinenko }
348*e16045dbSVladimir Serbinenko
349*e16045dbSVladimir Serbinenko
350*e16045dbSVladimir Serbinenko void
_UnstallCallback(void * cookie,status_t status,void * data,size_t actualLength)351*e16045dbSVladimir Serbinenko ELANDevice::_UnstallCallback(void *cookie, status_t status, void *data,
352*e16045dbSVladimir Serbinenko size_t actualLength)
353*e16045dbSVladimir Serbinenko {
354*e16045dbSVladimir Serbinenko ELANDevice *device = (ELANDevice *)cookie;
355*e16045dbSVladimir Serbinenko if (status != B_OK) {
356*e16045dbSVladimir Serbinenko TRACE_ALWAYS("Unable to unstall device: %s\n", strerror(status));
357*e16045dbSVladimir Serbinenko }
358*e16045dbSVladimir Serbinenko
359*e16045dbSVladimir Serbinenko // Now report the original failure, since we're ready to retry
360*e16045dbSVladimir Serbinenko _TransferCallback(cookie, B_ERROR, device->fTransferBuffer, 0);
361*e16045dbSVladimir Serbinenko }
362*e16045dbSVladimir Serbinenko
363*e16045dbSVladimir Serbinenko
364*e16045dbSVladimir Serbinenko void
_TransferCallback(void * cookie,status_t status,void * data,size_t actualLength)365*e16045dbSVladimir Serbinenko ELANDevice::_TransferCallback(void *cookie, status_t status, void *data,
366*e16045dbSVladimir Serbinenko size_t actualLength)
367*e16045dbSVladimir Serbinenko {
368*e16045dbSVladimir Serbinenko ELANDevice *device = (ELANDevice *)cookie;
369*e16045dbSVladimir Serbinenko
370*e16045dbSVladimir Serbinenko atomic_set(&device->fTransferScheduled, 0);
371*e16045dbSVladimir Serbinenko device->_SetReport(status, device->fTransferBuffer, actualLength);
372*e16045dbSVladimir Serbinenko }
373*e16045dbSVladimir Serbinenko
374*e16045dbSVladimir Serbinenko
375*e16045dbSVladimir Serbinenko status_t
_Reset()376*e16045dbSVladimir Serbinenko ELANDevice::_Reset()
377*e16045dbSVladimir Serbinenko {
378*e16045dbSVladimir Serbinenko CALLED();
379*e16045dbSVladimir Serbinenko status_t status = _SetPower(I2C_HID_POWER_ON);
380*e16045dbSVladimir Serbinenko if (status != B_OK)
381*e16045dbSVladimir Serbinenko return status;
382*e16045dbSVladimir Serbinenko
383*e16045dbSVladimir Serbinenko snooze(1000);
384*e16045dbSVladimir Serbinenko
385*e16045dbSVladimir Serbinenko uint8 cmd[] = {
386*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister & 0xff),
387*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister >> 8),
388*e16045dbSVladimir Serbinenko 0,
389*e16045dbSVladimir Serbinenko I2C_HID_CMD_RESET,
390*e16045dbSVladimir Serbinenko };
391*e16045dbSVladimir Serbinenko
392*e16045dbSVladimir Serbinenko status = _ExecCommand(I2C_OP_WRITE_STOP, cmd, sizeof(cmd), NULL, 0);
393*e16045dbSVladimir Serbinenko if (status != B_OK) {
394*e16045dbSVladimir Serbinenko _SetPower(I2C_HID_POWER_OFF);
395*e16045dbSVladimir Serbinenko return status;
396*e16045dbSVladimir Serbinenko }
397*e16045dbSVladimir Serbinenko
398*e16045dbSVladimir Serbinenko snooze(1000);
399*e16045dbSVladimir Serbinenko return B_OK;
400*e16045dbSVladimir Serbinenko }
401*e16045dbSVladimir Serbinenko
402*e16045dbSVladimir Serbinenko
403*e16045dbSVladimir Serbinenko status_t
_SetPower(uint8 power)404*e16045dbSVladimir Serbinenko ELANDevice::_SetPower(uint8 power)
405*e16045dbSVladimir Serbinenko {
406*e16045dbSVladimir Serbinenko CALLED();
407*e16045dbSVladimir Serbinenko uint8 cmd[] = {
408*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister & 0xff),
409*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister >> 8),
410*e16045dbSVladimir Serbinenko power,
411*e16045dbSVladimir Serbinenko I2C_HID_CMD_SET_POWER
412*e16045dbSVladimir Serbinenko };
413*e16045dbSVladimir Serbinenko
414*e16045dbSVladimir Serbinenko return _ExecCommand(I2C_OP_WRITE_STOP, cmd, sizeof(cmd), NULL, 0);
415*e16045dbSVladimir Serbinenko }
416*e16045dbSVladimir Serbinenko
417*e16045dbSVladimir Serbinenko
418*e16045dbSVladimir Serbinenko status_t
_ReadRegister(uint16_t reg,size_t length,void * value)419*e16045dbSVladimir Serbinenko ELANDevice::_ReadRegister(uint16_t reg, size_t length, void *value)
420*e16045dbSVladimir Serbinenko {
421*e16045dbSVladimir Serbinenko uint8_t cmd[2] = {
422*e16045dbSVladimir Serbinenko (uint8_t) (reg & 0xff), (uint8_t) ((reg >> 8) & 0xff) };
423*e16045dbSVladimir Serbinenko status_t status = _FetchBuffer(cmd, sizeof(cmd), fTransferBuffer,
424*e16045dbSVladimir Serbinenko length);
425*e16045dbSVladimir Serbinenko TRACE("Read register 0x%04x with value 0x%02x 0x%02x status=%d\n",
426*e16045dbSVladimir Serbinenko reg, fTransferBuffer[0], fTransferBuffer[1], status);
427*e16045dbSVladimir Serbinenko if (status != B_OK)
428*e16045dbSVladimir Serbinenko return status;
429*e16045dbSVladimir Serbinenko memcpy(value, fTransferBuffer, length);
430*e16045dbSVladimir Serbinenko return B_OK;
431*e16045dbSVladimir Serbinenko }
432*e16045dbSVladimir Serbinenko
433*e16045dbSVladimir Serbinenko
434*e16045dbSVladimir Serbinenko status_t
_WriteRegister(uint16_t reg,uint16_t value)435*e16045dbSVladimir Serbinenko ELANDevice::_WriteRegister(uint16_t reg, uint16_t value)
436*e16045dbSVladimir Serbinenko {
437*e16045dbSVladimir Serbinenko uint8_t cmd[4] = { (uint8_t) (reg & 0xff),
438*e16045dbSVladimir Serbinenko (uint8_t) ((reg >> 8) & 0xff),
439*e16045dbSVladimir Serbinenko (uint8_t) (value & 0xff),
440*e16045dbSVladimir Serbinenko (uint8_t) ((value >> 8) & 0xff) };
441*e16045dbSVladimir Serbinenko TRACE("Write register 0x%04x with value 0x%04x\n", reg, value);
442*e16045dbSVladimir Serbinenko status_t status = _FetchBuffer(cmd, sizeof(cmd), fTransferBuffer, 0);
443*e16045dbSVladimir Serbinenko TRACE("status=%d\n", status);
444*e16045dbSVladimir Serbinenko return status;
445*e16045dbSVladimir Serbinenko }
446*e16045dbSVladimir Serbinenko
447*e16045dbSVladimir Serbinenko
448*e16045dbSVladimir Serbinenko status_t
_FetchReport(uint8 type,uint8 id,size_t reportSize)449*e16045dbSVladimir Serbinenko ELANDevice::_FetchReport(uint8 type, uint8 id, size_t reportSize)
450*e16045dbSVladimir Serbinenko {
451*e16045dbSVladimir Serbinenko uint8 reportId = id > 15 ? 15 : id;
452*e16045dbSVladimir Serbinenko size_t cmdLength = 6;
453*e16045dbSVladimir Serbinenko uint8 cmd[] = {
454*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister & 0xff),
455*e16045dbSVladimir Serbinenko (uint8)(fDescriptor.wCommandRegister >> 8),
456*e16045dbSVladimir Serbinenko (uint8)(reportId | (type << 4)),
457*e16045dbSVladimir Serbinenko I2C_HID_CMD_GET_REPORT,
458*e16045dbSVladimir Serbinenko 0, 0, 0,
459*e16045dbSVladimir Serbinenko };
460*e16045dbSVladimir Serbinenko
461*e16045dbSVladimir Serbinenko int dataOffset = 4;
462*e16045dbSVladimir Serbinenko int reportIdLength = 1;
463*e16045dbSVladimir Serbinenko if (reportId == 15) {
464*e16045dbSVladimir Serbinenko cmd[dataOffset++] = id;
465*e16045dbSVladimir Serbinenko cmdLength++;
466*e16045dbSVladimir Serbinenko reportIdLength++;
467*e16045dbSVladimir Serbinenko }
468*e16045dbSVladimir Serbinenko cmd[dataOffset++] = fDescriptor.wDataRegister & 0xff;
469*e16045dbSVladimir Serbinenko cmd[dataOffset++] = fDescriptor.wDataRegister >> 8;
470*e16045dbSVladimir Serbinenko
471*e16045dbSVladimir Serbinenko size_t bufferLength = reportSize + reportIdLength + 2;
472*e16045dbSVladimir Serbinenko
473*e16045dbSVladimir Serbinenko status_t status = _FetchBuffer(cmd, cmdLength, fTransferBuffer,
474*e16045dbSVladimir Serbinenko bufferLength);
475*e16045dbSVladimir Serbinenko if (status != B_OK) {
476*e16045dbSVladimir Serbinenko atomic_set(&fTransferScheduled, 0);
477*e16045dbSVladimir Serbinenko return status;
478*e16045dbSVladimir Serbinenko }
479*e16045dbSVladimir Serbinenko
480*e16045dbSVladimir Serbinenko uint16 actualLength = fTransferBuffer[0] | (fTransferBuffer[1] << 8);
481*e16045dbSVladimir Serbinenko TRACE("_FetchReport %" B_PRIuSIZE " %" B_PRIu16 "\n", reportSize,
482*e16045dbSVladimir Serbinenko actualLength);
483*e16045dbSVladimir Serbinenko
484*e16045dbSVladimir Serbinenko if (actualLength <= 2 || actualLength == 0xffff || bufferLength == 0)
485*e16045dbSVladimir Serbinenko actualLength = 0;
486*e16045dbSVladimir Serbinenko else
487*e16045dbSVladimir Serbinenko actualLength -= 2;
488*e16045dbSVladimir Serbinenko
489*e16045dbSVladimir Serbinenko atomic_set(&fTransferScheduled, 0);
490*e16045dbSVladimir Serbinenko _SetReport(status,
491*e16045dbSVladimir Serbinenko (uint8*)((addr_t)fTransferBuffer + 2), actualLength);
492*e16045dbSVladimir Serbinenko return B_OK;
493*e16045dbSVladimir Serbinenko }
494*e16045dbSVladimir Serbinenko
495*e16045dbSVladimir Serbinenko
496*e16045dbSVladimir Serbinenko void
_SetReport(status_t status,uint8 * report,size_t length)497*e16045dbSVladimir Serbinenko ELANDevice::_SetReport(status_t status, uint8 *report, size_t length)
498*e16045dbSVladimir Serbinenko {
499*e16045dbSVladimir Serbinenko if (status != B_OK) {
500*e16045dbSVladimir Serbinenko report = NULL;
501*e16045dbSVladimir Serbinenko length = 0;
502*e16045dbSVladimir Serbinenko }
503*e16045dbSVladimir Serbinenko
504*e16045dbSVladimir Serbinenko if (length < MIN_ELAN_REPORT && length != 0 && status == B_OK)
505*e16045dbSVladimir Serbinenko status = B_ERROR;
506*e16045dbSVladimir Serbinenko
507*e16045dbSVladimir Serbinenko if (status == B_OK && length != 0 && report[0] != fReportID) {
508*e16045dbSVladimir Serbinenko report = NULL;
509*e16045dbSVladimir Serbinenko length = 0;
510*e16045dbSVladimir Serbinenko status = B_INTERRUPTED;
511*e16045dbSVladimir Serbinenko }
512*e16045dbSVladimir Serbinenko
513*e16045dbSVladimir Serbinenko if (report && length) {
514*e16045dbSVladimir Serbinenko report++;
515*e16045dbSVladimir Serbinenko length--;
516*e16045dbSVladimir Serbinenko }
517*e16045dbSVladimir Serbinenko
518*e16045dbSVladimir Serbinenko fReportStatus = status;
519*e16045dbSVladimir Serbinenko fCurrentReportLength = length;
520*e16045dbSVladimir Serbinenko memset(fCurrentReport, 0, sizeof(fCurrentReport));
521*e16045dbSVladimir Serbinenko if (report && status == B_OK)
522*e16045dbSVladimir Serbinenko memcpy(fCurrentReport, report, MIN(sizeof(fCurrentReport), length));
523*e16045dbSVladimir Serbinenko fConditionVariable.NotifyAll();
524*e16045dbSVladimir Serbinenko }
525*e16045dbSVladimir Serbinenko
526*e16045dbSVladimir Serbinenko
527*e16045dbSVladimir Serbinenko status_t
_FetchBuffer(uint8 * cmd,size_t cmdLength,void * buffer,size_t bufferLength)528*e16045dbSVladimir Serbinenko ELANDevice::_FetchBuffer(uint8* cmd, size_t cmdLength, void* buffer,
529*e16045dbSVladimir Serbinenko size_t bufferLength)
530*e16045dbSVladimir Serbinenko {
531*e16045dbSVladimir Serbinenko return _ExecCommand(I2C_OP_READ_STOP, cmd, cmdLength,
532*e16045dbSVladimir Serbinenko buffer, bufferLength);
533*e16045dbSVladimir Serbinenko }
534*e16045dbSVladimir Serbinenko
535*e16045dbSVladimir Serbinenko
536*e16045dbSVladimir Serbinenko status_t
_ExecCommand(i2c_op op,uint8 * cmd,size_t cmdLength,void * buffer,size_t bufferLength)537*e16045dbSVladimir Serbinenko ELANDevice::_ExecCommand(i2c_op op, uint8* cmd, size_t cmdLength, void* buffer,
538*e16045dbSVladimir Serbinenko size_t bufferLength)
539*e16045dbSVladimir Serbinenko {
540*e16045dbSVladimir Serbinenko status_t status = fI2C->acquire_bus(fI2CCookie);
541*e16045dbSVladimir Serbinenko if (status != B_OK)
542*e16045dbSVladimir Serbinenko return status;
543*e16045dbSVladimir Serbinenko status = fI2C->exec_command(fI2CCookie, I2C_OP_READ_STOP, cmd, cmdLength,
544*e16045dbSVladimir Serbinenko buffer, bufferLength);
545*e16045dbSVladimir Serbinenko fI2C->release_bus(fI2CCookie);
546*e16045dbSVladimir Serbinenko return status;
547*e16045dbSVladimir Serbinenko }
548