Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jikos/hid

Pull HID fixes from Jiri Kosina:

 - fix for how scaling linearization is computed in wiimote driver, by
   Cyan Ogilvie

 - endless retry loop fix in generic USB HID core reset-resume handling,
   by Alan Stern

 - two functional fixes affecting particular devices, and oops fix for
   wacom driver, by Jason Gerecke

 - multitouch slot numbering fix from Gabriele Mazzotta

 - a couple more small fixes on top

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: wacom: Support switching from vendor-defined device mode on G9 and G11
  HID: wacom: Initialize hid_data.inputmode to -1
  HID: microsoft: add support for 3 more devices
  HID: multitouch: Synchronize MT frame on reset_resume
  HID: wacom: fix Bamboo ONE oops
  HID: lenovo: Don't use stack variables for DMA buffers
  HID: usbhid: fix inconsistent reset/resume/reset-resume behavior
  HID: wiimote: Fix wiimote mp scale linearization
  • Loading branch information
Linus Torvalds committed Apr 11, 2016
2 parents 6c6563a + 326ea2a commit 1c74a7f
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 73 deletions.
3 changes: 3 additions & 0 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
Expand Down
3 changes: 3 additions & 0 deletions drivers/hid/hid-ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -676,13 +676,16 @@
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K 0x00b4
#define USB_DEVICE_ID_MS_NE4K 0x00db
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
#define USB_DEVICE_ID_MS_LK6K 0x00f9
#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_NE7K 0x071d
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
Expand Down
16 changes: 13 additions & 3 deletions drivers/hid/hid-lenovo.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,21 +184,31 @@ static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
unsigned char byte2, unsigned char byte3)
{
int ret;
unsigned char buf[] = {0x18, byte2, byte3};
unsigned char *buf;

buf = kzalloc(3, GFP_KERNEL);
if (!buf)
return -ENOMEM;

buf[0] = 0x18;
buf[1] = byte2;
buf[2] = byte3;

switch (hdev->product) {
case USB_DEVICE_ID_LENOVO_CUSBKBD:
ret = hid_hw_raw_request(hdev, 0x13, buf, sizeof(buf),
ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
break;
case USB_DEVICE_ID_LENOVO_CBTKBD:
ret = hid_hw_output_report(hdev, buf, sizeof(buf));
ret = hid_hw_output_report(hdev, buf, 3);
break;
default:
ret = -EINVAL;
break;
}

kfree(buf);

return ret < 0 ? ret : 0; /* BT returns 0, USB returns sizeof(buf) */
}

Expand Down
6 changes: 6 additions & 0 deletions drivers/hid/hid-microsoft.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,12 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_PRESENTER },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
.driver_data = MS_ERGONOMY | MS_RDESC_3K },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
Expand Down
1 change: 1 addition & 0 deletions drivers/hid/hid-multitouch.c
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ static void mt_release_contacts(struct hid_device *hid)
MT_TOOL_FINGER,
false);
}
input_mt_sync_frame(input_dev);
input_sync(input_dev);
}
}
Expand Down
14 changes: 8 additions & 6 deletions drivers/hid/hid-wiimote-modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -2049,9 +2049,11 @@ static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
* -----+------------------------------+-----+-----+
* The single bits Yaw, Roll, Pitch in the lower right corner specify
* whether the wiimote is rotating fast (0) or slow (1). Speed for slow
* roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
* linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
* and 9 for slow.
* roation is 8192/440 units / deg/s and for fast rotation 8192/2000
* units / deg/s. To get a linear scale for fast rotation we multiply
* by 2000/440 = ~4.5454 and scale both fast and slow by 9 to match the
* previous scale reported by this driver.
* This leaves a linear scale with 8192*9/440 (~167.564) units / deg/s.
* If the wiimote is not rotating the sensor reports 2^13 = 8192.
* Ext specifies whether an extension is connected to the motionp.
* which is parsed by wiimote-core.
Expand All @@ -2070,15 +2072,15 @@ static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
z -= 8192;

