Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID fixes from Jiri Kosina: - fix for how scaling linearization is computed in wiimote driver, by Cyan Ogilvie - endless retry loop fix in generic USB HID core reset-resume handling, by Alan Stern - two functional fixes affecting particular devices, and oops fix for wacom driver, by Jason Gerecke - multitouch slot numbering fix from Gabriele Mazzotta - a couple more small fixes on top * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: HID: wacom: Support switching from vendor-defined device mode on G9 and G11 HID: wacom: Initialize hid_data.inputmode to -1 HID: microsoft: add support for 3 more devices HID: multitouch: Synchronize MT frame on reset_resume HID: wacom: fix Bamboo ONE oops HID: lenovo: Don't use stack variables for DMA buffers HID: usbhid: fix inconsistent reset/resume/reset-resume behavior HID: wiimote: Fix wiimote mp scale linearization
This commit is contained in:
Коммит
1c74a7f812
|
@ -1979,6 +1979,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
|
||||
|
|
|
@ -676,6 +676,7 @@
|
|||
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
||||
#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048
|
||||
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
|
||||
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K 0x00b4
|
||||
#define USB_DEVICE_ID_MS_NE4K 0x00db
|
||||
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
|
||||
#define USB_DEVICE_ID_MS_LK6K 0x00f9
|
||||
|
@ -683,6 +684,8 @@
|
|||
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
|
||||
#define USB_DEVICE_ID_MS_NE7K 0x071d
|
||||
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
|
||||
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732
|
||||
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750
|
||||
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
|
||||
#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3
|
||||
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
|
||||
|
|
|
@ -184,21 +184,31 @@ static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
|
|||
unsigned char byte2, unsigned char byte3)
|
||||
{
|
||||
int ret;
|
||||
unsigned char buf[] = {0x18, byte2, byte3};
|
||||
unsigned char *buf;
|
||||
|
||||
buf = kzalloc(3, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
buf[0] = 0x18;
|
||||
buf[1] = byte2;
|
||||
buf[2] = byte3;
|
||||
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||
ret = hid_hw_raw_request(hdev, 0x13, buf, sizeof(buf),
|
||||
ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
ret = hid_hw_output_report(hdev, buf, sizeof(buf));
|
||||
ret = hid_hw_output_report(hdev, buf, 3);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return ret < 0 ? ret : 0; /* BT returns 0, USB returns sizeof(buf) */
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,12 @@ static const struct hid_device_id ms_devices[] = {
|
|||
.driver_data = MS_PRESENTER },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
|
||||
.driver_data = MS_ERGONOMY | MS_RDESC_3K },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
|
||||
.driver_data = MS_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
|
||||
|
|
|
@ -1169,6 +1169,7 @@ static void mt_release_contacts(struct hid_device *hid)
|
|||
MT_TOOL_FINGER,
|
||||
false);
|
||||
}
|
||||
input_mt_sync_frame(input_dev);
|
||||
input_sync(input_dev);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2049,9 +2049,11 @@ static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
|
|||
* -----+------------------------------+-----+-----+
|
||||
* The single bits Yaw, Roll, Pitch in the lower right corner specify
|
||||
* whether the wiimote is rotating fast (0) or slow (1). Speed for slow
|
||||
* roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
|
||||
* linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
|
||||
* and 9 for slow.
|
||||
* roation is 8192/440 units / deg/s and for fast rotation 8192/2000
|
||||
* units / deg/s. To get a linear scale for fast rotation we multiply
|
||||
* by 2000/440 = ~4.5454 and scale both fast and slow by 9 to match the
|
||||
* previous scale reported by this driver.
|
||||
* This leaves a linear scale with 8192*9/440 (~167.564) units / deg/s.
|
||||
* If the wiimote is not rotating the sensor reports 2^13 = 8192.
|
||||
* Ext specifies whether an extension is connected to the motionp.
|
||||
* which is parsed by wiimote-core.
|
||||
|
@ -2070,15 +2072,15 @@ static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
|
|||
z -= 8192;
|
||||
|
||||
if (!(ext[3] & 0x02))
|
||||
x *= 18;
|
||||
x = (x * 2000 * 9) / 440;
|
||||
else
|
||||
x *= 9;
|
||||
if (!(ext[4] & 0x02))
|
||||
y *= 18;
|
||||
y = (y * 2000 * 9) / 440;
|
||||
else
|
||||
y *= 9;
|
||||
if (!(ext[3] & 0x01))
|
||||
z *= 18;
|
||||
z = (z * 2000 * 9) / 440;
|
||||
else
|
||||
z *= 9;
|
||||
|
||||
|
|
|
@ -951,14 +951,6 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void usbhid_restart_queues(struct usbhid_device *usbhid)
|
||||
{
|
||||
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
|
||||
usbhid_restart_out_queue(usbhid);
|
||||
if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
|
||||
usbhid_restart_ctrl_queue(usbhid);
|
||||
}
|
||||
|
||||
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
|
@ -1404,6 +1396,37 @@ static void hid_cease_io(struct usbhid_device *usbhid)
|
|||
usb_kill_urb(usbhid->urbout);
|
||||
}
|
||||
|
||||
static void hid_restart_io(struct hid_device *hid)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
int clear_halt = test_bit(HID_CLEAR_HALT, &usbhid->iofl);
|
||||
int reset_pending = test_bit(HID_RESET_PENDING, &usbhid->iofl);
|
||||
|
||||
spin_lock_irq(&usbhid->lock);
|
||||
clear_bit(HID_SUSPENDED, &usbhid->iofl);
|
||||
usbhid_mark_busy(usbhid);
|
||||
|
||||
if (clear_halt || reset_pending)
|
||||
schedule_work(&usbhid->reset_work);
|
||||
usbhid->retry_delay = 0;
|
||||
spin_unlock_irq(&usbhid->lock);
|
||||
|
||||
if (reset_pending || !test_bit(HID_STARTED, &usbhid->iofl))
|
||||
return;
|
||||
|
||||
if (!clear_halt) {
|
||||
if (hid_start_in(hid) < 0)
|
||||
hid_io_error(hid);
|
||||
}
|
||||
|
||||
spin_lock_irq(&usbhid->lock);
|
||||
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
|
||||
usbhid_restart_out_queue(usbhid);
|
||||
if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
|
||||
usbhid_restart_ctrl_queue(usbhid);
|
||||
spin_unlock_irq(&usbhid->lock);
|
||||
}
|
||||
|
||||
/* Treat USB reset pretty much the same as suspend/resume */
|
||||
static int hid_pre_reset(struct usb_interface *intf)
|
||||
{
|
||||
|
@ -1453,14 +1476,14 @@ static int hid_post_reset(struct usb_interface *intf)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* No need to do another reset or clear a halted endpoint */
|
||||
spin_lock_irq(&usbhid->lock);
|
||||
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
|
||||
clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
|
||||
spin_unlock_irq(&usbhid->lock);
|
||||
hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
|
||||
status = hid_start_in(hid);
|
||||
if (status < 0)
|
||||
hid_io_error(hid);
|
||||
usbhid_restart_queues(usbhid);
|
||||
|
||||
hid_restart_io(hid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1483,25 +1506,9 @@ void usbhid_put_power(struct hid_device *hid)
|
|||
#ifdef CONFIG_PM
|
||||
static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
int status;
|
||||
|
||||
spin_lock_irq(&usbhid->lock);
|
||||
clear_bit(HID_SUSPENDED, &usbhid->iofl);
|
||||
usbhid_mark_busy(usbhid);
|
||||
|
||||
if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
|
||||
test_bit(HID_RESET_PENDING, &usbhid->iofl))
|
||||
schedule_work(&usbhid->reset_work);
|
||||
usbhid->retry_delay = 0;
|
||||
|
||||
usbhid_restart_queues(usbhid);
|
||||
spin_unlock_irq(&usbhid->lock);
|
||||
|
||||
status = hid_start_in(hid);
|
||||
if (status < 0)
|
||||
hid_io_error(hid);
|
||||
int status = 0;
|
||||
|
||||
hid_restart_io(hid);
|
||||
if (driver_suspended && hid->driver && hid->driver->resume)
|
||||
status = hid->driver->resume(hid);
|
||||
return status;
|
||||
|
@ -1570,12 +1577,8 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
static int hid_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct hid_device *hid = usb_get_intfdata (intf);
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
int status;
|
||||
|
||||
if (!test_bit(HID_STARTED, &usbhid->iofl))
|
||||
return 0;
|
||||
|
||||
status = hid_resume_common(hid, true);
|
||||
dev_dbg(&intf->dev, "resume status %d\n", status);
|
||||
return 0;
|
||||
|
@ -1584,10 +1587,8 @@ static int hid_resume(struct usb_interface *intf)
|
|||
static int hid_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct hid_device *hid = usb_get_intfdata(intf);
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
int status;
|
||||
|
||||
clear_bit(HID_SUSPENDED, &usbhid->iofl);
|
||||
status = hid_post_reset(intf);
|
||||
if (status >= 0 && hid->driver && hid->driver->reset_resume) {
|
||||
int ret = hid->driver->reset_resume(hid);
|
||||
|
|
|
@ -152,6 +152,25 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|||
hid_data->inputmode = field->report->id;
|
||||
hid_data->inputmode_index = usage->usage_index;
|
||||
break;
|
||||
|
||||
case HID_UP_DIGITIZER:
|
||||
if (field->report->id == 0x0B &&
|
||||
(field->application == WACOM_G9_DIGITIZER ||
|
||||
field->application == WACOM_G11_DIGITIZER)) {
|
||||
wacom->wacom_wac.mode_report = field->report->id;
|
||||
wacom->wacom_wac.mode_value = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WACOM_G9_PAGE:
|
||||
case WACOM_G11_PAGE:
|
||||
if (field->report->id == 0x03 &&
|
||||
(field->application == WACOM_G9_TOUCHSCREEN ||
|
||||
field->application == WACOM_G11_TOUCHSCREEN)) {
|
||||
wacom->wacom_wac.mode_report = field->report->id;
|
||||
wacom->wacom_wac.mode_value = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,26 +341,41 @@ static int wacom_hid_set_device_mode(struct hid_device *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wacom_set_device_mode(struct hid_device *hdev, int report_id,
|
||||
int length, int mode)
|
||||
static int wacom_set_device_mode(struct hid_device *hdev,
|
||||
struct wacom_wac *wacom_wac)
|
||||
{
|
||||
unsigned char *rep_data;
|
||||
u8 *rep_data;
|
||||
struct hid_report *r;
|
||||
struct hid_report_enum *re;
|
||||
int length;
|
||||
int error = -ENOMEM, limit = 0;
|
||||
|
||||
rep_data = kzalloc(length, GFP_KERNEL);
|
||||
if (wacom_wac->mode_report < 0)
|
||||
return 0;
|
||||
|
||||
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
||||
r = re->report_id_hash[wacom_wac->mode_report];
|
||||
if (!r)
|
||||
return -EINVAL;
|
||||
|
||||
rep_data = hid_alloc_report_buf(r, GFP_KERNEL);
|
||||
if (!rep_data)
|
||||
return error;
|
||||
return -ENOMEM;
|
||||
|
||||
length = hid_report_len(r);
|
||||
|
||||
do {
|
||||
rep_data[0] = report_id;
|
||||
rep_data[1] = mode;
|
||||
rep_data[0] = wacom_wac->mode_report;
|
||||
rep_data[1] = wacom_wac->mode_value;
|
||||
|
||||
error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data,
|
||||
length, 1);
|
||||
if (error >= 0)
|
||||
error = wacom_get_report(hdev, HID_FEATURE_REPORT,
|
||||
rep_data, length, 1);
|
||||
} while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES);
|
||||
} while (error >= 0 &&
|
||||
rep_data[1] != wacom_wac->mode_report &&
|
||||
limit++ < WAC_MSG_RETRIES);
|
||||
|
||||
kfree(rep_data);
|
||||
|
||||
|
@ -411,32 +445,41 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed,
|
|||
static int wacom_query_tablet_data(struct hid_device *hdev,
|
||||
struct wacom_features *features)
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||
|
||||
if (hdev->bus == BUS_BLUETOOTH)
|
||||
return wacom_bt_query_tablet_data(hdev, 1, features);
|
||||
|
||||
if (features->type == HID_GENERIC)
|
||||
return wacom_hid_set_device_mode(hdev);
|
||||
|
||||
if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
|
||||
if (features->type > TABLETPC) {
|
||||
/* MT Tablet PC touch */
|
||||
return wacom_set_device_mode(hdev, 3, 4, 4);
|
||||
}
|
||||
else if (features->type == WACOM_24HDT) {
|
||||
return wacom_set_device_mode(hdev, 18, 3, 2);
|
||||
}
|
||||
else if (features->type == WACOM_27QHDT) {
|
||||
return wacom_set_device_mode(hdev, 131, 3, 2);
|
||||
}
|
||||
else if (features->type == BAMBOO_PAD) {
|
||||
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||
}
|
||||
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
|
||||
if (features->type <= BAMBOO_PT) {
|
||||
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||
if (features->type != HID_GENERIC) {
|
||||
if (features->device_type & WACOM_DEVICETYPE_TOUCH) {
|
||||
if (features->type > TABLETPC) {
|
||||
/* MT Tablet PC touch */
|
||||
wacom_wac->mode_report = 3;
|
||||
wacom_wac->mode_value = 4;
|
||||
} else if (features->type == WACOM_24HDT) {
|
||||
wacom_wac->mode_report = 18;
|
||||
wacom_wac->mode_value = 2;
|
||||
} else if (features->type == WACOM_27QHDT) {
|
||||
wacom_wac->mode_report = 131;
|
||||
wacom_wac->mode_value = 2;
|
||||
} else if (features->type == BAMBOO_PAD) {
|
||||
wacom_wac->mode_report = 2;
|
||||
wacom_wac->mode_value = 2;
|
||||
}
|
||||
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
|
||||
if (features->type <= BAMBOO_PT) {
|
||||
wacom_wac->mode_report = 2;
|
||||
wacom_wac->mode_value = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wacom_set_device_mode(hdev, wacom_wac);
|
||||
|
||||
if (features->type == HID_GENERIC)
|
||||
return wacom_hid_set_device_mode(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1817,6 +1860,9 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
goto fail_type;
|
||||
}
|
||||
|
||||
wacom_wac->hid_data.inputmode = -1;
|
||||
wacom_wac->mode_report = -1;
|
||||
|
||||
wacom->usbdev = dev;
|
||||
wacom->intf = intf;
|
||||
mutex_init(&wacom->lock);
|
||||
|
|
|
@ -2425,6 +2425,17 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hack for the Bamboo One:
|
||||
* the device presents a PAD/Touch interface as most Bamboos and even
|
||||
* sends ghosts PAD data on it. However, later, we must disable this
|
||||
* ghost interface, and we can not detect it unless we set it here
|
||||
* to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH.
|
||||
*/
|
||||
if (features->type == BAMBOO_PEN &&
|
||||
features->pktlen == WACOM_PKGLEN_BBTOUCH3)
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
|
||||
/*
|
||||
* Raw Wacom-mode pen and touch events both come from interface
|
||||
* 0, whose HID descriptor has an application usage of 0xFF0D
|
||||
|
|
|
@ -84,6 +84,12 @@
|
|||
#define WACOM_DEVICETYPE_WL_MONITOR 0x0008
|
||||
|
||||
#define WACOM_VENDORDEFINED_PEN 0xff0d0001
|
||||
#define WACOM_G9_PAGE 0xff090000
|
||||
#define WACOM_G9_DIGITIZER (WACOM_G9_PAGE | 0x02)
|
||||
#define WACOM_G9_TOUCHSCREEN (WACOM_G9_PAGE | 0x11)
|
||||
#define WACOM_G11_PAGE 0xff110000
|
||||
#define WACOM_G11_DIGITIZER (WACOM_G11_PAGE | 0x02)
|
||||
#define WACOM_G11_TOUCHSCREEN (WACOM_G11_PAGE | 0x11)
|
||||
|
||||
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
|
||||
((f)->physical == HID_DG_STYLUS) || \
|
||||
|
@ -238,6 +244,8 @@ struct wacom_wac {
|
|||
int ps_connected;
|
||||
u8 bt_features;
|
||||
u8 bt_high_speed;
|
||||
int mode_report;
|
||||
int mode_value;
|
||||
struct hid_data hid_data;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче