diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 24 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 8 | ||||
-rw-r--r-- | drivers/hid/hid-magicmouse.c | 10 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 74 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-arvo.c | 21 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-arvo.h | 13 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-common.c | 20 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-common.h | 4 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.c | 56 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.h | 2 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-koneplus.c | 49 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-koneplus.h | 23 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kovaplus.c | 25 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kovaplus.h | 9 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-pyra.c | 25 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-pyra.h | 9 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.c | 489 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 8 |
21 files changed, 722 insertions, 152 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 6008e634853e..306b15f39c9c 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -319,6 +319,7 @@ config HID_MULTITOUCH - 3M PCT touch screens - ActionStar dual touch panels - Cando dual touch panels + - Chunghwa panels - CVTouch panels - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels @@ -449,6 +450,7 @@ config HID_QUANTA config HID_ROCCAT tristate "Roccat special event support" depends on USB_HID + select HID_ROCCAT_COMMON ---help--- Support for Roccat special events. Say Y here if you have a Roccat mouse or keyboard and want OSD or @@ -456,44 +458,40 @@ config HID_ROCCAT config HID_ROCCAT_COMMON tristate + depends on HID_ROCCAT config HID_ROCCAT_ARVO tristate "Roccat Arvo keyboard support" depends on USB_HID - select HID_ROCCAT - select HID_ROCCAT_COMMON + depends on HID_ROCCAT ---help--- Support for Roccat Arvo keyboard. config HID_ROCCAT_KONE tristate "Roccat Kone Mouse support" depends on USB_HID - select HID_ROCCAT - select HID_ROCCAT_COMMON + depends on HID_ROCCAT ---help--- Support for Roccat Kone mouse. config HID_ROCCAT_KONEPLUS tristate "Roccat Kone[+] mouse support" depends on USB_HID - select HID_ROCCAT - select HID_ROCCAT_COMMON + depends on HID_ROCCAT ---help--- Support for Roccat Kone[+] mouse. config HID_ROCCAT_KOVAPLUS tristate "Roccat Kova[+] mouse support" depends on USB_HID - select HID_ROCCAT - select HID_ROCCAT_COMMON + depends on HID_ROCCAT ---help--- Support for Roccat Kova[+] mouse. config HID_ROCCAT_PYRA tristate "Roccat Pyra mouse support" depends on USB_HID - select HID_ROCCAT - select HID_ROCCAT_COMMON + depends on HID_ROCCAT ---help--- Support for Roccat Pyra mouse. @@ -588,6 +586,12 @@ config HID_WACOM_POWER_SUPPLY Say Y here if you want to enable power supply status monitoring for Wacom Bluetooth devices. +config HID_WIIMOTE + tristate "Nintendo Wii Remote support" + depends on BT_HIDP + ---help--- + Support for the Nintendo Wii Remote bluetooth device. + config HID_ZEROPLUS tristate "Zeroplus based game controller support" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 21dea54b4482..0a0a38e9fd28 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_WACOM) += hid-wacom.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o +obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9657007e4927..1a5cf0c9cfca 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1359,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, @@ -1423,6 +1424,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, { 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) }, @@ -1508,6 +1510,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f9717e2a95a2..db63ccf21cc8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -173,6 +173,9 @@ #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 +#define USB_VENDOR_ID_CHUNGHWAT 0x2247 +#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 + #define USB_VENDOR_ID_CIDC 0x1677 #define USB_VENDOR_ID_CMEDIA 0x0d8c @@ -449,6 +452,7 @@ #define USB_VENDOR_ID_LUMIO 0x202e #define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 +#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007 #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 @@ -496,6 +500,9 @@ #define USB_VENDOR_ID_NEXTWINDOW 0x1926 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 +#define USB_VENDOR_ID_NINTENDO 0x057e +#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 + #define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 @@ -627,6 +634,7 @@ #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 +#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60 0x0064 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index a5eda4c8127a..0ec91c18a421 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -501,17 +501,9 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; - /* - * The device reponds with 'invalid report id' when feature - * report switching it into multitouch mode is sent to it. - * - * This results in -EIO from the _raw low-level transport callback, - * but there seems to be no other way of switching the mode. - * Thus the super-ugly hacky success check below. - */ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), HID_FEATURE_REPORT); - if (ret != -EIO) { + if (ret != sizeof(feature)) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index c0d1b15ca67c..58d0e7aaf088 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -64,6 +64,7 @@ struct mt_device { struct mt_class *mtclass; /* our mt device class */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ + int last_mt_collection; /* last known mt-related collection */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __u8 num_received; /* how many contacts we received */ __u8 num_expected; /* expected last contact index */ @@ -225,8 +226,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_GD_Y: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -237,8 +240,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; } return 0; @@ -246,31 +251,42 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_UP_DIGITIZER: switch (usage->hid) { case HID_DG_INRANGE: - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONFIDENCE: - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONTACTID: + if (!td->maxcontacts) + td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); td->last_slot_field = usage->hid; td->last_field_index = field->index; + td->last_mt_collection = usage->collection_index; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, @@ -279,8 +295,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_TIPPRESSURE: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -292,16 +310,20 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); - td->last_slot_field = usage->hid; - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) { + td->last_slot_field = usage->hid; + td->last_field_index = field->index; + } return 1; case HID_DG_CONTACTCOUNT: - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) + td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ - td->last_field_index = field->index; + if (td->last_mt_collection == usage->collection_index) + td->last_field_index = field->index; return -1; } /* let hid-input decide for the others */ @@ -516,6 +538,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) } td->mtclass = mtclass; td->inputmode = -1; + td->last_mt_collection = -1; hid_set_drvdata(hdev, td); ret = hid_parse(hdev); @@ -526,9 +549,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; - if (!td->maxcontacts) - td->maxcontacts = MT_DEFAULT_MAXCONTACT; - td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), GFP_KERNEL); if (!td->slots) { @@ -593,6 +613,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, + /* Chunghwa Telecom touch panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, + USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, + /* CVTouch panels */ { .driver_data = MT_CLS_DEFAULT, HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, @@ -651,6 +676,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, + USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, @@ -681,10 +709,10 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP)}, { .driver_data = MT_CLS_CONFIDENCE, - HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, { .driver_data = MT_CLS_CONFIDENCE, - HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX)}, /* Touch International panels */ diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c index 2307471d96dc..093bfad00b02 100644 --- a/drivers/hid/hid-roccat-arvo.c +++ b/drivers/hid/hid-roccat-arvo.c @@ -39,7 +39,7 @@ static ssize_t arvo_sysfs_show_mode_key(struct device *dev, int retval; mutex_lock(&arvo->arvo_lock); - retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY, + retval = roccat_common_receive(usb_dev, ARVO_COMMAND_MODE_KEY, &temp_buf, sizeof(struct arvo_mode_key)); mutex_unlock(&arvo->arvo_lock); if (retval) @@ -67,7 +67,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev, temp_buf.state = state; mutex_lock(&arvo->arvo_lock); - retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY, + retval = roccat_common_send(usb_dev, ARVO_COMMAND_MODE_KEY, &temp_buf, sizeof(struct arvo_mode_key)); mutex_unlock(&arvo->arvo_lock); if (retval) @@ -87,7 +87,7 @@ static ssize_t arvo_sysfs_show_key_mask(struct device *dev, int retval; mutex_lock(&arvo->arvo_lock); - retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK, + retval = roccat_common_receive(usb_dev, ARVO_COMMAND_KEY_MASK, &temp_buf, sizeof(struct arvo_key_mask)); mutex_unlock(&arvo->arvo_lock); if (retval) @@ -115,7 +115,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev, temp_buf.key_mask = key_mask; mutex_lock(&arvo->arvo_lock); - retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK, + retval = roccat_common_send(usb_dev, ARVO_COMMAND_KEY_MASK, &temp_buf, sizeof(struct arvo_key_mask)); mutex_unlock(&arvo->arvo_lock); if (retval) @@ -130,7 +130,7 @@ static int arvo_get_actual_profile(struct usb_device *usb_dev) struct arvo_actual_profile temp_buf; int retval; - retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE, + retval = roccat_common_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, &temp_buf, sizeof(struct arvo_actual_profile)); if (retval) @@ -163,11 +163,14 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev, if (retval) return retval; + if (profile < 1 || profile > 5) + return -EINVAL; + temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE; temp_buf.actual_profile = profile; mutex_lock(&arvo->arvo_lock); - retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE, + retval = roccat_common_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, &temp_buf, sizeof(struct arvo_actual_profile)); if (!retval) { arvo->actual_profile = profile; @@ -225,7 +228,7 @@ static ssize_t arvo_sysfs_write_button(struct file *fp, loff_t off, size_t count) { return arvo_sysfs_write(fp, kobj, buf, off, count, - sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON); + sizeof(struct arvo_button), ARVO_COMMAND_BUTTON); } static ssize_t arvo_sysfs_read_info(struct file *fp, @@ -233,7 +236,7 @@ static ssize_t arvo_sysfs_read_info(struct file *fp, loff_t off, size_t count) { return arvo_sysfs_read(fp, kobj, buf, off, count, - sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO); + sizeof(struct arvo_info), ARVO_COMMAND_INFO); } @@ -399,7 +402,7 @@ static int arvo_raw_event(struct hid_device *hdev, if (size != 3) return 0; - if (arvo->roccat_claimed) + if (arvo && arvo->roccat_claimed) arvo_report_to_chrdev(arvo, data); return 0; diff --git a/drivers/hid/hid-roccat-arvo.h b/drivers/hid/hid-roccat-arvo.h index d284a781c99e..ce8415e4f009 100644 --- a/drivers/hid/hid-roccat-arvo.h +++ b/drivers/hid/hid-roccat-arvo.h @@ -46,19 +46,6 @@ enum arvo_commands { ARVO_COMMAND_ACTUAL_PROFILE = 0x7, }; -enum arvo_usb_commands { - ARVO_USB_COMMAND_MODE_KEY = 0x303, - /* - * read/write - * Read uses both index bytes as profile/key indexes - * Write has index 0, profile/key is determined by payload - */ - ARVO_USB_COMMAND_BUTTON = 0x304, - ARVO_USB_COMMAND_INFO = 0x305, - ARVO_USB_COMMAND_KEY_MASK = 0x306, - ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307, -}; - struct arvo_special_report { uint8_t unknown1; /* always 0x01 */ uint8_t event; diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c index 13b1eb0c8c65..edf898dee28b 100644 --- a/drivers/hid/hid-roccat-common.c +++ b/drivers/hid/hid-roccat-common.c @@ -11,10 +11,16 @@ * any later version. */ +#include <linux/hid.h> #include <linux/slab.h> #include "hid-roccat-common.h" -int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, +static inline uint16_t roccat_common_feature_report(uint8_t report_id) +{ + return 0x300 | report_id; +} + +int roccat_common_receive(struct usb_device *usb_dev, uint report_id, void *data, uint size) { char *buf; @@ -25,9 +31,10 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, return -ENOMEM; len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_CLEAR_FEATURE, + HID_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + roccat_common_feature_report(report_id), + 0, buf, size, USB_CTRL_SET_TIMEOUT); memcpy(data, buf, size); kfree(buf); @@ -35,7 +42,7 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, } EXPORT_SYMBOL_GPL(roccat_common_receive); -int roccat_common_send(struct usb_device *usb_dev, uint usb_command, +int roccat_common_send(struct usb_device *usb_dev, uint report_id, void const *data, uint size) { char *buf; @@ -48,9 +55,10 @@ int roccat_common_send(struct usb_device *usb_dev, uint usb_command, memcpy(buf, data, size); len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_CONFIGURATION, + HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + roccat_common_feature_report(report_id), + 0, buf, size, USB_CTRL_SET_TIMEOUT); kfree(buf); return ((len < 0) ? len : ((len != size) ? -EIO : 0)); diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h index fe45fae05bb9..9a5bc61f9699 100644 --- a/drivers/hid/hid-roccat-common.h +++ b/drivers/hid/hid-roccat-common.h @@ -15,9 +15,9 @@ #include <linux/usb.h> #include <linux/types.h> -int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, +int roccat_common_receive(struct usb_device *usb_dev, uint report_id, void *data, uint size); -int roccat_common_send(struct usb_device *usb_dev, uint usb_command, +int roccat_common_send(struct usb_device *usb_dev, uint report_id, void const *data, uint size); #endif diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index a57838d15267..2b8f3a31ffb3 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -37,6 +37,47 @@ static uint profile_numbers[5] = {0, 1, 2, 3, 4}; +static int kone_receive(struct usb_device *usb_dev, uint usb_command, + void *data, uint size) +{ + char *buf; + int len; + + buf = kmalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), + HID_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + + memcpy(data, buf, size); + kfree(buf); + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +} + +static int kone_send(struct usb_device *usb_dev, uint usb_command, + void const *data, uint size) +{ + char *buf; + int len; + + buf = kmalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, data, size); + + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); + + kfree(buf); + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +} + /* kone_class is used for creating sysfs attributes via roccat char device */ static struct class *kone_class; @@ -68,7 +109,7 @@ static int kone_check_write(struct usb_device *usb_dev) */ msleep(80); - retval = roccat_common_receive(usb_dev, + retval = kone_receive(usb_dev, kone_command_confirm_write, &data, 1); if (retval) return retval; @@ -96,7 +137,7 @@ static int kone_check_write(struct usb_device *usb_dev) static int kone_get_settings(struct usb_device *usb_dev, struct kone_settings *buf) { - return roccat_common_receive(usb_dev, kone_command_settings, buf, + return kone_receive(usb_dev, kone_command_settings, buf, sizeof(struct kone_settings)); } @@ -109,7 +150,7 @@ static int kone_set_settings(struct usb_device *usb_dev, struct kone_settings const *settings) { int retval; - retval = roccat_common_send(usb_dev, kone_command_settings, + retval = kone_send(usb_dev, kone_command_settings, settings, sizeof(struct kone_settings)); if (retval) return retval; @@ -182,7 +223,7 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result) int retval; uint8_t data; - retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1); + retval = kone_receive(usb_dev, kone_command_weight, &data, 1); if (retval) return retval; @@ -201,7 +242,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) int retval; uint16_t data; - retval = roccat_common_receive(usb_dev, kone_command_firmware_version, + retval = kone_receive(usb_dev, kone_command_firmware_version, &data, 2); if (retval) return retval; @@ -384,7 +425,7 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number) { unsigned char value; value = number; - return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1); + return kone_send(usb_dev, kone_command_calibrate, &value, 1); } /* @@ -791,6 +832,9 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report, if (size != sizeof(struct kone_mouse_event)) return 0; + if (kone == NULL) + return 0; + /* * Firmware 1.38 introduced new behaviour for tilt and special buttons. * Pressed button is reported in each movement event. diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 4109a028e138..64abb5b8a59a 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -166,7 +166,7 @@ enum kone_mouse_events { /* osd events are thought to be display on screen */ kone_mouse_event_osd_dpi = 0xa0, kone_mouse_event_osd_profile = 0xb0, - /* TODO clarify meaning and occurrence of kone_mouse_event_calibration */ + /* TODO clarify meaning and occurence of kone_mouse_event_calibration */ kone_mouse_event_calibration = 0xc0, kone_mouse_event_call_overlong_macro = 0xe0, /* switch events notify if user changed values with mousebutton click */ diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 5b640a7a15a7..59e47770fa10 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -50,7 +50,7 @@ static int koneplus_send_control(struct usb_device *usb_dev, uint value, control.value = value; control.request = request; - return roccat_common_send(usb_dev, KONEPLUS_USB_COMMAND_CONTROL, + return roccat_common_send(usb_dev, KONEPLUS_COMMAND_CONTROL, &control, sizeof(struct koneplus_control)); } @@ -60,7 +60,7 @@ static int koneplus_receive_control_status(struct usb_device *usb_dev) struct koneplus_control control; do { - retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL, + retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_CONTROL, &control, sizeof(struct koneplus_control)); /* check if we get a completely wrong answer */ @@ -120,7 +120,7 @@ static int koneplus_select_profile(struct usb_device *usb_dev, uint number, static int koneplus_get_info(struct usb_device *usb_dev, struct koneplus_info *buf) { - return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO, + return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_INFO, buf, sizeof(struct koneplus_info)); } @@ -134,14 +134,14 @@ static int koneplus_get_profile_settings(struct usb_device *usb_dev, if (retval) return retval; - return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, + return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, buf, sizeof(struct koneplus_profile_settings)); } static int koneplus_set_profile_settings(struct usb_device *usb_dev, struct koneplus_profile_settings const *settings) { - return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, + return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, settings, sizeof(struct koneplus_profile_settings)); } @@ -155,14 +155,14 @@ static int koneplus_get_profile_buttons(struct usb_device *usb_dev, if (retval) return retval; - return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, + return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, buf, sizeof(struct koneplus_profile_buttons)); } static int koneplus_set_profile_buttons(struct usb_device *usb_dev, struct koneplus_profile_buttons const *buttons) { - return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, + return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, buttons, sizeof(struct koneplus_profile_buttons)); } @@ -172,7 +172,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev) struct koneplus_actual_profile buf; int retval; - retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, + retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, &buf, sizeof(struct koneplus_actual_profile)); return retval ? retval : buf.actual_profile; @@ -187,7 +187,7 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev, buf.size = sizeof(struct koneplus_actual_profile); buf.actual_profile = new_profile; - return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, + return koneplus_send(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, &buf, sizeof(struct koneplus_actual_profile)); } @@ -240,12 +240,20 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj, return real_size; } +static ssize_t koneplus_sysfs_write_talk(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + return koneplus_sysfs_write(fp, kobj, buf, off, count, + sizeof(struct koneplus_talk), KONEPLUS_COMMAND_TALK); +} + static ssize_t koneplus_sysfs_write_macro(struct file *fp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { return koneplus_sysfs_write(fp, kobj, buf, off, count, - sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO); + sizeof(struct koneplus_macro), KONEPLUS_COMMAND_MACRO); } static ssize_t koneplus_sysfs_read_sensor(struct file *fp, @@ -253,7 +261,7 @@ static ssize_t koneplus_sysfs_read_sensor(struct file *fp, loff_t off, size_t count) { return koneplus_sysfs_read(fp, kobj, buf, off, count, - sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); + sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR); } static ssize_t koneplus_sysfs_write_sensor(struct file *fp, @@ -261,7 +269,7 @@ static ssize_t koneplus_sysfs_write_sensor(struct file *fp, loff_t off, size_t count) { return koneplus_sysfs_write(fp, kobj, buf, off, count, - sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); + sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR); } static ssize_t koneplus_sysfs_write_tcu(struct file *fp, @@ -269,7 +277,7 @@ static ssize_t koneplus_sysfs_write_tcu(struct file *fp, loff_t off, size_t count) { return koneplus_sysfs_write(fp, kobj, buf, off, count, - sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU); + sizeof(struct koneplus_tcu), KONEPLUS_COMMAND_TCU); } static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, @@ -277,7 +285,7 @@ static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, loff_t off, size_t count) { return koneplus_sysfs_read(fp, kobj, buf, off, count, - sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU); + sizeof(struct koneplus_tcu_image), KONEPLUS_COMMAND_TCU); } static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp, @@ -423,6 +431,9 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, if (retval) return retval; + if (profile > 4) + return -EINVAL; + mutex_lock(&koneplus->koneplus_lock); retval = koneplus_set_actual_profile(usb_dev, profile); @@ -431,7 +442,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, return retval; } - koneplus->actual_profile = profile; + koneplus_profile_activated(koneplus, profile); roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE; roccat_report.data1 = profile + 1; @@ -557,6 +568,11 @@ static struct bin_attribute koneplus_bin_attributes[] = { .size = sizeof(struct koneplus_macro), .write = koneplus_sysfs_write_macro }, + { + .attr = { .name = "talk", .mode = 0220 }, + .size = sizeof(struct koneplus_talk), + .write = koneplus_sysfs_write_talk + }, __ATTR_NULL }; @@ -738,6 +754,9 @@ static int koneplus_raw_event(struct hid_device *hdev, != USB_INTERFACE_PROTOCOL_MOUSE) return 0; + if (koneplus == NULL) + return 0; + koneplus_keep_values_up_to_date(koneplus, data); if (koneplus->roccat_claimed) diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h index c57a376ab8ae..c03332a4fa9a 100644 --- a/drivers/hid/hid-roccat-koneplus.h +++ b/drivers/hid/hid-roccat-koneplus.h @@ -14,6 +14,12 @@ #include <linux/types.h> +struct koneplus_talk { + uint8_t command; /* KONEPLUS_COMMAND_TALK */ + uint8_t size; /* always 0x10 */ + uint8_t data[14]; +} __packed; + /* * case 1: writes request 80 and reads value 1 * @@ -137,26 +143,14 @@ enum koneplus_commands { KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, KONEPLUS_COMMAND_MACRO = 0x8, KONEPLUS_COMMAND_INFO = 0x9, + KONEPLUS_COMMAND_TCU = 0xc, KONEPLUS_COMMAND_E = 0xe, KONEPLUS_COMMAND_SENSOR = 0xf, + KONEPLUS_COMMAND_TALK = 0x10, KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b, KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c, }; -enum koneplus_usb_commands { - KONEPLUS_USB_COMMAND_CONTROL = 0x304, - KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305, - KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, - KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, - KONEPLUS_USB_COMMAND_MACRO = 0x308, - KONEPLUS_USB_COMMAND_INFO = 0x309, - KONEPLUS_USB_COMMAND_TCU = 0x30c, - KONEPLUS_USB_COMMAND_E = 0x30e, - KONEPLUS_USB_COMMAND_SENSOR = 0x30f, - KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b, - KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c, -}; - enum koneplus_mouse_report_numbers { KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1, KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2, @@ -193,6 +187,7 @@ enum koneplus_mouse_report_button_types { * data2 = action */ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0, + KONEPLUS_MOUSE_REPORT_TALK = 0xff, }; enum koneplus_mouse_report_button_action { diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 984be2f8967e..1f8336e3f584 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -58,7 +58,7 @@ static int kovaplus_send_control(struct usb_device *usb_dev, uint value, control.value = value; control.request = request; - retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL, + retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL, &control, sizeof(struct kovaplus_control)); return retval; @@ -70,7 +70,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev) struct kovaplus_control control; do { - retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL, + retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL, &control, sizeof(struct kovaplus_control)); /* check if we get a completely wrong answer */ @@ -90,7 +90,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev) if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) return -EINVAL; - hid_err(usb_dev, "kovaplus_receive_control_status: " + hid_err(usb_dev, "roccat_common_receive_control_status: " "unknown response value 0x%x\n", control.value); return -EINVAL; } while (1); @@ -119,7 +119,7 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, static int kovaplus_get_info(struct usb_device *usb_dev, struct kovaplus_info *buf) { - return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO, + return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO, buf, sizeof(struct kovaplus_info)); } @@ -133,14 +133,14 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev, if (retval) return retval; - return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS, + return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, buf, sizeof(struct kovaplus_profile_settings)); } static int kovaplus_set_profile_settings(struct usb_device *usb_dev, struct kovaplus_profile_settings const *settings) { - return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS, + return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, settings, sizeof(struct kovaplus_profile_settings)); } @@ -154,14 +154,14 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, if (retval) return retval; - return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS, + return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, buf, sizeof(struct kovaplus_profile_buttons)); } static int kovaplus_set_profile_buttons(struct usb_device *usb_dev, struct kovaplus_profile_buttons const *buttons) { - return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS, + return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, buttons, sizeof(struct kovaplus_profile_buttons)); } @@ -171,7 +171,7 @@ static int kovaplus_get_actual_profile(struct usb_device *usb_dev) struct kovaplus_actual_profile buf; int retval; - retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE, + retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, &buf, sizeof(struct kovaplus_actual_profile)); return retval ? retval : buf.actual_profile; @@ -186,7 +186,7 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev, buf.size = sizeof(struct kovaplus_actual_profile); buf.actual_profile = new_profile; - return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE, + return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, &buf, sizeof(struct kovaplus_actual_profile)); } @@ -337,7 +337,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, mutex_lock(&kovaplus->kovaplus_lock); retval = kovaplus_set_actual_profile(usb_dev, profile); - kovaplus->actual_profile = profile; + kovaplus_profile_activated(kovaplus, profile); mutex_unlock(&kovaplus->kovaplus_lock); if (retval) return retval; @@ -662,6 +662,9 @@ static int kovaplus_raw_event(struct hid_device *hdev, != USB_INTERFACE_PROTOCOL_MOUSE) return 0; + if (kovaplus == NULL) + return 0; + kovaplus_keep_values_up_to_date(kovaplus, data); if (kovaplus->roccat_claimed) diff --git a/drivers/hid/hid-roccat-kovaplus.h b/drivers/hid/hid-roccat-kovaplus.h index ce40607d21c7..fb2aed44a8e0 100644 --- a/drivers/hid/hid-roccat-kovaplus.h +++ b/drivers/hid/hid-roccat-kovaplus.h @@ -83,15 +83,6 @@ enum kovaplus_commands { KOVAPLUS_COMMAND_A = 0xa, }; -enum kovaplus_usb_commands { - KOVAPLUS_USB_COMMAND_CONTROL = 0x304, - KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305, - KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, - KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, - KOVAPLUS_USB_COMMAND_INFO = 0x309, - KOVAPLUS_USB_COMMAND_A = 0x30a, -}; - enum kovaplus_mouse_report_numbers { KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1, KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2, diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 38280c055a19..8140776bd8c5 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -53,7 +53,7 @@ static int pyra_send_control(struct usb_device *usb_dev, int value, control.value = value; control.request = request; - return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL, + return roccat_common_send(usb_dev, PYRA_COMMAND_CONTROL, &control, sizeof(struct pyra_control)); } @@ -64,7 +64,7 @@ static int pyra_receive_control_status(struct usb_device *usb_dev) do { msleep(10); - retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL, + retval = roccat_common_receive(usb_dev, PYRA_COMMAND_CONTROL, &control, sizeof(struct pyra_control)); /* requested too early, try again */ @@ -89,7 +89,7 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev, PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); if (retval) return retval; - return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, + return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, buf, sizeof(struct pyra_profile_settings)); } @@ -101,20 +101,20 @@ static int pyra_get_profile_buttons(struct usb_device *usb_dev, PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); if (retval) return retval; - return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, + return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, buf, sizeof(struct pyra_profile_buttons)); } static int pyra_get_settings(struct usb_device *usb_dev, struct pyra_settings *buf) { - return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS, + return roccat_common_receive(usb_dev, PYRA_COMMAND_SETTINGS, buf, sizeof(struct pyra_settings)); } static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) { - return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO, + return roccat_common_receive(usb_dev, PYRA_COMMAND_INFO, buf, sizeof(struct pyra_info)); } @@ -131,26 +131,22 @@ static int pyra_send(struct usb_device *usb_dev, uint command, static int pyra_set_profile_settings(struct usb_device *usb_dev, struct pyra_profile_settings const *settings) { - return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings, + return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, settings, sizeof(struct pyra_profile_settings)); } static int pyra_set_profile_buttons(struct usb_device *usb_dev, struct pyra_profile_buttons const *buttons) { - return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons, + return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, buttons, sizeof(struct pyra_profile_buttons)); } static int pyra_set_settings(struct usb_device *usb_dev, struct pyra_settings const *settings) { - int retval; - retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings, + return pyra_send(usb_dev, PYRA_COMMAND_SETTINGS, settings, sizeof(struct pyra_settings)); - if (retval) - return retval; - return pyra_receive_control_status(usb_dev); } static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, @@ -641,6 +637,9 @@ static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, != USB_INTERFACE_PROTOCOL_MOUSE) return 0; + if (pyra == NULL) + return 0; + pyra_keep_values_up_to_date(pyra, data); if (pyra->roccat_claimed) diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h index 14cbbe1621e0..0442d7fa2dcf 100644 --- a/drivers/hid/hid-roccat-pyra.h +++ b/drivers/hid/hid-roccat-pyra.h @@ -83,15 +83,6 @@ enum pyra_commands { PYRA_COMMAND_B = 0xb }; -enum pyra_usb_commands { - PYRA_USB_COMMAND_CONTROL = 0x304, - PYRA_USB_COMMAND_SETTINGS = 0x305, - PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306, - PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307, - PYRA_USB_COMMAND_INFO = 0x309, - PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */ -}; - enum pyra_mouse_report_numbers { PYRA_MOUSE_REPORT_NUMBER_HID = 1, PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2, diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c new file mode 100644 index 000000000000..a594383ce03d --- /dev/null +++ b/drivers/hid/hid-wiimote.c @@ -0,0 +1,489 @@ +/* + * HID driver for Nintendo Wiimote devices + * Copyright (c) 2011 David Herrmann + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/atomic.h> +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include "hid-ids.h" + +#define WIIMOTE_VERSION "0.1" +#define WIIMOTE_NAME "Nintendo Wii Remote" +#define WIIMOTE_BUFSIZE 32 + +struct wiimote_buf { + __u8 data[HID_MAX_BUFFER_SIZE]; + size_t size; +}; + +struct wiimote_state { + spinlock_t lock; + __u8 flags; +}; + +struct wiimote_data { + atomic_t ready; + struct hid_device *hdev; + struct input_dev *input; + + spinlock_t qlock; + __u8 head; + __u8 tail; + struct wiimote_buf outq[WIIMOTE_BUFSIZE]; + struct work_struct worker; + + struct wiimote_state state; +}; + +#define WIIPROTO_FLAG_LED1 0x01 +#define WIIPROTO_FLAG_LED2 0x02 +#define WIIPROTO_FLAG_LED3 0x04 +#define WIIPROTO_FLAG_LED4 0x08 +#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ + WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) + +enum wiiproto_reqs { + WIIPROTO_REQ_LED = 0x11, + WIIPROTO_REQ_DRM_K = 0x30, +}; + +enum wiiproto_keys { + WIIPROTO_KEY_LEFT, + WIIPROTO_KEY_RIGHT, + WIIPROTO_KEY_UP, + WIIPROTO_KEY_DOWN, + WIIPROTO_KEY_PLUS, + WIIPROTO_KEY_MINUS, + WIIPROTO_KEY_ONE, + WIIPROTO_KEY_TWO, + WIIPROTO_KEY_A, + WIIPROTO_KEY_B, + WIIPROTO_KEY_HOME, + WIIPROTO_KEY_COUNT +}; + +static __u16 wiiproto_keymap[] = { + KEY_LEFT, /* WIIPROTO_KEY_LEFT */ + KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ + KEY_UP, /* WIIPROTO_KEY_UP */ + KEY_DOWN, /* WIIPROTO_KEY_DOWN */ + KEY_NEXT, /* WIIPROTO_KEY_PLUS */ + KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ + BTN_1, /* WIIPROTO_KEY_ONE */ + BTN_2, /* WIIPROTO_KEY_TWO */ + BTN_A, /* WIIPROTO_KEY_A */ + BTN_B, /* WIIPROTO_KEY_B */ + BTN_MODE, /* WIIPROTO_KEY_HOME */ +}; + +#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ + dev)) + +static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, + size_t count) +{ + __u8 *buf; + ssize_t ret; + + if (!hdev->hid_output_raw_report) + return -ENODEV; + + buf = kmemdup(buffer, count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT); + + kfree(buf); + return ret; +} + +static void wiimote_worker(struct work_struct *work) +{ + struct wiimote_data *wdata = container_of(work, struct wiimote_data, + worker); + unsigned long flags; + + spin_lock_irqsave(&wdata->qlock, flags); + + while (wdata->head != wdata->tail) { + spin_unlock_irqrestore(&wdata->qlock, flags); + wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data, + wdata->outq[wdata->tail].size); + spin_lock_irqsave(&wdata->qlock, flags); + + wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE; + } + + spin_unlock_irqrestore(&wdata->qlock, flags); +} + +static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer, + size_t count) +{ + unsigned long flags; + __u8 newhead; + + if (count > HID_MAX_BUFFER_SIZE) { + hid_warn(wdata->hdev, "Sending too large output report\n"); + return; + } + + /* + * Copy new request into our output queue and check whether the + * queue is full. If it is full, discard this request. + * If it is empty we need to start a new worker that will + * send out the buffer to the hid device. + * If the queue is not empty, then there must be a worker + * that is currently sending out our buffer and this worker + * will reschedule itself until the queue is empty. + */ + + spin_lock_irqsave(&wdata->qlock, flags); + + memcpy(wdata->outq[wdata->head].data, buffer, count); + wdata->outq[wdata->head].size = count; + newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE; + + if (wdata->head == wdata->tail) { + wdata->head = newhead; + schedule_work(&wdata->worker); + } else if (newhead != wdata->tail) { + wdata->head = newhead; + } else { + hid_warn(wdata->hdev, "Output queue is full"); + } + + spin_unlock_irqrestore(&wdata->qlock, flags); +} + +static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) +{ + __u8 cmd[2]; + + leds &= WIIPROTO_FLAGS_LEDS; + if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds) + return; + wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds; + + cmd[0] = WIIPROTO_REQ_LED; + cmd[1] = 0; + + if (leds & WIIPROTO_FLAG_LED1) + cmd[1] |= 0x10; + if (leds & WIIPROTO_FLAG_LED2) + cmd[1] |= 0x20; + if (leds & WIIPROTO_FLAG_LED3) + cmd[1] |= 0x40; + if (leds & WIIPROTO_FLAG_LED4) + cmd[1] |= 0x80; + + wiimote_queue(wdata, cmd, sizeof(cmd)); +} + +#define wiifs_led_show_set(num) \ +static ssize_t wiifs_led_show_##num(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct wiimote_data *wdata = dev_to_wii(dev); \ + unsigned long flags; \ + int state; \ + \ + if (!atomic_read(&wdata->ready)) \ + return -EBUSY; \ + \ + spin_lock_irqsave(&wdata->state.lock, flags); \ + state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \ + spin_unlock_irqrestore(&wdata->state.lock, flags); \ + \ + return sprintf(buf, "%d\n", state); \ +} \ +static ssize_t wiifs_led_set_##num(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct wiimote_data *wdata = dev_to_wii(dev); \ + int tmp = simple_strtoul(buf, NULL, 10); \ + unsigned long flags; \ + __u8 state; \ + \ + if (!atomic_read(&wdata->ready)) \ + return -EBUSY; \ + \ + spin_lock_irqsave(&wdata->state.lock, flags); \ + \ + state = wdata->state.flags; \ + \ + if (tmp) \ + wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\ + else \ + wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\ + \ + spin_unlock_irqrestore(&wdata->state.lock, flags); \ + \ + return count; \ +} \ +static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \ + wiifs_led_set_##num) + +wiifs_led_show_set(1); +wiifs_led_show_set(2); +wiifs_led_show_set(3); +wiifs_led_show_set(4); + +static int wiimote_input_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + struct wiimote_data *wdata = input_get_drvdata(dev); + + if (!atomic_read(&wdata->ready)) + return -EBUSY; + /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */ + smp_rmb(); + + return 0; +} + +static void handler_keys(struct wiimote_data *wdata, const __u8 *payload) +{ + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT], + !!(payload[0] & 0x01)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT], + !!(payload[0] & 0x02)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN], + !!(payload[0] & 0x04)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP], + !!(payload[0] & 0x08)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS], + !!(payload[0] & 0x10)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO], + !!(payload[1] & 0x01)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE], + !!(payload[1] & 0x02)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B], + !!(payload[1] & 0x04)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A], + !!(payload[1] & 0x08)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS], + !!(payload[1] & 0x10)); + input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME], + !!(payload[1] & 0x80)); + input_sync(wdata->input); +} + +struct wiiproto_handler { + __u8 id; + size_t size; + void (*func)(struct wiimote_data *wdata, const __u8 *payload); +}; + +static struct wiiproto_handler handlers[] = { + { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, + { .id = 0 } +}; + +static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, + u8 *raw_data, int size) +{ + struct wiimote_data *wdata = hid_get_drvdata(hdev); + struct wiiproto_handler *h; + int i; + unsigned long flags; + + if (!atomic_read(&wdata->ready)) + return -EBUSY; + /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */ + smp_rmb(); + + if (size < 1) + return -EINVAL; + + spin_lock_irqsave(&wdata->state.lock, flags); + + for (i = 0; handlers[i].id; ++i) { + h = &handlers[i]; + if (h->id == raw_data[0] && h->size < size) + h->func(wdata, &raw_data[1]); + } + + spin_unlock_irqrestore(&wdata->state.lock, flags); + + return 0; +} + +static struct wiimote_data *wiimote_create(struct hid_device *hdev) +{ + struct wiimote_data *wdata; + int i; + + wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); + if (!wdata) + return NULL; + + wdata->input = input_allocate_device(); + if (!wdata->input) { + kfree(wdata); + return NULL; + } + + wdata->hdev = hdev; + hid_set_drvdata(hdev, wdata); + + input_set_drvdata(wdata->input, wdata); + wdata->input->event = wiimote_input_event; + wdata->input->dev.parent = &wdata->hdev->dev; + wdata->input->id.bustype = wdata->hdev->bus; + wdata->input->id.vendor = wdata->hdev->vendor; + wdata->input->id.product = wdata->hdev->product; + wdata->input->id.version = wdata->hdev->version; + wdata->input->name = WIIMOTE_NAME; + + set_bit(EV_KEY, wdata->input->evbit); + for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) + set_bit(wiiproto_keymap[i], wdata->input->keybit); + + spin_lock_init(&wdata->qlock); + INIT_WORK(&wdata->worker, wiimote_worker); + + spin_lock_init(&wdata->state.lock); + + return wdata; +} + +static void wiimote_destroy(struct wiimote_data *wdata) +{ + kfree(wdata); +} + +static int wiimote_hid_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct wiimote_data *wdata; + int ret; + + wdata = wiimote_create(hdev); + if (!wdata) { + hid_err(hdev, "Can't alloc device\n"); + return -ENOMEM; + } + + ret = device_create_file(&hdev->dev, &dev_attr_led1); + if (ret) + goto err; + ret = device_create_file(&hdev->dev, &dev_attr_led2); + if (ret) + goto err; + ret = device_create_file(&hdev->dev, &dev_attr_led3); + if (ret) + goto err; + ret = device_create_file(&hdev->dev, &dev_attr_led4); + if (ret) + goto err; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "HID parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "HW start failed\n"); + goto err; + } + + ret = input_register_device(wdata->input); + if (ret) { + hid_err(hdev, "Cannot register input device\n"); + goto err_stop; + } + + /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */ + smp_wmb(); + atomic_set(&wdata->ready, 1); + hid_info(hdev, "New device registered\n"); + + /* by default set led1 after device initialization */ + spin_lock_irq(&wdata->state.lock); + wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); + spin_unlock_irq(&wdata->state.lock); + + return 0; + +err_stop: + hid_hw_stop(hdev); +err: + input_free_device(wdata->input); + device_remove_file(&hdev->dev, &dev_attr_led1); + device_remove_file(&hdev->dev, &dev_attr_led2); + device_remove_file(&hdev->dev, &dev_attr_led3); + device_remove_file(&hdev->dev, &dev_attr_led4); + wiimote_destroy(wdata); + return ret; +} + +static void wiimote_hid_remove(struct hid_device *hdev) +{ + struct wiimote_data *wdata = hid_get_drvdata(hdev); + + hid_info(hdev, "Device removed\n"); + + device_remove_file(&hdev->dev, &dev_attr_led1); + device_remove_file(&hdev->dev, &dev_attr_led2); + device_remove_file(&hdev->dev, &dev_attr_led3); + device_remove_file(&hdev->dev, &dev_attr_led4); + + hid_hw_stop(hdev); + input_unregister_device(wdata->input); + + cancel_work_sync(&wdata->worker); + wiimote_destroy(wdata); +} + +static const struct hid_device_id wiimote_hid_devices[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_WIIMOTE) }, + { } +}; +MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); + +static struct hid_driver wiimote_hid_driver = { + .name = "wiimote", + .id_table = wiimote_hid_devices, + .probe = wiimote_hid_probe, + .remove = wiimote_hid_remove, + .raw_event = wiimote_hid_event, +}; + +static int __init wiimote_init(void) +{ + int ret; + + ret = hid_register_driver(&wiimote_hid_driver); + if (ret) + pr_err("Can't register wiimote hid driver\n"); + + return ret; +} + +static void __exit wiimote_exit(void) +{ + hid_unregister_driver(&wiimote_hid_driver); +} + +module_init(wiimote_init); +module_exit(wiimote_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); +MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver"); +MODULE_VERSION(WIIMOTE_VERSION); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0e30b140edca..621959d5cc42 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -74,6 +74,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index ff3c644888b1..7c1188b53c3e 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -248,12 +248,15 @@ static int hiddev_release(struct inode * inode, struct file * file) usbhid_close(list->hiddev->hid); usbhid_put_power(list->hiddev->hid); } else { + mutex_unlock(&list->hiddev->existancelock); kfree(list->hiddev); + kfree(list); + return 0; } } - kfree(list); mutex_unlock(&list->hiddev->existancelock); + kfree(list); return 0; } @@ -923,10 +926,11 @@ void hiddev_disconnect(struct hid_device *hid) usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { + mutex_unlock(&hiddev->existancelock); usbhid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { + mutex_unlock(&hiddev->existancelock); kfree(hiddev); } - mutex_unlock(&hiddev->existancelock); } |