if (!(ext[3] & 0x02))
x *= 18;
x = (x * 2000 * 9) / 440;
else
x *= 9;
if (!(ext[4] & 0x02))
y *= 18;
y = (y * 2000 * 9) / 440;
else
y *= 9;
if (!(ext[3] & 0x01))
z *= 18;
z = (z * 2000 * 9) / 440;
else
z *= 9;

Expand Down
73 changes: 37 additions & 36 deletions drivers/hid/usbhid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,14 +951,6 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
return ret;
}

static void usbhid_restart_queues(struct usbhid_device *usbhid)
{
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
usbhid_restart_out_queue(usbhid);
if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
usbhid_restart_ctrl_queue(usbhid);
}

static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
Expand Down Expand Up @@ -1404,6 +1396,37 @@ static void hid_cease_io(struct usbhid_device *usbhid)
usb_kill_urb(usbhid->urbout);
}

static void hid_restart_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);

spin_lock_irq(&usbhid->lock);
clear_bit(HID_SUSPENDED, &usbhid->iofl);
usbhid_mark_busy(usbhid);

if (clear_halt || reset_pending)
schedule_work(&usbhid->reset_work);
usbhid->retry_delay = 0;
spin_unlock_irq(&usbhid->lock);

if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
return;

if (!clear_halt) {
if (hid_start_in(hid) < 0)
hid_io_error(hid);
}

spin_lock_irq(&usbhid->lock);
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
usbhid_restart_out_queue(usbhid);
if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
usbhid_restart_ctrl_queue(usbhid);
spin_unlock_irq(&usbhid->lock);
}

/* Treat USB reset pretty much the same as suspend/resume */
static int hid_pre_reset(struct usb_interface *intf)
{
Expand Down Expand Up @@ -1453,14 +1476,14 @@ static int hid_post_reset(struct usb_interface *intf)
return 1;
}

/* No need to do another reset or clear a halted endpoint */
spin_lock_irq(&usbhid->lock);
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
status = hid_start_in(hid);
if (status < 0)
hid_io_error(hid);
usbhid_restart_queues(usbhid);

hid_restart_io(hid);

return 0;
}
Expand All @@ -1483,25 +1506,9 @@ void usbhid_put_power(struct hid_device *hid)
#ifdef CONFIG_PM
static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
{
struct usbhid_device *usbhid = hid->driver_data;
int status;

spin_lock_irq(&usbhid->lock);
clear_bit(HID_SUSPENDED, &usbhid->iofl);
usbhid_mark_busy(usbhid);

if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
test_bit(HID_RESET_PENDING, &usbhid->iofl))
schedule_work(&usbhid->reset_work);
usbhid->retry_delay = 0;

usbhid_restart_queues(usbhid);
spin_unlock_irq(&usbhid->lock);

status = hid_start_in(hid);
if (status < 0)
hid_io_error(hid);
int status = 0;

hid_restart_io(hid);
if (driver_suspended && hid->driver && hid->driver->resume)
status = hid->driver->resume(hid);
return status;
Expand Down Expand Up @@ -1570,12 +1577,8 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
static int hid_resume(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
struct usbhid_device *usbhid = hid->driver_data;
int status;

if (!test_bit(HID_STARTED, &usbhid->iofl))
return 0;

status = hid_resume_common(hid, true);
dev_dbg(&intf->dev, "resume status %d\n", status);
return 0;
Expand All @@ -1584,10 +1587,8 @@ static int hid_resume(struct usb_interface *intf)
static int hid_reset_resume(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
int status;

clear_bit(HID_SUSPENDED, &usbhid->iofl);
status = hid_post_reset(intf);
if (status >= 0 && hid->driver && hid->driver->reset_resume) {
int ret = hid->driver->reset_resume(hid);
Expand Down
102 changes: 74 additions & 28 deletions drivers/hid/wacom_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,25 @@ static void wacom_feature_mapping(struct hid_device *hdev,
hid_data->inputmode = field->report->id;
hid_data->inputmode_index = usage->usage_index;
break;

case HID_UP_DIGITIZER:
if (field->report->id == 0x0B &&
(field->application == WACOM_G9_DIGITIZER ||
field->application == WACOM_G11_DIGITIZER)) {
wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 0;
}
break;

case WACOM_G9_PAGE:
case WACOM_G11_PAGE:
if (field->report->id == 0x03 &&
(field->application == WACOM_G9_TOUCHSCREEN ||
field->application == WACOM_G11_TOUCHSCREEN)) {
wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 0;
}
break;
}
}

Expand Down Expand Up @@ -322,26 +341,41 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev)
return 0;
}

