Commit 7426ef52 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'upstream' into for-linus

Conflicts:
	drivers/hid/hid-wacom.c
parents 537b60d1 a8ab5d58
What: /sys/class/hidraw/hidraw*/device/speed
Date: April 2010
Kernel Version: 2.6.35
Contact: linux-bluetooth@vger.kernel.org
Description:
The /sys/class/hidraw/hidraw*/device/speed file controls
reporting speed of wacom bluetooth tablet. Reading from
this file returns 1 if tablet reports in high speed mode
or 0 otherwise. Writing to this file one of these values
switches reporting speed.
......@@ -273,7 +273,7 @@ config HID_SAMSUNG
depends on USB_HID
default !EMBEDDED
---help---
Support for Samsung InfraRed remote control.
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
tristate "Sony" if EMBEDDED
......@@ -332,7 +332,7 @@ config HID_TOPSEED
depends on USB_HID
default !EMBEDDED
---help---
Say Y if you have a TopSeed Cyberlink remote control.
Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control.
config HID_THRUSTMASTER
tristate "ThrustMaster devices support" if EMBEDDED
......@@ -357,6 +357,14 @@ config HID_WACOM
---help---
Support for Wacom Graphire Bluetooth tablet.
config HID_WACOM_POWER_SUPPLY
bool "Wacom Bluetooth devices power supply status support"
depends on HID_WACOM
select POWER_SUPPLY
---help---
Say Y here if you want to enable power supply status monitoring for
Wacom Bluetooth devices.
config HID_ZEROPLUS
tristate "Zeroplus based game controller support" if EMBEDDED
depends on USB_HID
......@@ -372,6 +380,13 @@ config ZEROPLUS_FF
Say Y here if you have a Zeroplus based game controller and want
to have force feedback support for it.
config HID_ZYDACRON
tristate "Zydacron remote control support" if EMBEDDED
depends on USB_HID
default !EMBEDDED
---help---
Support for Zydacron remote control.
endmenu
endif # HID_SUPPORT
......@@ -54,6 +54,7 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
......
/*
* HID driver for 3M PCT multitouch panels
*
* Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
*
*/
......@@ -25,7 +25,7 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
struct mmm_finger {
__s32 x, y;
__s32 x, y, w, h;
__u8 rank;
bool touch, valid;
};
......@@ -82,7 +82,18 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
1, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
field->logical_maximum = 59;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
......@@ -128,9 +139,15 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
/* this finger is just placeholder data, ignore */
} else if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR,
wide ? f->w : f->h);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
wide ? f->h : f->w);
input_mt_sync(input);
/*
* touchscreen emulation: maintain the age rank
......@@ -197,6 +214,14 @@ static int mmm_event(struct hid_device *hid, struct hid_field *field,
case HID_DG_CONFIDENCE:
md->valid = value;
break;
case HID_DG_WIDTH:
if (md->valid)
md->f[md->curid].w = value;
break;
case HID_DG_HEIGHT:
if (md->valid)
md->f[md->curid].h = value;
break;
case HID_DG_CONTACTID:
if (md->valid) {
md->curid = value;
......@@ -255,6 +280,7 @@ static void mmm_remove(struct hid_device *hdev)
static const struct hid_device_id mmm_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ }
};
MODULE_DEVICE_TABLE(hid, mmm_devices);
......@@ -287,5 +313,4 @@ static void __exit mmm_exit(void)
module_init(mmm_init);
module_exit(mmm_exit);
MODULE_LICENSE("GPL");
......@@ -653,10 +653,9 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
if (device->driver->report_fixup)
device->driver->report_fixup(device, start, size);
device->rdesc = kmalloc(size, GFP_KERNEL);
device->rdesc = kmemdup(start, size, GFP_KERNEL);
if (device->rdesc == NULL)
return -ENOMEM;
memcpy(device->rdesc, start, size);
device->rsize = size;
parser = vmalloc(sizeof(struct hid_parser));
......@@ -940,13 +939,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
unsigned count = field->report_count;
unsigned offset = field->report_offset;
unsigned size = field->report_size;
unsigned bitsused = offset + count * size;
unsigned n;
/* make sure the unused bits in the last byte are zeros */
if (count > 0 && size > 0 && (bitsused % 8) != 0)
data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */
implement(data, offset + n * size, size, s32ton(field->value[n], size));
......@@ -966,6 +960,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
if (report->id > 0)
*data++ = report->id;
memset(data, 0, ((report->size - 1) >> 3) + 1);
for (n = 0; n < report->maxfield; n++)
hid_output_field(report->field[n], data);
}
......@@ -1167,6 +1162,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
unsigned int i;
int len;
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
if (hdev->bus != BUS_USB)
connect_mask &= ~HID_CONNECT_HIDDEV;
if (hid_hiddev(hdev))
......@@ -1246,6 +1243,7 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
......@@ -1290,6 +1288,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ 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) },
......@@ -1343,6 +1342,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
......@@ -1359,8 +1359,10 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
{ 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) },
{ }
......@@ -1757,7 +1759,7 @@ int hid_add_device(struct hid_device *hdev)
/* we need to kill them here, otherwise they will stay allocated to
* wait for coming driver */
if (hid_ignore(hdev))
if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev))
return -ENODEV;
/* XXX hack, any other cleaner solution after the driver core
......@@ -1765,11 +1767,12 @@ int hid_add_device(struct hid_device *hdev)
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
hdev->vendor, hdev->product, atomic_inc_return(&id));
hid_debug_register(hdev, dev_name(&hdev->dev));
ret = device_add(&hdev->dev);
if (!ret)
hdev->status |= HID_STAT_ADDED;
hid_debug_register(hdev, dev_name(&hdev->dev));
else
hid_debug_unregister(hdev);
return ret;
}
......
......@@ -20,6 +20,7 @@
#define USB_VENDOR_ID_3M 0x0596
#define USB_DEVICE_ID_3M1968 0x0500
#define USB_DEVICE_ID_3M2256 0x0502
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
......@@ -123,6 +124,9 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_VENDOR_ID_CH 0x068e
#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2
#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4
......@@ -171,6 +175,9 @@
#define USB_VENDOR_ID_DRAGONRISE 0x0079
#define USB_VENDOR_ID_EGALAX 0x0EEF
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2700 0x0020
......@@ -409,6 +416,7 @@
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
......@@ -457,6 +465,7 @@
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0xbd
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
......@@ -475,6 +484,9 @@
#define USB_VENDOR_ID_ZEROPLUS 0x0c12
#define USB_VENDOR_ID_ZYDACRON 0x13EC
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
......
......@@ -126,6 +126,9 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
/* The following two entries are Playlist 1 and 2 on the MX3200 */
case 0x100f: lg_map_key_clear(KEY_FN_1); break;
case 0x1010: lg_map_key_clear(KEY_FN_2); break;
case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
......@@ -137,6 +140,7 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
case 0x1019: lg_map_key_clear(KEY_PROG1); break;
case 0x101a: lg_map_key_clear(KEY_PROG2); break;
case 0x101b: lg_map_key_clear(KEY_PROG3); break;
case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
......@@ -147,6 +151,11 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
case 0x102a: lg_map_key_clear(KEY_BACK); break;
case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
case 0x102d: lg_map_key_clear(KEY_WWW); break;
/* The following two are 'Start/answer call' and 'End/reject call'
on the MX3200 */
case 0x1031: lg_map_key_clear(KEY_OK); break;
case 0x1032: lg_map_key_clear(KEY_CANCEL); break;
case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
......
......@@ -7,6 +7,18 @@
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2007 Paul Walmsley
* Copyright (c) 2008 Jiri Slaby
* Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
*
*
* This driver supports several HID devices:
*
* [0419:0001] Samsung IrDA remote controller (reports as Cypress USB Mouse).
* various hid report fixups for different variants.
*
* [0419:0600] Creative Desktop Wireless 6000 keyboard/mouse combo
* several key mappings used from the consumer usage page
* deviate from the USB HUT 1.12 standard.
*
*/
/*
......@@ -17,14 +29,13 @@
*/
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
/*
* Samsung IrDA remote controller (reports as Cypress USB Mouse).
*
* There are several variants for 0419:0001:
*
* 1. 184 byte report descriptor
......@@ -43,21 +54,21 @@
* 4. 171 byte report descriptor
* Report #3 has an array field with logical range 0..1 instead of 1..3.
*/
static inline void samsung_dev_trace(struct hid_device *hdev,
static inline void samsung_irda_dev_trace(struct hid_device *hdev,
unsigned int rsize)
{
dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
"descriptor\n", rsize);
}
static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int rsize)
{
if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
rdesc[182] == 0x40) {
samsung_dev_trace(hdev, 184);
samsung_irda_dev_trace(hdev, 184);
rdesc[176] = 0xff;
rdesc[178] = 0x08;
rdesc[180] = 0x06;
......@@ -65,24 +76,80 @@ static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
} else
if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
rdesc[194] == 0x25 && rdesc[195] == 0x12) {
samsung_dev_trace(hdev, 203);
samsung_irda_dev_trace(hdev, 203);
rdesc[193] = 0x1;
rdesc[195] = 0xf;
} else
if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
rdesc[126] == 0x25 && rdesc[127] == 0x11) {
samsung_dev_trace(hdev, 135);
samsung_irda_dev_trace(hdev, 135);
rdesc[125] = 0x1;
rdesc[127] = 0xe;
} else
if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
rdesc[162] == 0x25 && rdesc[163] == 0x01) {
samsung_dev_trace(hdev, 171);
samsung_irda_dev_trace(hdev, 171);
rdesc[161] = 0x1;
rdesc[163] = 0x3;
}
}
#define samsung_kbd_mouse_map_key_clear(c) \
hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
if (1 != ifnum || HID_UP_CONSUMER != (usage->hid & HID_USAGE_PAGE))
return 0;
dbg_hid("samsung wireless keyboard/mouse input mapping event [0x%x]\n",
usage->hid & HID_USAGE);
switch (usage->hid & HID_USAGE) {
/* report 2 */
case 0x183: samsung_kbd_mouse_map_key_clear(KEY_MEDIA); break;
case 0x195: samsung_kbd_mouse_map_key_clear(KEY_EMAIL); break;
case 0x196: samsung_kbd_mouse_map_key_clear(KEY_CALC); break;
case 0x197: samsung_kbd_mouse_map_key_clear(KEY_COMPUTER); break;
case 0x22b: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break;
case 0x22c: samsung_kbd_mouse_map_key_clear(KEY_WWW); break;
case 0x22d: samsung_kbd_mouse_map_key_clear(KEY_BACK); break;
case 0x22e: samsung_kbd_mouse_map_key_clear(KEY_FORWARD); break;
case 0x22f: samsung_kbd_mouse_map_key_clear(KEY_FAVORITES); break;
case 0x230: samsung_kbd_mouse_map_key_clear(KEY_REFRESH); break;
case 0x231: samsung_kbd_mouse_map_key_clear(KEY_STOP); break;
default:
return 0;
}
return 1;
}
static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int rsize)
{
if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product)
samsung_irda_report_fixup(hdev, rdesc, rsize);
}
static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
int ret = 0;
if (USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE == hdev->product)
ret = samsung_kbd_mouse_input_mapping(hdev,
hi, field, usage, bit, max);
return ret;
}
static int samsung_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
......@@ -95,10 +162,12 @@ static int samsung_probe(struct hid_device *hdev,
goto err_free;
}
if (hdev->rsize == 184) {
/* disable hidinput, force hiddev */
cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
HID_CONNECT_HIDDEV_FORCE;
if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) {
if (hdev->rsize == 184) {
/* disable hidinput, force hiddev */
cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
HID_CONNECT_HIDDEV_FORCE;
}
}
ret = hid_hw_start(hdev, cmask);
......@@ -114,6 +183,7 @@ static int samsung_probe(struct hid_device *hdev,
static const struct hid_device_id samsung_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ }
};
MODULE_DEVICE_TABLE(hid, samsung_devices);
......@@ -122,6 +192,7 @@ static struct hid_driver samsung_driver = {
.name = "samsung",
.id_table = samsung_devices,
.report_fixup = samsung_report_fixup,
.input_mapping = samsung_input_mapping,
.probe = samsung_probe,
};
......
......@@ -3,6 +3,9 @@
*
* Copyright (c) 2008 Lev Babiev
* based on hid-cherry driver
*
* Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by
* Wayne Thomas 2010.
*/
/*
......@@ -24,23 +27,29 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
return 0;
switch (usage->hid & HID_USAGE) {
case 0x00d: ts_map_key_clear(KEY_HOME); break;
case 0x024: ts_map_key_clear(KEY_MENU); break;
case 0x025: ts_map_key_clear(KEY_TV); break;
case 0x048: ts_map_key_clear(KEY_RED); break;
case 0x047: ts_map_key_clear(KEY_GREEN); break;
case 0x049: ts_map_key_clear(KEY_YELLOW); break;
case 0x04a: ts_map_key_clear(KEY_BLUE); break;
case 0x04b: ts_map_key_clear(KEY_ANGLE); break;
case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break;
case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break;
case 0x031: ts_map_key_clear(KEY_AUDIO); break;
case 0x032: ts_map_key_clear(KEY_TEXT); break;
case 0x033: ts_map_key_clear(KEY_CHANNEL); break;
case 0x00d: ts_map_key_clear(KEY_MEDIA); break;
case 0x024: ts_map_key_clear(KEY_MENU); break;
case 0x025: ts_map_key_clear(KEY_TV); break;
case 0x031: ts_map_key_clear(KEY_AUDIO); break;
case 0x032: ts_map_key_clear(KEY_TEXT); break;
case 0x033: ts_map_key_clear(KEY_CHANNEL); break;
case 0x047: ts_map_key_clear(KEY_MP3); break;
case 0x048: ts_map_key_clear(KEY_TV2); break;
case 0x049: ts_map_key_clear(KEY_CAMERA); break;
case 0x04a: ts_map_key_clear(KEY_VIDEO); break;
case 0x04b: ts_map_key_clear(KEY_ANGLE); break;
case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break;
case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break;
case 0x050: ts_map_key_clear(KEY_RADIO); break;
case 0x05a: ts_map_key_clear(KEY_TEXT); break;
case 0x05b: ts_map_key_clear(KEY_RED); break;
case 0x05c: ts_map_key_clear(KEY_GREEN); break;
case 0x05d: ts_map_key_clear(KEY_YELLOW); break;
case 0x05e: ts_map_key_clear(KEY_BLUE); break;
default:
return 0;
}
......@@ -50,6 +59,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ }
};
MODULE_DEVICE_TABLE(hid, ts_devices);
......
......@@ -22,14 +22,159 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
#include <linux/power_supply.h>
#endif
#include "hid-ids.h"
struct wacom_data {
__u16 tool;
unsigned char butstate;
unsigned char high_speed;
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
int battery_capacity;
struct power_supply battery;
struct power_supply ac;
#endif
};
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
/*percent of battery capacity, 0 means AC online*/
static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY
};
static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE
};
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy,
struct wacom_data, battery);
int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CAPACITY:
/* show 100% battery capacity when charging */
if (power_state == 0)
val->intval = 100;
else
val->intval = power_state;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int wacom_ac_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
if (power_state == 0)
val->intval = 1;
else
val->intval = 0;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#endif
static void wacom_poke(struct hid_device *hdev, u8 speed)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
int limit, ret;
char rep_data[2];
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
if (speed == 0)
rep_data[0] = 0x05;
else
rep_data[0] = 0x06;
rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
wdata->high_speed = speed;
return;
}
}
/*
* Note that if the raw queries fail, it's not a hard failure and it
* is safe to continue
*/
dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n",
rep_data[0], ret);
return;
}
static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
{
struct wacom_data *wdata = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
}
static ssize_t wacom_store_speed(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
int new_speed;
if (sscanf(buf, "%1d", &new_speed ) != 1)
return -EINVAL;
if (new_speed == 0 || new_speed == 1) {
wacom_poke(hdev, new_speed);
return strnlen(buf, PAGE_SIZE);
} else
return -EINVAL;
}
static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO,
wacom_show_speed, wacom_store_speed);
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size)
{
......@@ -148,6 +293,12 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
input_sync(input);
}
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
/* Store current battery capacity */
rw = (data[7] >> 2 & 0x07);
if (rw != wdata->battery_capacity)
wdata->battery_capacity = rw;
#endif
return 1;
}
......@@ -157,9 +308,7 @@ static int wacom_probe(struct hid_device *hdev,
struct hid_input *hidinput;
struct input_dev *input;
struct wacom_data *wdata;
char rep_data[2];
int ret;
int limit;
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (wdata == NULL) {
......@@ -182,31 +331,53 @@ static int wacom_probe(struct hid_device *hdev,
goto err_free;
}
/*
* Note that if the raw queries fail, it's not a hard failure and it
* is safe to continue
*/
ret = device_create_file(&hdev->dev, &dev_attr_speed);
if (ret)
dev_warn(&hdev->dev,
"can't create sysfs speed attribute err: %d\n", ret);
/* Set Wacom mode2 */
rep_data[0] = 0x03; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret < 0)
dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret);
/* Set Wacom mode 2 with high reporting speed */
wacom_poke(hdev, 1);
/* 0x06 - high reporting speed, 0x05 - low speed */
rep_data[0] = 0x06; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret < 0)
dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret);
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
wdata->battery.properties = wacom_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
wdata->battery.get_property = wacom_battery_get_property;
wdata->battery.name = "wacom_battery";
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
wdata->battery.use_for_apm = 0;
ret = power_supply_register(&hdev->dev, &wdata->battery);
if (ret) {
dev_warn(&hdev->dev,
"can't create sysfs battery attribute, err: %d\n", ret);
/*
* battery attribute is not critical for the tablet, but if it
* failed then there is no need to create ac attribute
*/
goto move_on;
}
wdata->ac.properties = wacom_ac_props;
wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
wdata->ac.get_property = wacom_ac_get_property;
wdata->ac.name = "wacom_ac";
wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
wdata->ac.use_for_apm = 0;
ret = power_supply_register(&hdev->dev, &wdata->ac);
if (ret) {
dev_warn(&hdev->dev,
"can't create ac battery attribute, err: %d\n", ret);
/*
* ac attribute is not critical for the tablet, but if it
* failed then we don't want to battery attribute to exist
*/
power_supply_unregister(&wdata->battery);
}
move_on:
#endif
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
......@@ -251,13 +422,21 @@ static int wacom_probe(struct hid_device *hdev,
static void wacom_remove(struct hid_device *hdev)
{
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
struct wacom_data *wdata = hid_get_drvdata(hdev);
#endif
hid_hw_stop(hdev);
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
power_supply_unregister(&wdata->battery);
power_supply_unregister(&wdata->ac);
#endif
kfree(hid_get_drvdata(hdev));
}
static const struct hid_device_id wacom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ }
};
MODULE_DEVICE_TABLE(hid, wacom_devices);
......
/*
* HID driver for zydacron remote control
*
* Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
*/
/*
* 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/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
struct zc_device {
struct input_dev *input_ep81;
unsigned short last_key[4];
};
/*
* Zydacron remote control has an invalid HID report descriptor,
* that needs fixing before we can parse it.
*/
static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int rsize)
{
if (rsize >= 253 &&
rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
dev_info(&hdev->dev,
"fixing up zydacron remote control report "
"descriptor\n");
rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
}
}
#define zc_map_key_clear(c) \
hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
int i;
struct zc_device *zc = hid_get_drvdata(hdev);
zc->input_ep81 = hi->input;
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
return 0;
dbg_hid("zynacron input mapping event [0x%x]\n",
usage->hid & HID_USAGE);
switch (usage->hid & HID_USAGE) {
/* report 2 */
case 0x10:
zc_map_key_clear(KEY_MODE);
break;
case 0x30:
zc_map_key_clear(KEY_SCREEN);
break;
case 0x70:
zc_map_key_clear(KEY_INFO);
break;
/* report 3 */
case 0x04:
zc_map_key_clear(KEY_RADIO);
break;
/* report 4 */
case 0x0d:
zc_map_key_clear(KEY_PVR);
break;
case 0x25:
zc_map_key_clear(KEY_TV);
break;
case 0x47:
zc_map_key_clear(KEY_AUDIO);
break;
case 0x49:
zc_map_key_clear(KEY_AUX);
break;
case 0x4a:
zc_map_key_clear(KEY_VIDEO);
break;
case 0x48:
zc_map_key_clear(KEY_DVD);
break;
case 0x24:
zc_map_key_clear(KEY_MENU);
break;
case 0x32:
zc_map_key_clear(KEY_TEXT);
break;
default:
return 0;
}
for (i = 0; i < 4; i++)
zc->last_key[i] = 0;
return 1;
}
static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct zc_device *zc = hid_get_drvdata(hdev);
int ret = 0;
unsigned key;
unsigned short index;
if (report->id == data[0]) {
/* break keys */
for (index = 0; index < 4; index++) {
key = zc->last_key[index];
if (key) {
input_event(zc->input_ep81, EV_KEY, key, 0);
zc->last_key[index] = 0;
}
}
key = 0;
switch (report->id) {
case 0x02:
case 0x03:
switch (data[1]) {
case 0x10:
key = KEY_MODE;
index = 0;
break;
case 0x30:
key = KEY_SCREEN;
index = 1;
break;
case 0x70:
key = KEY_INFO;
index = 2;
break;
case 0x04:
key = KEY_RADIO;
index = 3;
break;
}
if (key) {
input_event(zc->input_ep81, EV_KEY, key, 1);
zc->last_key[index] = key;
}
ret = 1;
break;
}
}
return ret;
}
static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct zc_device *zc;
zc = kzalloc(sizeof(*zc), GFP_KERNEL);
if (zc == NULL) {
dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, zc);
ret = hid_parse(hdev);
if (ret) {
dev_err(&hdev->dev, "zydacron: parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
dev_err(&hdev->dev, "zydacron: hw start failed\n");
goto err_free;
}
return 0;
err_free:
kfree(zc);
return ret;
}
static void zc_remove(struct hid_device *hdev)
{
struct zc_device *zc = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
if (NULL != zc)
kfree(zc);
}
static const struct hid_device_id zc_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
{ }
};
MODULE_DEVICE_TABLE(hid, zc_devices);
static struct hid_driver zc_driver = {
.name = "zydacron",
.id_table = zc_devices,
.report_fixup = zc_report_fixup,
.input_mapping = zc_input_mapping,
.raw_event = zc_raw_event,
.probe = zc_probe,
.remove = zc_remove,
};
static int __init zc_init(void)
{
return hid_register_driver(&zc_driver);
}
static void __exit zc_exit(void)
{
hid_unregister_driver(&zc_driver);
}
module_init(zc_init);
module_exit(zc_exit);
MODULE_LICENSE("GPL");
......@@ -311,7 +311,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
-EFAULT : len;
break;
}
}
}
ret = -ENOTTY;
}
......
......@@ -807,16 +807,36 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
struct usb_host_interface *interface = intf->cur_altsetting;
int ret;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
((report_type + 1) << 8) | *buf,
interface->desc.bInterfaceNumber, buf + 1, count - 1,
USB_CTRL_SET_TIMEOUT);
/* count also the report id */
if (ret > 0)
ret++;
if (usbhid->urbout) {
int actual_length;
int skipped_report_id = 0;
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
count--;
skipped_report_id = 1;
}
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
buf, count, &actual_length,
USB_CTRL_SET_TIMEOUT);
/* return the number of bytes transferred */
if (ret == 0) {
ret = actual_length;
/* count also the report id */
if (skipped_report_id)
ret++;
}
} else {
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
((report_type + 1) << 8) | *buf,
interface->desc.bInterfaceNumber, buf + 1, count - 1,
USB_CTRL_SET_TIMEOUT);
/* count also the report id */
if (ret > 0)
ret++;
}
return ret;
}
......@@ -1019,12 +1039,15 @@ static int usbhid_start(struct hid_device *hid)
/* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs, it must be safe for any device
* that supports the keyboard boot protocol.
* In addition, enable remote wakeup by default for all keyboard
* devices supporting the boot protocol.
*/
if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
interface->desc.bInterfaceProtocol ==
USB_INTERFACE_PROTOCOL_KEYBOARD)
USB_INTERFACE_PROTOCOL_KEYBOARD) {
usbhid_set_leds(hid);
device_set_wakeup_enable(&dev->dev, 1);
}
return 0;
fail:
......@@ -1133,6 +1156,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
hid->product = le16_to_cpu(dev->descriptor.idProduct);
hid->name[0] = 0;
hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
if (intf->cur_altsetting->desc.bInterfaceProtocol ==
USB_INTERFACE_PROTOCOL_MOUSE)
hid->type = HID_TYPE_USBMOUSE;
......
......@@ -33,6 +33,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_EGALAX, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
......
......@@ -313,6 +313,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
goto fail2;
usb_set_intfdata(iface, kbd);
device_set_wakeup_enable(&dev->dev, 1);
return 0;
fail2:
......
......@@ -308,11 +308,13 @@ struct hid_item {
#define HID_QUIRK_NOTOUCH 0x00000002
#define HID_QUIRK_IGNORE 0x00000004
#define HID_QUIRK_NOGET 0x00000008
#define HID_QUIRK_HIDDEV_FORCE 0x00000010
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
#define HID_QUIRK_NO_IGNORE 0x40000000
/*
* This is the global environment of the parser. This information is
......
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