Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (30 commits) Revert "HID: add support for the Wacom Intuos 4 wireless" HID: fix up Kconfig entry for ACRUX driver HID: add ACRUX game controller force feedback support HID: Force input registration for "VEC footpedal" HID: add HID_QUIRK_HIDINPUT_FORCE HID: hid-input.c: indentation fixes HID: hiddev: use usb_find_interface, get rid of BKL HID: ignore digitizer usage Undefined (0x00) HID: Add support for Conceptronic CLLRCMCE HID: hid-ids.h: Whitespace fixup, align using TABs HID: picolcd: implement refcounting of framebuffer HID: picolcd: do not reallocate memory on depth change HID: picolcd: Add minimal palette required by fbcon on 8bpp HID: magicmouse: Correct parsing of large X and Y motions. HID: magicmouse: report last touch up HID: picolcd: fix deferred_io init/cleanup to fb ordering HID: hid-ids.h: keep vendor ids in alphabetical order HID: add proper support for Elecom BM084 bluetooth mouse HID: magicmouse: enable horizontal scrolling HID: magicmouse: add param for scroll speed ...
This commit is contained in:
Коммит
5cf65713f8
|
@ -33,19 +33,6 @@ Description: When read, this file returns the raw integer version number of the
|
|||
left. E.g. a returned value of 138 means 1.38
|
||||
This file is readonly.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version
|
||||
Date: March 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns the driver version.
|
||||
The format of the string is "v<major>.<minor>.<patchlevel>".
|
||||
This attribute is used by the userland tools to find the sysfs-
|
||||
paths of installed kone-mice and determine the capabilites of
|
||||
the driver. Versions of this driver for old kernels replace
|
||||
usbhid instead of generic-usb. The way to scan for this file
|
||||
has been chosen to provide a consistent way for all supported
|
||||
kernel versions.
|
||||
This file is readonly.
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]
|
||||
Date: March 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
|
|
@ -68,6 +68,14 @@ config HID_A4TECH
|
|||
---help---
|
||||
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
|
||||
|
||||
config HID_ACRUX_FF
|
||||
tristate "ACRUX force feedback support"
|
||||
depends on USB_HID
|
||||
select INPUT_FF_MEMLESS
|
||||
---help---
|
||||
Say Y here if you want to enable force feedback support for ACRUX
|
||||
game controllers.
|
||||
|
||||
config HID_APPLE
|
||||
tristate "Apple" if EMBEDDED
|
||||
depends on (USB_HID || BT_HIDP)
|
||||
|
@ -148,6 +156,12 @@ config HID_EGALAX
|
|||
---help---
|
||||
Support for the eGalax dual-touch panel.
|
||||
|
||||
config HID_ELECOM
|
||||
tristate "ELECOM"
|
||||
depends on BT_HIDP
|
||||
---help---
|
||||
Support for the ELECOM BM084 (bluetooth mouse).
|
||||
|
||||
config HID_EZKEY
|
||||
tristate "Ezkey" if EMBEDDED
|
||||
depends on USB_HID
|
||||
|
@ -417,10 +431,11 @@ config SMARTJOYPLUS_FF
|
|||
enable force feedback support for it.
|
||||
|
||||
config HID_TOPSEED
|
||||
tristate "TopSeed Cyberlink remote control support"
|
||||
tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
|
||||
depends on USB_HID
|
||||
---help---
|
||||
Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control.
|
||||
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
|
||||
CLLRCMCE remote control.
|
||||
|
||||
config HID_THRUSTMASTER
|
||||
tristate "ThrustMaster devices support"
|
||||
|
|
|
@ -24,6 +24,7 @@ endif
|
|||
|
||||
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
|
||||
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
|
||||
obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o
|
||||
obj-$(CONFIG_HID_APPLE) += hid-apple.o
|
||||
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
|
||||
obj-$(CONFIG_HID_CANDO) += hid-cando.o
|
||||
|
@ -32,6 +33,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
|||
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
|
||||
obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o
|
||||
obj-$(CONFIG_HID_EGALAX) += hid-egalax.o
|
||||
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
|
||||
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
|
||||
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
|
||||
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Force feedback support for ACRUX game controllers
|
||||
*
|
||||
* From what I have gathered, these devices are mass produced in China
|
||||
* by several vendors. They often share the same design as the original
|
||||
* Xbox 360 controller.
|
||||
*
|
||||
* 1a34:0802 "ACRUX USB GAMEPAD 8116"
|
||||
* - tested with a EXEQ EQ-PCU-02090 game controller.
|
||||
*
|
||||
* Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct axff_device {
|
||||
struct hid_report *report;
|
||||
};
|
||||
|
||||
static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
{
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
struct axff_device *axff = data;
|
||||
int left, right;
|
||||
|
||||
left = effect->u.rumble.strong_magnitude;
|
||||
right = effect->u.rumble.weak_magnitude;
|
||||
|
||||
dbg_hid("called with 0x%04x 0x%04x", left, right);
|
||||
|
||||
left = left * 0xff / 0xffff;
|
||||
right = right * 0xff / 0xffff;
|
||||
|
||||
axff->report->field[0]->value[0] = left;
|
||||
axff->report->field[1]->value[0] = right;
|
||||
axff->report->field[2]->value[0] = left;
|
||||
axff->report->field[3]->value[0] = right;
|
||||
dbg_hid("running with 0x%02x 0x%02x", left, right);
|
||||
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axff_init(struct hid_device *hid)
|
||||
{
|
||||
struct axff_device *axff;
|
||||
struct hid_report *report;
|
||||
struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
|
||||
struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct input_dev *dev = hidinput->input;
|
||||
int error;
|
||||
|
||||
if (list_empty(report_list)) {
|
||||
dev_err(&hid->dev, "no output reports found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
report = list_first_entry(report_list, struct hid_report, list);
|
||||
|
||||
if (report->maxfield < 4) {
|
||||
dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL);
|
||||
if (!axff)
|
||||
return -ENOMEM;
|
||||
|
||||
set_bit(FF_RUMBLE, dev->ffbit);
|
||||
|
||||
error = input_ff_create_memless(dev, axff, axff_play);
|
||||
if (error)
|
||||
goto err_free_mem;
|
||||
|
||||
axff->report = report;
|
||||
axff->report->field[0]->value[0] = 0x00;
|
||||
axff->report->field[1]->value[0] = 0x00;
|
||||
axff->report->field[2]->value[0] = 0x00;
|
||||
axff->report->field[3]->value[0] = 0x00;
|
||||
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
|
||||
|
||||
dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_mem:
|
||||
kfree(axff);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
int error;
|
||||
|
||||
dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
|
||||
|
||||
error = hid_parse(hdev);
|
||||
if (error) {
|
||||
dev_err(&hdev->dev, "parse failed\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
|
||||
if (error) {
|
||||
dev_err(&hdev->dev, "hw start failed\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = axff_init(hdev);
|
||||
if (error) {
|
||||
/*
|
||||
* Do not fail device initialization completely as device
|
||||
* may still be partially operable, just warn.
|
||||
*/
|
||||
dev_warn(&hdev->dev,
|
||||
"Failed to enable force feedback support, error: %d\n",
|
||||
error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id ax_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, ax_devices);
|
||||
|
||||
static struct hid_driver ax_driver = {
|
||||
.name = "acrux",
|
||||
.id_table = ax_devices,
|
||||
.probe = ax_probe,
|
||||
};
|
||||
|
||||
static int __init ax_init(void)
|
||||
{
|
||||
return hid_register_driver(&ax_driver);
|
||||
}
|
||||
|
||||
static void __exit ax_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&ax_driver);
|
||||
}
|
||||
|
||||
module_init(ax_init);
|
||||
module_exit(ax_exit);
|
||||
|
||||
MODULE_AUTHOR("Sergei Kolzun");
|
||||
MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1157,6 +1157,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
|||
|
||||
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
|
||||
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
|
||||
if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE)
|
||||
connect_mask |= HID_CONNECT_HIDINPUT_FORCE;
|
||||
if (hdev->bus != BUS_USB)
|
||||
connect_mask &= ~HID_CONNECT_HIDDEV;
|
||||
if (hid_hiddev(hdev))
|
||||
|
@ -1239,6 +1241,9 @@ static const struct hid_device_id hid_blacklist[] = {
|
|||
{ 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) },
|
||||
#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
|
||||
#endif
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
|
||||
|
@ -1294,6 +1299,7 @@ static const struct hid_device_id hid_blacklist[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
|
||||
|
@ -1375,10 +1381,10 @@ static const struct hid_device_id hid_blacklist[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
|
||||
{ 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) },
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* HID driver for Elecom BM084 (bluetooth mouse).
|
||||
* Removes a non-existing horizontal wheel from
|
||||
* the HID descriptor.
|
||||
* (This module is based on "hid-ortek".)
|
||||
*
|
||||
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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"
|
||||
|
||||
static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int rsize)
|
||||
{
|
||||
if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
|
||||
dev_info(&hdev->dev, "Fixing up Elecom BM084 "
|
||||
"report descriptor.\n");
|
||||
rdesc[47] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hid_device_id elecom_devices[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084)},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, elecom_devices);
|
||||
|
||||
static struct hid_driver elecom_driver = {
|
||||
.name = "elecom",
|
||||
.id_table = elecom_devices,
|
||||
.report_fixup = elecom_report_fixup
|
||||
};
|
||||
|
||||
static int __init elecom_init(void)
|
||||
{
|
||||
return hid_register_driver(&elecom_driver);
|
||||
}
|
||||
|
||||
static void __exit elecom_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&elecom_driver);
|
||||
}
|
||||
|
||||
module_init(elecom_init);
|
||||
module_exit(elecom_exit);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -34,6 +34,8 @@
|
|||
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
|
||||
#define USB_DEVICE_ID_ACECAD_302 0x0008
|
||||
|
||||
#define USB_VENDOR_ID_ACRUX 0x1a34
|
||||
|
||||
#define USB_VENDOR_ID_ADS_TECH 0x06e1
|
||||
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
|
||||
|
||||
|
@ -81,12 +83,12 @@
|
|||
#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
|
||||
|
@ -118,8 +120,8 @@
|
|||
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
|
||||
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
|
||||
|
||||
#define USB_VENDOR_ID_BELKIN 0x050d
|
||||
#define USB_DEVICE_ID_FLIP_KVM 0x3201
|
||||
#define USB_VENDOR_ID_BELKIN 0x050d
|
||||
#define USB_DEVICE_ID_FLIP_KVM 0x3201
|
||||
|
||||
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
|
||||
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
|
||||
|
@ -128,7 +130,7 @@
|
|||
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
|
||||
|
||||
#define USB_VENDOR_ID_CANDO 0x2087
|
||||
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
|
||||
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
|
||||
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
|
||||
|
||||
#define USB_VENDOR_ID_CH 0x068e
|
||||
|
@ -175,7 +177,7 @@
|
|||
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
|
||||
|
||||
#define USB_VENDOR_ID_DELORME 0x1163
|
||||
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
||||
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
||||
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
|
||||
|
||||
#define USB_VENDOR_ID_DMI 0x0c0b
|
||||
|
@ -187,20 +189,23 @@
|
|||
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
|
||||
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
|
||||
|
||||
#define USB_VENDOR_ID_ELECOM 0x056e
|
||||
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
|
||||
|
||||
#define USB_VENDOR_ID_ELO 0x04E7
|
||||
#define USB_DEVICE_ID_ELO_TS2700 0x0020
|
||||
|
||||
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
|
||||
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
|
||||
|
||||
#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
|
||||
#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
|
||||
|
||||
#define USB_VENDOR_ID_ETT 0x0664
|
||||
#define USB_DEVICE_ID_TC5UH 0x0309
|
||||
#define USB_DEVICE_ID_TC4UM 0x0306
|
||||
|
||||
#define USB_VENDOR_ID_EZKEY 0x0518
|
||||
#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9
|
||||
#define USB_DEVICE_ID_ETURBOTOUCH 0x0006
|
||||
|
||||
#define USB_VENDOR_ID_EZKEY 0x0518
|
||||
#define USB_DEVICE_ID_BTC_8193 0x0002
|
||||
|
||||
#define USB_VENDOR_ID_GAMERON 0x0810
|
||||
|
@ -297,9 +302,16 @@
|
|||
#define USB_VENDOR_ID_KBGEAR 0x084e
|
||||
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
|
||||
|
||||
#define USB_VENDOR_ID_KENSINGTON 0x047d
|
||||
#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041
|
||||
|
||||
#define USB_VENDOR_ID_KWORLD 0x1b80
|
||||
#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
|
||||
|
||||
#define USB_VENDOR_ID_KYE 0x0458
|
||||
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
|
||||
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
|
||||
|
||||
#define USB_VENDOR_ID_LABTEC 0x1020
|
||||
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
|
||||
|
||||
|
@ -319,9 +331,6 @@
|
|||
#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
|
||||
#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
|
||||
|
||||
#define USB_VENDOR_ID_KENSINGTON 0x047d
|
||||
#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041
|
||||
|
||||
#define USB_VENDOR_ID_LOGITECH 0x046d
|
||||
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
|
||||
|
@ -377,23 +386,23 @@
|
|||
#define USB_VENDOR_ID_MONTEREY 0x0566
|
||||
#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
|
||||
|
||||
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
|
||||
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
|
||||
|
||||
#define USB_VENDOR_ID_NATSU 0x08b7
|
||||
#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
|
||||
|
||||
#define USB_VENDOR_ID_NCR 0x0404
|
||||
#define USB_DEVICE_ID_NCR_FIRST 0x0300
|
||||
#define USB_DEVICE_ID_NCR_LAST 0x03ff
|
||||
|
||||
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
|
||||
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
|
||||
|
||||
#define USB_VENDOR_ID_NATSU 0x08b7
|
||||
#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
|
||||
|
||||
#define USB_VENDOR_ID_NEC 0x073e
|
||||
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
|
||||
|
||||
#define USB_VENDOR_ID_NEXTWINDOW 0x1926
|
||||
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
|
||||
|
||||
#define USB_VENDOR_ID_NTRIG 0x1b96
|
||||
#define USB_VENDOR_ID_NTRIG 0x1b96
|
||||
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
|
||||
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
|
||||
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0004
|
||||
|
@ -428,9 +437,12 @@
|
|||
#define USB_VENDOR_ID_PETALYNX 0x18b1
|
||||
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
|
||||
|
||||
#define USB_VENDOR_ID_PHILIPS 0x0471
|
||||
#define USB_VENDOR_ID_PHILIPS 0x0471
|
||||
#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
|
||||
|
||||
#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3
|
||||
#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
|
||||
|
||||
#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
|
||||
#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
|
||||
|
||||
|
@ -440,16 +452,16 @@
|
|||
#define USB_VENDOR_ID_PRODIGE 0x05af
|
||||
#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
|
||||
|
||||
#define USB_VENDOR_ID_QUANTA 0x0408
|
||||
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
|
||||
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
|
||||
|
||||
#define USB_VENDOR_ID_ROCCAT 0x1e7d
|
||||
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
|
||||
|
||||
#define USB_VENDOR_ID_SAITEK 0x06a3
|
||||
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
|
||||
|
||||
#define USB_VENDOR_ID_QUANTA 0x0408
|
||||
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
|
||||
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
|
||||
|
||||
#define USB_VENDOR_ID_SAMSUNG 0x0419
|
||||
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
|
||||
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
|
||||
|
@ -473,20 +485,23 @@
|
|||
|
||||
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
|
||||
|
||||
#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
|
||||
#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
|
||||
#define USB_VENDOR_ID_TOPSEED 0x0766
|
||||
#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
|
||||
|
||||
#define USB_VENDOR_ID_TOPSEED2 0x1784
|
||||
#define USB_DEVICE_ID_TOPSEED2_RF_COMBO 0x0004
|
||||
|
||||
#define USB_VENDOR_ID_TOPMAX 0x0663
|
||||
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
|
||||
|
||||
#define USB_VENDOR_ID_TOPSEED 0x0766
|
||||
#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
|
||||
#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
|
||||
#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
|
||||
|
||||
#define USB_VENDOR_ID_TURBOX 0x062a
|
||||
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
|
||||
|
||||
#define USB_VENDOR_ID_TWINHAN 0x6253
|
||||
#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
|
||||
#define USB_VENDOR_ID_TWINHAN 0x6253
|
||||
#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100
|
||||
|
||||
#define USB_VENDOR_ID_UCLOGIC 0x5543
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
|
||||
|
@ -501,7 +516,6 @@
|
|||
|
||||
#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
|
||||
|
@ -523,9 +537,4 @@
|
|||
#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
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -199,11 +199,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
case HID_GD_MOUSE:
|
||||
case HID_GD_POINTER: code += 0x110; break;
|
||||
case HID_GD_JOYSTICK:
|
||||
if (code <= 0xf)
|
||||
code += BTN_JOYSTICK;
|
||||
else
|
||||
code += BTN_TRIGGER_HAPPY;
|
||||
break;
|
||||
if (code <= 0xf)
|
||||
code += BTN_JOYSTICK;
|
||||
else
|
||||
code += BTN_TRIGGER_HAPPY;
|
||||
break;
|
||||
case HID_GD_GAMEPAD: code += 0x130; break;
|
||||
default:
|
||||
switch (field->physical) {
|
||||
|
@ -301,6 +301,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
|
||||
case HID_UP_DIGITIZER:
|
||||
switch (usage->hid & 0xff) {
|
||||
case 0x00: /* Undefined */
|
||||
goto ignore;
|
||||
|
||||
case 0x30: /* TipPressure */
|
||||
if (!test_bit(BTN_TOUCH, input->keybit)) {
|
||||
device->quirks |= HID_QUIRK_NOTOUCH;
|
||||
|
@ -480,7 +483,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
|
||||
case HID_UP_LOGIVENDOR:
|
||||
goto ignore;
|
||||
|
||||
|
||||
case HID_UP_PID:
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0xa4: map_key_clear(BTN_DEAD); break;
|
||||
|
@ -589,9 +592,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
|||
hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
|
||||
if (hat_dir < 0 || hat_dir > 8) hat_dir = 0;
|
||||
input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x);
|
||||
input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
|
||||
return;
|
||||
}
|
||||
input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
|
||||
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
|
||||
|
|
|
@ -30,6 +30,21 @@ static bool emulate_scroll_wheel = true;
|
|||
module_param(emulate_scroll_wheel, bool, 0644);
|
||||
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)
|
||||
return -EINVAL;
|
||||
scroll_speed = speed;
|
||||
return 0;
|
||||
}
|
||||
module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644);
|
||||
MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)");
|
||||
|
||||
static bool scroll_acceleration = false;
|
||||
module_param(scroll_acceleration, bool, 0644);
|
||||
MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
|
||||
|
||||
static bool report_touches = true;
|
||||
module_param(report_touches, bool, 0644);
|
||||
MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
|
||||
|
@ -50,6 +65,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
|
|||
#define TOUCH_STATE_START 0x30
|
||||
#define TOUCH_STATE_DRAG 0x40
|
||||
|
||||
#define SCROLL_ACCEL_DEFAULT 7
|
||||
|
||||
/**
|
||||
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
|
||||
* @input: Input device through which we report events.
|
||||
|
@ -78,8 +95,10 @@ struct magicmouse_sc {
|
|||
struct {
|
||||
short x;
|
||||
short y;
|
||||
short scroll_x;
|
||||
short scroll_y;
|
||||
u8 size;
|
||||
u8 down;
|
||||
} touches[16];
|
||||
int tracking_ids[16];
|
||||
};
|
||||
|
@ -141,7 +160,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
|
|||
input_report_key(msc->input, BTN_RIGHT, state & 2);
|
||||
|
||||
if (state != last_state)
|
||||
msc->scroll_accel = 0;
|
||||
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
|
||||
}
|
||||
|
||||
static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
|
||||
|
@ -152,6 +171,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
|||
int id = (misc >> 6) & 15;
|
||||
int x = x_y << 12 >> 20;
|
||||
int y = -(x_y >> 20);
|
||||
int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
|
||||
|
||||
/* Store tracking ID and other fields. */
|
||||
msc->tracking_ids[raw_id] = id;
|
||||
|
@ -160,42 +180,54 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
|||
msc->touches[id].size = misc & 63;
|
||||
|
||||
/* If requested, emulate a scroll wheel by detecting small
|
||||
* vertical touch motions along the middle of the mouse.
|
||||
* vertical touch motions.
|
||||
*/
|
||||
if (emulate_scroll_wheel &&
|
||||
middle_button_start < x && x < middle_button_stop) {
|
||||
static const int accel_profile[] = {
|
||||
256, 228, 192, 160, 128, 96, 64, 32,
|
||||
};
|
||||
if (emulate_scroll_wheel) {
|
||||
unsigned long now = jiffies;
|
||||
int step = msc->touches[id].scroll_y - y;
|
||||
|
||||
/* Reset acceleration after half a second. */
|
||||
if (time_after(now, msc->scroll_jiffies + HZ / 2))
|
||||
msc->scroll_accel = 0;
|
||||
int step_x = msc->touches[id].scroll_x - x;
|
||||
int step_y = msc->touches[id].scroll_y - y;
|
||||
|
||||
/* Calculate and apply the scroll motion. */
|
||||
switch (tdata[7] & TOUCH_STATE_MASK) {
|
||||
case TOUCH_STATE_START:
|
||||
msc->touches[id].scroll_x = x;
|
||||
msc->touches[id].scroll_y = y;
|
||||
msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
|
||||
ARRAY_SIZE(accel_profile) - 1);
|
||||
|
||||
/* Reset acceleration after half a second. */
|
||||
if (scroll_acceleration && time_before(now,
|
||||
msc->scroll_jiffies + HZ / 2))
|
||||
msc->scroll_accel = max_t(int,
|
||||
msc->scroll_accel - 1, 1);
|
||||
else
|
||||
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
|
||||
|
||||
break;
|
||||
case TOUCH_STATE_DRAG:
|
||||
step = step / accel_profile[msc->scroll_accel];
|
||||
if (step != 0) {
|
||||
msc->touches[id].scroll_y = y;
|
||||
step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
|
||||
if (step_x != 0) {
|
||||
msc->touches[id].scroll_x -= step_x *
|
||||
(64 - scroll_speed) * msc->scroll_accel;
|
||||
msc->scroll_jiffies = now;
|
||||
input_report_rel(input, REL_WHEEL, step);
|
||||
input_report_rel(input, REL_HWHEEL, -step_x);
|
||||
}
|
||||
|
||||
step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
|
||||
if (step_y != 0) {
|
||||
msc->touches[id].scroll_y -= step_y *
|
||||
(64 - scroll_speed) * msc->scroll_accel;
|
||||
msc->scroll_jiffies = now;
|
||||
input_report_rel(input, REL_WHEEL, step_y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the input events for this touch. */
|
||||
if (report_touches) {
|
||||
if (report_touches && down) {
|
||||
int orientation = (misc >> 10) - 32;
|
||||
|
||||
msc->touches[id].down = 1;
|
||||
|
||||
input_report_abs(input, ABS_MT_TRACKING_ID, id);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
|
||||
|
@ -215,7 +247,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
|||
{
|
||||
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
|
||||
struct input_dev *input = msc->input;
|
||||
int x, y, ts, ii, clicks;
|
||||
int x, y, ts, ii, clicks, last_up;
|
||||
|
||||
switch (data[0]) {
|
||||
case 0x10:
|
||||
|
@ -235,12 +267,26 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
|||
msc->ntouches = (size - 6) / 8;
|
||||
for (ii = 0; ii < msc->ntouches; ii++)
|
||||
magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
|
||||
|
||||
if (report_touches) {
|
||||
last_up = 1;
|
||||
for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
|
||||
if (msc->touches[ii].down) {
|
||||
last_up = 0;
|
||||
msc->touches[ii].down = 0;
|
||||
}
|
||||
}
|
||||
if (last_up) {
|
||||
input_mt_sync(input);
|
||||
}
|
||||
}
|
||||
|
||||
/* When emulating three-button mode, it is important
|
||||
* to have the current touch information before
|
||||
* generating a click event.
|
||||
*/
|
||||
x = (signed char)data[1];
|
||||
y = (signed char)data[2];
|
||||
x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
|
||||
y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
|
||||
clicks = data[3];
|
||||
break;
|
||||
case 0x20: /* Theoretically battery status (0-100), but I have
|
||||
|
@ -301,8 +347,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
|
|||
__set_bit(EV_REL, input->evbit);
|
||||
__set_bit(REL_X, input->relbit);
|
||||
__set_bit(REL_Y, input->relbit);
|
||||
if (emulate_scroll_wheel)
|
||||
if (emulate_scroll_wheel) {
|
||||
__set_bit(REL_WHEEL, input->relbit);
|
||||
__set_bit(REL_HWHEEL, input->relbit);
|
||||
}
|
||||
|
||||
if (report_touches) {
|
||||
__set_bit(EV_ABS, input->evbit);
|
||||
|
@ -345,6 +393,8 @@ static int magicmouse_probe(struct hid_device *hdev,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
|
||||
|
||||
msc->quirks = id->driver_data;
|
||||
hid_set_drvdata(hdev, msc);
|
||||
|
||||
|
|
|
@ -127,6 +127,26 @@ static const struct fb_var_screeninfo picolcdfb_var = {
|
|||
.height = 26,
|
||||
.bits_per_pixel = 1,
|
||||
.grayscale = 1,
|
||||
.red = {
|
||||
.offset = 0,
|
||||
.length = 1,
|
||||
.msb_right = 0,
|
||||
},
|
||||
.green = {
|
||||
.offset = 0,
|
||||
.length = 1,
|
||||
.msb_right = 0,
|
||||
},
|
||||
.blue = {
|
||||
.offset = 0,
|
||||
.length = 1,
|
||||
.msb_right = 0,
|
||||
},
|
||||
.transp = {
|
||||
.offset = 0,
|
||||
.length = 0,
|
||||
.msb_right = 0,
|
||||
},
|
||||
};
|
||||
#endif /* CONFIG_HID_PICOLCD_FB */
|
||||
|
||||
|
@ -188,6 +208,7 @@ struct picolcd_data {
|
|||
/* Framebuffer stuff */
|
||||
u8 fb_update_rate;
|
||||
u8 fb_bpp;
|
||||
u8 fb_force;
|
||||
u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */
|
||||
u8 *fb_bitmap; /* framebuffer */
|
||||
struct fb_info *fb_info;
|
||||
|
@ -346,7 +367,7 @@ static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
|
|||
const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
|
||||
for (i = 0; i < 64; i++) {
|
||||
tdata[i] <<= 1;
|
||||
tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01;
|
||||
tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
|
||||
}
|
||||
}
|
||||
} else if (bpp == 8) {
|
||||
|
@ -399,13 +420,10 @@ static int picolcd_fb_reset(struct picolcd_data *data, int clear)
|
|||
|
||||
if (data->fb_bitmap) {
|
||||
if (clear) {
|
||||
memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE);
|
||||
memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
|
||||
memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
|
||||
} else {
|
||||
/* invert 1 byte in each tile to force resend */
|
||||
for (i = 0; i < PICOLCDFB_SIZE; i += 64)
|
||||
data->fb_vbitmap[i] = ~data->fb_vbitmap[i];
|
||||
}
|
||||
data->fb_force = 1;
|
||||
}
|
||||
|
||||
/* schedule first output of framebuffer */
|
||||
|
@ -421,6 +439,9 @@ static void picolcd_fb_update(struct picolcd_data *data)
|
|||
int chip, tile, n;
|
||||
unsigned long flags;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
if (!(data->status & PICOLCD_READY_FB)) {
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
@ -440,14 +461,18 @@ static void picolcd_fb_update(struct picolcd_data *data)
|
|||
for (chip = 0; chip < 4; chip++)
|
||||
for (tile = 0; tile < 8; tile++)
|
||||
if (picolcd_fb_update_tile(data->fb_vbitmap,
|
||||
data->fb_bitmap, data->fb_bpp, chip, tile)) {
|
||||
data->fb_bitmap, data->fb_bpp, chip, tile) ||
|
||||
data->fb_force) {
|
||||
n += 2;
|
||||
if (!data->fb_info->par)
|
||||
return; /* device lost! */
|
||||
if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
|
||||
usbhid_wait_io(data->hdev);
|
||||
n = 0;
|
||||
}
|
||||
picolcd_fb_send_tile(data->hdev, chip, tile);
|
||||
}
|
||||
data->fb_force = false;
|
||||
if (n)
|
||||
usbhid_wait_io(data->hdev);
|
||||
}
|
||||
|
@ -511,11 +536,23 @@ static int picolcd_fb_blank(int blank, struct fb_info *info)
|
|||
static void picolcd_fb_destroy(struct fb_info *info)
|
||||
{
|
||||
struct picolcd_data *data = info->par;
|
||||
u32 *ref_cnt = info->pseudo_palette;
|
||||
int may_release;
|
||||
|
||||
info->par = NULL;
|
||||
if (data)
|
||||
data->fb_info = NULL;
|
||||
fb_deferred_io_cleanup(info);
|
||||
framebuffer_release(info);
|
||||
|
||||
ref_cnt--;
|
||||
mutex_lock(&info->lock);
|
||||
(*ref_cnt)--;
|
||||
may_release = !ref_cnt;
|
||||
mutex_unlock(&info->lock);
|
||||
if (may_release) {
|
||||
framebuffer_release(info);
|
||||
vfree((u8 *)info->fix.smem_start);
|
||||
}
|
||||
}
|
||||
|
||||
static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
|
@ -526,29 +563,37 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i
|
|||
/* only allow 1/8 bit depth (8-bit is grayscale) */
|
||||
*var = picolcdfb_var;
|
||||
var->activate = activate;
|
||||
if (bpp >= 8)
|
||||
if (bpp >= 8) {
|
||||
var->bits_per_pixel = 8;
|
||||
else
|
||||
var->red.length = 8;
|
||||
var->green.length = 8;
|
||||
var->blue.length = 8;
|
||||
} else {
|
||||
var->bits_per_pixel = 1;
|
||||
var->red.length = 1;
|
||||
var->green.length = 1;
|
||||
var->blue.length = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int picolcd_set_par(struct fb_info *info)
|
||||
{
|
||||
struct picolcd_data *data = info->par;
|
||||
u8 *o_fb, *n_fb;
|
||||
u8 *tmp_fb, *o_fb;
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
if (info->var.bits_per_pixel == data->fb_bpp)
|
||||
return 0;
|
||||
/* switch between 1/8 bit depths */
|
||||
if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
|
||||
return -EINVAL;
|
||||
|
||||
o_fb = data->fb_bitmap;
|
||||
n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel);
|
||||
if (!n_fb)
|
||||
o_fb = data->fb_bitmap;
|
||||
tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
|
||||
if (!tmp_fb)
|
||||
return -ENOMEM;
|
||||
|
||||
fb_deferred_io_cleanup(info);
|
||||
/* translate FB content to new bits-per-pixel */
|
||||
if (info->var.bits_per_pixel == 1) {
|
||||
int i, b;
|
||||
|
@ -558,24 +603,87 @@ static int picolcd_set_par(struct fb_info *info)
|
|||
p <<= 1;
|
||||
p |= o_fb[i*8+b] ? 0x01 : 0x00;
|
||||
}
|
||||
tmp_fb[i] = p;
|
||||
}
|
||||
memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
|
||||
info->fix.visual = FB_VISUAL_MONO01;
|
||||
info->fix.line_length = PICOLCDFB_WIDTH / 8;
|
||||
} else {
|
||||
int i;
|
||||
memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
|
||||
for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
|
||||
n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
|
||||
info->fix.visual = FB_VISUAL_TRUECOLOR;
|
||||
o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
|
||||
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
|
||||
info->fix.line_length = PICOLCDFB_WIDTH;
|
||||
}
|
||||
|
||||
data->fb_bitmap = n_fb;
|
||||
kfree(tmp_fb);
|
||||
data->fb_bpp = info->var.bits_per_pixel;
|
||||
info->screen_base = (char __force __iomem *)n_fb;
|
||||
info->fix.smem_start = (unsigned long)n_fb;
|
||||
info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp;
|
||||
fb_deferred_io_init(info);
|
||||
vfree(o_fb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do refcounting on our FB and cleanup per worker if FB is
|
||||
* closed after unplug of our device
|
||||
* (fb_release holds info->lock and still touches info after
|
||||
* we return so we can't release it immediately.
|
||||
*/
|
||||
struct picolcd_fb_cleanup_item {
|
||||
struct fb_info *info;
|
||||
struct picolcd_fb_cleanup_item *next;
|
||||
};
|
||||
static struct picolcd_fb_cleanup_item *fb_pending;
|
||||
DEFINE_SPINLOCK(fb_pending_lock);
|
||||
|
||||
static void picolcd_fb_do_cleanup(struct work_struct *data)
|
||||
{
|
||||
struct picolcd_fb_cleanup_item *item;
|
||||
unsigned long flags;
|
||||
|
||||
do {
|
||||
spin_lock_irqsave(&fb_pending_lock, flags);
|
||||
item = fb_pending;
|
||||
fb_pending = item ? item->next : NULL;
|
||||
spin_unlock_irqrestore(&fb_pending_lock, flags);
|
||||
|
||||
if (item) {
|
||||
u8 *fb = (u8 *)item->info->fix.smem_start;
|
||||
/* make sure we do not race against fb core when
|
||||
* releasing */
|
||||
mutex_lock(&item->info->lock);
|
||||
mutex_unlock(&item->info->lock);
|
||||
framebuffer_release(item->info);
|
||||
vfree(fb);
|
||||
}
|
||||
} while (item);
|
||||
}
|
||||
|
||||
DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
|
||||
|
||||
static int picolcd_fb_open(struct fb_info *info, int u)
|
||||
{
|
||||
u32 *ref_cnt = info->pseudo_palette;
|
||||
ref_cnt--;
|
||||
|
||||
(*ref_cnt)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int picolcd_fb_release(struct fb_info *info, int u)
|
||||
{
|
||||
u32 *ref_cnt = info->pseudo_palette;
|
||||
ref_cnt--;
|
||||
|
||||
(*ref_cnt)++;
|
||||
if (!*ref_cnt) {
|
||||
unsigned long flags;
|
||||
struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
|
||||
item--;
|
||||
spin_lock_irqsave(&fb_pending_lock, flags);
|
||||
item->next = fb_pending;
|
||||
fb_pending = item;
|
||||
spin_unlock_irqrestore(&fb_pending_lock, flags);
|
||||
schedule_work(&picolcd_fb_cleanup);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -583,6 +691,8 @@ static int picolcd_set_par(struct fb_info *info)
|
|||
static struct fb_ops picolcdfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_destroy = picolcd_fb_destroy,
|
||||
.fb_open = picolcd_fb_open,
|
||||
.fb_release = picolcd_fb_release,
|
||||
.fb_read = fb_sys_read,
|
||||
.fb_write = picolcd_fb_write,
|
||||
.fb_blank = picolcd_fb_blank,
|
||||
|
@ -660,11 +770,12 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
|
|||
{
|
||||
struct device *dev = &data->hdev->dev;
|
||||
struct fb_info *info = NULL;
|
||||
int error = -ENOMEM;
|
||||
int i, error = -ENOMEM;
|
||||
u8 *fb_vbitmap = NULL;
|
||||
u8 *fb_bitmap = NULL;
|
||||
u32 *palette;
|
||||
|
||||
fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel);
|
||||
fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
|
||||
if (fb_bitmap == NULL) {
|
||||
dev_err(dev, "can't get a free page for framebuffer\n");
|
||||
goto err_nomem;
|
||||
|
@ -678,18 +789,29 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
|
|||
|
||||
data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
|
||||
data->fb_defio = picolcd_fb_defio;
|
||||
info = framebuffer_alloc(0, dev);
|
||||
/* The extra memory is:
|
||||
* - struct picolcd_fb_cleanup_item
|
||||
* - u32 for ref_count
|
||||
* - 256*u32 for pseudo_palette
|
||||
*/
|
||||
info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
|
||||
if (info == NULL) {
|
||||
dev_err(dev, "failed to allocate a framebuffer\n");
|
||||
goto err_nomem;
|
||||
}
|
||||
|
||||
palette = info->par + sizeof(struct picolcd_fb_cleanup_item);
|
||||
*palette = 1;
|
||||
palette++;
|
||||
for (i = 0; i < 256; i++)
|
||||
palette[i] = i > 0 && i < 16 ? 0xff : 0;
|
||||
info->pseudo_palette = palette;
|
||||
info->fbdefio = &data->fb_defio;
|
||||
info->screen_base = (char __force __iomem *)fb_bitmap;
|
||||
info->fbops = &picolcdfb_ops;
|
||||
info->var = picolcdfb_var;
|
||||
info->fix = picolcdfb_fix;
|
||||
info->fix.smem_len = PICOLCDFB_SIZE;
|
||||
info->fix.smem_len = PICOLCDFB_SIZE*8;
|
||||
info->fix.smem_start = (unsigned long)fb_bitmap;
|
||||
info->par = data;
|
||||
info->flags = FBINFO_FLAG_DEFAULT;
|
||||
|
@ -707,18 +829,20 @@ static int picolcd_init_framebuffer(struct picolcd_data *data)
|
|||
dev_err(dev, "failed to create sysfs attributes\n");
|
||||
goto err_cleanup;
|
||||
}
|
||||
fb_deferred_io_init(info);
|
||||
data->fb_info = info;
|
||||
error = register_framebuffer(info);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to register framebuffer\n");
|
||||
goto err_sysfs;
|
||||
}
|
||||
fb_deferred_io_init(info);
|
||||
/* schedule first output of framebuffer */
|
||||
data->fb_force = 1;
|
||||
schedule_delayed_work(&info->deferred_work, 0);
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
fb_deferred_io_cleanup(info);
|
||||
device_remove_file(dev, &dev_attr_fb_update_rate);
|
||||
err_cleanup:
|
||||
data->fb_vbitmap = NULL;
|
||||
|
@ -737,19 +861,17 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data)
|
|||
{
|
||||
struct fb_info *info = data->fb_info;
|
||||
u8 *fb_vbitmap = data->fb_vbitmap;
|
||||
u8 *fb_bitmap = data->fb_bitmap;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
info->par = NULL;
|
||||
device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
|
||||
unregister_framebuffer(info);
|
||||
data->fb_vbitmap = NULL;
|
||||
data->fb_bitmap = NULL;
|
||||
data->fb_bpp = 0;
|
||||
data->fb_info = NULL;
|
||||
device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
|
||||
fb_deferred_io_cleanup(info);
|
||||
unregister_framebuffer(info);
|
||||
vfree(fb_bitmap);
|
||||
kfree(fb_vbitmap);
|
||||
}
|
||||
|
||||
|
@ -2566,6 +2688,13 @@ static void picolcd_remove(struct hid_device *hdev)
|
|||
spin_lock_irqsave(&data->lock, flags);
|
||||
data->status |= PICOLCD_FAILED;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
#ifdef CONFIG_HID_PICOLCD_FB
|
||||
/* short-circuit FB as early as possible in order to
|
||||
* avoid long delays if we host console.
|
||||
*/
|
||||
if (data->fb_info)
|
||||
data->fb_info->par = NULL;
|
||||
#endif
|
||||
|
||||
picolcd_exit_devfs(data);
|
||||
device_remove_file(&hdev->dev, &dev_attr_operation_mode);
|
||||
|
@ -2623,6 +2752,10 @@ static int __init picolcd_init(void)
|
|||
static void __exit picolcd_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&picolcd_driver);
|
||||
#ifdef CONFIG_HID_PICOLCD_FB
|
||||
flush_scheduled_work();
|
||||
WARN_ON(fb_pending);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(picolcd_init);
|
||||
|
|
|
@ -22,11 +22,6 @@
|
|||
* Is it possible to remove and reinstall the urb in raw-event- or any
|
||||
* other handler, or to defer this action to be executed somewhere else?
|
||||
*
|
||||
* TODO implement notification mechanism for overlong macro execution
|
||||
* If user wants to execute an overlong macro only the names of macroset
|
||||
* and macro are given. Should userland tap hidraw or is there an
|
||||
* additional streaming mechanism?
|
||||
*
|
||||
* TODO is it possible to overwrite group for sysfs attributes via udev?
|
||||
*/
|
||||
|
||||
|
@ -277,7 +272,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
|
|||
count = sizeof(struct kone_settings) - off;
|
||||
|
||||
mutex_lock(&kone->kone_lock);
|
||||
memcpy(buf, &kone->settings + off, count);
|
||||
memcpy(buf, ((char const *)&kone->settings) + off, count);
|
||||
mutex_unlock(&kone->kone_lock);
|
||||
|
||||
return count;
|
||||
|
@ -337,7 +332,7 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
|
|||
count = sizeof(struct kone_profile) - off;
|
||||
|
||||
mutex_lock(&kone->kone_lock);
|
||||
memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile));
|
||||
memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
|
||||
mutex_unlock(&kone->kone_lock);
|
||||
|
||||
return count;
|
||||
|
@ -622,18 +617,6 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* This file is used by userland software to find devices that are handled by
|
||||
* this driver. This provides a consistent way for actual and older kernels
|
||||
* where this driver replaced usbhid instead of generic-usb.
|
||||
* Driver capabilities are determined by version number.
|
||||
*/
|
||||
static ssize_t kone_sysfs_show_driver_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Read actual dpi settings.
|
||||
* Returns raw value for further processing. Refer to enum kone_polling_rates to
|
||||
|
@ -671,9 +654,6 @@ static DEVICE_ATTR(startup_profile, 0660,
|
|||
kone_sysfs_show_startup_profile,
|
||||
kone_sysfs_set_startup_profile);
|
||||
|
||||
static DEVICE_ATTR(kone_driver_version, 0440,
|
||||
kone_sysfs_show_driver_version, NULL);
|
||||
|
||||
static struct attribute *kone_attributes[] = {
|
||||
&dev_attr_actual_dpi.attr,
|
||||
&dev_attr_actual_profile.attr,
|
||||
|
@ -681,7 +661,6 @@ static struct attribute *kone_attributes[] = {
|
|||
&dev_attr_firmware_version.attr,
|
||||
&dev_attr_tcu.attr,
|
||||
&dev_attr_startup_profile.attr,
|
||||
&dev_attr_kone_driver_version.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1"
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ static int roccat_open(struct inode *inode, struct file *file)
|
|||
printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
|
||||
minor);
|
||||
error = -ENODEV;
|
||||
goto exit_unlock;
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
if (!device->open++) {
|
||||
|
@ -178,7 +178,7 @@ static int roccat_open(struct inode *inode, struct file *file)
|
|||
PM_HINT_FULLON);
|
||||
if (error < 0) {
|
||||
--device->open;
|
||||
goto exit_unlock;
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
error = device->hid->ll_driver->open(device->hid);
|
||||
|
@ -187,7 +187,7 @@ static int roccat_open(struct inode *inode, struct file *file)
|
|||
device->hid->ll_driver->power(device->hid,
|
||||
PM_HINT_NORMAL);
|
||||
--device->open;
|
||||
goto exit_unlock;
|
||||
goto exit_err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +202,9 @@ exit_unlock:
|
|||
mutex_unlock(&device->readers_lock);
|
||||
mutex_unlock(&devices_lock);
|
||||
return error;
|
||||
exit_err:
|
||||
kfree(reader);
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
static int roccat_release(struct inode *inode, struct file *file)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE)
|
||||
#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
|
||||
int roccat_connect(struct hid_device *hid);
|
||||
void roccat_disconnect(int minor);
|
||||
int roccat_report_event(int minor, u8 const *data, int len);
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
*
|
||||
* Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by
|
||||
* Wayne Thomas 2010.
|
||||
*
|
||||
* Modified to support Conceptronic CLLRCMCE by
|
||||
* Kees Bakker 2010.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -34,6 +37,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
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 0x027: ts_map_key_clear(KEY_MODE); 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;
|
||||
|
@ -60,6 +64,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) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, ts_devices);
|
||||
|
|
|
@ -436,7 +436,7 @@ static void wacom_remove(struct hid_device *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);
|
||||
|
|
|
@ -46,7 +46,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
|
|||
{
|
||||
struct hidraw_list *list = file->private_data;
|
||||
int ret = 0, len;
|
||||
char *report;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
mutex_lock(&list->read_mutex);
|
||||
|
@ -84,7 +83,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
report = list->buffer[list->tail].value;
|
||||
len = list->buffer[list->tail].len > count ?
|
||||
count : list->buffer[list->tail].len;
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ struct hiddev_list {
|
|||
struct mutex thread_lock;
|
||||
};
|
||||
|
||||
static struct hiddev *hiddev_table[HIDDEV_MINORS];
|
||||
static struct usb_driver hiddev_driver;
|
||||
|
||||
/*
|
||||
* Find a report, given the report's type and ID. The ID can be specified
|
||||
|
@ -265,22 +265,19 @@ static int hiddev_release(struct inode * inode, struct file * file)
|
|||
static int hiddev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct hiddev_list *list;
|
||||
int res, i;
|
||||
struct usb_interface *intf;
|
||||
struct hiddev *hiddev;
|
||||
int res;
|
||||
|
||||
/* See comment in hiddev_connect() for BKL explanation */
|
||||
lock_kernel();
|
||||
i = iminor(inode) - HIDDEV_MINOR_BASE;
|
||||
|
||||
if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
|
||||
intf = usb_find_interface(&hiddev_driver, iminor(inode));
|
||||
if (!intf)
|
||||
return -ENODEV;
|
||||
hiddev = usb_get_intfdata(intf);
|
||||
|
||||
if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
mutex_init(&list->thread_lock);
|
||||
|
||||
list->hiddev = hiddev_table[i];
|
||||
|
||||
|
||||
list->hiddev = hiddev;
|
||||
file->private_data = list;
|
||||
|
||||
/*
|
||||
|
@ -289,7 +286,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
|
|||
*/
|
||||
if (list->hiddev->exist) {
|
||||
if (!list->hiddev->open++) {
|
||||
res = usbhid_open(hiddev_table[i]->hid);
|
||||
res = usbhid_open(hiddev->hid);
|
||||
if (res < 0) {
|
||||
res = -EIO;
|
||||
goto bail;
|
||||
|
@ -301,12 +298,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
|
||||
spin_lock_irq(&list->hiddev->list_lock);
|
||||
list_add_tail(&list->node, &hiddev_table[i]->list);
|
||||
list_add_tail(&list->node, &hiddev->list);
|
||||
spin_unlock_irq(&list->hiddev->list_lock);
|
||||
|
||||
if (!list->hiddev->open++)
|
||||
if (list->hiddev->exist) {
|
||||
struct hid_device *hid = hiddev_table[i]->hid;
|
||||
struct hid_device *hid = hiddev->hid;
|
||||
res = usbhid_get_power(hid);
|
||||
if (res < 0) {
|
||||
res = -EIO;
|
||||
|
@ -314,13 +311,10 @@ static int hiddev_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
usbhid_open(hid);
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
bail:
|
||||
file->private_data = NULL;
|
||||
kfree(list);
|
||||
unlock_kernel();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -894,37 +888,14 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
|
|||
hid->hiddev = hiddev;
|
||||
hiddev->hid = hid;
|
||||
hiddev->exist = 1;
|
||||
|
||||
/*
|
||||
* BKL here is used to avoid race after usb_register_dev().
|
||||
* Once the device node has been created, open() could happen on it.
|
||||
* The code below will then fail, as hiddev_table hasn't been
|
||||
* updated.
|
||||
*
|
||||
* The obvious fix -- introducing mutex to guard hiddev_table[]
|
||||
* doesn't work, as usb_open() and usb_register_dev() both take
|
||||
* minor_rwsem, thus we'll have ABBA deadlock.
|
||||
*
|
||||
* Before BKL pushdown, usb_open() had been acquiring it in right
|
||||
* order, so _open() was safe to use it to protect from this race.
|
||||
* Now the order is different, but AB-BA deadlock still doesn't occur
|
||||
* as BKL is dropped on schedule() (i.e. while sleeping on
|
||||
* minor_rwsem). Fugly.
|
||||
*/
|
||||
lock_kernel();
|
||||
usb_set_intfdata(usbhid->intf, usbhid);
|
||||
retval = usb_register_dev(usbhid->intf, &hiddev_class);
|
||||
if (retval) {
|
||||
err_hid("Not able to get a minor for this device.");
|
||||
hid->hiddev = NULL;
|
||||
unlock_kernel();
|
||||
kfree(hiddev);
|
||||
return -1;
|
||||
} else {
|
||||
hid->minor = usbhid->intf->minor;
|
||||
hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -942,7 +913,6 @@ void hiddev_disconnect(struct hid_device *hid)
|
|||
hiddev->exist = 0;
|
||||
mutex_unlock(&hiddev->existancelock);
|
||||
|
||||
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
|
||||
usb_deregister_dev(usbhid->intf, &hiddev_class);
|
||||
|
||||
if (hiddev->open) {
|
||||
|
|
|
@ -311,6 +311,7 @@ struct hid_item {
|
|||
#define HID_QUIRK_HIDDEV_FORCE 0x00000010
|
||||
#define HID_QUIRK_BADPAD 0x00000020
|
||||
#define HID_QUIRK_MULTI_INPUT 0x00000040
|
||||
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
|
||||
|
|
Загрузка…
Ссылка в новой задаче