Merge branches 'for-3.12/devm', 'for-3.12/i2c-hid', 'for-3.12/i2c-hid-dt', 'for-3.12/logitech', 'for-3.12/multitouch-win8', 'for-3.12/trasnport-driver-cleanup', 'for-3.12/uhid', 'for-3.12/upstream' and 'for-3.12/wiimote' into for-linus

This commit is contained in:
54 changed files with 1326 additions and 459 deletions

View file

@ -743,6 +743,14 @@ config HID_WIIMOTE
To compile this driver as a module, choose M here: the
module will be called hid-wiimote.
config HID_XINMO
tristate "Xin-Mo non-fully compliant devices"
depends on HID
---help---
Support for Xin-Mo devices that are not fully compliant with the HID
standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here
if you have a Xin-Mo Dual Arcade controller.
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
depends on HID

View file

@ -110,6 +110,7 @@ obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_WACOM) += hid-wacom.o

View file

@ -90,11 +90,10 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct a4tech_sc *a4;
int ret;
a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);
if (a4 == NULL) {
hid_err(hdev, "can't alloc device descriptor\n");
ret = -ENOMEM;
goto err_free;
return -ENOMEM;
}
a4->quirks = id->driver_data;
@ -104,27 +103,16 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
return ret;
}
return 0;
err_free:
kfree(a4);
return ret;
}
static void a4_remove(struct hid_device *hdev)
{
struct a4tech_sc *a4 = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
kfree(a4);
}
static const struct hid_device_id a4_devices[] = {
@ -144,7 +132,6 @@ static struct hid_driver a4_driver = {
.input_mapped = a4_input_mapped,
.event = a4_event,
.probe = a4_probe,
.remove = a4_remove,
};
module_hid_driver(a4_driver);

View file

@ -349,7 +349,7 @@ static int apple_probe(struct hid_device *hdev,
unsigned int connect_mask = HID_CONNECT_DEFAULT;
int ret;
asc = kzalloc(sizeof(*asc), GFP_KERNEL);
asc = devm_kzalloc(&hdev->dev, sizeof(*asc), GFP_KERNEL);
if (asc == NULL) {
hid_err(hdev, "can't alloc apple descriptor\n");
return -ENOMEM;
@ -362,7 +362,7 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
return ret;
}
if (quirks & APPLE_HIDDEV)
@ -373,19 +373,10 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
return ret;
}
return 0;
err_free:
kfree(asc);
return ret;
}
static void apple_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
}
static const struct hid_device_id apple_devices[] = {
@ -551,7 +542,6 @@ static struct hid_driver apple_driver = {
.id_table = apple_devices,
.report_fixup = apple_report_fixup,
.probe = apple_probe,
.remove = apple_remove,
.event = apple_event,
.input_mapping = apple_input_mapping,
.input_mapped = apple_input_mapped,

View file

@ -63,6 +63,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
struct hid_report_enum *report_enum = device->report_enum + type;
struct hid_report *report;
if (id >= HID_MAX_IDS)
return NULL;
if (report_enum->report_id_hash[id])
return report_enum->report_id_hash[id];
@ -404,8 +406,10 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
case HID_GLOBAL_ITEM_TAG_REPORT_ID:
parser->global.report_id = item_udata(item);
if (parser->global.report_id == 0) {
hid_err(parser->device, "report_id 0 is invalid\n");
if (parser->global.report_id == 0 ||
parser->global.report_id >= HID_MAX_IDS) {
hid_err(parser->device, "report_id %u is invalid\n",
parser->global.report_id);
return -1;
}
return 0;
@ -450,7 +454,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
}
parser->local.delimiter_depth--;
}
return 1;
return 0;
case HID_LOCAL_ITEM_TAG_USAGE:
@ -575,7 +579,7 @@ static void hid_close_report(struct hid_device *device)
for (i = 0; i < HID_REPORT_TYPES; i++) {
struct hid_report_enum *report_enum = device->report_enum + i;
for (j = 0; j < 256; j++) {
for (j = 0; j < HID_MAX_IDS; j++) {
struct hid_report *report = report_enum->report_id_hash[j];
if (report)
hid_free_report(report);
@ -677,12 +681,61 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
return NULL;
}
static void hid_scan_usage(struct hid_device *hid, u32 usage)
static void hid_scan_input_usage(struct hid_parser *parser, u32 usage)
{
struct hid_device *hid = parser->device;
if (usage == HID_DG_CONTACTID)
hid->group = HID_GROUP_MULTITOUCH;
}
static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
{
if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
parser->global.report_size == 8)
parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
}
static void hid_scan_collection(struct hid_parser *parser, unsigned type)
{
struct hid_device *hid = parser->device;
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
}
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
{
__u32 data;
int i;
data = item_udata(item);
switch (item->tag) {
case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
hid_scan_collection(parser, data & 0xff);
break;
case HID_MAIN_ITEM_TAG_END_COLLECTION:
break;
case HID_MAIN_ITEM_TAG_INPUT:
for (i = 0; i < parser->local.usage_index; i++)
hid_scan_input_usage(parser, parser->local.usage[i]);
break;
case HID_MAIN_ITEM_TAG_OUTPUT:
break;
case HID_MAIN_ITEM_TAG_FEATURE:
for (i = 0; i < parser->local.usage_index; i++)
hid_scan_feature_usage(parser, parser->local.usage[i]);
break;
}
/* Reset the local parser environment */
memset(&parser->local, 0, sizeof(parser->local));
return 0;
}
/*
* Scan a report descriptor before the device is added to the bus.
* Sets device groups and other properties that determine what driver
@ -690,48 +743,41 @@ static void hid_scan_usage(struct hid_device *hid, u32 usage)
*/
static int hid_scan_report(struct hid_device *hid)
{
unsigned int page = 0, delim = 0;
struct hid_parser *parser;
struct hid_item item;
__u8 *start = hid->dev_rdesc;
__u8 *end = start + hid->dev_rsize;
unsigned int u, u_min = 0, u_max = 0;
struct hid_item item;
static int (*dispatch_type[])(struct hid_parser *parser,
struct hid_item *item) = {
hid_scan_main,
hid_parser_global,
hid_parser_local,
hid_parser_reserved
};
parser = vzalloc(sizeof(struct hid_parser));
if (!parser)
return -ENOMEM;
parser->device = hid;
hid->group = HID_GROUP_GENERIC;
while ((start = fetch_item(start, end, &item)) != NULL) {
if (item.format != HID_ITEM_FORMAT_SHORT)
return -EINVAL;
if (item.type == HID_ITEM_TYPE_GLOBAL) {
if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
page = item_udata(&item) << 16;
} else if (item.type == HID_ITEM_TYPE_LOCAL) {
if (delim > 1)
break;
u = item_udata(&item);
if (item.size <= 2)
u += page;
switch (item.tag) {
case HID_LOCAL_ITEM_TAG_DELIMITER:
delim += !!u;
break;
case HID_LOCAL_ITEM_TAG_USAGE:
hid_scan_usage(hid, u);
break;
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
u_min = u;
break;
case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
u_max = u;
for (u = u_min; u <= u_max; u++)
hid_scan_usage(hid, u);
break;
}
} else if (page == HID_UP_SENSOR &&
item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
}
/*
* The parsing is simpler than the one in hid_open_report() as we should
* be robust against hid errors. Those errors will be raised by
* hid_open_report() anyway.
*/
while ((start = fetch_item(start, end, &item)) != NULL)
dispatch_type[item.type](parser, &item);
/*
* Handle special flags set during scanning.
*/
if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) &&
(hid->group == HID_GROUP_MULTITOUCH))
hid->group = HID_GROUP_MULTITOUCH_WIN_8;
vfree(parser);
return 0;
}
@ -1128,7 +1174,8 @@ static void hid_output_field(const struct hid_device *hid,
}
/*
* Create a report.
* Create a report. 'data' has to be allocated using
* hid_alloc_report_buf() so that it has proper size.
*/
void hid_output_report(struct hid_report *report, __u8 *data)
@ -1144,6 +1191,22 @@ void hid_output_report(struct hid_report *report, __u8 *data)
}
EXPORT_SYMBOL_GPL(hid_output_report);
/*
* Allocator for buffer that is going to be passed to hid_output_report()
*/
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
{
/*
* 7 extra bytes are necessary to achieve proper functionality
* of implement() working on 8 byte chunks
*/
int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
return kmalloc(len, flags);
}
EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
/*
* Set a field value. The report this field belongs to has to be
* created and transferred to the device, to set this value in the
@ -1152,7 +1215,12 @@ EXPORT_SYMBOL_GPL(hid_output_report);
int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
{
unsigned size = field->report_size;
unsigned size;
if (!field)
return -1;
size = field->report_size;
hid_dump_input(field->report->device, field->usage + offset, value);
@ -1597,6 +1665,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
@ -1679,6 +1748,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
@ -1736,6 +1806,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
{ 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) },

View file

@ -98,7 +98,7 @@ static void holtekff_send(struct holtekff_device *holtekff,
holtekff->field->value[i] = data[i];
}
dbg_hid("sending %*ph\n", 7, data);
dbg_hid("sending %7ph\n", data);
hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
}

View file

@ -135,9 +135,9 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
@ -482,6 +482,7 @@
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
#define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138
#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR 0x4018
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
@ -658,6 +659,7 @@
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16 0x0012
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17 0x0013
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18 0x0014
#define USB_DEVICE_ID_NTRIG_DUOSENSE 0x1500
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
@ -716,6 +718,7 @@
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
#define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe
#define USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL 0x2db4
#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
@ -887,6 +890,9 @@
#define USB_VENDOR_ID_XAT 0x2505
#define USB_DEVICE_ID_XAT_CSR 0x0220
#define USB_VENDOR_ID_XIN_MO 0x16c0
#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1
#define USB_VENDOR_ID_XIROKU 0x1477
#define USB_DEVICE_ID_XIROKU_SPX 0x1006
#define USB_DEVICE_ID_XIROKU_MPX 0x1007

View file

@ -340,7 +340,7 @@ static int hidinput_get_battery_property(struct power_supply *psy,
{
struct hid_device *dev = container_of(psy, struct hid_device, battery);
int ret = 0;
__u8 buf[2] = {};
__u8 *buf;
switch (prop) {
case POWER_SUPPLY_PROP_PRESENT:
@ -349,12 +349,19 @@ static int hidinput_get_battery_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_CAPACITY:
buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
break;
}
ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
buf, sizeof(buf),
buf, 2,
dev->battery_report_type);
if (ret != 2) {
ret = -ENODATA;
kfree(buf);
break;
}
ret = 0;
@ -364,6 +371,7 @@ static int hidinput_get_battery_property(struct power_supply *psy,
buf[1] <= dev->battery_max)
val->intval = (100 * (buf[1] - dev->battery_min)) /
(dev->battery_max - dev->battery_min);
kfree(buf);
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
@ -1137,6 +1145,74 @@ unsigned int hidinput_count_leds(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hidinput_count_leds);
static void hidinput_led_worker(struct work_struct *work)
{
struct hid_device *hid = container_of(work, struct hid_device,
led_work);
struct hid_field *field;
struct hid_report *report;
int len;
__u8 *buf;
field = hidinput_get_led_field(hid);
if (!field)
return;
/*
* field->report is accessed unlocked regarding HID core. So there might
* be another incoming SET-LED request from user-space, which changes
* the LED state while we assemble our outgoing buffer. However, this
* doesn't matter as hid_output_report() correctly converts it into a
* boolean value no matter what information is currently set on the LED
* field (even garbage). So the remote device will always get a valid
* request.
* And in case we send a wrong value, a next led worker is spawned
* for every SET-LED request so the following worker will send the
* correct value, guaranteed!
*/
report = field->report;
/* use custom SET_REPORT request if possible (asynchronous) */
if (hid->ll_driver->request)
return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT);
/* fall back to generic raw-output-report */
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return;
hid_output_report(report, buf);
/* synchronous output report */
hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
kfree(buf);
}
static int hidinput_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_field *field;
int offset;
if (type == EV_FF)
return input_ff_event(dev, type, code, value);
if (type != EV_LED)
return -1;
if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}
hid_set_field(field, offset, value);
schedule_work(&hid->led_work);
return 0;
}
static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
@ -1183,7 +1259,10 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
}
input_set_drvdata(input_dev, hid);
input_dev->event = hid->ll_driver->hidinput_input_event;
if (hid->ll_driver->hidinput_input_event)
input_dev->event = hid->ll_driver->hidinput_input_event;
else if (hid->ll_driver->request || hid->hid_output_raw_report)
input_dev->event = hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
@ -1278,6 +1357,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
int i, j, k;
INIT_LIST_HEAD(&hid->inputs);
INIT_WORK(&hid->led_work, hidinput_led_worker);
if (!force) {
for (i = 0; i < hid->maxcollection; i++) {
@ -1379,6 +1459,12 @@ void hidinput_disconnect(struct hid_device *hid)
input_unregister_device(hidinput->input);
kfree(hidinput);
}
/* led_work is spawned by input_dev callbacks, but doesn't access the
* parent input_dev at all. Once all input devices are removed, we
* know that led_work will never get restarted, so we can cancel it
* synchronously and are safe. */
cancel_work_sync(&hid->led_work);
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);

