Commit 278de45e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID subsystem fixes from Jiri Kosina:

 - syzkaller-reported error handling fixes in various drivers, from
   various people

 - increase of HID report buffer size to 8K, which is apparently needed
   by certain modern devices

 - a few new device-ID-specific fixes / quirks

 - battery charging status reporting fix in logitech-hidpp, from Filipe
   Laíns

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: hid-bigbenff: fix race condition for scheduled work during removal
  HID: hid-bigbenff: call hid_hw_stop() in case of error
  HID: hid-bigbenff: fix general protection fault caused by double kfree
  HID: i2c-hid: add Trekstor Surfbook E11B to descriptor override
  HID: alps: Fix an error handling path in 'alps_input_configured()'
  HID: hiddev: Fix race in in hiddev_disconnect()
  HID: core: increase HID report buffer size to 8KiB
  HID: core: fix off-by-one memset in hid_report_raw_event()
  HID: apple: Add support for recent firmware on Magic Keyboards
  HID: ite: Only bind to keyboard USB interface on Acer SW5-012 keyboard dock
  HID: logitech-hidpp: BatteryVoltage: only read chargeStatus if extPower is active
parents e46bfaba 4eb1b01d
......@@ -730,7 +730,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (data->has_sp) {
input2 = input_allocate_device();
if (!input2) {
input_free_device(input2);
ret = -ENOMEM;
goto exit;
}
......
......@@ -340,7 +340,8 @@ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
unsigned long **bit, int *max)
{
if (usage->hid == (HID_UP_CUSTOM | 0x0003) ||
usage->hid == (HID_UP_MSVENDOR | 0x0003)) {
usage->hid == (HID_UP_MSVENDOR | 0x0003) ||
usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) {
/* The fn key on Apple USB keyboards */
set_bit(EV_REP, hi->input->evbit);
hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
......
......@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
struct bigben_device {
struct hid_device *hid;
struct hid_report *report;
bool removed;
u8 led_state; /* LED1 = 1 .. LED4 = 8 */
u8 right_motor_on; /* right motor off/on 0/1 */
u8 left_motor_force; /* left motor force 0-255 */
......@@ -190,6 +191,9 @@ static void bigben_worker(struct work_struct *work)
struct bigben_device, worker);
struct hid_field *report_field = bigben->report->field[0];
if (bigben->removed)
return;
if (bigben->work_led) {
bigben->work_led = false;
report_field->value[0] = 0x01; /* 1 = led message */
......@@ -220,10 +224,16 @@ static void bigben_worker(struct work_struct *work)
static int hid_bigben_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct bigben_device *bigben = data;
struct hid_device *hid = input_get_drvdata(dev);
struct bigben_device *bigben = hid_get_drvdata(hid);
u8 right_motor_on;
u8 left_motor_force;
if (!bigben) {
hid_err(hid, "no device data\n");
return 0;
}
if (effect->type != FF_RUMBLE)
return 0;
......@@ -298,8 +308,8 @@ static void bigben_remove(struct hid_device *hid)
{
struct bigben_device *bigben = hid_get_drvdata(hid);
bigben->removed = true;
cancel_work_sync(&bigben->worker);
hid_hw_close(hid);
hid_hw_stop(hid);
}
......@@ -319,6 +329,7 @@ static int bigben_probe(struct hid_device *hid,
return -ENOMEM;
hid_set_drvdata(hid, bigben);
bigben->hid = hid;
bigben->removed = false;
error = hid_parse(hid);
if (error) {
......@@ -341,10 +352,10 @@ static int bigben_probe(struct hid_device *hid,
INIT_WORK(&bigben->worker, bigben_worker);
error = input_ff_create_memless(hidinput->input, bigben,
error = input_ff_create_memless(hidinput->input, NULL,
hid_bigben_play_effect);
if (error)
return error;
goto error_hw_stop;
name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
......@@ -354,8 +365,10 @@ static int bigben_probe(struct hid_device *hid,
sizeof(struct led_classdev) + name_sz,
GFP_KERNEL
);
if (!led)
return -ENOMEM;
if (!led) {
error = -ENOMEM;
goto error_hw_stop;
}
name = (void *)(&led[1]);
snprintf(name, name_sz,
"%s:red:bigben%d",
......@@ -369,7 +382,7 @@ static int bigben_probe(struct hid_device *hid,
bigben->leds[n] = led;
error = devm_led_classdev_register(&hid->dev, led);
if (error)
return error;
goto error_hw_stop;
}
/* initial state: LED1 is on, no rumble effect */
......@@ -383,6 +396,10 @@ static int bigben_probe(struct hid_device *hid,
hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
return 0;
error_hw_stop:
hid_hw_stop(hid);
return error;
}
static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
......
......@@ -1741,7 +1741,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
rsize = ((report->size - 1) >> 3) + 1;
if (rsize > HID_MAX_BUFFER_SIZE)
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
rsize = HID_MAX_BUFFER_SIZE - 1;
else if (rsize > HID_MAX_BUFFER_SIZE)
rsize = HID_MAX_BUFFER_SIZE;
if (csize < rsize) {
......
......@@ -41,8 +41,9 @@ static const struct hid_device_id ite_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
{ HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) },
/* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS,
USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
USB_VENDOR_ID_SYNAPTICS,
USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
{ }
};
MODULE_DEVICE_TABLE(hid, ite_devices);
......
......@@ -1256,36 +1256,35 @@ static int hidpp20_battery_map_status_voltage(u8 data[3], int *voltage,
{
int status;
long charge_sts = (long)data[2];
long flags = (long) data[2];
*level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
switch (data[2] & 0xe0) {
case 0x00:
status = POWER_SUPPLY_STATUS_CHARGING;
break;
case 0x20:
status = POWER_SUPPLY_STATUS_FULL;
*level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
break;
case 0x40:
if (flags & 0x80)
switch (flags & 0x07) {
case 0:
status = POWER_SUPPLY_STATUS_CHARGING;
break;
case 1:
status = POWER_SUPPLY_STATUS_FULL;
*level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
break;
case 2:
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
status = POWER_SUPPLY_STATUS_UNKNOWN;
break;
}
else
status = POWER_SUPPLY_STATUS_DISCHARGING;
break;
case 0xe0:
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
status = POWER_SUPPLY_STATUS_UNKNOWN;
}
*charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
if (test_bit(3, &charge_sts)) {
if (test_bit(3, &flags)) {
*charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
}
if (test_bit(4, &charge_sts)) {
if (test_bit(4, &flags)) {
*charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
}
if (test_bit(5, &charge_sts)) {
if (test_bit(5, &flags)) {
*level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
}
......
......@@ -341,6 +341,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
},
.driver_data = (void *)&sipodev_desc
},
{
.ident = "Trekstor SURFBOOK E11B",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"),
},
.driver_data = (void *)&sipodev_desc
},
{
.ident = "Direkt-Tek DTLAPY116-2",
.matches = {
......
......@@ -932,9 +932,9 @@ void hiddev_disconnect(struct hid_device *hid)
hiddev->exist = 0;
if (hiddev->open) {
mutex_unlock(&hiddev->existancelock);
hid_hw_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait);
mutex_unlock(&hiddev->existancelock);
} else {
mutex_unlock(&hiddev->existancelock);
kfree(hiddev);
......
......@@ -492,7 +492,7 @@ struct hid_report_enum {
};
#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */
#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */
#define HID_MAX_BUFFER_SIZE 8192 /* 8kb */
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
#define HID_OUTPUT_FIFO_SIZE 64
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment