bcm5974: wsp(4) driver version with HID attachment.
MFC after: 2 month Tested by: Greg V (Type 4 touchpads)
This commit is contained in:
parent
82e38b012c
commit
5aa839c9e2
@ -70,6 +70,7 @@ MAN= aac.4 \
|
||||
axge.4 \
|
||||
axp.4 \
|
||||
bce.4 \
|
||||
bcm5974.4 \
|
||||
bcma.4 \
|
||||
bfe.4 \
|
||||
bge.4 \
|
||||
|
85
share/man/man4/bcm5974.4
Normal file
85
share/man/man4/bcm5974.4
Normal file
@ -0,0 +1,85 @@
|
||||
.\" Copyright (c) 2022 Vladimir Kondratyev <wulf@FreeBSD.org>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 27, 2022
|
||||
.Dt BCM5974 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm bcm5974
|
||||
.Nd Wellspring touchpad driver
|
||||
.Sh SYNOPSIS
|
||||
To compile this driver into the kernel, place the following lines into
|
||||
your kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device bcm5974"
|
||||
.Cd "device hidbus"
|
||||
.Cd "device hid"
|
||||
.Cd "device usbhid"
|
||||
.Cd "device usb"
|
||||
.Cd "device evdev"
|
||||
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a
|
||||
module at boot time, place the following line in
|
||||
.Xr loader.conf 5 :
|
||||
.Bd -literal -offset indent
|
||||
bcm5974_load="YES"
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides support for the Wellspring touchpads found in many Apple
|
||||
laptops.
|
||||
.Pp
|
||||
To get multi-touch device working in
|
||||
.Xr X 7 ,
|
||||
install
|
||||
.Pa ports/x11-drivers/xf86-input-libinput .
|
||||
.Sh FILES
|
||||
.Nm
|
||||
creates a pseudo-device file,
|
||||
.Pa /dev/input/eventX
|
||||
which presents the multi-touch device as an input event device.
|
||||
.Sh SEE ALSO
|
||||
.Xr hid 4 ,
|
||||
.Xr loader.conf 5 ,
|
||||
.Xr xorg.conf 5 Pq Pa ports/x11/xorg ,
|
||||
.Xr libinput 4 Pq Pa ports/x11-drivers/xf86-input-libinput .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
driver was written by
|
||||
.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
|
||||
It is based on
|
||||
.Xr wsp 4
|
||||
driver written by
|
||||
.An Huang Wen Hui Aq Mt huanghwh@gmail.com .
|
||||
.Sh BUGS
|
||||
.Nm
|
||||
cannot act like
|
||||
.Xr sysmouse 4
|
@ -1791,6 +1791,7 @@ dev/gpio/gpio_if.m optional gpio
|
||||
dev/gpio/gpiobus_if.m optional gpio
|
||||
dev/gpio/gpiopps.c optional gpiopps fdt
|
||||
dev/gpio/ofw_gpiobus.c optional fdt gpio
|
||||
dev/hid/bcm5974.c optional bcm5974
|
||||
dev/hid/hconf.c optional hconf
|
||||
dev/hid/hcons.c optional hcons
|
||||
dev/hid/hgame.c optional hgame
|
||||
|
794
sys/dev/hid/bcm5974.c
Normal file
794
sys/dev/hid/bcm5974.c
Normal file
@ -0,0 +1,794 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2012 Huang Wen Hui
|
||||
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <dev/evdev/input.h>
|
||||
#include <dev/evdev/evdev.h>
|
||||
|
||||
#define HID_DEBUG_VAR bcm5974_debug
|
||||
#include <dev/hid/hid.h>
|
||||
#include <dev/hid/hidbus.h>
|
||||
#include <dev/hid/hidquirk.h>
|
||||
|
||||
#include <dev/usb/usb.h>
|
||||
#include <dev/usb/usbdi.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
#include <dev/usb/usb_ioctl.h>
|
||||
|
||||
#include "usbdevs.h"
|
||||
|
||||
#define BCM5974_BUFFER_MAX (248 * 4) /* 4 Type4 SPI frames */
|
||||
#define BCM5974_TLC_PAGE HUP_GENERIC_DESKTOP
|
||||
#define BCM5974_TLC_USAGE HUG_MOUSE
|
||||
|
||||
/* magic to switch device from HID (default) mode into raw */
|
||||
/* Type1 & Type2 trackpads */
|
||||
#define BCM5974_USB_IFACE_INDEX 0
|
||||
#define BCM5974_USB_REPORT_LEN 8
|
||||
#define BCM5974_USB_REPORT_ID 0
|
||||
#define BCM5974_USB_MODE_RAW 0x01
|
||||
#define BCM5974_USB_MODE_HID 0x08
|
||||
/* Type4 trackpads */
|
||||
#define BCM5974_HID_REPORT_LEN 2
|
||||
#define BCM5974_HID_REPORT_ID 2
|
||||
#define BCM5974_HID_MODE_RAW 0x01
|
||||
#define BCM5974_HID_MODE_HID 0x00
|
||||
|
||||
/* Tunables */
|
||||
static SYSCTL_NODE(_hw_hid, OID_AUTO, bcm5974, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
|
||||
"HID wellspring touchpad");
|
||||
|
||||
#ifdef HID_DEBUG
|
||||
enum wsp_log_level {
|
||||
BCM5974_LLEVEL_DISABLED = 0,
|
||||
BCM5974_LLEVEL_ERROR,
|
||||
BCM5974_LLEVEL_DEBUG, /* for troubleshooting */
|
||||
BCM5974_LLEVEL_INFO, /* for diagnostics */
|
||||
};
|
||||
/* the default is to only log errors */
|
||||
static int bcm5974_debug = BCM5974_LLEVEL_ERROR;
|
||||
|
||||
SYSCTL_INT(_hw_hid_bcm5974, OID_AUTO, debug, CTLFLAG_RWTUN,
|
||||
&bcm5974_debug, BCM5974_LLEVEL_ERROR, "BCM5974 debug level");
|
||||
#endif /* HID_DEBUG */
|
||||
|
||||
/*
|
||||
* Some tables, structures, definitions and constant values for the
|
||||
* touchpad protocol has been copied from Linux's
|
||||
* "drivers/input/mouse/bcm5974.c" which has the following copyright
|
||||
* holders under GPLv2. All device specific code in this driver has
|
||||
* been written from scratch. The decoding algorithm is based on
|
||||
* output from FreeBSD's usbdump.
|
||||
*
|
||||
* Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
|
||||
* Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com)
|
||||
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
|
||||
* Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net)
|
||||
* Copyright (C) 2005 Stelian Pop (stelian@popies.net)
|
||||
* Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
|
||||
* Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
|
||||
* Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
|
||||
* Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch)
|
||||
*/
|
||||
|
||||
/* trackpad header types */
|
||||
enum tp_type {
|
||||
TYPE1, /* plain trackpad */
|
||||
TYPE2, /* button integrated in trackpad */
|
||||
TYPE3, /* additional header fields since June 2013 */
|
||||
TYPE4, /* additional header field for pressure data */
|
||||
TYPE_CNT
|
||||
};
|
||||
|
||||
/* list of device capability bits */
|
||||
#define HAS_INTEGRATED_BUTTON 1
|
||||
|
||||
struct tp_type_params {
|
||||
uint8_t caps; /* device capability bitmask */
|
||||
uint8_t button; /* offset to button data */
|
||||
uint8_t offset; /* offset to trackpad finger data */
|
||||
uint8_t delta; /* offset from header to finger struct */
|
||||
} const static tp[TYPE_CNT] = {
|
||||
[TYPE1] = {
|
||||
.caps = 0,
|
||||
.button = 0,
|
||||
.offset = 13 * 2,
|
||||
.delta = 0,
|
||||
},
|
||||
[TYPE2] = {
|
||||
.caps = HAS_INTEGRATED_BUTTON,
|
||||
.button = 15,
|
||||
.offset = 15 * 2,
|
||||
.delta = 0,
|
||||
},
|
||||
[TYPE3] = {
|
||||
.caps = HAS_INTEGRATED_BUTTON,
|
||||
.button = 23,
|
||||
.offset = 19 * 2,
|
||||
.delta = 0,
|
||||
},
|
||||
[TYPE4] = {
|
||||
.caps = HAS_INTEGRATED_BUTTON,
|
||||
.button = 31,
|
||||
.offset = 23 * 2,
|
||||
.delta = 2,
|
||||
},
|
||||
};
|
||||
|
||||
/* trackpad finger structure - little endian */
|
||||
struct tp_finger {
|
||||
int16_t origin; /* zero when switching track finger */
|
||||
int16_t abs_x; /* absolute x coodinate */
|
||||
int16_t abs_y; /* absolute y coodinate */
|
||||
int16_t rel_x; /* relative x coodinate */
|
||||
int16_t rel_y; /* relative y coodinate */
|
||||
int16_t tool_major; /* tool area, major axis */
|
||||
int16_t tool_minor; /* tool area, minor axis */
|
||||
int16_t orientation; /* 16384 when point, else 15 bit angle */
|
||||
int16_t touch_major; /* touch area, major axis */
|
||||
int16_t touch_minor; /* touch area, minor axis */
|
||||
int16_t unused[2]; /* zeros */
|
||||
int16_t pressure; /* pressure on forcetouch touchpad */
|
||||
int16_t multi; /* one finger: varies, more fingers:
|
||||
* constant */
|
||||
} __packed;
|
||||
|
||||
/* trackpad finger data size, empirically at least ten fingers */
|
||||
#define MAX_FINGERS MAX_MT_SLOTS
|
||||
|
||||
#define MAX_FINGER_ORIENTATION 16384
|
||||
|
||||
enum {
|
||||
BCM5974_FLAG_WELLSPRING1,
|
||||
BCM5974_FLAG_WELLSPRING2,
|
||||
BCM5974_FLAG_WELLSPRING3,
|
||||
BCM5974_FLAG_WELLSPRING4,
|
||||
BCM5974_FLAG_WELLSPRING4A,
|
||||
BCM5974_FLAG_WELLSPRING5,
|
||||
BCM5974_FLAG_WELLSPRING6A,
|
||||
BCM5974_FLAG_WELLSPRING6,
|
||||
BCM5974_FLAG_WELLSPRING5A,
|
||||
BCM5974_FLAG_WELLSPRING7,
|
||||
BCM5974_FLAG_WELLSPRING7A,
|
||||
BCM5974_FLAG_WELLSPRING8,
|
||||
BCM5974_FLAG_WELLSPRING9,
|
||||
BCM5974_FLAG_MAX,
|
||||
};
|
||||
|
||||
/* device-specific parameters */
|
||||
struct bcm5974_axis {
|
||||
int snratio; /* signal-to-noise ratio */
|
||||
int min; /* device minimum reading */
|
||||
int max; /* device maximum reading */
|
||||
int size; /* physical size, mm */
|
||||
};
|
||||
|
||||
/* device-specific configuration */
|
||||
struct bcm5974_dev_params {
|
||||
const struct tp_type_params* tp;
|
||||
struct bcm5974_axis p; /* finger pressure limits */
|
||||
struct bcm5974_axis w; /* finger width limits */
|
||||
struct bcm5974_axis x; /* horizontal limits */
|
||||
struct bcm5974_axis y; /* vertical limits */
|
||||
struct bcm5974_axis o; /* orientation limits */
|
||||
};
|
||||
|
||||
/* logical signal quality */
|
||||
#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
|
||||
#define SN_WIDTH 25 /* width signal-to-noise ratio */
|
||||
#define SN_COORD 250 /* coordinate signal-to-noise ratio */
|
||||
#define SN_ORIENT 10 /* orientation signal-to-noise ratio */
|
||||
|
||||
static const struct bcm5974_dev_params bcm5974_dev_params[BCM5974_FLAG_MAX] = {
|
||||
[BCM5974_FLAG_WELLSPRING1] = {
|
||||
.tp = tp + TYPE1,
|
||||
.p = { SN_PRESSURE, 0, 256, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4824, 5342, 105 },
|
||||
.y = { SN_COORD, -172, 5820, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING2] = {
|
||||
.tp = tp + TYPE1,
|
||||
.p = { SN_PRESSURE, 0, 256, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4824, 4824, 105 },
|
||||
.y = { SN_COORD, -172, 4290, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING3] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4460, 5166, 105 },
|
||||
.y = { SN_COORD, -75, 6700, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING4] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4620, 5140, 105 },
|
||||
.y = { SN_COORD, -150, 6600, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING4A] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4616, 5112, 105 },
|
||||
.y = { SN_COORD, -142, 5234, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING5] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4415, 5050, 105 },
|
||||
.y = { SN_COORD, -55, 6680, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING6] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4620, 5140, 105 },
|
||||
.y = { SN_COORD, -150, 6600, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING5A] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4750, 5280, 105 },
|
||||
.y = { SN_COORD, -150, 6730, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING6A] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4620, 5140, 105 },
|
||||
.y = { SN_COORD, -150, 6600, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING7] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4750, 5280, 105 },
|
||||
.y = { SN_COORD, -150, 6730, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING7A] = {
|
||||
.tp = tp + TYPE2,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4750, 5280, 105 },
|
||||
.y = { SN_COORD, -150, 6730, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING8] = {
|
||||
.tp = tp + TYPE3,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4620, 5140, 105 },
|
||||
.y = { SN_COORD, -150, 6600, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
[BCM5974_FLAG_WELLSPRING9] = {
|
||||
.tp = tp + TYPE4,
|
||||
.p = { SN_PRESSURE, 0, 300, 0 },
|
||||
.w = { SN_WIDTH, 0, 2048, 0 },
|
||||
.x = { SN_COORD, -4828, 5345, 105 },
|
||||
.y = { SN_COORD, -203, 6803, 75 },
|
||||
.o = { SN_ORIENT,
|
||||
-MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
#define BCM5974_DEV(v,p,i) { \
|
||||
HID_BVPI(BUS_USB, USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i), \
|
||||
HID_TLC(BCM5974_TLC_PAGE, BCM5974_TLC_USAGE), \
|
||||
}
|
||||
|
||||
static const struct hid_device_id bcm5974_devs[] = {
|
||||
/* MacbookAir1.1 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING_ANSI, BCM5974_FLAG_WELLSPRING1),
|
||||
BCM5974_DEV(APPLE, WELLSPRING_ISO, BCM5974_FLAG_WELLSPRING1),
|
||||
BCM5974_DEV(APPLE, WELLSPRING_JIS, BCM5974_FLAG_WELLSPRING1),
|
||||
|
||||
/* MacbookProPenryn, aka wellspring2 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING2_ANSI, BCM5974_FLAG_WELLSPRING2),
|
||||
BCM5974_DEV(APPLE, WELLSPRING2_ISO, BCM5974_FLAG_WELLSPRING2),
|
||||
BCM5974_DEV(APPLE, WELLSPRING2_JIS, BCM5974_FLAG_WELLSPRING2),
|
||||
|
||||
/* Macbook5,1 (unibody), aka wellspring3 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING3_ANSI, BCM5974_FLAG_WELLSPRING3),
|
||||
BCM5974_DEV(APPLE, WELLSPRING3_ISO, BCM5974_FLAG_WELLSPRING3),
|
||||
BCM5974_DEV(APPLE, WELLSPRING3_JIS, BCM5974_FLAG_WELLSPRING3),
|
||||
|
||||
/* MacbookAir3,2 (unibody), aka wellspring4 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING4_ANSI, BCM5974_FLAG_WELLSPRING4),
|
||||
BCM5974_DEV(APPLE, WELLSPRING4_ISO, BCM5974_FLAG_WELLSPRING4),
|
||||
BCM5974_DEV(APPLE, WELLSPRING4_JIS, BCM5974_FLAG_WELLSPRING4),
|
||||
|
||||
/* MacbookAir3,1 (unibody), aka wellspring4 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING4A_ANSI, BCM5974_FLAG_WELLSPRING4A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING4A_ISO, BCM5974_FLAG_WELLSPRING4A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING4A_JIS, BCM5974_FLAG_WELLSPRING4A),
|
||||
|
||||
/* Macbook8 (unibody, March 2011) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING5_ANSI, BCM5974_FLAG_WELLSPRING5),
|
||||
BCM5974_DEV(APPLE, WELLSPRING5_ISO, BCM5974_FLAG_WELLSPRING5),
|
||||
BCM5974_DEV(APPLE, WELLSPRING5_JIS, BCM5974_FLAG_WELLSPRING5),
|
||||
|
||||
/* MacbookAir4,1 (unibody, July 2011) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING6A_ANSI, BCM5974_FLAG_WELLSPRING6A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING6A_ISO, BCM5974_FLAG_WELLSPRING6A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING6A_JIS, BCM5974_FLAG_WELLSPRING6A),
|
||||
|
||||
/* MacbookAir4,2 (unibody, July 2011) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING6_ANSI, BCM5974_FLAG_WELLSPRING6),
|
||||
BCM5974_DEV(APPLE, WELLSPRING6_ISO, BCM5974_FLAG_WELLSPRING6),
|
||||
BCM5974_DEV(APPLE, WELLSPRING6_JIS, BCM5974_FLAG_WELLSPRING6),
|
||||
|
||||
/* Macbook8,2 (unibody) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING5A_ANSI, BCM5974_FLAG_WELLSPRING5A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING5A_ISO, BCM5974_FLAG_WELLSPRING5A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING5A_JIS, BCM5974_FLAG_WELLSPRING5A),
|
||||
|
||||
/* MacbookPro10,1 (unibody, June 2012) */
|
||||
/* MacbookPro11,1-3 (unibody, June 2013) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING7_ANSI, BCM5974_FLAG_WELLSPRING7),
|
||||
BCM5974_DEV(APPLE, WELLSPRING7_ISO, BCM5974_FLAG_WELLSPRING7),
|
||||
BCM5974_DEV(APPLE, WELLSPRING7_JIS, BCM5974_FLAG_WELLSPRING7),
|
||||
|
||||
/* MacbookPro10,2 (unibody, October 2012) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING7A_ANSI, BCM5974_FLAG_WELLSPRING7A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING7A_ISO, BCM5974_FLAG_WELLSPRING7A),
|
||||
BCM5974_DEV(APPLE, WELLSPRING7A_JIS, BCM5974_FLAG_WELLSPRING7A),
|
||||
|
||||
/* MacbookAir6,2 (unibody, June 2013) */
|
||||
BCM5974_DEV(APPLE, WELLSPRING8_ANSI, BCM5974_FLAG_WELLSPRING8),
|
||||
BCM5974_DEV(APPLE, WELLSPRING8_ISO, BCM5974_FLAG_WELLSPRING8),
|
||||
BCM5974_DEV(APPLE, WELLSPRING8_JIS, BCM5974_FLAG_WELLSPRING8),
|
||||
|
||||
/* MacbookPro12,1 MacbookPro11,4 */
|
||||
BCM5974_DEV(APPLE, WELLSPRING9_ANSI, BCM5974_FLAG_WELLSPRING9),
|
||||
BCM5974_DEV(APPLE, WELLSPRING9_ISO, BCM5974_FLAG_WELLSPRING9),
|
||||
BCM5974_DEV(APPLE, WELLSPRING9_JIS, BCM5974_FLAG_WELLSPRING9),
|
||||
};
|
||||
|
||||
struct bcm5974_softc {
|
||||
device_t sc_dev;
|
||||
struct evdev_dev *sc_evdev;
|
||||
/* device configuration */
|
||||
const struct bcm5974_dev_params *sc_params;
|
||||
};
|
||||
|
||||
static const uint8_t bcm5974_rdesc[] = {
|
||||
0x05, BCM5974_TLC_PAGE, /* Usage Page (BCM5974_TLC_PAGE) */
|
||||
0x09, BCM5974_TLC_USAGE,/* Usage (BCM5974_TLC_USAGE) */
|
||||
0xA1, 0x01, /* Collection (Application) */
|
||||
0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
|
||||
0x09, 0x01, /* Usage (0x01) */
|
||||
0x15, 0x00, /* Logical Minimum (0) */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x96, /* Report Count (BCM5974_BUFFER_MAX) */
|
||||
BCM5974_BUFFER_MAX & 0xFF,
|
||||
BCM5974_BUFFER_MAX >> 8 & 0xFF,
|
||||
0x81, 0x02, /* Input (Data,Var,Abs) */
|
||||
0xC0, /* End Collection */
|
||||
};
|
||||
|
||||
/*
|
||||
* function prototypes
|
||||
*/
|
||||
static evdev_open_t bcm5974_ev_open;
|
||||
static evdev_close_t bcm5974_ev_close;
|
||||
static const struct evdev_methods bcm5974_evdev_methods = {
|
||||
.ev_open = &bcm5974_ev_open,
|
||||
.ev_close = &bcm5974_ev_close,
|
||||
};
|
||||
static hid_intr_t bcm5974_intr;
|
||||
|
||||
/* Device methods. */
|
||||
static device_identify_t bcm5974_identify;
|
||||
static device_probe_t bcm5974_probe;
|
||||
static device_attach_t bcm5974_attach;
|
||||
static device_detach_t bcm5974_detach;
|
||||
|
||||
/*
|
||||
* Type1 and Type2 touchpads use keyboard USB interface to switch from HID to
|
||||
* RAW mode. Although it is possible to extend hkbd driver to support such a
|
||||
* mode change requests, it's not wanted due to cross device tree dependencies.
|
||||
* So, find lowest common denominator (struct usb_device of grandparent usbhid
|
||||
* driver) of touchpad and keyboard drivers and issue direct USB requests.
|
||||
*/
|
||||
static int
|
||||
bcm5974_set_device_mode_usb(struct bcm5974_softc *sc, bool on)
|
||||
{
|
||||
uint8_t mode_bytes[BCM5974_USB_REPORT_LEN];
|
||||
struct usb_ctl_request ucr;
|
||||
int err;
|
||||
|
||||
ucr.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE;
|
||||
ucr.ucr_request.bRequest = UR_GET_REPORT;
|
||||
USETW2(ucr.ucr_request.wValue,
|
||||
UHID_FEATURE_REPORT, BCM5974_USB_REPORT_ID);
|
||||
ucr.ucr_request.wIndex[0] = BCM5974_USB_IFACE_INDEX;
|
||||
ucr.ucr_request.wIndex[1] = 0;
|
||||
USETW(ucr.ucr_request.wLength, BCM5974_USB_REPORT_LEN);
|
||||
ucr.ucr_data = mode_bytes;
|
||||
|
||||
err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
|
||||
if (err != 0) {
|
||||
DPRINTF("Failed to read device mode (%d)\n", err);
|
||||
return (EIO);
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* XXX Need to wait at least 250ms for hardware to get
|
||||
* ready. The device mode handling appears to be handled
|
||||
* asynchronously and we should not issue these commands too
|
||||
* quickly.
|
||||
*/
|
||||
pause("WHW", hz / 4);
|
||||
#endif
|
||||
mode_bytes[0] = on ? BCM5974_USB_MODE_RAW : BCM5974_USB_MODE_HID;
|
||||
ucr.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
||||
ucr.ucr_request.bRequest = UR_SET_REPORT;
|
||||
|
||||
err = hid_ioctl(sc->sc_dev, USB_REQUEST, (uintptr_t)&ucr);
|
||||
if (err != 0) {
|
||||
DPRINTF("Failed to write device mode (%d)\n", err);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_set_device_mode_hid(struct bcm5974_softc *sc, bool on)
|
||||
{
|
||||
uint8_t mode_bytes[BCM5974_HID_REPORT_LEN] = {
|
||||
BCM5974_HID_REPORT_ID,
|
||||
on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID,
|
||||
};
|
||||
#if 0
|
||||
int err;
|
||||
|
||||
err = hid_get_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
|
||||
NULL, HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID);
|
||||
if (err != 0) {
|
||||
DPRINTF("Failed to read device mode (%d)\n", err);
|
||||
return (err);
|
||||
}
|
||||
/*
|
||||
* XXX Need to wait at least 250ms for hardware to get
|
||||
* ready. The device mode handling appears to be handled
|
||||
* asynchronously and we should not issue these commands too
|
||||
* quickly.
|
||||
*/
|
||||
pause("WHW", hz / 4);
|
||||
mode_bytes[1] = on ? BCM5974_HID_MODE_RAW : BCM5974_HID_MODE_HID;
|
||||
#endif
|
||||
return (hid_set_report(sc->sc_dev, mode_bytes, BCM5974_HID_REPORT_LEN,
|
||||
HID_FEATURE_REPORT, BCM5974_HID_REPORT_ID));
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_set_device_mode(struct bcm5974_softc *sc, bool on)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (sc->sc_params->tp - tp) {
|
||||
case TYPE1:
|
||||
case TYPE2:
|
||||
err = bcm5974_set_device_mode_usb(sc, on);
|
||||
break;
|
||||
case TYPE3: /* Type 3 does not require a mode switch */
|
||||
break;
|
||||
case TYPE4:
|
||||
err = bcm5974_set_device_mode_hid(sc, on);
|
||||
break;
|
||||
default:
|
||||
KASSERT(0 == 1, ("Unknown trackpad type"));
|
||||
}
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static void
|
||||
bcm5974_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
void *d_ptr;
|
||||
hid_size_t d_len;
|
||||
|
||||
/*
|
||||
* The bcm5974 touchpad has no stable RAW mode TLC in its report
|
||||
* descriptor. So replace existing HID mode mouse TLC with dummy one
|
||||
* to set proper transport layer buffer sizes, make driver probe
|
||||
* simpler and prevent unwanted hms driver attachment.
|
||||
*/
|
||||
if (HIDBUS_LOOKUP_ID(parent, bcm5974_devs) != NULL &&
|
||||
hid_get_report_descr(parent, &d_ptr, &d_len) == 0 &&
|
||||
hid_is_mouse(d_ptr, d_len))
|
||||
hid_set_report_descr(parent, bcm5974_rdesc,
|
||||
sizeof(bcm5974_rdesc));
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_probe(device_t dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = HIDBUS_LOOKUP_DRIVER_INFO(dev, bcm5974_devs);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
hidbus_set_desc(dev, "Touchpad");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_attach(device_t dev)
|
||||
{
|
||||
struct bcm5974_softc *sc = device_get_softc(dev);
|
||||
const struct hid_device_info *hw = hid_get_device_info(dev);
|
||||
int err;
|
||||
|
||||
DPRINTFN(BCM5974_LLEVEL_INFO, "sc=%p\n", sc);
|
||||
|
||||
sc->sc_dev = dev;
|
||||
|
||||
/* get device specific configuration */
|
||||
sc->sc_params = bcm5974_dev_params + hidbus_get_driver_info(dev);
|
||||
|
||||
sc->sc_evdev = evdev_alloc();
|
||||
evdev_set_name(sc->sc_evdev, device_get_desc(dev));
|
||||
evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
|
||||
evdev_set_id(sc->sc_evdev, hw->idBus, hw->idVendor, hw->idProduct,
|
||||
hw->idVersion);
|
||||
evdev_set_serial(sc->sc_evdev, hw->serial);
|
||||
evdev_set_methods(sc->sc_evdev, sc, &bcm5974_evdev_methods);
|
||||
evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
|
||||
evdev_support_event(sc->sc_evdev, EV_SYN);
|
||||
evdev_support_event(sc->sc_evdev, EV_ABS);
|
||||
evdev_support_event(sc->sc_evdev, EV_KEY);
|
||||
evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */
|
||||
|
||||
#define BCM5974_ABS(evdev, code, param) \
|
||||
evdev_support_abs((evdev), (code), (param).min, (param).max, \
|
||||
((param).max - (param).min) / (param).snratio, 0, \
|
||||
(param).size != 0 ? ((param).max - (param).min) / (param).size : 0);
|
||||
|
||||
/* finger position */
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_X, sc->sc_params->x);
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_POSITION_Y, sc->sc_params->y);
|
||||
/* finger pressure */
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_PRESSURE, sc->sc_params->p);
|
||||
/* finger touch area */
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, sc->sc_params->w);
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_TOUCH_MINOR, sc->sc_params->w);
|
||||
/* finger approach area */
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MAJOR, sc->sc_params->w);
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_WIDTH_MINOR, sc->sc_params->w);
|
||||
/* finger orientation */
|
||||
BCM5974_ABS(sc->sc_evdev, ABS_MT_ORIENTATION, sc->sc_params->o);
|
||||
/* button properties */
|
||||
evdev_support_key(sc->sc_evdev, BTN_LEFT);
|
||||
if ((sc->sc_params->tp->caps & HAS_INTEGRATED_BUTTON) != 0)
|
||||
evdev_support_prop(sc->sc_evdev, INPUT_PROP_BUTTONPAD);
|
||||
/* Enable automatic touch assignment for type B MT protocol */
|
||||
evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT,
|
||||
0, MAX_FINGERS - 1, 0, 0, 0);
|
||||
evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID,
|
||||
-1, MAX_FINGERS - 1, 0, 0, 0);
|
||||
evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK);
|
||||
evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL);
|
||||
/* Synaptics compatibility events */
|
||||
evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT);
|
||||
|
||||
err = evdev_register(sc->sc_evdev);
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
hidbus_set_intr(dev, bcm5974_intr, sc);
|
||||
|
||||
return (0);
|
||||
|
||||
detach:
|
||||
bcm5974_detach(dev);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_detach(device_t dev)
|
||||
{
|
||||
struct bcm5974_softc *sc = device_get_softc(dev);
|
||||
|
||||
evdev_free(sc->sc_evdev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bcm5974_intr(void *context, void *data, hid_size_t len)
|
||||
{
|
||||
struct bcm5974_softc *sc = context;
|
||||
const struct bcm5974_dev_params *params = sc->sc_params;
|
||||
union evdev_mt_slot slot_data;
|
||||
struct tp_finger *f;
|
||||
int ntouch; /* the finger number in touch */
|
||||
int ibt; /* button status */
|
||||
int i;
|
||||
int slot;
|
||||
uint8_t fsize = sizeof(struct tp_finger) + params->tp->delta;
|
||||
|
||||
if ((len < params->tp->offset + fsize) ||
|
||||
((len - params->tp->offset) % fsize) != 0) {
|
||||
DPRINTFN(BCM5974_LLEVEL_INFO, "Invalid length: %d, %x, %x\n",
|
||||
len, sc->tp_data[0], sc->tp_data[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
ibt = ((uint8_t *)data)[params->tp->button];
|
||||
ntouch = (len - params->tp->offset) / fsize;
|
||||
|
||||
for (i = 0, slot = 0; i != ntouch; i++) {
|
||||
f = (struct tp_finger *)(((uint8_t *)data) +
|
||||
params->tp->offset + params->tp->delta + i * fsize);
|
||||
DPRINTFN(BCM5974_LLEVEL_INFO,
|
||||
"[%d]ibt=%d, taps=%d, o=%4d, ax=%5d, ay=%5d, "
|
||||
"rx=%5d, ry=%5d, tlmaj=%4d, tlmin=%4d, ot=%4x, "
|
||||
"tchmaj=%4d, tchmin=%4d, presure=%4d, m=%4x\n",
|
||||
i, ibt, ntouch, le16toh(f->origin), le16toh(f->abs_x),
|
||||
le16toh(f->abs_y), le16toh(f->rel_x), le16toh(f->rel_y),
|
||||
le16toh(f->tool_major), le16toh(f->tool_minor),
|
||||
le16toh(f->orientation), le16toh(f->touch_major),
|
||||
le16toh(f->touch_minor), le16toh(f->pressure),
|
||||
le16toh(f->multi));
|
||||
|
||||
if (f->touch_major == 0)
|
||||
continue;
|
||||
slot_data = (union evdev_mt_slot) {
|
||||
.id = slot,
|
||||
.x = le16toh(f->abs_x),
|
||||
.y = params->y.min + params->y.max - le16toh(f->abs_y),
|
||||
.p = le16toh(f->pressure),
|
||||
.maj = le16toh(f->touch_major) << 1,
|
||||
.min = le16toh(f->touch_minor) << 1,
|
||||
.w_maj = le16toh(f->tool_major) << 1,
|
||||
.w_min = le16toh(f->tool_minor) << 1,
|
||||
.ori = params->o.max - le16toh(f->orientation),
|
||||
};
|
||||
evdev_mt_push_slot(sc->sc_evdev, slot, &slot_data);
|
||||
slot++;
|
||||
}
|
||||
|
||||
evdev_push_key(sc->sc_evdev, BTN_LEFT, ibt);
|
||||
evdev_sync(sc->sc_evdev);
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_ev_open(struct evdev_dev *evdev)
|
||||
{
|
||||
struct bcm5974_softc *sc = evdev_get_softc(evdev);
|
||||
int err;
|
||||
|
||||
/*
|
||||
* By default the touchpad behaves like a HID device, sending
|
||||
* packets with reportID = 8. Such reports contain only
|
||||
* limited information. They encode movement deltas and button
|
||||
* events, but do not include data from the pressure
|
||||
* sensors. The device input mode can be switched from HID
|
||||
* reports to raw sensor data using vendor-specific USB
|
||||
* control commands:
|
||||
*/
|
||||
err = bcm5974_set_device_mode(sc, true);
|
||||
if (err != 0) {
|
||||
DPRINTF("failed to set mode to RAW MODE (%d)\n", err);
|
||||
return (err);
|
||||
}
|
||||
|
||||
return (hidbus_intr_start(sc->sc_dev));
|
||||
}
|
||||
|
||||
static int
|
||||
bcm5974_ev_close(struct evdev_dev *evdev)
|
||||
{
|
||||
struct bcm5974_softc *sc = evdev_get_softc(evdev);
|
||||
int err;
|
||||
|
||||
err = hidbus_intr_stop(sc->sc_dev);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
/*
|
||||
* During re-enumeration of the device we need to force the
|
||||
* device back into HID mode before switching it to RAW
|
||||
* mode. Else the device does not work like expected.
|
||||
*/
|
||||
err = bcm5974_set_device_mode(sc, false);
|
||||
if (err != 0)
|
||||
DPRINTF("Failed to set mode to HID MODE (%d)\n", err);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static device_method_t bcm5974_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_identify, bcm5974_identify),
|
||||
DEVMETHOD(device_probe, bcm5974_probe),
|
||||
DEVMETHOD(device_attach, bcm5974_attach),
|
||||
DEVMETHOD(device_detach, bcm5974_detach),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t bcm5974_driver = {
|
||||
.name = "bcm5974",
|
||||
.methods = bcm5974_methods,
|
||||
.size = sizeof(struct bcm5974_softc)
|
||||
};
|
||||
|
||||
static devclass_t bcm5974_devclass;
|
||||
|
||||
DRIVER_MODULE(bcm5974, hidbus, bcm5974_driver, bcm5974_devclass, NULL, 0);
|
||||
MODULE_DEPEND(bcm5974, hidbus, 1, 1, 1);
|
||||
MODULE_DEPEND(bcm5974, hid, 1, 1, 1);
|
||||
MODULE_DEPEND(bcm5974, evdev, 1, 1, 1);
|
||||
MODULE_VERSION(bcm5974, 1);
|
||||
HID_PNP_INFO(bcm5974_devs);
|
@ -8,6 +8,7 @@ SUBDIR = \
|
||||
hidraw
|
||||
|
||||
SUBDIR += \
|
||||
bcm5974 \
|
||||
hconf \
|
||||
hcons \
|
||||
hgame \
|
||||
|
10
sys/modules/hid/bcm5974/Makefile
Normal file
10
sys/modules/hid/bcm5974/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/hid
|
||||
|
||||
KMOD= bcm5974
|
||||
SRCS= bcm5974.c
|
||||
SRCS+= opt_hid.h
|
||||
SRCS+= bus_if.h device_if.h usbdevs.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user