View file

@ -268,6 +268,26 @@ static __u8 easypen_m610x_rdesc_fixed[] = {
0xC0 /* End Collection */
};
static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize, int offset, const char *device_name) {
/*
* the fixup that need to be done:
* - change Usage Maximum in the Comsumer Control
* (report ID 3) to a reasonable value
*/
if (*rsize >= offset + 31 &&
/* Usage Page (Consumer Devices) */
rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
/* Usage (Consumer Control) */
rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
/* Usage Maximum > 12287 */
rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
hid_info(hdev, "fixing up %s report descriptor\n", device_name);
rdesc[offset + 12] = 0x2f;
}
return rdesc;
}
static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
@ -315,23 +335,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
}
break;
case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
/*
* the fixup that need to be done:
* - change Usage Maximum in the Comsumer Control
* (report ID 3) to a reasonable value
*/
if (*rsize >= 135 &&
/* Usage Page (Consumer Devices) */
rdesc[104] == 0x05 && rdesc[105] == 0x0c &&
/* Usage (Consumer Control) */
rdesc[106] == 0x09 && rdesc[107] == 0x01 &&
/* Usage Maximum > 12287 */
rdesc[114] == 0x2a && rdesc[116] > 0x2f) {
hid_info(hdev,
"fixing up Genius Gila Gaming Mouse "
"report descriptor\n");
rdesc[116] = 0x2f;
}
rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
"Genius Gila Gaming Mouse");
break;
case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
"Genius Gx Imperator Keyboard");
break;
}
return rdesc;
@ -428,6 +437,8 @@ static const struct hid_device_id kye_devices[] = {
USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
{ }
};
MODULE_DEVICE_TABLE(hid, kye_devices);

View file

