Commit e1c9b9ff authored by Jiri Kosina's avatar Jiri Kosina

Merge branches 'for-4.5/upstream-fixes', 'for-4.6/cmedia', 'for-4.6/i2c-hid',...

Merge branches 'for-4.5/upstream-fixes', 'for-4.6/cmedia', 'for-4.6/i2c-hid', 'for-4.6/logitech', 'for-4.6/multitouch', 'for-4.6/penmount', 'for-4.6/sony', 'for-4.6/thingm', 'for-4.6/upstream' and 'for-4.6/wacom' into for-linus
......@@ -196,6 +196,12 @@ config HID_PRODIKEYS
multimedia keyboard, but will lack support for the musical keyboard
and some additional multimedia keys.
config HID_CMEDIA
tristate "CMedia CM6533 HID audio jack controls"
depends on HID
---help---
Support for CMedia CM6533 HID audio jack controls.
config HID_CP2112
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
depends on USB_HID && I2C && GPIOLIB
......
......@@ -29,6 +29,7 @@ obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o
obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
......
/*
* HID driver for CMedia CM6533 audio jack controls
*
* Copyright (C) 2015 Ben Chen <ben_chen@bizlinktech.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("Ben Chen");
MODULE_DESCRIPTION("CM6533 HID jack controls");
MODULE_LICENSE("GPL");
#define CM6533_JD_TYPE_COUNT 1
#define CM6533_JD_RAWEV_LEN 16
#define CM6533_JD_SFX_OFFSET 8
/*
*
*CM6533 audio jack HID raw events:
*
*Plug in:
*01000600 002083xx 080008c0 10000000
*about 3 seconds later...
*01000a00 002083xx 08000380 10000000
*01000600 002083xx 08000380 10000000
*
*Plug out:
*01000400 002083xx 080008c0 x0000000
*/
static const u8 ji_sfx[] = { 0x08, 0x00, 0x08, 0xc0 };
static const u8 ji_in[] = { 0x01, 0x00, 0x06, 0x00 };
static const u8 ji_out[] = { 0x01, 0x00, 0x04, 0x00 };
static int jack_switch_types[CM6533_JD_TYPE_COUNT] = {
SW_HEADPHONE_INSERT,
};
struct cmhid {
struct input_dev *input_dev;
struct hid_device *hid;
unsigned short switch_map[CM6533_JD_TYPE_COUNT];
};
static void hp_ev(struct hid_device *hid, struct cmhid *cm, int value)
{
input_report_switch(cm->input_dev, SW_HEADPHONE_INSERT, value);
input_sync(cm->input_dev);
}
static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
u8 *data, int len)
{
struct cmhid *cm = hid_get_drvdata(hid);
if (len != CM6533_JD_RAWEV_LEN)
goto out;
if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
goto out;
if (!memcmp(data, ji_out, sizeof(ji_out))) {
hp_ev(hid, cm, 0);
goto out;
}
if (!memcmp(data, ji_in, sizeof(ji_in))) {
hp_ev(hid, cm, 1);
goto out;
}
out:
return 0;
}
static int cmhid_input_configured(struct hid_device *hid,
struct hid_input *hidinput)
{
struct input_dev *input_dev = hidinput->input;
struct cmhid *cm = hid_get_drvdata(hid);
int i;
cm->input_dev = input_dev;
memcpy(cm->switch_map, jack_switch_types, sizeof(cm->switch_map));
input_dev->evbit[0] = BIT(EV_SW);
for (i = 0; i < CM6533_JD_TYPE_COUNT; i++)
input_set_capability(cm->input_dev,
EV_SW, jack_switch_types[i]);
return 0;
}
static int cmhid_input_mapping(struct hid_device *hid,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
return -1;
}
static int cmhid_probe(struct hid_device *hid, const struct hid_device_id *id)
{
int ret;
struct cmhid *cm;
cm = kzalloc(sizeof(struct cmhid), GFP_KERNEL);
if (!cm) {
ret = -ENOMEM;
goto allocfail;
}
cm->hid = hid;
hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
hid_set_drvdata(hid, cm);
ret = hid_parse(hid);
if (ret) {
hid_err(hid, "parse failed\n");
goto fail;
}
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
if (ret) {
hid_err(hid, "hw start failed\n");
goto fail;
}
return 0;
fail:
kfree(cm);
allocfail:
return ret;
}
static void cmhid_remove(struct hid_device *hid)
{
struct cmhid *cm = hid_get_drvdata(hid);
hid_hw_stop(hid);
kfree(cm);
}
static const struct hid_device_id cmhid_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) },
{ }
};
MODULE_DEVICE_TABLE(hid, cmhid_devices);
static struct hid_driver cmhid_driver = {
.name = "cm6533_jd",
.id_table = cmhid_devices,
.raw_event = cmhid_raw_event,
.input_configured = cmhid_input_configured,
.probe = cmhid_probe,
.remove = cmhid_remove,
.input_mapping = cmhid_input_mapping,
};
module_hid_driver(cmhid_driver);
......@@ -1965,6 +1965,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
......@@ -2049,6 +2050,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
......@@ -2097,6 +2099,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) },
{ }
};
......
......@@ -151,7 +151,7 @@ static inline int drff_init(struct hid_device *hid)
* descriptor. In any case, it's a wonder it works on Windows.
*
* Usage Page (Desktop), ; Generic desktop controls (01h)
* Usage (Joystik), ; Joystik (04h, application collection)
* Usage (Joystick), ; Joystick (04h, application collection)
* Collection (Application),
* Collection (Logical),
* Report Size (8),
......@@ -207,7 +207,7 @@ static inline int drff_init(struct hid_device *hid)
/* Fixed report descriptor for PID 0x011 joystick */
static __u8 pid0011_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x14, /* Logical Minimum (0), */
......
......@@ -249,6 +249,7 @@
#define USB_VENDOR_ID_CMEDIA 0x0d8c
#define USB_DEVICE_ID_CM109 0x000e
#define USB_DEVICE_ID_CM6533 0x0022
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
......@@ -683,6 +684,7 @@
#define USB_DEVICE_ID_MS_NE7K 0x071d
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#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
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
......@@ -877,6 +879,9 @@
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000
#define USB_VENDOR_ID_SINO_LITE 0x1345
#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
......@@ -1052,7 +1057,7 @@
#define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */
#define USB_VENDOR_ID_MULTIPLE_1781 0x1781
#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a8d
#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a9d
#define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b
#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002
......
......@@ -61,7 +61,7 @@
*/
static __u8 df_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
......@@ -127,7 +127,7 @@ static __u8 df_rdesc_fixed[] = {
static __u8 dfp_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
......@@ -175,7 +175,7 @@ static __u8 dfp_rdesc_fixed[] = {
static __u8 fv_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
......@@ -242,7 +242,7 @@ static __u8 fv_rdesc_fixed[] = {
static __u8 momo_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
......@@ -288,7 +288,7 @@ static __u8 momo_rdesc_fixed[] = {
static __u8 momo2_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0x09, 0x04, /* Usage (Joystick), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
......
This diff is collapsed.
......@@ -286,6 +286,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD),
.driver_data = MS_ERGONOMY},
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
......
......@@ -396,6 +396,11 @@ static void mt_feature_mapping(struct hid_device *hdev,
td->is_buttonpad = true;
break;
case 0xff0000c5:
/* Retrieve the Win8 blob once to enable some devices */
if (usage->usage_index == 0)
mt_get_feature(hdev, field->report);
break;
}
}
......@@ -1133,6 +1138,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
if (ret)
dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n",
hdev->name);
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
......@@ -1145,8 +1153,30 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
#ifdef CONFIG_PM
static void mt_release_contacts(struct hid_device *hid)
{
struct hid_input *hidinput;
list_for_each_entry(hidinput, &hid->inputs, list) {
struct input_dev *input_dev = hidinput->input;
struct input_mt *mt = input_dev->mt;
int i;
if (mt) {
for (i = 0; i < mt->num_slots; i++) {
input_mt_slot(input_dev, i);
input_mt_report_slot_state(input_dev,
MT_TOOL_FINGER,
false);
}
input_sync(input_dev);
}
}
}
static int mt_reset_resume(struct hid_device *hdev)
{
mt_release_contacts(hdev);
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
return 0;
......
......@@ -23,8 +23,12 @@ static int penmount_input_mapping(struct hid_device *hdev,
struct hid_usage *usage, unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
if (((usage->hid - 1) & HID_USAGE) == 0) {
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
} else {
return -1;
}
}
return 0;
......
This diff is collapsed.
......@@ -14,7 +14,6 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include "hid-ids.h"
......@@ -56,7 +55,6 @@ struct thingm_rgb {
struct thingm_led red;
struct thingm_led green;
struct thingm_led blue;
struct work_struct work;
u8 num;
};
......@@ -79,9 +77,13 @@ static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
mutex_lock(&tdev->lock);
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
mutex_unlock(&tdev->lock);
return ret < 0 ? ret : 0;
}
......@@ -89,16 +91,31 @@ static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
int ret;
/*
* A read consists of two operations: sending the read command
* and the actual read from the device. Use the mutex to protect
* the full sequence of both operations.
*/
mutex_lock(&tdev->lock);
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0)
goto err;
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0)
return ret;
goto err;
ret = 0;
hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
return 0;
err:
mutex_unlock(&tdev->lock);
return ret;
}
static int thingm_version(struct thingm_device *tdev)
......@@ -106,10 +123,6 @@ static int thingm_version(struct thingm_device *tdev)
u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
int err;
err = thingm_send(tdev, buf);
if (err)
return err;
err = thingm_recv(tdev, buf);
if (err)
return err;
......@@ -131,25 +144,17 @@ static int thingm_write_color(struct thingm_rgb *rgb)
return thingm_send(rgb->tdev, buf);
}
static void thingm_work(struct work_struct *work)
{
struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
mutex_lock(&rgb->tdev->lock);
if (thingm_write_color(rgb))
hid_err(rgb->tdev->hdev, "failed to write color\n");
mutex_unlock(&rgb->tdev->lock);
}
static void thingm_led_set(struct led_classdev *ldev,
enum led_brightness brightness)
static int thingm_led_set(struct led_classdev *ldev,
enum led_brightness brightness)
{
struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
int ret;
ret = thingm_write_color(led->rgb);
if (ret)
hid_err(led->rgb->tdev->hdev, "failed to write color\n");
/* the ledclass has already stored the brightness value */
schedule_work(&led->rgb->work);
return ret;
}
static int thingm_init_rgb(struct thingm_rgb *rgb)
......@@ -162,10 +167,11 @@ static int thingm_init_rgb(struct thingm_rgb *rgb)
"thingm%d:red:led%d", minor, rgb->num);
rgb->red.ldev.name = rgb->red.name;
rgb->red.ldev.max_brightness = 255;
rgb->red.ldev.brightness_set = thingm_led_set;
rgb->red.ldev.brightness_set_blocking = thingm_led_set;
rgb->red.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev);
err = devm_led_classdev_register(&rgb->tdev->hdev->dev,
&rgb->red.ldev);
if (err)
return err;
......@@ -174,46 +180,27 @@ static int thingm_init_rgb(struct thingm_rgb *rgb)
"thingm%d:green:led%d", minor, rgb->num);
rgb->green.ldev.name = rgb->green.name;
rgb->green.ldev.max_brightness = 255;
rgb->green.ldev.brightness_set = thingm_led_set;
rgb->green.ldev.brightness_set_blocking = thingm_led_set;
rgb->green.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev);
err = devm_led_classdev_register(&rgb->tdev->hdev->dev,
&rgb->green.ldev);
if (err)
goto unregister_red;
return err;
/* Register the blue diode */
snprintf(rgb->blue.name, sizeof(rgb->blue.name),
"thingm%d:blue:led%d", minor, rgb->num);
rgb->blue.ldev.name = rgb->blue.name;
rgb->blue.ldev.max_brightness = 255;
rgb->blue.ldev.brightness_set = thingm_led_set;
rgb->blue.ldev.brightness_set_blocking = thingm_led_set;
rgb->blue.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev);
if (err)
goto unregister_green;
INIT_WORK(&rgb->work, thingm_work);
return 0;
unregister_green:
led_classdev_unregister(&rgb->green.ldev);
unregister_red:
led_classdev_unregister(&rgb->red.ldev);
err = devm_led_classdev_register(&rgb->tdev->hdev->dev,
&rgb->blue.ldev);
return err;
}
static void thingm_remove_rgb(struct thingm_rgb *rgb)
{
led_classdev_unregister(&rgb->red.ldev);
led_classdev_unregister(&rgb->green.ldev);
led_classdev_unregister(&rgb->blue.ldev);
flush_work(&rgb->work);
}
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct thingm_device *tdev;
......@@ -229,17 +216,13 @@ static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
err = hid_parse(hdev);
if (err)
goto error;
err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (err)
goto error;
return err;
mutex_init(&tdev->lock);
err = thingm_version(tdev);
if (err)
goto stop;
return err;
hid_dbg(hdev, "firmware version: %c.%c\n",
tdev->version.major, tdev->version.minor);
......@@ -250,17 +233,18 @@ static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!tdev->fwinfo) {
hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
err = -ENODEV;
goto stop;
return -ENODEV;
}
tdev->rgb = devm_kzalloc(&hdev->dev,
sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
GFP_KERNEL);
if (!tdev->rgb) {
err = -ENOMEM;
goto stop;
}
if (!tdev->rgb)
return -ENOMEM;
err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (err)
return err;
for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
struct thingm_rgb *rgb = tdev->rgb + i;
......@@ -269,28 +253,12 @@ static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
rgb->num = tdev->fwinfo->first + i;
err = thingm_init_rgb(rgb);
if (err) {
while (--i >= 0)
thingm_remove_rgb(tdev->rgb + i);
goto stop;
hid_hw_stop(hdev);
return err;
}
}
return 0;
stop:
hid_hw_stop(hdev);
error:
return err;
}
static void thingm_remove(struct hid_device *hdev)
{
struct thingm_device *tdev = hid_get_drvdata(hdev);
int i;
hid_hw_stop(hdev);
for (i = 0; i < tdev->fwinfo->numrgb; ++i)
thingm_remove_rgb(tdev->rgb + i);
}
static const struct hid_device_id thingm_table[] = {
......@@ -302,7 +270,6 @@ MODULE_DEVICE_TABLE(hid, thingm_table);
static struct hid_driver thingm_driver = {
.name = "thingm",
.probe = thingm_probe,
.remove = thingm_remove,
.id_table = thingm_table,
};
......
......@@ -283,17 +283,21 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
u16 size;
int args_len;
int index = 0;
i2c_hid_dbg(ihid, "%s\n", __func__);
if (data_len > ihid->bufsize)
return -EINVAL;
/* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ +
size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
int args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
2 /* dataRegister */ +
size /* args */;
int index = 0;
i2c_hid_dbg(ihid, "%s\n", __func__);
if (!use_data && maxOutputLength == 0)
return -ENOSYS;
......@@ -1108,13 +1112,30 @@ static int i2c_hid_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid = ihid->hid;
int ret = 0;
int ret;
int wake_status;
if (hid->driver && hid->driver->suspend)
if (hid->driver && hid->driver->suspend) {
/*
* Wake up the device so that IO issues in
* HID driver's suspend code can succeed.
*/
ret = pm_runtime_resume(dev);
if (ret < 0)
return ret;
ret = hid->driver->suspend(hid, PMSG_SUSPEND);
if (ret < 0)
return ret;
}
if (!pm_runtime_suspended(dev)) {
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
disable_irq(ihid->irq);
}
disable_irq(ihid->irq);
if (device_may_wakeup(&client->dev)) {
wake_status = enable_irq_wake(ihid->irq);
if (!wake_status)
......@@ -1124,10 +1145,7 @@ static int i2c_hid_suspend(struct device *dev)
wake_status);
}
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
return ret;
return 0;
}
static int i2c_hid_resume(struct device *dev)
......@@ -1138,11 +1156,6 @@ static int i2c_hid_resume(struct device *dev)
struct hid_device *hid = ihid->hid;
int wake_status;
enable_irq(ihid->irq);
ret = i2c_hid_hwreset(client);
if (ret)
return ret;
if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
wake_status = disable_irq_wake(ihid->irq);
if (!wake_status)
......@@ -1152,6 +1165,16 @@ static int i2c_hid_resume(struct device *dev)
wake_status);
}
/* We'll resume to full power */
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
enable_irq(ihid->irq);
ret = i2c_hid_hwreset(client);
if (ret)
return ret;
if (hid->driver && hid->driver->reset_resume) {
ret = hid->driver->reset_resume(hid);
return ret;
......@@ -1191,6 +1214,7 @@ static const struct dev_pm_ops i2c_hid_pm = {
static const struct i2c_device_id i2c_hid_id_table[] = {
{ "hid", 0 },
{ "hid-over-i2c", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
......
This diff is collapsed.
......@@ -575,16 +575,102 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
return 1;
}
static int wacom_intuos_get_tool_type(int tool_id)
{
int tool_type;
switch (tool_id) {
case 0x812: /* Inking pen */
case 0x801: /* Intuos3 Inking pen */
case 0x120802: /* Intuos4/5 Inking Pen */
case 0x012:
tool_type = BTN_TOOL_PENCIL;
break;
case 0x822: /* Pen */
case 0x842:
case 0x852:
case 0x823: /* Intuos3 Grip Pen */
case 0x813: /* Intuos3 Classic Pen */
case 0x885: /* Intuos3 Marker Pen */
case 0x802: /* Intuos4/5 13HD/24HD General Pen */
case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
case 0x8e2: /* IntuosHT2 pen */
case 0x022:
case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */
case 0x160802: /* Cintiq 13HD Pro Pen */
case 0x180802: /* DTH2242 Pen */
case 0x100802: /* Intuos4/5 13HD/24HD General Pen */
tool_type = BTN_TOOL_PEN;
break;
case 0x832: /* Stroke pen */
case 0x032:
tool_type = BTN_TOOL_BRUSH;
break;
case 0x007: /* Mouse 4D and 2D */
case 0x09c:
case 0x094:
case 0x017: /* Intuos3 2D Mouse */
case 0x806: /* Intuos4 Mouse */
tool_type = BTN_TOOL_MOUSE;
break;
case 0x096: /* Lens cursor */
case 0x097: /* Intuos3 Lens cursor */
case 0x006: /* Intuos4 Lens cursor */
tool_type = BTN_TOOL_LENS;
break;
case 0x82a: /* Eraser */
case 0x85a:
case 0x91a:
case 0xd1a:
case 0x0fa:
case 0x82b: /* Intuos3 Grip Pen Eraser */
case 0x81b: /* Intuos3 Classic Pen Eraser */
case 0x91b: /* Intuos3 Airbrush Eraser */
case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */
case 0x18080a: /* DTH2242 Eraser */
case 0x10080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
tool_type = BTN_TOOL_RUBBER;
break;
case 0xd12:
case 0x912:
case 0x112:
case 0x913: /* Intuos3 Airbrush */
case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
tool_type = BTN_TOOL_AIRBRUSH;
break;
default: /* Unknown tool */
tool_type = BTN_TOOL_PEN;
break;
}
return tool_type;
}
static int wacom_intuos_inout(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
int idx = 0;
int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
/* tool number */
if (features->type == INTUOS)
idx = data[1] & 0x01;
if (!(((data[1] & 0xfc) == 0xc0) || /* in prox */
((data[1] & 0xfe) == 0x20) || /* in range */
((data[1] & 0xfe) == 0x80))) /* out prox */
return 0;
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
......@@ -596,116 +682,24 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
((data[7] & 0x0f) << 20) | ((data[8] & 0xf0) << 12);
switch (wacom->id[idx]) {
case 0x812: /* Inking pen */
case 0x801: /* Intuos3 Inking pen */
case 0x120802: /* Intuos4/5 Inking Pen */
case 0x012:
wacom->tool[idx] = BTN_TOOL_PENCIL;
break;
case 0x822: /* Pen */
case 0x842:
case 0x852:
case 0x823: /* Intuos3 Grip Pen */
case 0x813: /* Intuos3 Classic Pen */
case 0x885: /* Intuos3 Marker Pen */
case 0x802: /* Intuos4/5 13HD/24HD General Pen */
case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
case 0x022:
case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */
case 0x160802: /* Cintiq 13HD Pro Pen */
case 0x180802: /* DTH2242 Pen */
case 0x100802: /* Intuos4/5 13HD/24HD General Pen */
wacom->tool[idx] = BTN_TOOL_PEN;
break;
case 0x832: /* Stroke pen */
case 0x032:
wacom->tool[idx] = BTN_TOOL_BRUSH;
break;
case 0x007: /* Mouse 4D and 2D */
case 0x09c:
case 0x094:
case 0x017: /* Intuos3 2D Mouse */
case 0x806: /* Intuos4 Mouse */
wacom->tool[idx] = BTN_TOOL_MOUSE;
break;
case 0x096: /* Lens cursor */
case 0x097: /* Intuos3 Lens cursor */
case 0x006: /* Intuos4 Lens cursor */
wacom->tool[idx] = BTN_TOOL_LENS;
break;
case 0x82a: /* Eraser */
case 0x85a:
case 0x91a:
case 0xd1a:
case 0x0fa:
case 0x82b: /* Intuos3 Grip Pen Eraser */
case 0x81b: /* Intuos3 Classic Pen Eraser */
case 0x91b: /* Intuos3 Airbrush Eraser */
case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */
case 0x18080a: /* DTH2242 Eraser */
case 0x10080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
wacom->tool[idx] = BTN_TOOL_RUBBER;
break;
case 0xd12:
case 0x912:
case 0x112:
case 0x913: /* Intuos3 Airbrush */
case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
break;
default: /* Unknown tool */
wacom->tool[idx] = BTN_TOOL_PEN;
break;
}
wacom->tool[idx] = wacom_intuos_get_tool_type(wacom->id[idx]);
return 1;
}
/*
* don't report events for invalid data
*/
/* older I4 styli don't work with new Cintiqs */
if ((!((wacom->id[idx] >> 20) & 0x01) &&
(features->type == WACOM_21UX2)) ||
/* Only large Intuos support Lense Cursor */
(wacom->tool[idx] == BTN_TOOL_LENS &&
(features->type == INTUOS3 ||
features->type == INTUOS3S ||
features->type == INTUOS4 ||
features->type == INTUOS4S ||
features->type == INTUOS5 ||
features->type == INTUOS5S ||
features->type == INTUOSPM ||
features->type == INTUOSPS)) ||
/* Cintiq doesn't send data when RDY bit isn't set */
(features->type == CINTIQ && !(data[1] & 0x40)))
return 1;
/* in Range */
if ((data[1] & 0xfe) == 0x20) {
if (features->type != INTUOSHT2)
wacom->shared->stylus_in_proximity = true;
wacom->shared->stylus_in_proximity = true;
if (wacom->shared->touch_down)
/* in Range while exiting */
if (wacom->reporting_data) {
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
return 2;
}
return 1;
/* in Range while exiting */
if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
return 2;
}
/* Exit report */
......@@ -750,13 +744,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
return 2;
}
/* don't report other events if we don't know the ID */
if (!wacom->id[idx]) {
/* but reschedule a read of the current tool */
wacom_intuos_schedule_prox_event(wacom);
return 1;
}
return 0;
}
......@@ -897,6 +884,36 @@ static int wacom_intuos_general(struct wacom_wac *wacom)
data[0] != WACOM_REPORT_INTUOS_PEN)
return 0;
if (wacom->shared->touch_down)
return 1;
/* don't report events if we don't know the tool ID */
if (!wacom->id[idx]) {
/* but reschedule a read of the current tool */
wacom_intuos_schedule_prox_event(wacom);
return 1;
}
/*
* don't report events for invalid data
*/
/* older I4 styli don't work with new Cintiqs */
if ((!((wacom->id[idx] >> 20) & 0x01) &&
(features->type == WACOM_21UX2)) ||
/* Only large Intuos support Lense Cursor */
(wacom->tool[idx] == BTN_TOOL_LENS &&
(features->type == INTUOS3 ||
features->type == INTUOS3S ||
features->type == INTUOS4 ||
features->type == INTUOS4S ||
features->type == INTUOS5 ||
features->type == INTUOS5S ||
features->type == INTUOSPM ||
features->type == INTUOSPS)) ||
/* Cintiq doesn't send data when RDY bit isn't set */
(features->type == CINTIQ && !(data[1] & 0x40)))
return 1;
x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
distance = data[9] >> 2;
......
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