static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
int length, int mode)
static int wacom_set_device_mode(struct hid_device *hdev,
struct wacom_wac *wacom_wac)
{
unsigned char *rep_data;
u8 *rep_data;
struct hid_report *r;
struct hid_report_enum *re;
int length;
int error = -ENOMEM, limit = 0;

rep_data = kzalloc(length, GFP_KERNEL);
if (wacom_wac->mode_report < 0)
return 0;

re = &(hdev->report_enum[HID_FEATURE_REPORT]);
r = re->report_id_hash[wacom_wac->mode_report];
if (!r)
return -EINVAL;

rep_data = hid_alloc_report_buf(r, GFP_KERNEL);
if (!rep_data)
return error;
return -ENOMEM;

length = hid_report_len(r);

do {
rep_data[0] = report_id;
rep_data[1] = mode;
rep_data[0] = wacom_wac->mode_report;
rep_data[1] = wacom_wac->mode_value;

error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
length, 1);
if (error >= 0)
error = wacom_get_report(hdev, HID_FEATURE_REPORT,
rep_data, length, 1);
} while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES);
} while (error >= 0 &&
rep_data[1] != wacom_wac->mode_report &&
limit++ < WAC_MSG_RETRIES);

kfree(rep_data);

Expand Down Expand Up @@ -411,32 +445,41 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
static int wacom_query_tablet_data(struct hid_device *hdev,
struct wacom_features *features)
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;

if (hdev->bus == BUS_BLUETOOTH)
return wacom_bt_query_tablet_data(hdev, 1, features);

if (features->type == HID_GENERIC)
return wacom_hid_set_device_mode(hdev);

if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
if (features->type > TABLETPC) {
/* MT Tablet PC touch */
return wacom_set_device_mode(hdev, 3, 4, 4);
}
else if (features->type == WACOM_24HDT) {
return wacom_set_device_mode(hdev, 18, 3, 2);
}
else if (features->type == WACOM_27QHDT) {
return wacom_set_device_mode(hdev, 131, 3, 2);
}
else if (features->type == BAMBOO_PAD) {
return wacom_set_device_mode(hdev, 2, 2, 2);
}
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
if (features->type <= BAMBOO_PT) {
return wacom_set_device_mode(hdev, 2, 2, 2);
if (features->type != HID_GENERIC) {
if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
if (features->type > TABLETPC) {
/* MT Tablet PC touch */
wacom_wac->mode_report = 3;
wacom_wac->mode_value = 4;
} else if (features->type == WACOM_24HDT) {
wacom_wac->mode_report = 18;
wacom_wac->mode_value = 2;
} else if (features->type == WACOM_27QHDT) {
wacom_wac->mode_report = 131;
wacom_wac->mode_value = 2;
} else if (features->type == BAMBOO_PAD) {
wacom_wac->mode_report = 2;
wacom_wac->mode_value = 2;
}
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
if (features->type <= BAMBOO_PT) {
wacom_wac->mode_report = 2;
wacom_wac->mode_value = 2;
}
}
}

wacom_set_device_mode(hdev, wacom_wac);

if (features->type == HID_GENERIC)
return wacom_hid_set_device_mode(hdev);

return 0;
}

Expand Down Expand Up @@ -1817,6 +1860,9 @@ static int wacom_probe(struct hid_device *hdev,
goto fail_type;
}

wacom_wac->hid_data.inputmode = -1;
wacom_wac->mode_report = -1;

wacom->usbdev = dev;
wacom->intf = intf;
mutex_init(&wacom->lock);
Expand Down
Loading

0 comments on commit 1c74a7f

Please sign in to comment.