@ -619,7 +619,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
struct hid_field *field;
struct hid_report *report;
unsigned char data[8];
unsigned char *data;
int offset;
dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
@ -635,6 +635,13 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
return -1;
}
hid_set_field(field, offset, value);
data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
if (!data) {
dev_warn(&dev->dev, "failed to allocate report buf memory\n");
return -1;
}
hid_output_report(field->report, &data[0]);
output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
@ -645,8 +652,9 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
return 0;
kfree(data);
return 0;
}
static int logi_dj_ll_start(struct hid_device *hid)
@ -801,10 +809,10 @@ static int logi_dj_probe(struct hid_device *hdev,
}
/* This is enabling the polling urb on the IN endpoint */
retval = hdev->ll_driver->open(hdev);
retval = hid_hw_open(hdev);
if (retval < 0) {
dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned "
"error:%d\n", __func__, retval);
dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
__func__, retval);
goto llopen_failed;
}
@ -821,7 +829,7 @@ static int logi_dj_probe(struct hid_device *hdev,
return retval;
logi_dj_recv_query_paired_devices_failed:
hdev->ll_driver->close(hdev);
hid_hw_close(hdev);
llopen_failed:
switch_to_dj_mode_fail:
@ -863,7 +871,7 @@ static void logi_dj_remove(struct hid_device *hdev)
cancel_work_sync(&djrcv_dev->work);
hdev->ll_driver->close(hdev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
/* I suppose that at this point the only context that can access

View file

@ -36,7 +36,7 @@ MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
static unsigned int scroll_speed = 32;
static int param_set_scroll_speed(const char *val, struct kernel_param *kp) {
unsigned long speed;
if (!val || strict_strtoul(val, 0, &speed) || speed > 63)
if (!val || kstrtoul(val, 0, &speed) || speed > 63)
return -EINVAL;
scroll_speed = speed;
return 0;
@ -484,7 +484,7 @@ static int magicmouse_probe(struct hid_device *hdev,
struct hid_report *report;
int ret;
msc = kzalloc(sizeof(*msc), GFP_KERNEL);
msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
if (msc == NULL) {
hid_err(hdev, "can't alloc magicmouse descriptor\n");
return -ENOMEM;
@ -498,13 +498,13 @@ static int magicmouse_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "magicmouse hid parse failed\n");
goto err_free;
return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "magicmouse hw start failed\n");
goto err_free;
return ret;
}
if (!msc->input) {
@ -548,19 +548,9 @@ static int magicmouse_probe(struct hid_device *hdev,
return 0;
err_stop_hw:
hid_hw_stop(hdev);
err_free:
kfree(msc);
return ret;
}
static void magicmouse_remove(struct hid_device *hdev)
{
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
kfree(msc);
}
static const struct hid_device_id magic_mice[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
@ -574,7 +564,6 @@ static struct hid_driver magicmouse_driver = {
.name = "magicmouse",
.id_table = magic_mice,
.probe = magicmouse_probe,
.remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
.input_mapping = magicmouse_input_mapping,
.input_configured = magicmouse_input_configured,

View file

@ -133,6 +133,7 @@ static void mt_post_parse(struct mt_device *td);
#define MT_CLS_NSMU 0x000a
#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
#define MT_CLS_DUAL_CONTACT_ID 0x0011
#define MT_CLS_WIN_8 0x0012
/* vendor specific classes */
#define MT_CLS_3M 0x0101
@ -205,6 +206,11 @@ static struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SLOT_IS_CONTACTID,
.maxcontacts = 2 },
{ .name = MT_CLS_WIN_8,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_IGNORE_DUPLICATES |
MT_QUIRK_HOVERING |
MT_QUIRK_CONTACT_CNT_ACCURATE },
/*
* vendor specific classes
@ -261,17 +267,6 @@ static struct mt_class mt_classes[] = {
{ }
};
static void mt_free_input_name(struct hid_input *hi)
{
struct hid_device *hdev = hi->report->device;
const char *name = hi->input->name;
if (name != hdev->name) {
hi->input->name = hdev->name;
kfree(name);
}
}
static ssize_t mt_show_quirks(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -343,19 +338,6 @@ static void mt_feature_mapping(struct hid_device *hdev,
td->maxcontacts = td->mtclass.maxcontacts;
break;
case 0xff0000c5:
if (field->report_count == 256 && field->report_size == 8) {
/* Win 8 devices need special quirks */
__s32 *quirks = &td->mtclass.quirks;
*quirks |= MT_QUIRK_ALWAYS_VALID;
*quirks |= MT_QUIRK_IGNORE_DUPLICATES;
*quirks |= MT_QUIRK_HOVERING;
*quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE;
*quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
*quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
*quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
}
break;
}
}
@ -415,13 +397,6 @@ static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
static void mt_pen_input_configured(struct hid_device *hdev,
struct hid_input *hi)
{
char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
if (name) {
sprintf(name, "%s Pen", hi->input->name);
mt_free_input_name(hi);
hi->input->name = name;
}
/* force BTN_STYLUS to allow tablet matching in udev */
__set_bit(BTN_STYLUS, hi->input->keybit);
}
@ -928,16 +903,26 @@ static void mt_post_parse(struct mt_device *td)
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
char *name = kstrdup(hdev->name, GFP_KERNEL);
if (name)
hi->input->name = name;
char *name;
const char *suffix = NULL;
if (hi->report->id == td->mt_report_id)
mt_touch_input_configured(hdev, hi);
if (hi->report->id == td->pen_report_id)
if (hi->report->field[0]->physical == HID_DG_STYLUS) {
suffix = "Pen";
mt_pen_input_configured(hdev, hi);
}
if (suffix) {
name = devm_kzalloc(&hi->input->dev,
strlen(hdev->name) + strlen(suffix) + 2,
GFP_KERNEL);
if (name) {
sprintf(name, "%s %s", hdev->name, suffix);
hi->input->name = name;
}
}
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@ -945,7 +930,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret, i;
struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
struct hid_input *hi;
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
@ -967,7 +951,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
/*
* Handle special quirks for Windows 8 certified devices.
*/
if (id->group == HID_GROUP_MULTITOUCH_WIN_8)
/*
* Some multitouch screens do not like to be polled for input
* reports. Fortunately, the Win8 spec says that all touches
* should be sent during each report, making the initialization
* of input reports unnecessary.
*/
hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS;
td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
return -ENOMEM;
@ -980,11 +976,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->pen_report_id = -1;
hid_set_drvdata(hdev, td);
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
GFP_KERNEL);
if (!td->fields) {
dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
ret = -ENOMEM;
goto fail;
return -ENOMEM;
}
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
@ -992,29 +988,22 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret != 0)
goto fail;
return ret;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
goto hid_fail;
return ret;
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
kfree(td->fields);
/* release .fields memory as it is not used anymore */
devm_kfree(&hdev->dev, td->fields);
td->fields = NULL;
return 0;
hid_fail:
list_for_each_entry(hi, &hdev->inputs, list)
mt_free_input_name(hi);
fail:
kfree(td->fields);
kfree(td);
return ret;
}
#ifdef CONFIG_PM
@ -1039,17 +1028,8 @@ static int mt_resume(struct hid_device *hdev)
static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct hid_input *hi;
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
list_for_each_entry(hi, &hdev->inputs, list)
mt_free_input_name(hi);
hid_hw_stop(hdev);
kfree(td);
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id mt_devices[] = {
@ -1371,6 +1351,11 @@ static const struct hid_device_id mt_devices[] = {
/* Generic MT device */
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
/* Generic Win 8 certified MT device */
{ .driver_data = MT_CLS_WIN_8,
HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
HID_ANY_ID, HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, mt_devices);

View file

@ -115,7 +115,8 @@ static inline int ntrig_get_mode(struct hid_device *hdev)
struct hid_report *report = hdev->report_enum[HID_FEATURE_REPORT].
report_id_hash[0x0d];
if (!report)
if (!report || report->maxfield < 1 ||
report->field[0]->report_count < 1)
return -EINVAL;
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
@ -237,7 +238,7 @@ static ssize_t set_min_width(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > nd->sensor_physical_width)
@ -272,7 +273,7 @@ static ssize_t set_min_height(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > nd->sensor_physical_height)
@ -306,7 +307,7 @@ static ssize_t set_activate_slack(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > 0x7f)
@ -341,7 +342,7 @@ static ssize_t set_activation_width(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > nd->sensor_physical_width)
@ -377,7 +378,7 @@ static ssize_t set_activation_height(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > nd->sensor_physical_height)
@ -411,7 +412,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
unsigned long val;
if (strict_strtoul(buf, 0, &val))
if (kstrtoul(buf, 0, &val))
return -EINVAL;
/*

View file

@ -145,6 +145,7 @@ void picolcd_exit_cir(struct picolcd_data *data)
struct rc_dev *rdev = data->rc_dev;
data->rc_dev = NULL;
rc_unregister_device(rdev);
if (rdev)
rc_unregister_device(rdev);
}

View file

@ -290,7 +290,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
buf += 10;
cnt -= 10;
}
if (!report)
if (!report || report->maxfield != 1)
return -EINVAL;
while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))

View file

@ -394,7 +394,7 @@ static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
void picolcd_debug_out_report(struct picolcd_data *data,
struct hid_device *hdev, struct hid_report *report)
{
u8 raw_data[70];
u8 *raw_data;
int raw_size = (report->size >> 3) + 1;
char *buff;
#define BUFF_SZ 256
@ -407,19 +407,19 @@ void picolcd_debug_out_report(struct picolcd_data *data,
if (!buff)
return;
raw_data = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!raw_data) {
kfree(buff);
return;
}
snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ",
report->id, raw_size);
hid_debug_event(hdev, buff);
if (raw_size + 5 > sizeof(raw_data)) {
kfree(buff);
hid_debug_event(hdev, " TOO BIG\n");
return;
} else {
raw_data[0] = report->id;
hid_output_report(report, raw_data);
dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
hid_debug_event(hdev, buff);
}
raw_data[0] = report->id;
hid_output_report(report, raw_data);
dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
hid_debug_event(hdev, buff);
switch (report->id) {
case REPORT_LED_STATE:
@ -644,6 +644,7 @@ void picolcd_debug_out_report(struct picolcd_data *data,
break;
}
wake_up_interruptible(&hdev->debug_wait);
kfree(raw_data);
kfree(buff);
}

View file

@ -593,10 +593,14 @@ err_nomem:
void picolcd_exit_framebuffer(struct picolcd_data *data)
{
struct fb_info *info = data->fb_info;
struct picolcd_fb_data *fbdata = info->par;
struct picolcd_fb_data *fbdata;
unsigned long flags;
if (!info)
return;
device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
fbdata = info->par;
/* disconnect framebuffer from HID dev */
spin_lock_irqsave(&fbdata->lock, flags);

View file

@ -132,8 +132,14 @@ static int plff_init(struct hid_device *hid)
strong = &report->field[0]->value[2];
weak = &report->field[0]->value[3];
debug("detected single-field device");
} else if (report->maxfield >= 4 && report->field[0]->maxusage == 1 &&
report->field[0]->usage[0].hid == (HID_UP_LED | 0x43)) {
} else if (report->field[0]->maxusage == 1 &&
report->field[0]->usage[0].hid ==
(HID_UP_LED | 0x43) &&
report->maxfield >= 4 &&
report->field[0]->report_count >= 1 &&
report->field[1]->report_count >= 1 &&
report->field[2]->report_count >= 1 &&
report->field[3]->report_count >= 1) {
report->field[0]->value[0] = 0x00;
report->field[1]->value[0] = 0x00;
strong = &report->field[2]->value[0];

View file

@ -59,7 +59,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
unsigned long state;
int retval;
retval = strict_strtoul(buf, 10, &state);
retval = kstrtoul(buf, 10, &state);
if (retval)
return retval;
@ -107,7 +107,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
unsigned long key_mask;
int retval;
retval = strict_strtoul(buf, 10, &key_mask);
retval = kstrtoul(buf, 10, &key_mask);
if (retval)
return retval;
@ -159,7 +159,7 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
unsigned long profile;
int retval;
retval = strict_strtoul(buf, 10, &profile);
retval = kstrtoul(buf, 10, &profile);
if (retval)
return retval;

View file

@ -82,7 +82,7 @@ static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
isku = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = strict_strtoul(buf, 10, &profile);
retval = kstrtoul(buf, 10, &profile);
if (retval)
return retval;

View file

@ -456,7 +456,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
kone = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = strict_strtoul(buf, 10, &state);
retval = kstrtoul(buf, 10, &state);
if (retval)
return retval;
@ -545,7 +545,7 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
kone = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = strict_strtoul(buf, 10, &new_startup_profile);
retval = kstrtoul(buf, 10, &new_startup_profile);
if (retval)
return retval;

View file

@ -246,7 +246,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
koneplus = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = strict_strtoul(buf, 10, &profile);
retval = kstrtoul(buf, 10, &profile);
if (retval)
return retval;

View file

@ -262,6 +262,7 @@ static int konepure_raw_event(struct hid_device *hdev,
static const struct hid_device_id konepure_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
{ }
};
@ -300,5 +301,5 @@ module_init(konepure_init);
module_exit(konepure_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat KonePure driver");
MODULE_DESCRIPTION("USB Roccat KonePure/Optical driver");
MODULE_LICENSE("GPL v2");

View file

@ -282,7 +282,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = strict_strtoul(buf, 10, &profile);
retval = kstrtoul(buf, 10, &profile);
if (retval)
return retval;

View file

@ -221,7 +221,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
mutex_lock(&data->mutex);
report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
if (!report || (field_index >= report->maxfield)) {
if (!report || (field_index >= report->maxfield) ||
report->field[field_index]->report_count < 1) {
ret = -EINVAL;
goto done_proc;
}
@ -416,7 +417,7 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
return 1;
ptr = raw_data;
ptr++; /*Skip report id*/
ptr++; /* Skip report id */
spin_lock_irqsave(&pdata->lock, flags);

View file

@ -624,7 +624,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct sony_sc *sc;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
sc = kzalloc(sizeof(*sc), GFP_KERNEL);
sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
hid_err(hdev, "can't alloc sony descriptor\n");
return -ENOMEM;
@ -636,7 +636,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
return ret;
}
if (sc->quirks & VAIO_RDESC_CONSTANT)
@ -649,7 +649,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
return ret;
}
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
@ -669,8 +669,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
err_stop:
hid_hw_stop(hdev);
err_free:
kfree(sc);
return ret;
}
@ -682,7 +680,6 @@ static void sony_remove(struct hid_device *hdev)
buzz_remove(hdev);
hid_hw_stop(hdev);
kfree(sc);
}
static const struct hid_device_id sony_devices[] = {

View file

@ -3,7 +3,7 @@
* Fixes "jumpy" cursor and removes nonexistent keyboard LEDS from
* the HID descriptor.
*
* Copyright (c) 2011 Stefan Kriwanek <mail@stefankriwanek.de>
* Copyright (c) 2011, 2013 Stefan Kriwanek <dev@stefankriwanek.de>
*/
/*
@ -46,8 +46,13 @@ static int speedlink_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
/* No other conditions due to usage_table. */
/* Fix "jumpy" cursor (invalid events sent by device). */
if (value == 256)
/* This fixes the "jumpy" cursor occuring due to invalid events sent
* by the device. Some devices only send them with value==+256, others
* don't. However, catching abs(value)>=256 is restrictive enough not
* to interfere with devices that were bug-free (has been tested).
*/
if (abs(value) >= 256)
return 1;
/* Drop useless distance 0 events (on button clicks etc.) as well */
if (value == 0)

View file

@ -212,10 +212,12 @@ static __u8 select_drm(struct wiimote_data *wdata)
if (ir == WIIPROTO_FLAG_IR_BASIC) {
if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
if (ext)
return WIIPROTO_REQ_DRM_KAIE;
else
return WIIPROTO_REQ_DRM_KAI;
/* GEN10 and ealier devices bind IR formats to DRMs.
* Hence, we cannot use DRM_KAI here as it might be
* bound to IR_EXT. Use DRM_KAIE unconditionally so we
* work with all devices and our parsers can use the
* fixed formats, too. */
return WIIPROTO_REQ_DRM_KAIE;
} else {
return WIIPROTO_REQ_DRM_KIE;
}
@ -439,8 +441,7 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
if (ret != 6)
return WIIMOTE_EXT_NONE;
hid_dbg(wdata->hdev, "extension ID: %02x:%02x %02x:%02x %02x:%02x\n",
rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
hid_dbg(wdata->hdev, "extension ID: %6phC\n", rmem);
if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
@ -454,6 +455,12 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
return WIIMOTE_EXT_BALANCE_BOARD;
if (rmem[4] == 0x01 && rmem[5] == 0x20)
return WIIMOTE_EXT_PRO_CONTROLLER;
if (rmem[0] == 0x01 && rmem[1] == 0x00 &&
rmem[4] == 0x01 && rmem[5] == 0x03)
return WIIMOTE_EXT_GUITAR_HERO_DRUMS;
if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
rmem[4] == 0x01 && rmem[5] == 0x03)
return WIIMOTE_EXT_GUITAR_HERO_GUITAR;
return WIIMOTE_EXT_UNKNOWN;
}
@ -487,6 +494,8 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
/* map MP with correct pass-through mode */
switch (exttype) {
case WIIMOTE_EXT_CLASSIC_CONTROLLER:
case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
wmem = 0x07;
break;
case WIIMOTE_EXT_NUNCHUK:
@ -510,14 +519,12 @@ static bool wiimote_cmd_read_mp(struct wiimote_data *wdata, __u8 *rmem)
if (ret != 6)
return false;
hid_dbg(wdata->hdev, "motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
hid_dbg(wdata->hdev, "motion plus ID: %6phC\n", rmem);
if (rmem[5] == 0x05)
return true;
hid_info(wdata->hdev, "unknown motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
hid_info(wdata->hdev, "unknown motion plus ID: %6phC\n", rmem);
return false;
}
@ -533,8 +540,7 @@ static __u8 wiimote_cmd_read_mp_mapped(struct wiimote_data *wdata)
if (ret != 6)
return WIIMOTE_MP_NONE;
hid_dbg(wdata->hdev, "mapped motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
hid_dbg(wdata->hdev, "mapped motion plus ID: %6phC\n", rmem);
if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
@ -1077,6 +1083,8 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
[WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
[WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
[WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = "Nintendo Wii Guitar Hero Drums",
[WIIMOTE_EXT_GUITAR_HERO_GUITAR] = "Nintendo Wii Guitar Hero Guitar",
};
/*
@ -1126,9 +1134,8 @@ static void wiimote_init_hotplug(struct wiimote_data *wdata)
wiimote_ext_unload(wdata);
if (exttype == WIIMOTE_EXT_UNKNOWN) {
hid_info(wdata->hdev, "cannot detect extension; %02x:%02x %02x:%02x %02x:%02x\n",
extdata[0], extdata[1], extdata[2],
extdata[3], extdata[4], extdata[5]);
hid_info(wdata->hdev, "cannot detect extension; %6phC\n",
extdata);
} else if (exttype == WIIMOTE_EXT_NONE) {
spin_lock_irq(&wdata->state.lock);
wdata->state.exttype = WIIMOTE_EXT_NONE;
@ -1663,6 +1670,10 @@ static ssize_t wiimote_ext_show(struct device *dev,
return sprintf(buf, "balanceboard\n");
case WIIMOTE_EXT_PRO_CONTROLLER:
return sprintf(buf, "procontroller\n");
case WIIMOTE_EXT_GUITAR_HERO_DRUMS:
return sprintf(buf, "drums\n");
case WIIMOTE_EXT_GUITAR_HERO_GUITAR:
return sprintf(buf, "guitar\n");
case WIIMOTE_EXT_UNKNOWN:
/* fallthrough */
default:

View file

@ -1833,6 +1833,396 @@ static const struct wiimod_ops wiimod_pro = {
.in_ext = wiimod_pro_in_ext,
};
/*
* Drums
* Guitar-Hero, Rock-Band and other games came bundled with drums which can
* be plugged as extension to a Wiimote. Drum-reports are still not entirely
* figured out, but the most important information is known.
* We create a separate device for drums and report all information via this
* input device.
*/
static inline void wiimod_drums_report_pressure(struct wiimote_data *wdata,
__u8 none, __u8 which,
__u8 pressure, __u8 onoff,
__u8 *store, __u16 code,
__u8 which_code)
{
static const __u8 default_pressure = 3;
if (!none && which == which_code) {
*store = pressure;
input_report_abs(wdata->extension.input, code, *store);
} else if (onoff != !!*store) {
*store = onoff ? default_pressure : 0;
input_report_abs(wdata->extension.input, code, *store);
}
}
static void wiimod_drums_in_ext(struct wiimote_data *wdata, const __u8 *ext)
{
__u8 pressure, which, none, hhp, sx, sy;
__u8 o, r, y, g, b, bass, bm, bp;
/* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 1 | 0 | 0 | SX <5:0> |
* 2 | 0 | 0 | SY <5:0> |
* -----+-----+-----+-----------------------------+-----+
* 3 | HPP | NON | WHICH <5:1> | ? |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 5 | ? | 1 | 1 | B- | 1 | B+ | 1 | ? |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 6 | O | R | Y | G | B | BSS | 1 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* All buttons are 0 if pressed
*
* With Motion+ enabled, the following bits will get invalid:
* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 1 | 0 | 0 | SX <5:1> |XXXXX|
* 2 | 0 | 0 | SY <5:1> |XXXXX|
* -----+-----+-----+-----------------------------+-----+
* 3 | HPP | NON | WHICH <5:1> | ? |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 4 | SOFT <7:5> | 0 | 1 | 1 | 0 | ? |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 5 | ? | 1 | 1 | B- | 1 | B+ | 1 |XXXXX|
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 6 | O | R | Y | G | B | BSS |XXXXX|XXXXX|
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
*/
pressure = 7 - (ext[3] >> 5);
which = (ext[2] >> 1) & 0x1f;
none = !!(ext[2] & 0x40);
hhp = !(ext[2] & 0x80);
sx = ext[0] & 0x3f;
sy = ext[1] & 0x3f;
o = !(ext[5] & 0x80);
r = !(ext[5] & 0x40);
y = !(ext[5] & 0x20);
g = !(ext[5] & 0x10);
b = !(ext[5] & 0x08);
bass = !(ext[5] & 0x04);
bm = !(ext[4] & 0x10);
bp = !(ext[4] & 0x04);
wiimod_drums_report_pressure(wdata, none, which, pressure,
o, &wdata->state.pressure_drums[0],
ABS_CYMBAL_RIGHT, 0x0e);
wiimod_drums_report_pressure(wdata, none, which, pressure,
r, &wdata->state.pressure_drums[1],
ABS_TOM_LEFT, 0x19);
wiimod_drums_report_pressure(wdata, none, which, pressure,
y, &wdata->state.pressure_drums[2],
ABS_CYMBAL_LEFT, 0x11);
wiimod_drums_report_pressure(wdata, none, which, pressure,
g, &wdata->state.pressure_drums[3],
ABS_TOM_FAR_RIGHT, 0x12);
wiimod_drums_report_pressure(wdata, none, which, pressure,
b, &wdata->state.pressure_drums[4],
ABS_TOM_RIGHT, 0x0f);
/* Bass shares pressure with hi-hat (set via hhp) */
wiimod_drums_report_pressure(wdata, none, hhp ? 0xff : which, pressure,
bass, &wdata->state.pressure_drums[5],
ABS_BASS, 0x1b);
/* Hi-hat has no on/off values, just pressure. Force to off/0. */
wiimod_drums_report_pressure(wdata, none, hhp ? which : 0xff, pressure,
0, &wdata->state.pressure_drums[6],
ABS_HI_HAT, 0x0e);
input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
input_report_key(wdata->extension.input, BTN_START, bp);
input_report_key(wdata->extension.input, BTN_SELECT, bm);
input_sync(wdata->extension.input);
}
static int wiimod_drums_open(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
static void wiimod_drums_close(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
}
static int wiimod_drums_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
int ret;
wdata->extension.input = input_allocate_device();
if (!wdata->extension.input)
return -ENOMEM;
input_set_drvdata(wdata->extension.input, wdata);
wdata->extension.input->open = wiimod_drums_open;
wdata->extension.input->close = wiimod_drums_close;
wdata->extension.input->dev.parent = &wdata->hdev->dev;
wdata->extension.input->id.bustype = wdata->hdev->bus;
wdata->extension.input->id.vendor = wdata->hdev->vendor;
wdata->extension.input->id.product = wdata->hdev->product;
wdata->extension.input->id.version = wdata->hdev->version;
wdata->extension.input->name = WIIMOTE_NAME " Drums";
set_bit(EV_KEY, wdata->extension.input->evbit);
set_bit(BTN_START, wdata->extension.input->keybit);
set_bit(BTN_SELECT, wdata->extension.input->keybit);
set_bit(EV_ABS, wdata->extension.input->evbit);
set_bit(ABS_X, wdata->extension.input->absbit);
set_bit(ABS_Y, wdata->extension.input->absbit);
set_bit(ABS_TOM_LEFT, wdata->extension.input->absbit);
set_bit(ABS_TOM_RIGHT, wdata->extension.input->absbit);
set_bit(ABS_TOM_FAR_RIGHT, wdata->extension.input->absbit);
set_bit(ABS_CYMBAL_LEFT, wdata->extension.input->absbit);
set_bit(ABS_CYMBAL_RIGHT, wdata->extension.input->absbit);
set_bit(ABS_BASS, wdata->extension.input->absbit);
set_bit(ABS_HI_HAT, wdata->extension.input->absbit);
input_set_abs_params(wdata->extension.input,
ABS_X, -32, 31, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_Y, -32, 31, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_TOM_LEFT, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_TOM_RIGHT, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_TOM_FAR_RIGHT, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_CYMBAL_LEFT, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_CYMBAL_RIGHT, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_BASS, 0, 7, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_HI_HAT, 0, 7, 0, 0);
ret = input_register_device(wdata->extension.input);
if (ret)
goto err_free;
return 0;
err_free:
input_free_device(wdata->extension.input);
wdata->extension.input = NULL;
return ret;
}
static void wiimod_drums_remove(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
if (!wdata->extension.input)
return;
input_unregister_device(wdata->extension.input);
wdata->extension.input = NULL;
}
static const struct wiimod_ops wiimod_drums = {
.flags = 0,
.arg = 0,
.probe = wiimod_drums_probe,
.remove = wiimod_drums_remove,
.in_ext = wiimod_drums_in_ext,
};
/*
* Guitar
* Guitar-Hero, Rock-Band and other games came bundled with guitars which can
* be plugged as extension to a Wiimote.
* We create a separate device for guitars and report all information via this
* input device.
*/
static void wiimod_guitar_in_ext(struct wiimote_data *wdata, const __u8 *ext)
{
__u8 sx, sy, tb, wb, bd, bm, bp, bo, br, bb, bg, by, bu;
/* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 1 | 0 | 0 | SX <5:0> |
* 2 | 0 | 0 | SY <5:0> |
* -----+-----+-----+-----+-----------------------------+
* 3 | 0 | 0 | 0 | TB <4:0> |
* -----+-----+-----+-----+-----------------------------+
* 4 | 0 | 0 | 0 | WB <4:0> |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 5 | 1 | BD | 1 | B- | 1 | B+ | 1 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 6 | BO | BR | BB | BG | BY | 1 | 1 | BU |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* All buttons are 0 if pressed
*
* With Motion+ enabled, the following bits will get invalid:
* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 1 | 0 | 0 | SX <5:1> |XXXXX|
* 2 | 0 | 0 | SY <5:1> |XXXXX|
* -----+-----+-----+-----+-----------------------+-----+
* 3 | 0 | 0 | 0 | TB <4:0> |
* -----+-----+-----+-----+-----------------------------+
* 4 | 0 | 0 | 0 | WB <4:0> |
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 5 | 1 | BD | 1 | B- | 1 | B+ | 1 |XXXXX|
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
* 6 | BO | BR | BB | BG | BY | 1 |XXXXX|XXXXX|
* -----+-----+-----+-----+-----+-----+-----+-----+-----+
*/
sx = ext[0] & 0x3f;
sy = ext[1] & 0x3f;
tb = ext[2] & 0x1f;
wb = ext[3] & 0x1f;
bd = !(ext[4] & 0x40);
bm = !(ext[4] & 0x10);
bp = !(ext[4] & 0x04);
bo = !(ext[5] & 0x80);
br = !(ext[5] & 0x40);
bb = !(ext[5] & 0x20);
bg = !(ext[5] & 0x10);
by = !(ext[5] & 0x08);
bu = !(ext[5] & 0x01);
input_report_abs(wdata->extension.input, ABS_X, sx - 0x20);
input_report_abs(wdata->extension.input, ABS_Y, sy - 0x20);
input_report_abs(wdata->extension.input, ABS_FRET_BOARD, tb);
input_report_abs(wdata->extension.input, ABS_WHAMMY_BAR, wb - 0x10);
input_report_key(wdata->extension.input, BTN_MODE, bm);
input_report_key(wdata->extension.input, BTN_START, bp);
input_report_key(wdata->extension.input, BTN_STRUM_BAR_UP, bu);
input_report_key(wdata->extension.input, BTN_STRUM_BAR_DOWN, bd);
input_report_key(wdata->extension.input, BTN_FRET_FAR_UP, bg);
input_report_key(wdata->extension.input, BTN_FRET_UP, br);
input_report_key(wdata->extension.input, BTN_FRET_MID, by);
input_report_key(wdata->extension.input, BTN_FRET_LOW, bb);
input_report_key(wdata->extension.input, BTN_FRET_FAR_LOW, bo);
input_sync(wdata->extension.input);
}
static int wiimod_guitar_open(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
static void wiimod_guitar_close(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
}
static int wiimod_guitar_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
int ret;
wdata->extension.input = input_allocate_device();
if (!wdata->extension.input)
return -ENOMEM;
input_set_drvdata(wdata->extension.input, wdata);
wdata->extension.input->open = wiimod_guitar_open;
wdata->extension.input->close = wiimod_guitar_close;
wdata->extension.input->dev.parent = &wdata->hdev->dev;
wdata->extension.input->id.bustype = wdata->hdev->bus;
wdata->extension.input->id.vendor = wdata->hdev->vendor;
wdata->extension.input->id.product = wdata->hdev->product;
wdata->extension.input->id.version = wdata->hdev->version;
wdata->extension.input->name = WIIMOTE_NAME " Guitar";
set_bit(EV_KEY, wdata->extension.input->evbit);
set_bit(BTN_MODE, wdata->extension.input->keybit);
set_bit(BTN_START, wdata->extension.input->keybit);
set_bit(BTN_FRET_FAR_UP, wdata->extension.input->keybit);
set_bit(BTN_FRET_UP, wdata->extension.input->keybit);
set_bit(BTN_FRET_MID, wdata->extension.input->keybit);
set_bit(BTN_FRET_LOW, wdata->extension.input->keybit);
set_bit(BTN_FRET_FAR_LOW, wdata->extension.input->keybit);
set_bit(BTN_STRUM_BAR_UP, wdata->extension.input->keybit);
set_bit(BTN_STRUM_BAR_DOWN, wdata->extension.input->keybit);
set_bit(EV_ABS, wdata->extension.input->evbit);
set_bit(ABS_X, wdata->extension.input->absbit);
set_bit(ABS_Y, wdata->extension.input->absbit);
set_bit(ABS_FRET_BOARD, wdata->extension.input->absbit);
set_bit(ABS_WHAMMY_BAR, wdata->extension.input->absbit);
input_set_abs_params(wdata->extension.input,
ABS_X, -32, 31, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_Y, -32, 31, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_FRET_BOARD, 0, 0x1f, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_WHAMMY_BAR, 0, 0x0f, 1, 1);
ret = input_register_device(wdata->extension.input);
if (ret)
goto err_free;
return 0;
err_free:
input_free_device(wdata->extension.input);
wdata->extension.input = NULL;
return ret;
}
static void wiimod_guitar_remove(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
if (!wdata->extension.input)
return;
input_unregister_device(wdata->extension.input);
wdata->extension.input = NULL;
}
static const struct wiimod_ops wiimod_guitar = {
.flags = 0,
.arg = 0,
.probe = wiimod_guitar_probe,
.remove = wiimod_guitar_remove,
.in_ext = wiimod_guitar_in_ext,
};
/*
* Builtin Motion Plus
* This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
@ -2083,4 +2473,6 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
[WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic,
[WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
[WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
[WIIMOTE_EXT_GUITAR_HERO_DRUMS] = &wiimod_drums,
[WIIMOTE_EXT_GUITAR_HERO_GUITAR] = &wiimod_guitar,
};

View file

@ -88,6 +88,8 @@ enum wiimote_exttype {
WIIMOTE_EXT_CLASSIC_CONTROLLER,
WIIMOTE_EXT_BALANCE_BOARD,
WIIMOTE_EXT_PRO_CONTROLLER,
WIIMOTE_EXT_GUITAR_HERO_DRUMS,
WIIMOTE_EXT_GUITAR_HERO_GUITAR,
WIIMOTE_EXT_NUM,
};
@ -135,6 +137,7 @@ struct wiimote_state {
/* calibration data */
__u16 calib_bboard[4][3];
__u8 pressure_drums[7];
};
struct wiimote_data {

61
drivers/hid/hid-xinmo.c Normal file
View file

@ -0,0 +1,61 @@
/*
* HID driver for Xin-Mo devices, currently only the Dual Arcade controller.
* Fixes the negative axis event values (the devices sends -2) to match the
* logical axis minimum of the HID report descriptor (the report announces
* -1). It is needed because hid-input discards out of bounds values.
* (This module is based on "hid-saitek" and "hid-lg".)
*
* Copyright (c) 2013 Olivier Scherler
*/
/*
* 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 <linux/kernel.h>
#include "hid-ids.h"
/*
* Fix negative events that are out of bounds.
*/
static int xinmo_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
switch (usage->code) {
case ABS_X:
case ABS_Y:
case ABS_Z:
case ABS_RX:
if (value < -1) {
input_event(field->hidinput->input, usage->type,
usage->code, -1);
return 1;
}
break;
}
return 0;
}
static const struct hid_device_id xinmo_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
{ }
};
MODULE_DEVICE_TABLE(hid, xinmo_devices);
static struct hid_driver xinmo_driver = {
.name = "xinmo",
.id_table = xinmo_devices,
.event = xinmo_event
};
module_hid_driver(xinmo_driver);
MODULE_LICENSE("GPL");

View file

@ -169,7 +169,7 @@ 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);
zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL);
if (zc == NULL) {
hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
@ -180,28 +180,16 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
return ret;
}
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);
kfree(zc);
}
static const struct hid_device_id zc_devices[] = {
@ -217,7 +205,6 @@ static struct hid_driver zc_driver = {
.input_mapping = zc_input_mapping,
.raw_event = zc_raw_event,
.probe = zc_probe,
.remove = zc_remove,
};
module_hid_driver(zc_driver);

View file

@ -113,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
__u8 *buf;
int ret = 0;
if (!hidraw_table[minor]) {
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
ret = -ENODEV;
goto out;
}
@ -253,6 +253,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list;
unsigned long flags;
int err = 0;
if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
@ -261,16 +262,11 @@ static int hidraw_open(struct inode *inode, struct file *file)
}
mutex_lock(&minors_lock);
if (!hidraw_table[minor]) {
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
err = -ENODEV;
goto out_unlock;
}
list->hidraw = hidraw_table[minor];
mutex_init(&list->read_mutex);
list_add_tail(&list->node, &hidraw_table[minor]->list);
file->private_data = list;
dev = hidraw_table[minor];
if (!dev->open++) {
err = hid_hw_power(dev->hid, PM_HINT_FULLON);
@ -283,9 +279,16 @@ static int hidraw_open(struct inode *inode, struct file *file)
if (err < 0) {
hid_hw_power(dev->hid, PM_HINT_NORMAL);
dev->open--;
goto out_unlock;
}
}
list->hidraw = hidraw_table[minor];
mutex_init(&list->read_mutex);
spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
list_add_tail(&list->node, &hidraw_table[minor]->list);
spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
file->private_data = list;
out_unlock:
mutex_unlock(&minors_lock);
out:
@ -302,39 +305,41 @@ static int hidraw_fasync(int fd, struct file *file, int on)
return fasync_helper(fd, file, on, &list->fasync);
}
static void drop_ref(struct hidraw *hidraw, int exists_bit)
{
if (exists_bit) {
hid_hw_close(hidraw->hid);
hidraw->exist = 0;
if (hidraw->open)
wake_up_interruptible(&hidraw->wait);
} else {
--hidraw->open;
}
if (!hidraw->open && !hidraw->exist) {
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
hidraw_table[hidraw->minor] = NULL;
kfree(hidraw);
}
}
static int hidraw_release(struct inode * inode, struct file * file)
{
unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list = file->private_data;
int ret;
int i;
unsigned long flags;
mutex_lock(&minors_lock);
if (!hidraw_table[minor]) {
ret = -ENODEV;
goto unlock;
}
spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
list_del(&list->node);
dev = hidraw_table[minor];
if (!--dev->open) {
if (list->hidraw->exist) {
hid_hw_power(dev->hid, PM_HINT_NORMAL);
hid_hw_close(dev->hid);
} else {
kfree(list->hidraw);
}
}
for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
kfree(list->buffer[i].value);
spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
kfree(list);
ret = 0;
unlock:
mutex_unlock(&minors_lock);
return ret;
drop_ref(hidraw_table[minor], 0);
mutex_unlock(&minors_lock);
return 0;
}
static long hidraw_ioctl(struct file *file, unsigned int cmd,
@ -457,7 +462,9 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
struct hidraw *dev = hid->hidraw;
struct hidraw_list *list;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(list, &dev->list, node) {
int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
@ -472,6 +479,7 @@ int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
list->head = new_head;
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&dev->list_lock, flags);
wake_up_interruptible(&dev->wait);
return ret;
@ -519,6 +527,7 @@ int hidraw_connect(struct hid_device *hid)
}
init_waitqueue_head(&dev->wait);
spin_lock_init(&dev->list_lock);
INIT_LIST_HEAD(&dev->list);
dev->hid = hid;
@ -539,18 +548,9 @@ void hidraw_disconnect(struct hid_device *hid)
struct hidraw *hidraw = hid->hidraw;
mutex_lock(&minors_lock);
hidraw->exist = 0;
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
drop_ref(hidraw, 1);
hidraw_table[hidraw->minor] = NULL;
if (hidraw->open) {
hid_hw_close(hid);
wake_up_interruptible(&hidraw->wait);
} else {
kfree(hidraw);
}
mutex_unlock(&minors_lock);
}
EXPORT_SYMBOL_GPL(hidraw_disconnect);

