mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
ietp(4): Load dummy HID report descriptor if mangled
Some Elantech trackpads have a mangled HID report descriptor, which reads as having an incorrect input size (i.e. < IETP_REPORT_LEN_LO). If the input size is incorrect, load a dummy report descriptor. Reviewed by: wulf MFC after: 1 week Differential revision: https://reviews.freebsd.org/D38387
This commit is contained in:
parent
e4d3f1e40a
commit
8d5fef85f0
1 changed files with 70 additions and 23 deletions
|
|
@ -118,7 +118,7 @@ struct ietp_softc {
|
|||
uint16_t trace_y;
|
||||
uint16_t res_x; /* dots per mm */
|
||||
uint16_t res_y;
|
||||
bool hi_precission;
|
||||
bool hi_precision;
|
||||
bool is_clickpad;
|
||||
bool has_3buttons;
|
||||
};
|
||||
|
|
@ -132,9 +132,10 @@ static int ietp_attach(struct ietp_softc *);
|
|||
static int ietp_detach(struct ietp_softc *);
|
||||
static int32_t ietp_res2dpmm(uint8_t, bool);
|
||||
|
||||
static device_probe_t ietp_iic_probe;
|
||||
static device_attach_t ietp_iic_attach;
|
||||
static device_detach_t ietp_iic_detach;
|
||||
static device_identify_t ietp_iic_identify;
|
||||
static device_probe_t ietp_iic_probe;
|
||||
static device_attach_t ietp_iic_attach;
|
||||
static device_detach_t ietp_iic_detach;
|
||||
static device_resume_t ietp_iic_resume;
|
||||
|
||||
static int ietp_iic_read_reg(device_t, uint16_t, size_t, void *);
|
||||
|
|
@ -200,6 +201,17 @@ static const struct hid_device_id ietp_iic_devs[] = {
|
|||
IETP_IIC_DEV("ELAN1000"),
|
||||
};
|
||||
|
||||
static uint8_t const ietp_dummy_rdesc[] = {
|
||||
0x05, HUP_GENERIC_DESKTOP, /* Usage Page (Generic Desktop Ctrls) */
|
||||
0x09, HUG_MOUSE, /* Usage (Mouse) */
|
||||
0xA1, 0x01, /* Collection (Application) */
|
||||
0x09, 0x01, /* Usage (0x01) */
|
||||
0x95, IETP_REPORT_LEN_LO, /* Report Count (IETP_REPORT_LEN_LO) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x81, 0x02, /* Input (Data,Var,Abs) */
|
||||
0xC0, /* End Collection */
|
||||
};
|
||||
|
||||
static const struct evdev_methods ietp_evdev_methods = {
|
||||
.ev_open = &ietp_ev_open,
|
||||
.ev_close = &ietp_ev_close,
|
||||
|
|
@ -241,9 +253,9 @@ ietp_attach(struct ietp_softc *sc)
|
|||
int32_t minor, major;
|
||||
int error;
|
||||
|
||||
sc->report_id = sc->hi_precission ?
|
||||
sc->report_id = sc->hi_precision ?
|
||||
IETP_REPORT_ID_HI : IETP_REPORT_ID_LO;
|
||||
sc->report_len = sc->hi_precission ?
|
||||
sc->report_len = sc->hi_precision ?
|
||||
IETP_REPORT_LEN_HI : IETP_REPORT_LEN_LO;
|
||||
|
||||
/* Try to detect 3-rd button by relative mouse TLC */
|
||||
|
|
@ -334,15 +346,31 @@ ietp_intr(void *context, void *buf, hid_size_t len)
|
|||
int32_t x, y, w, h, wh;
|
||||
|
||||
/* we seem to get 0 length reports sometimes, ignore them */
|
||||
report = buf;
|
||||
if (*report != sc->report_id || len < sc->report_len)
|
||||
if (len == 0)
|
||||
return;
|
||||
if (len != sc->report_len) {
|
||||
DPRINTF("wrong report length (%d vs %d expected)", len, sc->report_len);
|
||||
return;
|
||||
}
|
||||
|
||||
report = buf;
|
||||
if (*report != sc->report_id)
|
||||
return;
|
||||
|
||||
evdev_push_key(sc->evdev, BTN_LEFT,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_LMB);
|
||||
evdev_push_key(sc->evdev, BTN_MIDDLE,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_MMB);
|
||||
evdev_push_key(sc->evdev, BTN_RIGHT,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_RMB);
|
||||
evdev_push_abs(sc->evdev, ABS_DISTANCE,
|
||||
(report[IETP_HOVER_INFO] & 0x40) >> 6);
|
||||
|
||||
for (finger = 0, fdata = report + IETP_FINGER_DATA;
|
||||
finger < IETP_MAX_FINGERS;
|
||||
finger++, fdata += IETP_FINGER_DATA_LEN) {
|
||||
if ((report[IETP_TOUCH_INFO] & (1 << (finger + 3))) != 0) {
|
||||
if (sc->hi_precission) {
|
||||
if (sc->hi_precision) {
|
||||
x = fdata[0] << 8 | fdata[1];
|
||||
y = fdata[2] << 8 | fdata[3];
|
||||
wh = report[IETP_WH_DATA + finger];
|
||||
|
|
@ -379,28 +407,46 @@ ietp_intr(void *context, void *buf, hid_size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
evdev_push_key(sc->evdev, BTN_LEFT,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_LMB);
|
||||
evdev_push_key(sc->evdev, BTN_MIDDLE,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_MMB);
|
||||
evdev_push_key(sc->evdev, BTN_RIGHT,
|
||||
report[IETP_TOUCH_INFO] & IETP_TOUCH_RMB);
|
||||
evdev_push_abs(sc->evdev, ABS_DISTANCE,
|
||||
(report[IETP_HOVER_INFO] & 0x40) >> 6);
|
||||
|
||||
evdev_sync(sc->evdev);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ietp_res2dpmm(uint8_t res, bool hi_precission)
|
||||
ietp_res2dpmm(uint8_t res, bool hi_precision)
|
||||
{
|
||||
int32_t dpi;
|
||||
|
||||
dpi = hi_precission ? 300 + res * 100 : 790 + res * 10;
|
||||
dpi = hi_precision ? 300 + res * 100 : 790 + res * 10;
|
||||
|
||||
return (dpi * 10 /254);
|
||||
}
|
||||
|
||||
static void
|
||||
ietp_iic_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
void *d_ptr;
|
||||
hid_size_t d_len;
|
||||
int isize;
|
||||
uint8_t iid;
|
||||
|
||||
if (HIDBUS_LOOKUP_ID(parent, ietp_iic_devs) == NULL)
|
||||
return;
|
||||
if (hid_get_report_descr(parent, &d_ptr, &d_len) != 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some Elantech trackpads have a mangled HID report descriptor, which
|
||||
* reads as having an incorrect input size (i.e. < IETP_REPORT_LEN_LO).
|
||||
* If the input size is incorrect, load a dummy report descriptor.
|
||||
*/
|
||||
|
||||
isize = hid_report_size_max(d_ptr, d_len, hid_input, &iid);
|
||||
if (isize >= IETP_REPORT_LEN_LO)
|
||||
return;
|
||||
|
||||
hid_set_report_descr(parent, ietp_dummy_rdesc,
|
||||
sizeof(ietp_dummy_rdesc));
|
||||
}
|
||||
|
||||
static int
|
||||
ietp_iic_probe(device_t dev)
|
||||
{
|
||||
|
|
@ -442,7 +488,7 @@ ietp_iic_attach(device_t dev)
|
|||
return (EIO);
|
||||
}
|
||||
pattern = buf == 0xFFFF ? 0 : buf8[1];
|
||||
sc->hi_precission = pattern >= 0x02;
|
||||
sc->hi_precision = pattern >= 0x02;
|
||||
|
||||
reg = pattern >= 0x01 ? IETP_IC_TYPE : IETP_OSM_VERSION;
|
||||
if (ietp_iic_read_reg(dev, reg, sizeof(buf), &buf) != 0) {
|
||||
|
|
@ -492,8 +538,8 @@ ietp_iic_attach(device_t dev)
|
|||
return (EIO);
|
||||
}
|
||||
/* Conversion from internal format to dot per mm */
|
||||
sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precission);
|
||||
sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precission);
|
||||
sc->res_x = ietp_res2dpmm(buf8[0], sc->hi_precision);
|
||||
sc->res_y = ietp_res2dpmm(buf8[1], sc->hi_precision);
|
||||
|
||||
return (ietp_attach(sc));
|
||||
}
|
||||
|
|
@ -610,6 +656,7 @@ ietp_iic_write_reg(device_t dev, uint16_t reg, uint16_t val)
|
|||
}
|
||||
|
||||
static device_method_t ietp_methods[] = {
|
||||
DEVMETHOD(device_identify, ietp_iic_identify),
|
||||
DEVMETHOD(device_probe, ietp_iic_probe),
|
||||
DEVMETHOD(device_attach, ietp_iic_attach),
|
||||
DEVMETHOD(device_detach, ietp_iic_detach),
|
||||
|
|
|
|||
Loading…
Reference in a new issue