Commit ee9ec4f8 authored by Linus Torvalds's avatar Linus Torvalds

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: (36 commits)
  HID: hid-multitouch: cosmetic changes, sort classes and devices
  HID: hid-multitouch: class MT_CLS_STANTUM is redundant with MT_CLS_CONFIDENCE
  HID: hid-multitouch: add support for Unitec panels
  HID: hid-multitouch: add support for Touch International panels
  HID: hid-multitouch: add support for GoodTouch panels
  HID: hid-multitouch: add support for CVTouch panels
  HID: hid-multitouch: add support for ActionStar panels
  HID: hiddev: fix race between hiddev_disconnect and hiddev_release
  HID: magicmouse: ignore 'ivalid report id' while switching modes
  HID: fix a crash in hid_report_raw_event() function.
  HID: hid-multitouch: add support for Elo TouchSystems 2515 IntelliTouch Plus
  HID: assorted usage updates from hut 1.12
  HID: roccat: fix actual/startup profile sysfs attribute in koneplus
  HID: hid-multitouch: Add support for Lumio panels
  HID: 'name' and 'phys' in 'struct hid_device' can never be NULL
  HID: hid-multitouch: add support for Ilitek dual-touch panel
  HID: picolcd: Avoid compile warning/error triggered by copy_from_user()
  HID: add support for Logitech G27 wheel
  HID: hiddev: fix error path in hiddev_read when interrupted
  HID: add support for Sony Navigation Controller
  ...