View file

@ -35,6 +35,7 @@
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/i2c/i2c-hid.h>
@ -756,29 +757,6 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
return ret;
}
static int i2c_hid_hidinput_input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_field *field;
int offset;
if (type == EV_FF)
return input_ff_event(dev, type, code, value);
if (type != EV_LED)
return -1;
offset = hidinput_find_field(hid, type, code, &field);
if (offset == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}
return hid_set_field(field, offset, value);
}
static struct hid_ll_driver i2c_hid_ll_driver = {
.parse = i2c_hid_parse,
.start = i2c_hid_start,
@ -787,7 +765,6 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.close = i2c_hid_close,
.power = i2c_hid_power,
.request = i2c_hid_request,
.hidinput_input_event = i2c_hid_hidinput_input_event,
};
static int i2c_hid_init_irq(struct i2c_client *client)
@ -824,8 +801,8 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
* bytes 2-3 -> bcdVersion (has to be 1.00) */
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %*ph\n",
__func__, 4, ihid->hdesc_buffer);
i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
ihid->hdesc_buffer);
if (ret) {
dev_err(&client->dev,
@ -934,6 +911,42 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
}
#endif
#ifdef CONFIG_OF
static int i2c_hid_of_probe(struct i2c_client *client,
struct i2c_hid_platform_data *pdata)
{
struct device *dev = &client->dev;
u32 val;
int ret;
ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
if (ret) {
dev_err(&client->dev, "HID register address not provided\n");
return -ENODEV;
}
if (val >> 16) {
dev_err(&client->dev, "Bad HID register address: 0x%08x\n",
val);
return -EINVAL;
}
pdata->hid_descriptor_address = val;
return 0;
}
static const struct of_device_id i2c_hid_of_match[] = {
{ .compatible = "hid-over-i2c" },
{},
};
MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
#else
static inline int i2c_hid_of_probe(struct i2c_client *client,
struct i2c_hid_platform_data *pdata)
{
return -ENODEV;
}
#endif
static int i2c_hid_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
@ -955,7 +968,11 @@ static int i2c_hid_probe(struct i2c_client *client,
if (!ihid)
return -ENOMEM;
if (!platform_data) {
if (client->dev.of_node) {
ret = i2c_hid_of_probe(client, &ihid->pdata);
if (ret)
goto err;
} else if (!platform_data) {
ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
if (ret) {
dev_err(&client->dev,
@ -1096,6 +1113,7 @@ static struct i2c_driver i2c_hid_driver = {
.owner = THIS_MODULE,
.pm = &i2c_hid_pm,
.acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
.of_match_table = of_match_ptr(i2c_hid_of_match),
},
.probe = i2c_hid_probe,

View file

@ -116,30 +116,6 @@ static void uhid_hid_close(struct hid_device *hid)
uhid_queue_event(uhid, UHID_CLOSE);
}
static int uhid_hid_input(struct input_dev *input, unsigned int type,
unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(input);
struct uhid_device *uhid = hid->driver_data;
unsigned long flags;
struct uhid_event *ev;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev)
return -ENOMEM;
ev->type = UHID_OUTPUT_EV;
ev->u.output_ev.type = type;
ev->u.output_ev.code = code;
ev->u.output_ev.value = value;
spin_lock_irqsave(&uhid->qlock, flags);
uhid_queue(uhid, ev);
spin_unlock_irqrestore(&uhid->qlock, flags);
return 0;
}
static int uhid_hid_parse(struct hid_device *hid)
{
struct uhid_device *uhid = hid->driver_data;
@ -273,7 +249,6 @@ static struct hid_ll_driver uhid_hid_driver = {
.stop = uhid_hid_stop,
.open = uhid_hid_open,
.close = uhid_hid_close,
.hidinput_input_event = uhid_hid_input,
.parse = uhid_hid_parse,
};
@ -659,3 +634,4 @@ module_exit(uhid_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <[email protected]>");
MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
MODULE_ALIAS("devname:" UHID_NAME);

View file

@ -535,7 +535,6 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
{
int head;
struct usbhid_device *usbhid = hid->driver_data;
int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
@ -546,7 +545,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
return;
}
usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
hid_warn(hid, "output queueing failed\n");
return;
@ -595,7 +594,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
}
if (dir == USB_DIR_OUT) {
usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
hid_warn(hid, "control queueing failed\n");
return;
@ -649,62 +648,6 @@ static void usbhid_submit_report(struct hid_device *hid, struct hid_report *repo
spin_unlock_irqrestore(&usbhid->lock, flags);
}
/* Workqueue routine to send requests to change LEDs */
static void hid_led(struct work_struct *work)
{
struct usbhid_device *usbhid =
container_of(work, struct usbhid_device, led_work);
struct hid_device *hid = usbhid->hid;
struct hid_field *field;
unsigned long flags;
field = hidinput_get_led_field(hid);
if (!field) {
hid_warn(hid, "LED event field not found\n");
return;
}
spin_lock_irqsave(&usbhid->lock, flags);
if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) {
usbhid->ledcount = hidinput_count_leds(hid);
hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount);
__usbhid_submit_report(hid, field->report, USB_DIR_OUT);
}
spin_unlock_irqrestore(&usbhid->lock, flags);
}
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct usbhid_device *usbhid = hid->driver_data;
struct hid_field *field;
unsigned long flags;
int offset;
if (type == EV_FF)
return input_ff_event(dev, type, code, value);
if (type != EV_LED)
return -1;
if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}
spin_lock_irqsave(&usbhid->lock, flags);
hid_set_field(field, offset, value);
spin_unlock_irqrestore(&usbhid->lock, flags);
/*
* Defer performing requested LED action.
* This is more likely gather all LED changes into a single URB.
*/
schedule_work(&usbhid->led_work);
return 0;
}
static int usbhid_wait_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@ -807,12 +750,17 @@ void usbhid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
struct usbhid_device *usbhid = hid->driver_data;
struct hid_report_enum *report_enum;
int err, ret;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN);
if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
report_enum = &hid->report_enum[HID_INPUT_REPORT];
list_for_each_entry(report, &report_enum->report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN);
}
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
report_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(report, &report_enum->report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN);
err = 0;
@ -857,7 +805,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
return -1;
}
void usbhid_set_leds(struct hid_device *hid)
static void usbhid_set_leds(struct hid_device *hid)
{
struct hid_field *field;
int offset;
@ -867,7 +815,6 @@ void usbhid_set_leds(struct hid_device *hid)
usbhid_submit_report(hid, field->report, USB_DIR_OUT);
}
}
EXPORT_SYMBOL_GPL(usbhid_set_leds);
/*
* Traverse the supplied list of reports and find the longest
@ -1274,7 +1221,6 @@ static struct hid_ll_driver usb_hid_driver = {
.open = usbhid_open,
.close = usbhid_close,
.power = usbhid_power,
.hidinput_input_event = usb_hidinput_input_event,
.request = usbhid_request,
.wait = usbhid_wait_io,
.idle = usbhid_idle,
@ -1368,8 +1314,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
INIT_WORK(&usbhid->led_work, hid_led);
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
@ -1402,7 +1346,6 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
{
del_timer_sync(&usbhid->io_retry);
cancel_work_sync(&usbhid->reset_work);
cancel_work_sync(&usbhid->led_work);
}
static void hid_cease_io(struct usbhid_device *usbhid)
@ -1522,15 +1465,17 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
struct usbhid_device *usbhid = hid->driver_data;
int status = 0;
bool driver_suspended = false;
unsigned int ledcount;
if (PMSG_IS_AUTO(message)) {
ledcount = hidinput_count_leds(hid);
spin_lock_irq(&usbhid->lock); /* Sync with error handler */
if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
&& !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
&& !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
&& !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
&& !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
&& (!usbhid->ledcount || ignoreled))
&& (!ledcount || ignoreled))
{
set_bit(HID_SUSPENDED, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);

View file

@ -109,6 +109,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
{ 0, 0 }
};

View file

@ -92,9 +92,6 @@ struct usbhid_device {
unsigned int retry_delay; /* Delay length in ms */
struct work_struct reset_work; /* Task context for resets */
wait_queue_head_t wait; /* For sleeping */
int ledcount; /* counting the number of active leds */
struct work_struct led_work; /* Task context for setting LEDs */
};
#define hid_to_usb_dev(hid_dev) \