Commit cf26057a 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 updates from Jiri Kosina:

 - high-resolution scrolling support that gracefully handles differences
   between MS and Logitech implementations in HW, from Peter Hutterer
   and Harry Cutts

 - MSI IRQ support for intel-ish driver, from Song Hongyan

 - support for new hardware (Cougar 700K, Odys Winbook 13, ASUS FX503VD,
   ASUS T101HA) from Daniel M. Lambea, Hans de Goede and Aleix Roca
   Nonell

 - other small assorted fixups

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (22 commits)
  HID: i2c-hid: Add Odys Winbook 13 to descriptor override
  HID: lenovo: Add checks to fix of_led_classdev_register
  HID: intel-ish-hid: add MSI interrupt support
  HID: debug: Change to use DEFINE_SHOW_ATTRIBUTE macro
  HID: doc: fix wrong data structure reference for UHID_OUTPUT
  HID: intel-ish-hid: fixes incorrect error handling
  HID: asus: Add support for the ASUS T101HA keyboard dock
  HID: logitech: Use LDJ_DEVICE macro for existing Logitech mice
  HID: logitech: Enable high-resolution scrolling on Logitech mice
  HID: logitech: Add function to enable HID++ 1.0 "scrolling acceleration"
  HID: logitech-hidpp: fix typo, hiddpp to hidpp
  HID: input: use the Resolution Multiplier for high-resolution scrolling
  HID: core: process the Resolution Multiplier
  HID: core: store the collections as a basic tree
  Input: add `REL_WHEEL_HI_RES` and `REL_HWHEEL_HI_RES`
  HID: input: support Microsoft wireless radio control hotkey
  HID: use macros in IS_INPUT_APPLICATION
  HID: asus: Add support for the ASUS FX503VD laptop
  HID: asus: Add event handler to catch unmapped Asus Vendor UsagePage codes
  HID: cougar: Add support for Cougar 700K Gaming Keyboard
  ...
parents 1686cc1a bd8879fa
......@@ -160,7 +160,7 @@ them but you should handle them according to your needs.
UHID_OUTPUT:
This is sent if the HID device driver wants to send raw data to the I/O
device on the interrupt channel. You should read the payload and forward it to
the device. The payload is of type "struct uhid_data_req".
the device. The payload is of type "struct uhid_output_req".
This may be received even though you haven't received UHID_OPEN, yet.
UHID_GET_REPORT:
......
......@@ -190,7 +190,26 @@ A few EV_REL codes have special meanings:
* REL_WHEEL, REL_HWHEEL:
- These codes are used for vertical and horizontal scroll wheels,
respectively.
respectively. The value is the number of detents moved on the wheel, the
physical size of which varies by device. For high-resolution wheels
this may be an approximation based on the high-resolution scroll events,
see REL_WHEEL_HI_RES. These event codes are legacy codes and
REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES should be preferred where
available.
* REL_WHEEL_HI_RES, REL_HWHEEL_HI_RES:
- High-resolution scroll wheel data. The accumulated value 120 represents
movement by one detent. For devices that do not provide high-resolution
scrolling, the value is always a multiple of 120. For devices with
high-resolution scrolling, the value may be a fraction of 120.
If a vertical scroll wheel supports high-resolution scrolling, this code
will be emitted in addition to REL_WHEEL or REL_HWHEEL. The REL_WHEEL
and REL_HWHEEL may be an approximation based on the high-resolution
scroll events. There is no guarantee that the high-resolution data
is a multiple of 120 at the time of an emulated REL_WHEEL or REL_HWHEEL
event.
EV_ABS
------
......
......@@ -70,6 +70,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define QUIRK_T100_KEYBOARD BIT(6)
#define QUIRK_T100CHI BIT(7)
#define QUIRK_G752_KEYBOARD BIT(8)
#define QUIRK_T101HA_DOCK BIT(9)
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
QUIRK_NO_INIT_REPORTS | \
......@@ -241,6 +242,18 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
return 1;
}
static int asus_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
(usage->hid & HID_USAGE) != 0x00 && !usage->type) {
hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
usage->hid & HID_USAGE);
}
return 0;
}
static int asus_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
......@@ -510,6 +523,7 @@ static int asus_input_mapping(struct hid_device *hdev,
case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
case 0x7c: asus_map_key_clear(KEY_MICMUTE); break;
case 0x82: asus_map_key_clear(KEY_CAMERA); break;
case 0x88: asus_map_key_clear(KEY_RFKILL); break;
case 0xb5: asus_map_key_clear(KEY_CALC); break;
......@@ -528,6 +542,9 @@ static int asus_input_mapping(struct hid_device *hdev,
/* Fn+Space Power4Gear Hybrid */
case 0x5c: asus_map_key_clear(KEY_PROG3); break;
/* Fn+F5 "fan" symbol on FX503VD */
case 0x99: asus_map_key_clear(KEY_PROG4); break;
default:
/* ASUS lazily declares 256 usages, ignore the rest,
* as some make the keyboard appear as a pointer device. */
......@@ -683,6 +700,11 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
/* use hid-multitouch for T101HA touchpad */
if (id->driver_data & QUIRK_T101HA_DOCK &&
hdev->collection->usage == HID_GD_MOUSE)
return -ENODEV;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "Asus hw start failed: %d\n", ret);
......@@ -805,12 +827,17 @@ static const struct hid_device_id asus_devices[] = {
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
QUIRK_USE_KBD_BACKLIGHT },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD),
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD), QUIRK_T101HA_DOCK },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
......@@ -832,6 +859,7 @@ static struct hid_driver asus_driver = {
#ifdef CONFIG_PM
.reset_resume = asus_reset_resume,
#endif
.event = asus_event,
.raw_event = asus_raw_event
};
module_hid_driver(asus_driver);
......
......@@ -172,6 +172,8 @@ static int open_collection(struct hid_parser *parser, unsigned type)
collection->type = type;
collection->usage = usage;
collection->level = parser->collection_stack_ptr - 1;
collection->parent = parser->active_collection;
parser->active_collection = collection;
if (type == HID_COLLECTION_APPLICATION)
parser->device->maxapplication++;
......@@ -190,6 +192,8 @@ static int close_collection(struct hid_parser *parser)
return -EINVAL;
}
parser->collection_stack_ptr--;
if (parser->active_collection)
parser->active_collection = parser->active_collection->parent;
return 0;
}
......@@ -290,6 +294,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->usage[i].collection_index =
parser->local.collection_index[j];
field->usage[i].usage_index = i;
field->usage[i].resolution_multiplier = 1;
}
field->maxusage = usages;
......@@ -943,6 +948,167 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
}
EXPORT_SYMBOL_GPL(hid_validate_values);
static int hid_calculate_multiplier(struct hid_device *hid,
struct hid_field *multiplier)
{
int m;
__s32 v = *multiplier->value;
__s32 lmin = multiplier->logical_minimum;
__s32 lmax = multiplier->logical_maximum;
__s32 pmin = multiplier->physical_minimum;
__s32 pmax = multiplier->physical_maximum;
/*
* "Because OS implementations will generally divide the control's
* reported count by the Effective Resolution Multiplier, designers
* should take care not to establish a potential Effective
* Resolution Multiplier of zero."
* HID Usage Table, v1.12, Section 4.3.1, p31
*/
if (lmax - lmin == 0)
return 1;
/*
* Handling the unit exponent is left as an exercise to whoever
* finds a device where that exponent is not 0.
*/
m = ((v - lmin)/(lmax - lmin) * (pmax - pmin) + pmin);
if (unlikely(multiplier->unit_exponent != 0)) {
hid_warn(hid,
"unsupported Resolution Multiplier unit exponent %d\n",
multiplier->unit_exponent);
}
/* There are no devices with an effective multiplier > 255 */
if (unlikely(m == 0 || m > 255 || m < -255)) {
hid_warn(hid, "unsupported Resolution Multiplier %d\n", m);
m = 1;
}
return m;
}
static void hid_apply_multiplier_to_field(struct hid_device *hid,
struct hid_field *field,
struct hid_collection *multiplier_collection,
int effective_multiplier)
{
struct hid_collection *collection;
struct hid_usage *usage;
int i;
/*
* If multiplier_collection is NULL, the multiplier applies
* to all fields in the report.
* Otherwise, it is the Logical Collection the multiplier applies to
* but our field may be in a subcollection of that collection.
*/
for (i = 0; i < field->maxusage; i++) {
usage = &field->usage[i];
collection = &hid->collection[usage->collection_index];
while (collection && collection != multiplier_collection)
collection = collection->parent;
if (collection || multiplier_collection == NULL)
usage->resolution_multiplier = effective_multiplier;
}
}
static void hid_apply_multiplier(struct hid_device *hid,
struct hid_field *multiplier)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
struct hid_field *field;
struct hid_collection *multiplier_collection;
int effective_multiplier;
int i;
/*
* "The Resolution Multiplier control must be contained in the same
* Logical Collection as the control(s) to which it is to be applied.
* If no Resolution Multiplier is defined, then the Resolution
* Multiplier defaults to 1. If more than one control exists in a
* Logical Collection, the Resolution Multiplier is associated with
* all controls in the collection. If no Logical Collection is
* defined, the Resolution Multiplier is associated with all
* controls in the report."
* HID Usage Table, v1.12, Section 4.3.1, p30
*
* Thus, search from the current collection upwards until we find a
* logical collection. Then search all fields for that same parent
* collection. Those are the fields the multiplier applies to.
*
* If we have more than one multiplier, it will overwrite the
* applicable fields later.
*/
multiplier_collection = &hid->collection[multiplier->usage->collection_index];
while (multiplier_collection &&
multiplier_collection->type != HID_COLLECTION_LOGICAL)
multiplier_collection = multiplier_collection->parent;
effective_multiplier = hid_calculate_multiplier(hid, multiplier);
rep_enum = &hid->report_enum[HID_INPUT_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) {
for (i = 0; i < rep->maxfield; i++) {
field = rep->field[i];
hid_apply_multiplier_to_field(hid, field,
multiplier_collection,
effective_multiplier);
}
}
}
/*
* hid_setup_resolution_multiplier - set up all resolution multipliers
*
* @device: hid device
*
* Search for all Resolution Multiplier Feature Reports and apply their
* value to all matching Input items. This only updates the internal struct
* fields.
*
* The Resolution Multiplier is applied by the hardware. If the multiplier
* is anything other than 1, the hardware will send pre-multiplied events
* so that the same physical interaction generates an accumulated
* accumulated_value = value * * multiplier
* This may be achieved by sending
* - "value * multiplier" for each event, or
* - "value" but "multiplier" times as frequently, or
* - a combination of the above
* The only guarantee is that the same physical interaction always generates
* an accumulated 'value * multiplier'.
*
* This function must be called before any event processing and after
* any SetRequest to the Resolution Multiplier.
*/
void hid_setup_resolution_multiplier(struct hid_device *hid)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
struct hid_usage *usage;
int i, j;
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) {
for (i = 0; i < rep->maxfield; i++) {
/* Ignore if report count is out of bounds. */
if (rep->field[i]->report_count < 1)
continue;
for (j = 0; j < rep->field[i]->maxusage; j++) {
usage = &rep->field[i]->usage[j];
if (usage->hid == HID_GD_RESOLUTION_MULTIPLIER)
hid_apply_multiplier(hid,
rep->field[i]);
}
}
}
}
EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
/**
* hid_open_report - open a driver-specific device report
*
......@@ -1039,9 +1205,17 @@ int hid_open_report(struct hid_device *device)
hid_err(device, "unbalanced delimiter at end of report description\n");
goto err;
}
/*
* fetch initial values in case the device's
* default multiplier isn't the recommended 1
*/
hid_setup_resolution_multiplier(device);
kfree(parser->collection_stack);
vfree(parser);
device->status |= HID_STAT_PARSED;
return 0;
}
}
......
......@@ -326,6 +326,8 @@ module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
static struct hid_device_id cougar_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD) },
{}
};
MODULE_DEVICE_TABLE(hid, cougar_id_table);
......
......@@ -1072,11 +1072,6 @@ static int hid_debug_rdesc_show(struct seq_file *f, void *p)
return 0;
}
static int hid_debug_rdesc_open(struct inode *inode, struct file *file)
{
return single_open(file, hid_debug_rdesc_show, inode->i_private);
}
static int hid_debug_events_open(struct inode *inode, struct file *file)
{
int err = 0;
......@@ -1211,12 +1206,7 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
return 0;
}
static const struct file_operations hid_debug_rdesc_fops = {
.open = hid_debug_rdesc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(hid_debug_rdesc);
static const struct file_operations hid_debug_events_fops = {
.owner = THIS_MODULE,
......
......@@ -187,12 +187,14 @@
#define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD 0x17e0
#define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807
#define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502
#define USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD 0x183d
#define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a
#define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585
#define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
......@@ -1025,6 +1027,7 @@
#define USB_VENDOR_ID_SOLID_YEAR 0x060b
#define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a
#define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD 0x700a
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
......
......@@ -712,7 +712,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_abs_clear(usage->hid & 0xf);
break;
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE) {
set_bit(REL_WHEEL, input->relbit);
map_rel(REL_WHEEL_HI_RES);
} else {
map_abs(usage->hid & 0xf);
}
break;
case HID_GD_SLIDER: case HID_GD_DIAL:
if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf);
else
......@@ -1012,7 +1020,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
case 0x238: map_rel(REL_HWHEEL); break;
case 0x238: /* AC Pan */
set_bit(REL_HWHEEL, input->relbit);
map_rel(REL_HWHEEL_HI_RES);
break;
case 0x23d: map_key_clear(KEY_EDIT); break;
case 0x25f: map_key_clear(KEY_CANCEL); break;
case 0x269: map_key_clear(KEY_INSERT); break;
......@@ -1200,6 +1211,38 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
static void hidinput_handle_scroll(struct hid_usage *usage,
struct input_dev *input,
__s32 value)
{
int code;
int hi_res, lo_res;
if (value == 0)
return;
if (usage->code == REL_WHEEL_HI_RES)
code = REL_WHEEL;
else
code = REL_HWHEEL;
/*
* Windows reports one wheel click as value 120. Where a high-res
* scroll wheel is present, a fraction of 120 is reported instead.
* Our REL_WHEEL_HI_RES axis does the same because all HW must
* adhere to the 120 expectation.
*/
hi_res = value * 120/usage->resolution_multiplier;
usage->wheel_accumulated += hi_res;
lo_res = usage->wheel_accumulated/120;
if (lo_res)
usage->wheel_accumulated -= lo_res * 120;
input_event(input, EV_REL, code, lo_res);
input_event(input, EV_REL, usage->code, hi_res);
}
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
......@@ -1262,6 +1305,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
return;
if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
usage->code == REL_HWHEEL_HI_RES)) {
hidinput_handle_scroll(usage, input, value);
return;
}
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
(usage->code == ABS_VOLUME)) {
int count = abs(value);
......@@ -1489,6 +1538,58 @@ static void hidinput_close(struct input_dev *dev)
hid_hw_close(hid);
}
static void hidinput_change_resolution_multipliers(struct hid_device *hid)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
struct hid_usage *usage;
int i, j;
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) {
bool update_needed = false;
if (rep->maxfield == 0)
continue;
/*
* If we have more than one feature within this report we
* need to fill in the bits from the others before we can
* overwrite the ones for the Resolution Multiplier.
*/
if (rep->maxfield > 1) {
hid_hw_request(hid, rep, HID_REQ_GET_REPORT);
hid_hw_wait(hid);
}
for (i = 0; i < rep->maxfield; i++) {
__s32 logical_max = rep->field[i]->logical_maximum;
/* There is no good reason for a Resolution
* Multiplier to have a count other than 1.
* Ignore that case.
*/
if (rep->field[i]->report_count != 1)
continue;
for (j = 0; j < rep->field[i]->maxusage; j++) {
usage = &rep->field[i]->usage[j];
if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
continue;
*rep->field[i]->value = logical_max;
update_needed = true;
}
}
if (update_needed)
hid_hw_request(hid, rep, HID_REQ_SET_REPORT);
}
/* refresh our structs */
hid_setup_resolution_multiplier(hid);
}
static void report_features(struct hid_device *hid)
{
struct hid_driver *drv = hid->driver;
......@@ -1782,6 +1883,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
hidinput_change_resolution_multipliers(hid);
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
if (drv->input_configured &&
drv->input_configured(hid, hidinput))
......@@ -1840,4 +1943,3 @@ void hidinput_disconnect(struct hid_device *hid)
cancel_work_sync(&hid->led_work);
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);
......@@ -743,7 +743,9 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
data_pointer->led_mute.dev = dev;
led_classdev_register(dev, &data_pointer->led_mute);
ret = led_classdev_register(dev, &data_pointer->led_mute);
if (ret < 0)
goto err;
data_pointer->led_micmute.name = name_micmute;
data_pointer->led_micmute.brightness_get =
......@@ -751,7 +753,11 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev)
data_pointer->led_micmute.brightness_set =
lenovo_led_brightness_set_tpkbd;
data_pointer->led_micmute.dev = dev;
led_classdev_register(dev, &data_pointer->led_micmute);
ret = led_classdev_register(dev, &data_pointer->led_micmute);
if (ret < 0) {
led_classdev_unregister(&data_pointer->led_mute);
goto err;
}
lenovo_features_set_tpkbd(hdev);
......
This diff is collapsed.
......@@ -107,8 +107,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
/*
* The first byte of the report buffer is expected to be a report number.
*
* This function is to be called with the minors_lock mutex held.
*/
static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
......@@ -117,6 +115,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
__u8 *buf;
int ret = 0;
lockdep_assert_held(&minors_lock);
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
ret = -ENODEV;
goto out;
......@@ -181,8 +181,6 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
* of buffer is the report number to request, or 0x0 if the defice does not
* use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
* or HID_INPUT_REPORT.
*
* This function is to be called with the minors_lock mutex held.
*/
static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
{
......@@ -192,6 +190,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
int ret = 0, len;
unsigned char report_number;
lockdep_assert_held(&minors_lock);
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
ret = -ENODEV;
goto out;
......
......@@ -346,6 +346,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
},
.driver_data = (void *)&sipodev_desc
},
{
.ident = "Odys Winbook 13",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "WINBOOK 13"),
},
.driver_data = (void *)&sipodev_desc
},
{ } /* Terminate list */
};
......
......@@ -117,6 +117,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret;
struct ish_hw *hw;
unsigned long irq_flag = 0;
struct ishtp_device *ishtp;
struct device *dev = &pdev->dev;
......@@ -156,8 +157,12 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
/* request and enable interrupt */
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (!pdev->msi_enabled && !pdev->msix_enabled)
irq_flag = IRQF_SHARED;
ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, ishtp);
irq_flag, KBUILD_MODNAME, ishtp);
if (ret) {
dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
return ret;
......
......@@ -222,7 +222,7 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
err_hid_device:
kfree(hid_data);
err_hid_data:
kfree(hid);
hid_destroy_device(hid);
return rv;
}
......
......@@ -219,6 +219,7 @@ struct hid_item {
#define HID_GD_VBRZ 0x00010045
#define HID_GD_VNO 0x00010046
#define HID_GD_FEATURE 0x00010047
#define HID_GD_RESOLUTION_MULTIPLIER 0x00010048
#define HID_GD_SYSTEM_CONTROL 0x00010080
#define HID_GD_UP 0x00010090
#define HID_GD_DOWN 0x00010091
......@@ -232,12 +233,14 @@ struct hid_item {
#define HID_DC_BATTERYSTRENGTH 0x00060020
#define HID_CP_CONSUMER_CONTROL 0x000c0001
#define HID_CP_AC_PAN 0x000c0238
#define HID_DG_DIGITIZER 0x000d0001
#define HID_DG_PEN 0x000d0002
#define HID_DG_LIGHTPEN 0x000d0003
#define HID_DG_TOUCHSCREEN 0x000d0004
#define HID_DG_TOUCHPAD 0x000d0005
#define HID_DG_WHITEBOARD 0x000d0006
#define HID_DG_STYLUS 0x000d0020
#define HID_DG_PUCK 0x000d0021
#define HID_DG_FINGER 0x000d0022
......@@ -427,6 +430,7 @@ struct hid_local {
*/
struct hid_collection {
struct hid_collection *parent;
unsigned type;
unsigned usage;
unsigned level;
......@@ -436,12 +440,16 @@ struct hid_usage {
unsigned hid; /* hid usage code */
unsigned collection_index; /* index into collection array */
unsigned usage_index; /* index into usage array */
__s8 resolution_multiplier;/* Effective Resolution Multiplier
(HUT v1.12, 4.3.1), default: 1 */
/* hidinput data */
__s8 wheel_factor; /* 120/resolution_multiplier */
__u16 code; /* input driver code */
__u8 type; /* input driver type */
__s8 hat_min; /* hat switch fun */
__s8 hat_max; /* ditto */
__s8 hat_dir; /* ditto */
__s16 wheel_accumulated; /* hi-res wheel */
};
struct hid_input;
......@@ -650,6 +658,7 @@ struct hid_parser {
unsigned int *collection_stack;
unsigned int collection_stack_ptr;
unsigned int collection_stack_size;
struct hid_collection *active_collection;
struct hid_device *device;
unsigned int scan_flags;
};
......@@ -836,7 +845,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev,
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006)))
#define IS_INPUT_APPLICATION(a) \
(((a >= HID_UP_GENDESK) && (a <= HID_GD_MULTIAXIS)) \
|| ((a >= HID_DG_PEN) && (a <= HID_DG_WHITEBOARD)) \
|| (a == HID_GD_SYSTEM_CONTROL) || (a == HID_CP_CONSUMER_CONTROL) \
|| (a == HID_GD_WIRELESS_RADIO_CTLS))
/* HID core API */
......@@ -892,6 +905,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
unsigned int type, unsigned int id,
unsigned int field_index,
unsigned int report_counts);
void hid_setup_resolution_multiplier(struct hid_device *hid);
int hid_open_report(struct hid_device *device);
int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
......
......@@ -716,6 +716,8 @@
* the situation described above.
*/
#define REL_RESERVED 0x0a
#define REL_WHEEL_HI_RES 0x0b
#define REL_HWHEEL_HI_RES 0x0c
#define REL_MAX 0x0f
#define REL_CNT (REL_MAX+1)
......
......@@ -119,7 +119,7 @@ int main(int argc, char **argv)
if (res < 0)
perror("HIDIOCSFEATURE");
else
printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
printf("ioctl HIDIOCSFEATURE returned: %d\n", res);
/* Get Feature */
buf[0] = 0x9; /* Report Number */
......
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