parents e0c6b8a1 366a2382
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the actual
profile. This value is persistent, so its equivalent to the
profile that's active when the mouse is powered on next time.
When written, this file sets the number of the startup profile
and the mouse activates this profile immediately.
Please use actual_profile, it does the same thing.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in
range 0-4.
This file is readonly.
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the actual
profile. This value is persistent, so its equivalent to the
profile that's active when the mouse is powered on next time.
When written, this file sets the number of the startup profile
and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version
......@@ -89,16 +92,6 @@ Description: The mouse has a tracking- and a distance-control-unit. These
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the profile
that's active when the mouse is powered on.
When written, this file sets the number of the startup profile
and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
......
HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
==================================================================
The hidraw driver provides a raw interface to USB and Bluetooth Human
Interface Devices (HIDs). It differs from hiddev in that reports sent and
received are not parsed by the HID parser, but are sent to and received from
the device unmodified.
Hidraw should be used if the userspace application knows exactly how to
communicate with the hardware device, and is able to construct the HID
reports manually. This is often the case when making userspace drivers for
custom HID devices.
Hidraw is also useful for communicating with non-conformant HID devices
which send and receive data in a way that is inconsistent with their report
descriptors. Because hiddev parses reports which are sent and received
through it, checking them against the device's report descriptor, such
communication with these non-conformant devices is impossible using hiddev.
Hidraw is the only alternative, short of writing a custom kernel driver, for
these non-conformant devices.
A benefit of hidraw is that its use by userspace applications is independent
of the underlying hardware type. Currently, Hidraw is implemented for USB
and Bluetooth. In the future, as new hardware bus types are developed which
use the HID specification, hidraw will be expanded to add support for these
new bus types.
Hidraw uses a dynamic major number, meaning that udev should be relied on to
create hidraw device nodes. Udev will typically create the device nodes
directly under /dev (eg: /dev/hidraw0). As this location is distribution-
and udev rule-dependent, applications should use libudev to locate hidraw
devices attached to the system. There is a tutorial on libudev with a
working example at:
http://www.signal11.us/oss/udev/
The HIDRAW API
---------------
read()
-------
read() will read a queued report received from the HID device. On USB
devices, the reports read using read() are the reports sent from the device
on the INTERRUPT IN endpoint. By default, read() will block until there is
a report available to be read. read() can be made non-blocking, by passing
the O_NONBLOCK flag to open(), or by setting the O_NONBLOCK flag using
fcntl().
On a device which uses numbered reports, the first byte of the returned data
will be the report number; the report data follows, beginning in the second
byte. For devices which do not use numbered reports, the report data
will begin at the first byte.
write()
--------
The write() function will write a report to the device. For USB devices, if
the device has an INTERRUPT OUT endpoint, the report will be sent on that
endpoint. If it does not, the report will be sent over the control endpoint,
using a SET_REPORT transfer.
The first byte of the buffer passed to write() should be set to the report
number. If the device does not use numbered reports, the first byte should
be set to 0. The report data itself should begin at the second byte.
ioctl()
--------
Hidraw supports the following ioctls:
HIDIOCGRDESCSIZE: Get Report Descriptor Size
This ioctl will get the size of the device's report descriptor.
HIDIOCGRDESC: Get Report Descriptor
This ioctl returns the device's report descriptor using a
hidraw_report_descriptor struct. Make sure to set the size field of the
hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
HIDIOCGRAWINFO: Get Raw Info
This ioctl will return a hidraw_devinfo struct containing the bus type, the
vendor ID (VID), and product ID (PID) of the device. The bus type can be one
of:
BUS_USB
BUS_HIL
BUS_BLUETOOTH
BUS_VIRTUAL
which are defined in linux/input.h.
HIDIOCGRAWNAME(len): Get Raw Name
This ioctl returns a string containing the vendor and product strings of
the device. The returned string is Unicode, UTF-8 encoded.
HIDIOCGRAWPHYS(len): Get Physical Address
This ioctl returns a string representing the physical address of the device.
For USB devices, the string contains the physical path to the device (the
USB controller, hubs, ports, etc). For Bluetooth devices, the string
contains the hardware (MAC) address of the device.
HIDIOCSFEATURE(len): Send a Feature Report
This ioctl will send a feature report to the device. Per the HID
specification, feature reports are always sent using the control endpoint.
Set the first byte of the supplied buffer to the report number. For devices
which do not use numbered reports, set the first byte to 0. The report data
begins in the second byte. Make sure to set len accordingly, to one more
than the length of the report (to account for the report number).
HIDIOCGFEATURE(len): Get a Feature Report
This ioctl will request a feature report from the device using the control
endpoint. The first byte of the supplied buffer should be set to the report
number of the requested report. For devices which do not use numbered
reports, set the first byte to 0. The report will be returned starting at
the first byte of the buffer (ie: the report number is not returned).
Example
---------
In samples/, find hid-example.c, which shows examples of read(), write(),
and all the ioctls for hidraw. The code may be used by anyone for any
purpose, and can serve as a starting point for developing applications using
hidraw.
Document by:
Alan Ott <alan@signal11.us>, Signal 11 Software
......@@ -55,12 +55,6 @@ source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
depends on HID
config HID_3M_PCT
tristate "3M PCT touchscreen"
depends on USB_HID
---help---
Support for 3M PCT touch screens.
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
depends on USB_HID
......@@ -100,12 +94,6 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
config HID_CANDO
tristate "Cando dual touch panel"
depends on USB_HID
---help---
Support for Cando dual touch panel.
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID
......@@ -300,12 +288,6 @@ config HID_MICROSOFT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MOSART
tristate "MosArt dual-touch panels"
depends on USB_HID
---help---
Support for MosArt dual-touch panels.
config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID
......@@ -320,13 +302,25 @@ config HID_MULTITOUCH
Generic support for HID multitouch panels.
Say Y here if you have one of the following devices:
- 3M PCT touch screens
- ActionStar dual touch panels
- Cando dual touch panels
- CVTouch panels
- Cypress TrueTouch panels
- Elo TouchSystems IntelliTouch Plus panels
- GeneralTouch 'Sensing Win7-TwoFinger' panels
- GoodTouch panels
- Hanvon dual touch panels
- Ilitek dual touch panels
- IrTouch Infrared USB panels
- Lumio CrystalTouch panels
- MosArt dual-touch panels
- PenMount dual touch panels
- Pixcir dual touch panels
- 'Sensing Win7-TwoFinger' panel by GeneralTouch
- eGalax dual-touch panels, including the
Joojoo and Wetab tablets
- eGalax dual-touch panels, including the Joojoo and Wetab tablets
- Stantum multitouch panels
- Touch International Panels
- Unitec Panels
If unsure, say N.
......@@ -500,12 +494,6 @@ config HID_SONY
---help---
Support for Sony PS3 controller.
config HID_STANTUM
tristate "Stantum multitouch panel"
depends on USB_HID
---help---
Support for Stantum multitouch panel.
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
depends on USB_HID
......
......@@ -25,12 +25,10 @@ ifdef CONFIG_LOGIWII_FF
hid-logitech-y += hid-lg4ff.o
endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
......@@ -47,7 +45,6 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MOSART) += hid-mosart.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
......@@ -66,7 +63,6 @@ obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
obj-$(CONFIG_HID_STANTUM) += hid-stantum.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
......
/*
* HID driver for 3M PCT multitouch panels
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/
/*
* 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/slab.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("3M PCT multitouch panels");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
#define SN_WIDTH 128
struct mmm_finger {
__s32 x, y, w, h;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
__u8 curid;
__u8 nexp, nreal;
bool touch, valid;
};
static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
int f1 = field->logical_minimum;
int f2 = field->logical_maximum;
int df = f2 - f1;
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_BUTTON:
return -1;
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
input_set_abs_params(hi->input, ABS_MT_POSITION_X,
f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
f1, f2, df / SN_MOVE, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
f1, f2, df / SN_MOVE, 0);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
f1, f2, df / SN_MOVE, 0);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
/* we do not want to map these: no input-oriented meaning */
case 0x14:
case 0x23:
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
case HID_DG_INRANGE:
case HID_DG_CONFIDENCE:
return -1;
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
f1, f2, df / SN_WIDTH, 0);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
f1, f2, df / SN_WIDTH, 0);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
input_mt_init_slots(hi->input, MAX_SLOTS);
return 1;
}
/* let hid-input decide for the others */
return 0;
case 0xff000000:
/* we do not want to map these: no input-oriented meaning */
return -1;
}
return 0;
}
static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
/* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
set_bit(usage->type, hi->input->evbit);
return -1;
}
/*
* this function is called when a whole packet has been received and processed,
* so that it can decide what to send to the input layer.
*/
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
int i;
for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i];
if (!f->valid) {
/* this finger is just placeholder data, ignore */
continue;
}
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
/* divided by two to match visual scale of touch */
int major = max(f->w, f->h) >> 1;
int minor = min(f->w, f->h) >> 1;
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
}
f->valid = 0;
}
input_mt_report_pointer_emulation(input, true);
input_sync(input);
}
/*
* this function is called upon all reports
* so that we can accumulate contact point information,
* and call input_mt_sync after each point.
*/
static int mmm_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct mmm_data *md = hid_get_drvdata(hid);
/*
* strangely, this function can be called before
* field->hidinput is initialized!
*/
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_TIPSWITCH:
md->touch = value;
break;
case HID_DG_CONFIDENCE:
md->valid = value;
break;
case HID_DG_WIDTH:
if (md->valid)
md->f[md->curid].w = value;
break;
case HID_DG_HEIGHT:
if (md->valid)
md->f[md->curid].h = value;
break;
case HID_DG_CONTACTID:
value = clamp_val(value, 0, MAX_SLOTS - 1);
if (md->valid) {
md->curid = value;
md->f[value].touch = md->touch;
md->f[value].valid = 1;
md->nreal++;
}
break;
case HID_GD_X:
if (md->valid)
md->f[md->curid].x = value;
break;
case HID_GD_Y:
if (md->valid)
md->f[md->curid].y = value;
break;
case HID_DG_CONTACTCOUNT:
if (value)
md->nexp = value;
if (md->nreal >= md->nexp) {
mmm_filter_event(md, input);
md->nreal = 0;
}
break;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct mmm_data *md;
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
if (!md) {
hid_err(hdev, "cannot allocate 3M data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, md);
ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
kfree(md);
return ret;
}
static void mmm_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id mmm_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ }
};
MODULE_DEVICE_TABLE(hid, mmm_devices);
static const struct hid_usage_id mmm_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver mmm_driver = {
.name = "3m-pct",
.id_table = mmm_devices,
.probe = mmm_probe,
.remove = mmm_remove,
.input_mapping = mmm_input_mapping,
.input_mapped = mmm_input_mapped,
.usage_table = mmm_grabbed_usages,
.event = mmm_event,
};
static int __init mmm_init(void)
{
return hid_register_driver(&mmm_driver);
}
static void __exit mmm_exit(void)
{
hid_unregister_driver(&mmm_driver);
}
module_init(mmm_init);
module_exit(mmm_exit);
/*
* HID driver for Cando dual-touch panels
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
*
*/
/*
* 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/slab.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("Cando dual-touch panel");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
struct cando_data {
__u16 x, y;
__u8 id;
__s8 oldest; /* id of the oldest finger in previous frame */
bool valid; /* valid finger data, or just placeholder? */
bool first; /* is this the first finger in this frame? */
__s8 firstid; /* id of the first finger in the frame */
__u16 firstx, firsty; /* (x, y) of the first finger in the frame */
};
static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_TIPSWITCH:
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_INRANGE:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
}
return 0;
}
return 0;
}
static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);
return 0;
}
/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void cando_filter_event(struct cando_data *td, struct input_dev *input)
{
td->first = !td->first; /* touchscreen emulation */
if (!td->valid) {
/*
* touchscreen emulation: if this is the second finger and
* the first was valid, the first was the oldest; if the
* first was not valid and there was a valid finger in the
* previous frame, this is a release.
*/
if (td->first) {
td->firstid = -1;
} else if (td->firstid >= 0) {
input_event(input, EV_ABS, ABS_X, td->firstx);
input_event(input, EV_ABS, ABS_Y, td->firsty);
td->oldest = td->firstid;
} else if (td->oldest >= 0) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
td->oldest = -1;
}
return;
}
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_mt_sync(input);
/*
* touchscreen emulation: if there was no touching finger previously,
* emit touch event
*/
if (td->oldest < 0) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
td->oldest = td->id;
}
/*
* touchscreen emulation: if this is the first finger, wait for the
* second; the oldest is then the second if it was the oldest already
* or if there was no first, the first otherwise.
*/
if (td->first) {
td->firstx = td->x;
td->firsty = td->y;
td->firstid = td->id;
} else {
int x, y, oldest;
if (td->id == td->oldest || td->firstid < 0) {
x = td->x;
y = td->y;
oldest = td->id;
} else {
x = td->firstx;
y = td->firsty;
oldest = td->firstid;
}
input_event(input, EV_ABS, ABS_X, x);
input_event(input, EV_ABS, ABS_Y, y);
td->oldest = oldest;
}
}
static int cando_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct cando_data *td = hid_get_drvdata(hid);
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = value;
break;
case HID_DG_CONTACTID:
td->id = value;
break;
case HID_GD_X:
td->x = value;
break;
case HID_GD_Y:
td->y = value;
cando_filter_event(td, input);
break;
case HID_DG_TIPSWITCH:
/* avoid interference from generic hidinput handling */
break;
default:
/* fallback to the generic hidinput handling */
return 0;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct cando_data *td;
td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
if (!td) {
hid_err(hdev, "cannot allocate Cando Touch data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, td);
td->first = false;
td->oldest = -1;
td->valid = false;
ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
kfree(td);
return ret;
}
static void cando_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id cando_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ }
};
MODULE_DEVICE_TABLE(hid, cando_devices);
static const struct hid_usage_id cando_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver cando_driver = {
.name = "cando-touch",
.id_table = cando_devices,
.probe = cando_probe,
.remove = cando_remove,
.input_mapping = cando_input_mapping,
.input_mapped = cando_input_mapped,
.usage_table = cando_grabbed_usages,
.event = cando_event,
};
static int __init cando_init(void)
{
return hid_register_driver(&cando_driver);
}
static void __exit cando_exit(void)
{
hid_unregister_driver(&cando_driver);
}
module_init(cando_init);
module_exit(cando_exit);
......@@ -1045,6 +1045,9 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
rsize = ((report->size - 1) >> 3) + 1;
if (rsize > HID_MAX_BUFFER_SIZE)
rsize = HID_MAX_BUFFER_SIZE;
if (csize < rsize) {
dbg_hid("report %d is too short, (%d < %d)\n", report->id,
csize, rsize);
......@@ -1290,6 +1293,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
{ 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) },
......@@ -1356,6 +1360,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
......@@ -1369,17 +1374,20 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
......@@ -1408,10 +1416,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
......@@ -1441,6 +1451,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
......@@ -1454,6 +1465,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
......@@ -1470,12 +1482,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
{ 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_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
{ 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_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
......
......@@ -37,6 +37,9 @@
#define USB_VENDOR_ID_ACRUX 0x1a34
#define USB_VENDOR_ID_ACTIONSTAR 0x2101
#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011
#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
......@@ -182,6 +185,9 @@
#define USB_VENDOR_ID_CREATIVELABS 0x041e
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
#define USB_VENDOR_ID_CVTOUCH 0x1ff7
#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
......@@ -220,6 +226,7 @@
#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2515 0x0022
#define USB_DEVICE_ID_ELO_TS2700 0x0020
#define USB_VENDOR_ID_EMS 0x2006
......@@ -255,6 +262,9 @@
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
#define USB_VENDOR_ID_GOODTOUCH 0x1aad
#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f
#define USB_VENDOR_ID_GOTOP 0x08f2
#define USB_DEVICE_ID_SUPER_Q2 0x007f
#define USB_DEVICE_ID_GOGOPEN 0x00ce
......@@ -334,6 +344,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
#define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
......@@ -398,6 +411,7 @@
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
......@@ -411,6 +425,9 @@
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
#define USB_VENDOR_ID_LUMIO 0x202e
#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
......@@ -488,6 +505,9 @@
#define USB_VENDOR_ID_PANTHERLORD 0x0810
#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
#define USB_VENDOR_ID_PENMOUNT 0x14e1
#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500
#define USB_VENDOR_ID_PETALYNX 0x18b1
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
......@@ -531,6 +551,7 @@
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
......@@ -551,6 +572,10 @@
#define USB_VENDOR_ID_SUNPLUS 0x04fc
#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
#define USB_VENDOR_ID_SYMBOL 0x05e0
#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TOPSEED 0x0766
......@@ -562,6 +587,9 @@
#define USB_VENDOR_ID_TOPMAX 0x0663
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
#define USB_VENDOR_ID_TOUCH_INTL 0x1e5e
#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH 0x0313
#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
......@@ -579,6 +607,10 @@
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19
#define USB_VENDOR_ID_VERNIER 0x08f7
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
......
......@@ -44,11 +44,11 @@ static const unsigned char hid_keyboard[256] = {
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
};
......@@ -357,6 +357,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1: map_key_clear(KEY_POWER); break;
case 0x2: map_key_clear(KEY_SLEEP); break;
case 0x3: map_key_clear(KEY_WAKEUP); break;
case 0x4: map_key_clear(KEY_CONTEXT_MENU); break;
case 0x5: map_key_clear(KEY_MENU); break;
case 0x6: map_key_clear(KEY_PROG1); break;
case 0x7: map_key_clear(KEY_HELP); break;
case 0x8: map_key_clear(KEY_EXIT); break;
case 0x9: map_key_clear(KEY_SELECT); break;
case 0xa: map_key_clear(KEY_RIGHT); break;
case 0xb: map_key_clear(KEY_LEFT); break;
case 0xc: map_key_clear(KEY_UP); break;
case 0xd: map_key_clear(KEY_DOWN); break;
case 0xe: map_key_clear(KEY_POWER2); break;
case 0xf: map_key_clear(KEY_RESTART); break;
default: goto unknown;
}
break;
......@@ -466,16 +478,39 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
break;
case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */
switch (usage->hid & HID_USAGE) {
case 0x000: goto ignore;
case 0x030: map_key_clear(KEY_POWER); break;
case 0x031: map_key_clear(KEY_RESTART); break;
case 0x032: map_key_clear(KEY_SLEEP); break;
case 0x034: map_key_clear(KEY_SLEEP); break;
case 0x035: map_key_clear(KEY_KBDILLUMTOGGLE); break;
case 0x036: map_key_clear(BTN_MISC); break;
case 0x040: map_key_clear(KEY_MENU); break;
case 0x045: map_key_clear(KEY_RADIO); break;
case 0x040: map_key_clear(KEY_MENU); break; /* Menu */
case 0x041: map_key_clear(KEY_SELECT); break; /* Menu Pick */
case 0x042: map_key_clear(KEY_UP); break; /* Menu Up */
case 0x043: map_key_clear(KEY_DOWN); break; /* Menu Down */
case 0x044: map_key_clear(KEY_LEFT); break; /* Menu Left */
case 0x045: map_key_clear(KEY_RIGHT); break; /* Menu Right */
case 0x046: map_key_clear(KEY_ESC); break; /* Menu Escape */
case 0x047: map_key_clear(KEY_KPPLUS); break; /* Menu Value Increase */
case 0x048: map_key_clear(KEY_KPMINUS); break; /* Menu Value Decrease */
case 0x060: map_key_clear(KEY_INFO); break; /* Data On Screen */
case 0x061: map_key_clear(KEY_SUBTITLE); break; /* Closed Caption */
case 0x063: map_key_clear(KEY_VCR); break; /* VCR/TV */
case 0x065: map_key_clear(KEY_CAMERA); break; /* Snapshot */
case 0x069: map_key_clear(KEY_RED); break;
case 0x06a: map_key_clear(KEY_GREEN); break;
case 0x06b: map_key_clear(KEY_BLUE); break;
case 0x06c: map_key_clear(KEY_YELLOW); break;
case 0x06d: map_key_clear(KEY_ZOOM); break;
case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
case 0x083: map_key_clear(KEY_LAST); break;
case 0x084: map_key_clear(KEY_ENTER); break;
case 0x088: map_key_clear(KEY_PC); break;
case 0x089: map_key_clear(KEY_TV); break;
case 0x08a: map_key_clear(KEY_WWW); break;
......@@ -509,6 +544,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0b7: map_key_clear(KEY_STOPCD); break;
case 0x0b8: map_key_clear(KEY_EJECTCD); break;
case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break;
case 0x0b9: map_key_clear(KEY_SHUFFLE); break;
case 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
......@@ -516,6 +553,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x0f5: map_key_clear(KEY_SLOW); break;
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
......@@ -532,6 +570,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18e: map_key_clear(KEY_CALENDAR); break;
case 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break;
case 0x193: map_key_clear(KEY_PLAYER); break;
case 0x194: map_key_clear(KEY_FILE); break;
case 0x196: map_key_clear(KEY_WWW); break;
case 0x199: map_key_clear(KEY_CHAT); break;
......@@ -540,8 +579,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1b6: map_key_clear(KEY_MEDIA); break;
case 0x1b7: map_key_clear(KEY_SOUND); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break;
case 0x1b8: map_key_clear(KEY_VIDEO); break;
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x201: map_key_clear(KEY_NEW); break;
......@@ -570,7 +611,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
case 0x238: map_rel(REL_HWHEEL); break;
case 0x23d: map_key_clear(KEY_EDIT); break;
case 0x25f: map_key_clear(KEY_CANCEL); break;
case 0x269: map_key_clear(KEY_INSERT); break;
case 0x26a: map_key_clear(KEY_DELETE); break;
case 0x279: map_key_clear(KEY_REDO); break;
case 0x289: map_key_clear(KEY_REPLY); break;
......
......@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
......
......@@ -72,6 +72,9 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc287, ff_joystick_ac },
{ 0x046d, 0xc293, ff_joystick },
{ 0x046d, 0xc294, ff_wheel },
{ 0x046d, 0xc298, ff_wheel },
{ 0x046d, 0xc299, ff_wheel },
{ 0x046d, 0xc29b, ff_wheel },
{ 0x046d, 0xc295, ff_joystick },
{ 0x046d, 0xc298, ff_wheel },
{ 0x046d, 0xc299, ff_wheel },
......
......@@ -501,9 +501,17 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report->size = 6;
/*
* The device reponds with 'invalid report id' when feature
* report switching it into multitouch mode is sent to it.
*
* This results in -EIO from the _raw low-level transport callback,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
if (ret != sizeof(feature)) {
if (ret != -EIO) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
......
/*
* HID driver for the multitouch panel on the ASUS EeePC T91MT
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.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 <linux/slab.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("MosArt dual-touch panel");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
struct mosart_data {
__u16 x, y;
__u8 id;
bool valid; /* valid finger data, or just placeholder? */
bool first; /* is this the first finger in this frame? */
bool activity_now; /* at least one active finger in this frame? */
bool activity; /* at least one active finger previously? */
};
static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_CONFIDENCE:
case HID_DG_TIPSWITCH:
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
case HID_DG_TIPPRESSURE:
case HID_DG_WIDTH:
case HID_DG_HEIGHT:
return -1;
case HID_DG_INRANGE:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
}
return 0;
case 0xff000000:
/* ignore HID features */
return -1;
case HID_UP_BUTTON:
/* ignore buttons */
return -1;
}
return 0;
}
static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);
return 0;
}
/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
{
td->first = !td->first; /* touchscreen emulation */
if (!td->valid) {
/*
* touchscreen emulation: if no finger in this frame is valid
* and there previously was finger activity, this is a release
*/
if (!td->first && !td->activity_now && td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
td->activity = false;
}
return;
}
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_mt_sync(input);
td->valid = false;
/* touchscreen emulation: if first active finger in this frame... */
if (!td->activity_now) {
/* if there was no previous activity, emit touch event */
if (!td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
td->activity = true;
}
td->activity_now = true;
/* and in any case this is our preferred finger */
input_event(input, EV_ABS, ABS_X, td->x);
input_event(input, EV_ABS, ABS_Y, td->y);
}
}
static int mosart_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct mosart_data *td = hid_get_drvdata(hid);
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = !!value;
break;
case HID_GD_X:
td->x = value;
break;
case HID_GD_Y:
td->y = value;
mosart_filter_event(td, input);
break;
case HID_DG_CONTACTID:
td->id = value;
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
td->first = false;
td->activity_now = false;
break;
case HID_DG_CONFIDENCE:
case HID_DG_TIPSWITCH:
/* avoid interference from generic hidinput handling */
break;
default:
/* fallback to the generic hidinput handling */
return 0;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct mosart_data *td;
td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
if (!td) {
hid_err(hdev, "cannot allocate MosArt data\n");
return -ENOMEM;
}
td->valid = false;
td->activity = false;
td->activity_now = false;
td->first = false;
hid_set_drvdata(hdev, td);
/* currently, it's better to have one evdev device only */
#if 0
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
#endif
ret = hid_parse(hdev);
if (ret == 0)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret == 0) {
struct hid_report_enum *re = hdev->report_enum
+ HID_FEATURE_REPORT;
struct hid_report *r = re->report_id_hash[7];
r->field[0]->value[0] = 0x02;
usbhid_submit_report(hdev, r, USB_DIR_OUT);
} else
kfree(td);
return ret;
}
#ifdef CONFIG_PM
static int mosart_reset_resume(struct hid_device *hdev)
{
struct hid_report_enum *re = hdev->report_enum
+ HID_FEATURE_REPORT;
struct hid_report *r = re->report_id_hash[7];
r->field[0]->value[0] = 0x02;
usbhid_submit_report(hdev, r, USB_DIR_OUT);
return 0;
}
#endif
static void mosart_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id mosart_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ }
};
MODULE_DEVICE_TABLE(hid, mosart_devices);
static const struct hid_usage_id mosart_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver mosart_driver = {
.name = "mosart",
.id_table = mosart_devices,
.probe = mosart_probe,
.remove = mosart_remove,
.input_mapping = mosart_input_mapping,
.input_mapped = mosart_input_mapped,
.usage_table = mosart_grabbed_usages,
.event = mosart_event,
#ifdef CONFIG_PM
.reset_resume = mosart_reset_resume,
#endif
};
static int __init mosart_init(void)
{
return hid_register_driver(&mosart_driver);
}
static void __exit mosart_exit(void)
{
hid_unregister_driver(&mosart_driver);
}
module_init(mosart_init);
module_exit(mosart_exit);
This diff is collapsed.
......@@ -1585,11 +1585,11 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
memset(raw_data, 0, sizeof(raw_data));
raw_data[0] = *off & 0xff;
raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
raw_data[2] = min((size_t)20, s);
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
if (copy_from_user(raw_data+3, u, raw_data[2]))
if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
return -EFAULT;
resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
sizeof(raw_data));
......
......@@ -167,28 +167,28 @@ static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
}
/* retval is 0-4 on success, < 0 on error */
static int koneplus_get_startup_profile(struct usb_device *usb_dev)
static int koneplus_get_actual_profile(struct usb_device *usb_dev)
{
struct koneplus_startup_profile buf;
struct koneplus_actual_profile buf;
int retval;
retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
&buf, sizeof(struct koneplus_startup_profile));
retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
&buf, sizeof(struct koneplus_actual_profile));
return retval ? retval : buf.startup_profile;
return retval ? retval : buf.actual_profile;
}
static int koneplus_set_startup_profile(struct usb_device *usb_dev,
int startup_profile)
static int koneplus_set_actual_profile(struct usb_device *usb_dev,
int new_profile)
{
struct koneplus_startup_profile buf;
struct koneplus_actual_profile buf;
buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
buf.size = sizeof(struct koneplus_startup_profile);
buf.startup_profile = startup_profile;
buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
buf.size = sizeof(struct koneplus_actual_profile);
buf.actual_profile = new_profile;
return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
&buf, sizeof(struct koneplus_profile_buttons));
return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
&buf, sizeof(struct koneplus_actual_profile));
}
static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
......@@ -398,21 +398,22 @@ static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
return sizeof(struct koneplus_profile_buttons);
}
static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct koneplus_device *koneplus =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
}
static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
struct koneplus_device *koneplus;
struct usb_device *usb_dev;
unsigned long profile;
int retval;
struct koneplus_roccat_report roccat_report;
dev = dev->parent->parent;
koneplus = hid_get_drvdata(dev_get_drvdata(dev));
......@@ -423,20 +424,25 @@ static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
return retval;
mutex_lock(&koneplus->koneplus_lock);
retval = koneplus_set_startup_profile(usb_dev, profile);
retval = koneplus_set_actual_profile(usb_dev, profile);
if (retval) {
mutex_unlock(&koneplus->koneplus_lock);
if (retval)
return retval;
}
return size;
}
koneplus->actual_profile = profile;
static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct koneplus_device *koneplus =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
roccat_report.data1 = profile + 1;
roccat_report.data2 = 0;
roccat_report.profile = profile + 1;
roccat_report_event(koneplus->chrdev_minor,
(uint8_t const *)&roccat_report);
mutex_unlock(&koneplus->koneplus_lock);
return size;
}
static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
......@@ -448,11 +454,12 @@ static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
}
static struct device_attribute koneplus_attributes[] = {
__ATTR(actual_profile, 0660,
koneplus_sysfs_show_actual_profile,
koneplus_sysfs_set_actual_profile),
__ATTR(startup_profile, 0660,
koneplus_sysfs_show_startup_profile,
koneplus_sysfs_set_startup_profile),
__ATTR(actual_profile, 0440,
koneplus_sysfs_show_actual_profile, NULL),
koneplus_sysfs_show_actual_profile,
koneplus_sysfs_set_actual_profile),
__ATTR(firmware_version, 0440,
koneplus_sysfs_show_firmware_version, NULL),
__ATTR_NULL
......@@ -557,15 +564,10 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus)
{
int retval, i;
static uint wait = 100; /* device will freeze with just 60 */
static uint wait = 200;
mutex_init(&koneplus->koneplus_lock);
koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
if (koneplus->startup_profile < 0)
return koneplus->startup_profile;
msleep(wait);
retval = koneplus_get_info(usb_dev, &koneplus->info);
if (retval)
return retval;
......@@ -584,7 +586,11 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
return retval;
}
koneplus_profile_activated(koneplus, koneplus->startup_profile);
msleep(wait);
retval = koneplus_get_actual_profile(usb_dev);
if (retval < 0)
return retval;
koneplus_profile_activated(koneplus, retval);
return 0;
}
......
......@@ -40,10 +40,10 @@ enum koneplus_control_values {
KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
};
struct koneplus_startup_profile {
uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
struct koneplus_actual_profile {
uint8_t command; /* KONEPLUS_COMMAND_ACTUAL_PROFILE */
uint8_t size; /* always 3 */
uint8_t startup_profile; /* Range 0-4! */
uint8_t actual_profile; /* Range 0-4! */
} __attribute__ ((__packed__));
struct koneplus_profile_settings {
......@@ -132,7 +132,7 @@ struct koneplus_tcu_image {
enum koneplus_commands {
KONEPLUS_COMMAND_CONTROL = 0x4,
KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
KONEPLUS_COMMAND_MACRO = 0x8,
......@@ -145,7 +145,7 @@ enum koneplus_commands {
enum koneplus_usb_commands {
KONEPLUS_USB_COMMAND_CONTROL = 0x304,
KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
KONEPLUS_USB_COMMAND_MACRO = 0x308,
......@@ -215,7 +215,6 @@ struct koneplus_device {
struct mutex koneplus_lock;
int startup_profile;
struct koneplus_info info;
struct koneplus_profile_settings profile_settings[5];
struct koneplus_profile_buttons profile_buttons[5];
......
......@@ -178,6 +178,8 @@ static void sony_remove(struct hid_device *hdev)
static const struct hid_device_id sony_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_BT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
......
/*
* HID driver for Stantum multitouch panels
*
* Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
*
*/
/*
* 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/slab.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("Stantum HID multitouch panels");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
struct stantum_data {
__s32 x, y, z, w, h; /* x, y, pressure, width, height */
__u16 id; /* touch id */
bool valid; /* valid finger data, or just placeholder? */
bool first; /* first finger in the HID packet? */
bool activity; /* at least one active finger so far? */
};
static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_INRANGE:
case HID_DG_CONFIDENCE:
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
1, 1, 0, 0);
return 1;
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
return 1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
}
return 0;
case 0xff000000:
/* no input-oriented meaning */
return -1;
}
return 0;
}
static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);
return 0;
}
/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void stantum_filter_event(struct stantum_data *sd,
struct input_dev *input)
{
bool wide;
if (!sd->valid) {
/*
* touchscreen emulation: if the first finger is not valid and
* there previously was finger activity, this is a release
*/
if (sd->first && sd->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
sd->activity = false;
}
return;
}
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
wide = (sd->w > sd->h);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
input_mt_sync(input);
sd->valid = false;
/* touchscreen emulation */
if (sd->first) {
if (!sd->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
sd->activity = true;
}
input_event(input, EV_ABS, ABS_X, sd->x);
input_event(input, EV_ABS, ABS_Y, sd->y);
}
sd->first = false;
}
static int stantum_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct stantum_data *sd = hid_get_drvdata(hid);
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
/* this is the last field in a finger */
stantum_filter_event(sd, input);
break;
case HID_DG_WIDTH:
sd->w = value;
break;
case HID_DG_HEIGHT:
sd->h = value;
break;
case HID_GD_X:
sd->x = value;
break;
case HID_GD_Y:
sd->y = value;
break;
case HID_DG_TIPPRESSURE:
sd->z = value;
break;
case HID_DG_CONTACTID:
sd->id = value;
break;
case HID_DG_CONFIDENCE:
sd->valid = !!value;
break;
case 0xff000002:
/* this comes only before the first finger */
sd->first = true;
break;
default:
/* ignore the others */
return 1;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int stantum_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
struct stantum_data *sd;
sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
if (!sd) {
hid_err(hdev, "cannot allocate Stantum data\n");
return -ENOMEM;
}
sd->valid = false;
sd->first = false;
sd->activity = false;
hid_set_drvdata(hdev, sd);
ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
kfree(sd);
return ret;
}
static void stantum_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id stantum_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
{ }
};
MODULE_DEVICE_TABLE(hid, stantum_devices);
static const struct hid_usage_id stantum_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver stantum_driver = {
.name = "stantum",
.id_table = stantum_devices,
.probe = stantum_probe,
.remove = stantum_remove,
.input_mapping = stantum_input_mapping,
.input_mapped = stantum_input_mapped,
.usage_table = stantum_grabbed_usages,
.event = stantum_event,
};
static int __init stantum_init(void)
{
return hid_register_driver(&stantum_driver);
}
static void __exit stantum_exit(void)
{
hid_unregister_driver(&stantum_driver);
}
module_init(stantum_init);
module_exit(stantum_exit);
......@@ -101,8 +101,8 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
return ret;
}
/* the first byte is expected to be a report number */
/* This function is to be called with the minors_lock mutex held */
/* The first byte is expected to be a report number.
* This function is to be called with the minors_lock mutex held */
static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
......@@ -166,11 +166,11 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
/* This function performs a Get_Report transfer over the control endpoint
per section 7.2.1 of the HID specification, version 1.1. The first byte
of buffer is the report number to request, or 0x0 if the defice does not
use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
or HID_INPUT_REPORT. This function is to be called with the minors_lock
mutex held. */
* per section 7.2.1 of the HID specification, version 1.1. The first byte
* of buffer is the report number to request, or 0x0 if the defice does not
* use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
* or HID_INPUT_REPORT. This function is to be called with the minors_lock
* mutex held. */
static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
......@@ -207,7 +207,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
}
/* Read the first byte from the user. This is the report number,
which is passed to dev->hid_get_raw_report(). */
* which is passed to dev->hid_get_raw_report(). */
if (copy_from_user(&report_number, buffer, 1)) {
ret = -EFAULT;
goto out_free;
......@@ -395,12 +395,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
int len;
if (!hid->name) {
ret = 0;
break;
}
len = strlen(hid->name) + 1;
int len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
ret = copy_to_user(user_arg, hid->name, len) ?
......@@ -409,12 +404,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
int len;
if (!hid->phys) {
ret = 0;
break;
}
len = strlen(hid->phys) + 1;
int len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
ret = copy_to_user(user_arg, hid->phys, len) ?
......
......@@ -68,6 +68,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
......
......@@ -242,6 +242,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
list_del(&list->node);
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
mutex_lock(&list->hiddev->existancelock);
if (!--list->hiddev->open) {
if (list->hiddev->exist) {
usbhid_close(list->hiddev->hid);
......@@ -252,6 +253,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
}
kfree(list);
mutex_unlock(&list->hiddev->existancelock);
return 0;
}
......@@ -300,17 +302,21 @@ static int hiddev_open(struct inode *inode, struct file *file)
list_add_tail(&list->node, &hiddev->list);
spin_unlock_irq(&list->hiddev->list_lock);
mutex_lock(&hiddev->existancelock);
if (!list->hiddev->open++)
if (list->hiddev->exist) {
struct hid_device *hid = hiddev->hid;
res = usbhid_get_power(hid);
if (res < 0) {
res = -EIO;
goto bail;
goto bail_unlock;
}
usbhid_open(hid);
}
mutex_unlock(&hiddev->existancelock);
return 0;
bail_unlock:
mutex_unlock(&hiddev->existancelock);
bail:
file->private_data = NULL;
kfree(list);
......@@ -367,8 +373,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
/* let O_NONBLOCK tasks run */
mutex_unlock(&list->thread_lock);
schedule();
if (mutex_lock_interruptible(&list->thread_lock))
if (mutex_lock_interruptible(&list->thread_lock)) {
finish_wait(&list->hiddev->wait, &wait);
return -EINTR;
}
set_current_state(TASK_INTERRUPTIBLE);
}
finish_wait(&list->hiddev->wait, &wait);
......@@ -801,14 +809,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
int len;
if (!hid->name) {
r = 0;
break;
}
len = strlen(hid->name) + 1;
int len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
r = copy_to_user(user_arg, hid->name, len) ?
......@@ -817,14 +818,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
int len;
if (!hid->phys) {
r = 0;
break;
}
len = strlen(hid->phys) + 1;
int len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
r = copy_to_user(user_arg, hid->phys, len) ?
......@@ -925,7 +919,6 @@ void hiddev_disconnect(struct hid_device *hid)
mutex_lock(&hiddev->existancelock);
hiddev->exist = 0;
mutex_unlock(&hiddev->existancelock);
usb_deregister_dev(usbhid->intf, &hiddev_class);
......@@ -935,4 +928,5 @@ void hiddev_disconnect(struct hid_device *hid)
} else {
kfree(hiddev);
}
mutex_unlock(&hiddev->existancelock);
}
......@@ -61,4 +61,10 @@ config SAMPLE_KDB
Build an example of how to dynamically add the hello
command to the kdb shell.
config SAMPLE_HIDRAW
bool "Build simple hidraw example"
depends on HIDRAW && HEADERS_CHECK
help
Build an example of how to use hidraw from userspace.
endif # SAMPLES
# Makefile for Linux samples code
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \
hw_breakpoint/ kfifo/ kdb/
hw_breakpoint/ kfifo/ kdb/ hidraw/
# kbuild trick to avoid linker error. Can be omitted if a module is built.
obj- := dummy.o
# List of programs to build
hostprogs-y := hid-example
# Tell kbuild to always build the programs
always := $(hostprogs-y)
HOSTCFLAGS_hid-example.o += -I$(objtree)/usr/include
/*
* Hidraw Userspace Example
*
* Copyright (c) 2010 Alan Ott <alan@signal11.us>
* Copyright (c) 2010 Signal 11 Software
*
* The code may be used by anyone for any purpose,
* and can serve as a starting point for developing
* applications using hidraw.
*/
/* Linux */
#include <linux/types.h>
#include <linux/input.h>
#include <linux/hidraw.h>
/*
* Ugly hack to work around failing compilation on systems that don't
* yet populate new version of hidraw.h to userspace.
*
* If you need this, please have your distro update the kernel headers.
*/
#ifndef HIDIOCSFEATURE
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#endif
/* Unix */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* C */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
const char *bus_str(int bus);
int main(int argc, char **argv)
{
int fd;
int i, res, desc_size = 0;
char buf[256];
struct hidraw_report_descriptor rpt_desc;
struct hidraw_devinfo info;
/* Open the Device with non-blocking reads. In real life,
don't use a hard coded path; use libudev instead. */
fd = open("/dev/hidraw0", O_RDWR|O_NONBLOCK);
if (fd < 0) {
perror("Unable to open device");
return 1;
}
memset(&rpt_desc, 0x0, sizeof(rpt_desc));
memset(&info, 0x0, sizeof(info));
memset(buf, 0x0, sizeof(buf));
/* Get Report Descriptor Size */
res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);
if (res < 0)
perror("HIDIOCGRDESCSIZE");
else
printf("Report Descriptor Size: %d\n", desc_size);
/* Get Report Descriptor */
rpt_desc.size = desc_size;
res = ioctl(fd, HIDIOCGRDESC, &rpt_desc);
if (res < 0) {
perror("HIDIOCGRDESC");
} else {
printf("Report Descriptor:\n");
for (i = 0; i < rpt_desc.size; i++)
printf("%hhx ", rpt_desc.value[i]);
puts("\n");
}
/* Get Raw Name */
res = ioctl(fd, HIDIOCGRAWNAME(256), buf);
if (res < 0)
perror("HIDIOCGRAWNAME");
else
printf("Raw Name: %s\n", buf);
/* Get Physical Location */
res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);
if (res < 0)
perror("HIDIOCGRAWPHYS");
else
printf("Raw Phys: %s\n", buf);
/* Get Raw Info */
res = ioctl(fd, HIDIOCGRAWINFO, &info);
if (res < 0) {
perror("HIDIOCGRAWINFO");
} else {
printf("Raw Info:\n");
printf("\tbustype: %d (%s)\n",
info.bustype, bus_str(info.bustype));
printf("\tvendor: 0x%04hx\n", info.vendor);
printf("\tproduct: 0x%04hx\n", info.product);
}
/* Set Feature */
buf[0] = 0x9; /* Report Number */
buf[1] = 0xff;
buf[2] = 0xff;
buf[3] = 0xff;
res = ioctl(fd, HIDIOCSFEATURE(4), buf);
if (res < 0)
perror("HIDIOCSFEATURE");
else
printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
/* Get Feature */
buf[0] = 0x9; /* Report Number */
res = ioctl(fd, HIDIOCGFEATURE(256), buf);
if (res < 0) {
perror("HIDIOCGFEATURE");
} else {
printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
printf("Report data (not containing the report number):\n\t");
for (i = 0; i < res; i++)
printf("%hhx ", buf[i]);
puts("\n");
}
/* Send a Report to the Device */
buf[0] = 0x1; /* Report Number */
buf[1] = 0x77;
res = write(fd, buf, 2);
if (res < 0) {
printf("Error: %d\n", errno);
perror("write");
} else {
printf("write() wrote %d bytes\n", res);
}
/* Get a report from the device */
res = read(fd, buf, 16);
if (res < 0) {
perror("read");
} else {
printf("read() read %d bytes:\n\t", res);
for (i = 0; i < res; i++)
printf("%hhx ", buf[i]);
puts("\n");
}
close(fd);
return 0;
}
const char *
bus_str(int bus)
{
switch (bus) {
case BUS_USB:
return "USB";
break;
case BUS_HIL:
return "HIL";
break;
case BUS_BLUETOOTH:
return "Bluetooth";
break;
case BUS_VIRTUAL:
return "Virtual";
break;
default:
return "Other";
break;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment