提交 d6b92c2c 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid into next

Pull HID patches from Jiri Kosina:
 - RMI driver for Synaptics touchpads, by Benjamin Tissoires, Andrew
   Duggan and Jiri Kosina
 - cleanup of hid-sony driver and improved support for Sixaxis and
   Dualshock 4, by Frank Praznik
 - other usual small fixes and support for new device IDs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (29 commits)
  HID: thingm: thingm_fwinfo[] doesn't need to be global
  HID: core: add two new usages for digitizer
  HID: hid-sensor-hub: new device id and quirk for STM Sensor hub
  HID: usbhid: enable NO_INIT_REPORTS quirk for Semico USB Keykoard
  HID: hid-sensor-hub: Set report quirk for Microsoft Surface
  HID: debug: add labels for HID Sensor Usages
  HID: uhid: Use kmemdup instead of kmalloc + memcpy
  HID: rmi: do not handle touchscreens through hid-rmi
  HID: quirk for Saitek RAT7 and MMO7 mices' mode button
  HID: core: fix validation of report id 0
  HID: rmi: fix masks for x and w_x data
  HID: rmi: fix wrong struct field name
  HID: rmi: do not fetch more than 16 bytes in a query
  HID: rmi: check for the existence of some optional queries before reading query 12
  HID: i2c-hid: hid report descriptor retrieval changes
  HID: add missing hid usages
  HID: hid-sony - allow 3rd party INTEC controller to turn off all leds
  HID: sony: Add blink support to the Sixaxis and DualShock 4 LEDs
  HID: sony: Initialize the controller LEDs with a device ID value
  HID: sony: Use the controller Bluetooth MAC address as the unique value in the battery name string
  ...
What: /sys/class/leds/blink1::<serial>/rgb
Date: January 2013
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Description: The ThingM blink1 is an USB RGB LED. The color notation is
3-byte hexadecimal. Read this attribute to get the last set
color. Write the 24-bit hexadecimal color to change the current
LED color. The default color is full white (0xFFFFFF).
For instance, set the color to green with: echo 00FF00 > rgb
What: /sys/class/leds/blink1::<serial>/fade
Date: January 2013
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Description: This attribute allows to set a fade time in milliseconds for
the next color change. Read the attribute to know the current
fade time. The default value is set to 0 (no fade time). For
instance, set a fade time of 2 seconds with: echo 2000 > fade
What: /sys/class/leds/blink1::<serial>/play
Date: January 2013
Contact: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Description: This attribute is used to play/pause the light patterns. Write 1
to start playing, 0 to stop. Reading this attribute returns the
current playing status.
......@@ -608,7 +608,10 @@ config HID_SAITEK
Support for Saitek devices that are not fully compliant with the
HID standard.
Currently only supports the PS1000 controller.
Supported devices:
- PS1000 Dual Analog Pad
- R.A.T.7 Gaming Mouse
- M.M.O.7 Gaming Mouse
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
......@@ -657,6 +660,14 @@ config HID_SUNPLUS
---help---
Support for Sunplus wireless desktop.
config HID_RMI
tristate "Synaptics RMI4 device support"
depends on HID
---help---
Support for Synaptics RMI4 touchpads.
Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid
and want support for its special functionalities.
config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support"
depends on HID
......
......@@ -97,6 +97,7 @@ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o
obj-$(CONFIG_HID_RMI) += hid-rmi.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
......
......@@ -779,6 +779,14 @@ static int hid_scan_report(struct hid_device *hid)
(hid->group == HID_GROUP_MULTITOUCH))
hid->group = HID_GROUP_MULTITOUCH_WIN_8;
/*
* Vendor specific handlings
*/
if ((hid->vendor == USB_VENDOR_ID_SYNAPTICS) &&
(hid->group == HID_GROUP_GENERIC))
/* hid-rmi should take care of them, not hid-generic */
hid->group = HID_GROUP_RMI;
vfree(parser);
return 0;
}
......@@ -842,7 +850,17 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
* ->numbered being checked, which may not always be the case when
* drivers go to access report values.
*/
report = hid->report_enum[type].report_id_hash[id];
if (id == 0) {
/*
* Validating on id 0 means we should examine the first
* report in the list.
*/
report = list_entry(
hid->report_enum[type].report_list.next,
struct hid_report, list);
} else {
report = hid->report_enum[type].report_id_hash[id];
}
if (!report) {
hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
return NULL;
......@@ -1868,7 +1886,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
#endif
#if IS_ENABLED(CONFIG_HID_SAITEK)
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
......
......@@ -165,6 +165,8 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x53, "DeviceIndex"},
{0, 0x54, "ContactCount"},
{0, 0x55, "ContactMaximumNumber"},
{0, 0x5A, "SecondaryBarrelSwitch"},
{0, 0x5B, "TransducerSerialNumber"},
{ 15, 0, "PhysicalInterfaceDevice" },
{0, 0x00, "Undefined"},
{0, 0x01, "Physical_Interface_Device"},
......@@ -272,6 +274,85 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"},
{ 0x20, 0, "Sensor" },
{ 0x20, 0x01, "Sensor" },
{ 0x20, 0x10, "Biometric" },
{ 0x20, 0x11, "BiometricHumanPresence" },
{ 0x20, 0x12, "BiometricHumanProximity" },
{ 0x20, 0x13, "BiometricHumanTouch" },
{ 0x20, 0x20, "Electrical" },
{ 0x20, 0x21, "ElectricalCapacitance" },
{ 0x20, 0x22, "ElectricalCurrent" },
{ 0x20, 0x23, "ElectricalPower" },
{ 0x20, 0x24, "ElectricalInductance" },
{ 0x20, 0x25, "ElectricalResistance" },
{ 0x20, 0x26, "ElectricalVoltage" },
{ 0x20, 0x27, "ElectricalPoteniometer" },
{ 0x20, 0x28, "ElectricalFrequency" },
{ 0x20, 0x29, "ElectricalPeriod" },
{ 0x20, 0x30, "Environmental" },
{ 0x20, 0x31, "EnvironmentalAtmosphericPressure" },
{ 0x20, 0x32, "EnvironmentalHumidity" },
{ 0x20, 0x33, "EnvironmentalTemperature" },
{ 0x20, 0x34, "EnvironmentalWindDirection" },
{ 0x20, 0x35, "EnvironmentalWindSpeed" },
{ 0x20, 0x40, "Light" },
{ 0x20, 0x41, "LightAmbientLight" },
{ 0x20, 0x42, "LightConsumerInfrared" },
{ 0x20, 0x50, "Location" },
{ 0x20, 0x51, "LocationBroadcast" },
{ 0x20, 0x52, "LocationDeadReckoning" },
{ 0x20, 0x53, "LocationGPS" },
{ 0x20, 0x54, "LocationLookup" },
{ 0x20, 0x55, "LocationOther" },
{ 0x20, 0x56, "LocationStatic" },
{ 0x20, 0x57, "LocationTriangulation" },
{ 0x20, 0x60, "Mechanical" },
{ 0x20, 0x61, "MechanicalBooleanSwitch" },
{ 0x20, 0x62, "MechanicalBooleanSwitchArray" },
{ 0x20, 0x63, "MechanicalMultivalueSwitch" },
{ 0x20, 0x64, "MechanicalForce" },
{ 0x20, 0x65, "MechanicalPressure" },
{ 0x20, 0x66, "MechanicalStrain" },
{ 0x20, 0x67, "MechanicalWeight" },
{ 0x20, 0x68, "MechanicalHapticVibrator" },
{ 0x20, 0x69, "MechanicalHallEffectSwitch" },
{ 0x20, 0x70, "Motion" },
{ 0x20, 0x71, "MotionAccelerometer1D" },
{ 0x20, 0x72, "MotionAccelerometer2D" },
{ 0x20, 0x73, "MotionAccelerometer3D" },
{ 0x20, 0x74, "MotionGyrometer1D" },
{ 0x20, 0x75, "MotionGyrometer2D" },
{ 0x20, 0x76, "MotionGyrometer3D" },
{ 0x20, 0x77, "MotionMotionDetector" },
{ 0x20, 0x78, "MotionSpeedometer" },
{ 0x20, 0x79, "MotionAccelerometer" },
{ 0x20, 0x7A, "MotionGyrometer" },
{ 0x20, 0x80, "Orientation" },
{ 0x20, 0x81, "OrientationCompass1D" },
{ 0x20, 0x82, "OrientationCompass2D" },
{ 0x20, 0x83, "OrientationCompass3D" },
{ 0x20, 0x84, "OrientationInclinometer1D" },
{ 0x20, 0x85, "OrientationInclinometer2D" },
{ 0x20, 0x86, "OrientationInclinometer3D" },
{ 0x20, 0x87, "OrientationDistance1D" },
{ 0x20, 0x88, "OrientationDistance2D" },
{ 0x20, 0x89, "OrientationDistance3D" },
{ 0x20, 0x8A, "OrientationDeviceOrientation" },
{ 0x20, 0x8B, "OrientationCompass" },
{ 0x20, 0x8C, "OrientationInclinometer" },
{ 0x20, 0x8D, "OrientationDistance" },
{ 0x20, 0x90, "Scanner" },
{ 0x20, 0x91, "ScannerBarcode" },
{ 0x20, 0x91, "ScannerRFID" },
{ 0x20, 0x91, "ScannerNFC" },
{ 0x20, 0xA0, "Time" },
{ 0x20, 0xA1, "TimeAlarmTimer" },
{ 0x20, 0xA2, "TimeRealTimeClock" },
{ 0x20, 0xE0, "Other" },
{ 0x20, 0xE1, "OtherCustom" },
{ 0x20, 0xE2, "OtherGeneric" },
{ 0x20, 0xE3, "OtherGenericEnumerator" },
{ 0x84, 0, "Power Device" },
{ 0x84, 0x02, "PresentStatus" },
{ 0x84, 0x03, "ChangeStatus" },
......@@ -855,6 +936,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
[KEY_KBDILLUMUP] = "KbdIlluminationUp",
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
[KEY_BUTTONCONFIG] = "ButtonConfig",
[KEY_TASKMANAGER] = "TaskManager",
[KEY_JOURNAL] = "Journal",
[KEY_CONTROLPANEL] = "ControlPanel",
[KEY_APPSELECT] = "AppSelect",
[KEY_SCREENSAVER] = "ScreenSaver",
[KEY_VOICECOMMAND] = "VoiceCommand",
[KEY_BRIGHTNESS_MIN] = "BrightnessMin",
[KEY_BRIGHTNESS_MAX] = "BrightnessMax",
[KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
};
static const char *relatives[REL_MAX + 1] = {
......
......@@ -463,6 +463,7 @@
#define USB_VENDOR_ID_STM_0 0x0483
#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1
#define USB_DEVICE_ID_STM_HID_SENSOR_1 0x9100
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
......@@ -633,6 +634,9 @@
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
......@@ -764,11 +768,16 @@
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
#define USB_DEVICE_ID_SAITEK_PS1000 0x0621
#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
#define USB_VENDOR_ID_SEMICO 0x1a2c
#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023
#define USB_VENDOR_ID_SENNHEISER 0x1395
#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c
......
......@@ -684,9 +684,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case 0x46: /* TabletPick */
case 0x5a: /* SecondaryBarrelSwitch */
map_key_clear(BTN_STYLUS2);
break;
case 0x5b: /* TransducerSerialNumber */
set_bit(MSC_SERIAL, input->mscbit);
break;
default: goto unknown;
}
break;
......@@ -721,6 +726,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x06c: map_key_clear(KEY_YELLOW); break;
case 0x06d: map_key_clear(KEY_ZOOM); break;
case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break;
case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break;
case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break;
case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break;
case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break;
case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); 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;
......@@ -761,6 +773,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
case 0x0e2: map_key_clear(KEY_MUTE); break;
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
......@@ -768,6 +781,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x0f5: map_key_clear(KEY_SLOW); break;
case 0x181: map_key_clear(KEY_BUTTONCONFIG); break;
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
......@@ -781,6 +795,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
case 0x18e: map_key_clear(KEY_CALENDAR); break;
case 0x18f: map_key_clear(KEY_TASKMANAGER); break;
case 0x190: map_key_clear(KEY_JOURNAL); 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;
......@@ -789,12 +805,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
case 0x19f: map_key_clear(KEY_CONTROLPANEL); break;
case 0x1a2: map_key_clear(KEY_APPSELECT); break;
case 0x1a3: map_key_clear(KEY_NEXT); break;
case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
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 0x1ae: map_key_clear(KEY_KEYBOARD); break;
case 0x1b1: map_key_clear(KEY_SCREENSAVER); break;
case 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break;
......
/*
* Copyright (c) 2013 Andrew Duggan <aduggan@synaptics.com>
* Copyright (c) 2013 Synaptics Incorporated
* Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2014 Red Hat, Inc
*
* 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/kernel.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include "hid-ids.h"
#define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */
#define RMI_WRITE_REPORT_ID 0x09 /* Output Report */
#define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */
#define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */
#define RMI_ATTN_REPORT_ID 0x0c /* Input Report */
#define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */
/* flags */
#define RMI_READ_REQUEST_PENDING BIT(0)
#define RMI_READ_DATA_PENDING BIT(1)
#define RMI_STARTED BIT(2)
enum rmi_mode_type {
RMI_MODE_OFF = 0,
RMI_MODE_ATTN_REPORTS = 1,
RMI_MODE_NO_PACKED_ATTN_REPORTS = 2,
};
struct rmi_function {
unsigned page; /* page of the function */
u16 query_base_addr; /* base address for queries */
u16 command_base_addr; /* base address for commands */
u16 control_base_addr; /* base address for controls */
u16 data_base_addr; /* base address for datas */
unsigned int interrupt_base; /* cross-function interrupt number
* (uniq in the device)*/
unsigned int interrupt_count; /* number of interrupts */
unsigned int report_size; /* size of a report */
unsigned long irq_mask; /* mask of the interrupts
* (to be applied against ATTN IRQ) */
};
/**
* struct rmi_data - stores information for hid communication
*
* @page_mutex: Locks current page to avoid changing pages in unexpected ways.
* @page: Keeps track of the current virtual page
*
* @wait: Used for waiting for read data
*
* @writeReport: output buffer when writing RMI registers
* @readReport: input buffer when reading RMI registers
*
* @input_report_size: size of an input report (advertised by HID)
* @output_report_size: size of an output report (advertised by HID)
*
* @flags: flags for the current device (started, reading, etc...)
*
* @f11: placeholder of internal RMI function F11 description
* @f30: placeholder of internal RMI function F30 description
*
* @max_fingers: maximum finger count reported by the device
* @max_x: maximum x value reported by the device
* @max_y: maximum y value reported by the device
*
* @gpio_led_count: count of GPIOs + LEDs reported by F30
* @button_count: actual physical buttons count
* @button_mask: button mask used to decode GPIO ATTN reports
* @button_state_mask: pull state of the buttons
*
* @input: pointer to the kernel input device
*
* @reset_work: worker which will be called in case of a mouse report
* @hdev: pointer to the struct hid_device
*/
struct rmi_data {
struct mutex page_mutex;
int page;
wait_queue_head_t wait;
u8 *writeReport;
u8 *readReport;
int input_report_size;
int output_report_size;
unsigned long flags;
struct rmi_function f11;
struct rmi_function f30;
unsigned int max_fingers;
unsigned int max_x;
unsigned int max_y;
unsigned int x_size_mm;
unsigned int y_size_mm;
unsigned int gpio_led_count;
unsigned int button_count;
unsigned long button_mask;
unsigned long button_state_mask;
struct input_dev *input;
struct work_struct reset_work;
struct hid_device *hdev;
};
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
static int rmi_write_report(struct hid_device *hdev, u8 *report, int len);
/**
* rmi_set_page - Set RMI page
* @hdev: The pointer to the hid_device struct
* @page: The new page address.
*
* RMI devices have 16-bit addressing, but some of the physical
* implementations (like SMBus) only have 8-bit addressing. So RMI implements
* a page address at 0xff of every page so we can reliable page addresses
* every 256 registers.
*
* The page_mutex lock must be held when this function is entered.
*
* Returns zero on success, non-zero on failure.
*/
static int rmi_set_page(struct hid_device *hdev, u8 page)
{
struct rmi_data *data = hid_get_drvdata(hdev);
int retval;
data->writeReport[0] = RMI_WRITE_REPORT_ID;
data->writeReport[1] = 1;
data->writeReport[2] = 0xFF;
data->writeReport[4] = page;
retval = rmi_write_report(hdev, data->writeReport,
data->output_report_size);
if (retval != data->output_report_size) {
dev_err(&hdev->dev,
"%s: set page failed: %d.", __func__, retval);
return retval;
}
data->page = page;
return 0;
}
static int rmi_set_mode(struct hid_device *hdev, u8 mode)
{
int ret;
u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, txbuf,
sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0) {
dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode,
ret);
return ret;
}
return 0;
}
static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
{
int ret;
ret = hid_hw_output_report(hdev, (void *)report, len);
if (ret < 0) {
dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
return ret;
}
return ret;
}
static int rmi_read_block(struct hid_device *hdev, u16 addr, void *buf,
const int len)
{
struct rmi_data *data = hid_get_drvdata(hdev);
int ret;
int bytes_read;
int bytes_needed;
int retries;
int read_input_count;
mutex_lock(&data->page_mutex);
if (RMI_PAGE(addr) != data->page) {
ret = rmi_set_page(hdev, RMI_PAGE(addr));
if (ret < 0)
goto exit;
}
for (retries = 5; retries > 0; retries--) {
data->writeReport[0] = RMI_READ_ADDR_REPORT_ID;
data->writeReport[1] = 0; /* old 1 byte read count */
data->writeReport[2] = addr & 0xFF;
data->writeReport[3] = (addr >> 8) & 0xFF;
data->writeReport[4] = len & 0xFF;
data->writeReport[5] = (len >> 8) & 0xFF;
set_bit(RMI_READ_REQUEST_PENDING, &data->flags);
ret = rmi_write_report(hdev, data->writeReport,
data->output_report_size);
if (ret != data->output_report_size) {
clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
dev_err(&hdev->dev,
"failed to write request output report (%d)\n",
ret);
goto exit;
}
bytes_read = 0;
bytes_needed = len;
while (bytes_read < len) {
if (!wait_event_timeout(data->wait,
test_bit(RMI_READ_DATA_PENDING, &data->flags),
msecs_to_jiffies(1000))) {
hid_warn(hdev, "%s: timeout elapsed\n",
__func__);
ret = -EAGAIN;
break;
}
read_input_count = data->readReport[1];
memcpy(buf + bytes_read, &data->readReport[2],
read_input_count < bytes_needed ?
read_input_count : bytes_needed);
bytes_read += read_input_count;
bytes_needed -= read_input_count;
clear_bit(RMI_READ_DATA_PENDING, &data->flags);
}
if (ret >= 0) {
ret = 0;
break;
}
}
exit:
clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
mutex_unlock(&data->page_mutex);
return ret;
}
static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf)
{
return rmi_read_block(hdev, addr, buf, 1);
}
static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
u8 finger_state, u8 *touch_data)
{
int x, y, wx, wy;
int wide, major, minor;
int z;
input_mt_slot(hdata->input, slot);
input_mt_report_slot_state(hdata->input, MT_TOOL_FINGER,
finger_state == 0x01);
if (finger_state == 0x01) {
x = (touch_data[0] << 4) | (touch_data[2] & 0x0F);
y = (touch_data[1] << 4) | (touch_data[2] >> 4);
wx = touch_data[3] & 0x0F;
wy = touch_data[3] >> 4;
wide = (wx > wy);
major = max(wx, wy);
minor = min(wx, wy);
z = touch_data[4];
/* y is inverted */
y = hdata->max_y - y;
input_event(hdata->input, EV_ABS, ABS_MT_POSITION_X, x);
input_event(hdata->input, EV_ABS, ABS_MT_POSITION_Y, y);
input_event(hdata->input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(hdata->input, EV_ABS, ABS_MT_PRESSURE, z);
input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
}
}
static void rmi_reset_work(struct work_struct *work)
{
struct rmi_data *hdata = container_of(work, struct rmi_data,
reset_work);
/* switch the device to RMI if we receive a generic mouse report */
rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS);
}
static inline int rmi_schedule_reset(struct hid_device *hdev)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
return schedule_work(&hdata->reset_work);
}
static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
int size)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
int offset;
int i;
if (size < hdata->f11.report_size)
return 0;
if (!(irq & hdata->f11.irq_mask))
return 0;
offset = (hdata->max_fingers >> 2) + 1;
for (i = 0; i < hdata->max_fingers; i++) {
int fs_byte_position = i >> 2;
int fs_bit_position = (i & 0x3) << 1;
int finger_state = (data[fs_byte_position] >> fs_bit_position) &
0x03;
rmi_f11_process_touch(hdata, i, finger_state,
&data[offset + 5 * i]);
}
input_mt_sync_frame(hdata->input);
input_sync(hdata->input);
return hdata->f11.report_size;
}
static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
int size)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
int i;
int button = 0;
bool value;
if (!(irq & hdata->f30.irq_mask))
return 0;
for (i = 0; i < hdata->gpio_led_count; i++) {
if (test_bit(i, &hdata->button_mask)) {
value = (data[i / 8] >> (i & 0x07)) & BIT(0);
if (test_bit(i, &hdata->button_state_mask))
value = !value;
input_event(hdata->input, EV_KEY, BTN_LEFT + button++,
value);
}
}
return hdata->f30.report_size;
}
static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
unsigned long irq_mask = 0;
unsigned index = 2;
if (!(test_bit(RMI_STARTED, &hdata->flags)))
return 0;
irq_mask |= hdata->f11.irq_mask;
irq_mask |= hdata->f30.irq_mask;
if (data[1] & ~irq_mask)
hid_warn(hdev, "unknown intr source:%02lx %s:%d\n",
data[1] & ~irq_mask, __FILE__, __LINE__);
if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) {
index += rmi_f11_input_event(hdev, data[1], &data[index],
size - index);
index += rmi_f30_input_event(hdev, data[1], &data[index],
size - index);
} else {
index += rmi_f30_input_event(hdev, data[1], &data[index],
size - index);
index += rmi_f11_input_event(hdev, data[1], &data[index],
size - index);
}
return 1;
}
static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
hid_err(hdev, "no read request pending\n");
return 0;
}
memcpy(hdata->readReport, data, size < hdata->input_report_size ?
size : hdata->input_report_size);
set_bit(RMI_READ_DATA_PENDING, &hdata->flags);
wake_up(&hdata->wait);
return 1;
}
static int rmi_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
switch (data[0]) {
case RMI_READ_DATA_REPORT_ID:
return rmi_read_data_event(hdev, data, size);
case RMI_ATTN_REPORT_ID:
return rmi_input_event(hdev, data, size);
case RMI_MOUSE_REPORT_ID:
rmi_schedule_reset(hdev);
break;
}
return 0;
}
static int rmi_post_reset(struct hid_device *hdev)
{
return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
}
static int rmi_post_resume(struct hid_device *hdev)
{
return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
}
#define RMI4_MAX_PAGE 0xff
#define RMI4_PAGE_SIZE 0x0100
#define PDT_START_SCAN_LOCATION 0x00e9
#define PDT_END_SCAN_LOCATION 0x0005
#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
struct pdt_entry {
u8 query_base_addr:8;
u8 command_base_addr:8;
u8 control_base_addr:8;
u8 data_base_addr:8;
u8 interrupt_source_count:3;
u8 bits3and4:2;
u8 function_version:2;
u8 bit7:1;
u8 function_number:8;
} __attribute__((__packed__));
static inline unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count)
{
return GENMASK(irq_count + irq_base - 1, irq_base);
}
static void rmi_register_function(struct rmi_data *data,
struct pdt_entry *pdt_entry, int page, unsigned interrupt_count)
{
struct rmi_function *f = NULL;
u16 page_base = page << 8;
switch (pdt_entry->function_number) {
case 0x11:
f = &data->f11;
break;
case 0x30:
f = &data->f30;
break;
}
if (f) {
f->page = page;
f->query_base_addr = page_base | pdt_entry->query_base_addr;
f->command_base_addr = page_base | pdt_entry->command_base_addr;
f->control_base_addr = page_base | pdt_entry->control_base_addr;
f->data_base_addr = page_base | pdt_entry->data_base_addr;
f->interrupt_base = interrupt_count;
f->interrupt_count = pdt_entry->interrupt_source_count;
f->irq_mask = rmi_gen_mask(f->interrupt_base,
f->interrupt_count);
}
}
static int rmi_scan_pdt(struct hid_device *hdev)
{
struct rmi_data *data = hid_get_drvdata(hdev);
struct pdt_entry entry;
int page;
bool page_has_function;
int i;
int retval;
int interrupt = 0;
u16 page_start, pdt_start , pdt_end;
hid_info(hdev, "Scanning PDT...\n");
for (page = 0; (page <= RMI4_MAX_PAGE); page++) {
page_start = RMI4_PAGE_SIZE * page;
pdt_start = page_start + PDT_START_SCAN_LOCATION;
pdt_end = page_start + PDT_END_SCAN_LOCATION;
page_has_function = false;
for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) {
retval = rmi_read_block(hdev, i, &entry, sizeof(entry));
if (retval) {
hid_err(hdev,
"Read of PDT entry at %#06x failed.\n",
i);
goto error_exit;
}
if (RMI4_END_OF_PDT(entry.function_number))
break;
page_has_function = true;
hid_info(hdev, "Found F%02X on page %#04x\n",
entry.function_number, page);
rmi_register_function(data, &entry, page, interrupt);
interrupt += entry.interrupt_source_count;
}
if (!page_has_function)
break;
}
hid_info(hdev, "%s: Done with PDT scan.\n", __func__);
retval = 0;
error_exit:
return retval;
}
static int rmi_populate_f11(struct hid_device *hdev)
{
struct rmi_data *data = hid_get_drvdata(hdev);
u8 buf[20];
int ret;
bool has_query9;
bool has_query10;
bool has_query11;
bool has_query12;
bool has_physical_props;
unsigned x_size, y_size;
u16 query12_offset;
if (!data->f11.query_base_addr) {
hid_err(hdev, "No 2D sensor found, giving up.\n");
return -ENODEV;
}
/* query 0 contains some useful information */
ret = rmi_read(hdev, data->f11.query_base_addr, buf);
if (ret) {
hid_err(hdev, "can not get query 0: %d.\n", ret);
return ret;
}
has_query9 = !!(buf[0] & BIT(3));
has_query11 = !!(buf[0] & BIT(4));
has_query12 = !!(buf[0] & BIT(5));
/* query 1 to get the max number of fingers */
ret = rmi_read(hdev, data->f11.query_base_addr + 1, buf);
if (ret) {
hid_err(hdev, "can not get NumberOfFingers: %d.\n", ret);
return ret;
}
data->max_fingers = (buf[0] & 0x07) + 1;
if (data->max_fingers > 5)
data->max_fingers = 10;
data->f11.report_size = data->max_fingers * 5 +
DIV_ROUND_UP(data->max_fingers, 4);
if (!(buf[0] & BIT(4))) {
hid_err(hdev, "No absolute events, giving up.\n");
return -ENODEV;
}
/* query 8 to find out if query 10 exists */
ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
if (ret) {
hid_err(hdev, "can not read gesture information: %d.\n", ret);
return ret;
}
has_query10 = !!(buf[0] & BIT(2));
/*
* At least 8 queries are guaranteed to be present in F11
* +1 for query12.
*/
query12_offset = 9;
if (has_query9)
++query12_offset;
if (has_query10)
++query12_offset;
if (has_query11)
++query12_offset;
/* query 12 to know if the physical properties are reported */
if (has_query12) {
ret = rmi_read(hdev, data->f11.query_base_addr
+ query12_offset, buf);
if (ret) {
hid_err(hdev, "can not get query 12: %d.\n", ret);
return ret;
}
has_physical_props = !!(buf[0] & BIT(5));
if (has_physical_props) {
ret = rmi_read_block(hdev,
data->f11.query_base_addr
+ query12_offset + 1, buf, 4);
if (ret) {
hid_err(hdev, "can not read query 15-18: %d.\n",
ret);
return ret;
}
x_size = buf[0] | (buf[1] << 8);
y_size = buf[2] | (buf[3] << 8);
data->x_size_mm = DIV_ROUND_CLOSEST(x_size, 10);
data->y_size_mm = DIV_ROUND_CLOSEST(y_size, 10);
hid_info(hdev, "%s: size in mm: %d x %d\n",
__func__, data->x_size_mm, data->y_size_mm);
}
}
/*
* retrieve the ctrl registers
* the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
* and there is no way to know if the first 20 bytes are here or not.
* We use only the first 10 bytes, so get only them.
*/
ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 10);
if (ret) {
hid_err(hdev, "can not read ctrl block of size 10: %d.\n", ret);
return ret;
}
data->max_x = buf[6] | (buf[7] << 8);
data->max_y = buf[8] | (buf[9] << 8);
return 0;
}
static int rmi_populate_f30(struct hid_device *hdev)
{
struct rmi_data *data = hid_get_drvdata(hdev);
u8 buf[20];
int ret;
bool has_gpio, has_led;
unsigned bytes_per_ctrl;
u8 ctrl2_addr;
int ctrl2_3_length;
int i;
/* function F30 is for physical buttons */
if (!data->f30.query_base_addr) {
hid_err(hdev, "No GPIO/LEDs found, giving up.\n");
return -ENODEV;
}
ret = rmi_read_block(hdev, data->f30.query_base_addr, buf, 2);
if (ret) {
hid_err(hdev, "can not get F30 query registers: %d.\n", ret);
return ret;
}
has_gpio = !!(buf[0] & BIT(3));
has_led = !!(buf[0] & BIT(2));
data->gpio_led_count = buf[1] & 0x1f;
/* retrieve ctrl 2 & 3 registers */
bytes_per_ctrl = (data->gpio_led_count + 7) / 8;
/* Ctrl0 is present only if both has_gpio and has_led are set*/
ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0;
/* Ctrl1 is always be present */
ctrl2_addr += bytes_per_ctrl;
ctrl2_3_length = 2 * bytes_per_ctrl;
data->f30.report_size = bytes_per_ctrl;
ret = rmi_read_block(hdev, data->f30.control_base_addr + ctrl2_addr,
buf, ctrl2_3_length);
if (ret) {
hid_err(hdev, "can not read ctrl 2&3 block of size %d: %d.\n",
ctrl2_3_length, ret);
return ret;
}
for (i = 0; i < data->gpio_led_count; i++) {
int byte_position = i >> 3;
int bit_position = i & 0x07;
u8 dir_byte = buf[byte_position];
u8 data_byte = buf[byte_position + bytes_per_ctrl];
bool dir = (dir_byte >> bit_position) & BIT(0);
bool dat = (data_byte >> bit_position) & BIT(0);
if (dir == 0) {
/* input mode */
if (dat) {
/* actual buttons have pull up resistor */
data->button_count++;
set_bit(i, &data->button_mask);
set_bit(i, &data->button_state_mask);
}
}
}
return 0;
}
static int rmi_populate(struct hid_device *hdev)
{
int ret;
ret = rmi_scan_pdt(hdev);
if (ret) {
hid_err(hdev, "PDT scan failed with code %d.\n", ret);
return ret;
}
ret = rmi_populate_f11(hdev);
if (ret) {
hid_err(hdev, "Error while initializing F11 (%d).\n", ret);
return ret;
}
ret = rmi_populate_f30(hdev);
if (ret)
hid_warn(hdev, "Error while initializing F30 (%d).\n", ret);
return 0;
}
static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct rmi_data *data = hid_get_drvdata(hdev);
struct input_dev *input = hi->input;
int ret;
int res_x, res_y, i;
data->input = input;
hid_dbg(hdev, "Opening low level driver\n");
ret = hid_hw_open(hdev);
if (ret)
return;
/* Allow incoming hid reports */
hid_device_io_start(hdev);
ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
if (ret < 0) {
dev_err(&hdev->dev, "failed to set rmi mode\n");
goto exit;
}
ret = rmi_set_page(hdev, 0);
if (ret < 0) {
dev_err(&hdev->dev, "failed to set page select to 0.\n");
goto exit;
}
ret = rmi_populate(hdev);
if (ret)
goto exit;
__set_bit(EV_ABS, input->evbit);
input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0);
if (data->x_size_mm && data->y_size_mm) {
res_x = (data->max_x - 1) / data->x_size_mm;
res_y = (data->max_y - 1) / data->y_size_mm;
input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
}
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
if (data->button_count) {
__set_bit(EV_KEY, input->evbit);
for (i = 0; i < data->button_count; i++)
__set_bit(BTN_LEFT + i, input->keybit);
if (data->button_count == 1)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
}
set_bit(RMI_STARTED, &data->flags);
exit:
hid_device_io_stop(hdev);
hid_hw_close(hdev);
}
static int rmi_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
/* we want to make HID ignore the advertised HID collection */
return -1;
}
static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct rmi_data *data = NULL;
int ret;
size_t alloc_size;
data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
INIT_WORK(&data->reset_work, rmi_reset_work);
data->hdev = hdev;
hid_set_drvdata(hdev, data);
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
return ret;
}
data->input_report_size = (hdev->report_enum[HID_INPUT_REPORT]
.report_id_hash[RMI_ATTN_REPORT_ID]->size >> 3)
+ 1 /* report id */;
data->output_report_size = (hdev->report_enum[HID_OUTPUT_REPORT]
.report_id_hash[RMI_WRITE_REPORT_ID]->size >> 3)
+ 1 /* report id */;
alloc_size = data->output_report_size + data->input_report_size;
data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
if (!data->writeReport) {
ret = -ENOMEM;
return ret;
}
data->readReport = data->writeReport + data->output_report_size;
init_waitqueue_head(&data->wait);
mutex_init(&data->page_mutex);
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
return ret;
}
if (!test_bit(RMI_STARTED, &data->flags)) {
hid_hw_stop(hdev);
return -EIO;
}
return 0;
}
static void rmi_remove(struct hid_device *hdev)
{
struct rmi_data *hdata = hid_get_drvdata(hdev);
clear_bit(RMI_STARTED, &hdata->flags);
hid_hw_stop(hdev);
}
static const struct hid_device_id rmi_id[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, rmi_id);
static struct hid_driver rmi_driver = {
.name = "hid-rmi",
.id_table = rmi_id,
.probe = rmi_probe,
.remove = rmi_remove,
.raw_event = rmi_raw_event,
.input_mapping = rmi_input_mapping,
.input_configured = rmi_input_configured,
#ifdef CONFIG_PM
.resume = rmi_post_resume,
.reset_resume = rmi_post_reset,
#endif
};
module_hid_driver(rmi_driver);
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
MODULE_DESCRIPTION("RMI HID driver");
MODULE_LICENSE("GPL");
/*
* HID driver for Saitek devices, currently only the PS1000 (USB gamepad).
* HID driver for Saitek devices.
*
* PS1000 (USB gamepad):
* Fixes the HID report descriptor by removing a non-existent axis and
* clearing the constant bit on the input reports for buttons and d-pad.
* (This module is based on "hid-ortek".)
*
* Copyright (c) 2012 Andreas Hübner
*
* R.A.T.7, M.M.O.7 (USB gaming mice):
* Fixes the mode button which cycles through three constantly pressed
* buttons. All three press events are mapped to one button and the
* missing release event is generated immediately.
*
*/
/*
......@@ -21,12 +28,57 @@
#include "hid-ids.h"
#define SAITEK_FIX_PS1000 0x0001
#define SAITEK_RELEASE_MODE_RAT7 0x0002
#define SAITEK_RELEASE_MODE_MMO7 0x0004
struct saitek_sc {
unsigned long quirks;
int mode;
};
static int saitek_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
unsigned long quirks = id->driver_data;
struct saitek_sc *ssc;
int ret;
ssc = devm_kzalloc(&hdev->dev, sizeof(*ssc), GFP_KERNEL);
if (ssc == NULL) {
hid_err(hdev, "can't alloc saitek descriptor\n");
return -ENOMEM;
}
ssc->quirks = quirks;
ssc->mode = -1;
hid_set_drvdata(hdev, ssc);
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
return ret;
}
return 0;
}
static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33
&& rdesc[94] == 0x81 && rdesc[95] == 0x03
&& rdesc[110] == 0x81 && rdesc[111] == 0x03) {
struct saitek_sc *ssc = hid_get_drvdata(hdev);
if ((ssc->quirks & SAITEK_FIX_PS1000) && *rsize == 137 &&
rdesc[20] == 0x09 && rdesc[21] == 0x33 &&
rdesc[94] == 0x81 && rdesc[95] == 0x03 &&
rdesc[110] == 0x81 && rdesc[111] == 0x03) {
hid_info(hdev, "Fixing up Saitek PS1000 report descriptor\n");
......@@ -42,8 +94,93 @@ static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
static int saitek_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *raw_data, int size)
{
struct saitek_sc *ssc = hid_get_drvdata(hdev);
if (ssc->quirks & SAITEK_RELEASE_MODE_RAT7 && size == 7) {
/* R.A.T.7 uses bits 13, 14, 15 for the mode */
int mode = -1;
if (raw_data[1] & 0x01)
mode = 0;
else if (raw_data[1] & 0x02)
mode = 1;
else if (raw_data[1] & 0x04)
mode = 2;
/* clear mode bits */
raw_data[1] &= ~0x07;
if (mode != ssc->mode) {
hid_dbg(hdev, "entered mode %d\n", mode);
if (ssc->mode != -1) {
/* use bit 13 as the mode button */
raw_data[1] |= 0x04;
}
ssc->mode = mode;
}
} else if (ssc->quirks & SAITEK_RELEASE_MODE_MMO7 && size == 8) {
/* M.M.O.7 uses bits 8, 22, 23 for the mode */
int mode = -1;
if (raw_data[1] & 0x80)
mode = 0;
else if (raw_data[2] & 0x01)
mode = 1;
else if (raw_data[2] & 0x02)
mode = 2;
/* clear mode bits */
raw_data[1] &= ~0x80;
raw_data[2] &= ~0x03;
if (mode != ssc->mode) {
hid_dbg(hdev, "entered mode %d\n", mode);
if (ssc->mode != -1) {
/* use bit 8 as the mode button, bits 22
* and 23 do not represent buttons
* according to the HID report descriptor
*/
raw_data[1] |= 0x80;
}
ssc->mode = mode;
}
}
return 0;
}
static int saitek_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct saitek_sc *ssc = hid_get_drvdata(hdev);
struct input_dev *input = field->hidinput->input;
if (usage->type == EV_KEY && value &&
(((ssc->quirks & SAITEK_RELEASE_MODE_RAT7) &&
usage->code - BTN_MOUSE == 10) ||
((ssc->quirks & SAITEK_RELEASE_MODE_MMO7) &&
usage->code - BTN_MOUSE == 15))) {
input_report_key(input, usage->code, 1);
/* report missing release event */
input_report_key(input, usage->code, 0);
return 1;
}
return 0;
}
static const struct hid_device_id saitek_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000)},
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
.driver_data = SAITEK_FIX_PS1000 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
.driver_data = SAITEK_RELEASE_MODE_MMO7 },
{ }
};
......@@ -52,7 +189,10 @@ MODULE_DEVICE_TABLE(hid, saitek_devices);
static struct hid_driver saitek_driver = {
.name = "saitek",
.id_table = saitek_devices,
.report_fixup = saitek_report_fixup
.probe = saitek_probe,
.report_fixup = saitek_report_fixup,
.raw_event = saitek_raw_event,
.event = saitek_event,
};
module_hid_driver(saitek_driver);
......
......@@ -705,8 +705,17 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
USB_DEVICE_ID_INTEL_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
USB_DEVICE_ID_MS_SURFACE_PRO_2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
USB_DEVICE_ID_MS_TOUCH_COVER_2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
USB_DEVICE_ID_MS_TYPE_COVER_2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
USB_DEVICE_ID_STM_HID_SENSOR),
USB_DEVICE_ID_STM_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS,
USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA),
......
......@@ -33,6 +33,7 @@
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/idr.h>
#include <linux/input/mt.h>
#include "hid-ids.h"
......@@ -717,8 +718,39 @@ static enum power_supply_property sony_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
};
struct sixaxis_led {
__u8 time_enabled; /* the total time the led is active (0xff means forever) */
__u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
__u8 enabled;
__u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */
__u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */
} __packed;
struct sixaxis_rumble {
__u8 padding;
__u8 right_duration; /* Right motor duration (0xff means forever) */
__u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
__u8 left_duration; /* Left motor duration (0xff means forever) */
__u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
} __packed;
struct sixaxis_output_report {
__u8 report_id;
struct sixaxis_rumble rumble;
__u8 padding[4];
__u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
struct sixaxis_led led[4]; /* LEDx at (4 - x) */
struct sixaxis_led _reserved; /* LED5, not actually soldered */
} __packed;
union sixaxis_output_report_01 {
struct sixaxis_output_report data;
__u8 buf[36];
};
static spinlock_t sony_dev_list_lock;
static LIST_HEAD(sony_device_list);
static DEFINE_IDA(sony_device_id_allocator);
struct sony_sc {
spinlock_t lock;
......@@ -728,6 +760,7 @@ struct sony_sc {
unsigned long quirks;
struct work_struct state_worker;
struct power_supply battery;
int device_id;
#ifdef CONFIG_SONY_FF
__u8 left;
......@@ -740,6 +773,8 @@ struct sony_sc {
__u8 battery_charging;
__u8 battery_capacity;
__u8 led_state[MAX_LEDS];
__u8 led_delay_on[MAX_LEDS];
__u8 led_delay_off[MAX_LEDS];
__u8 led_count;
};
......@@ -1048,6 +1083,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev)
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
}
static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
{
static const __u8 sixaxis_leds[10][4] = {
{ 0x01, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0x00, 0x00 },
{ 0x00, 0x00, 0x01, 0x00 },
{ 0x00, 0x00, 0x00, 0x01 },
{ 0x01, 0x00, 0x00, 0x01 },
{ 0x00, 0x01, 0x00, 0x01 },
{ 0x00, 0x00, 0x01, 0x01 },
{ 0x01, 0x00, 0x01, 0x01 },
{ 0x00, 0x01, 0x01, 0x01 },
{ 0x01, 0x01, 0x01, 0x01 }
};
BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0]));
if (id < 0)
return;
id %= 10;
memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
}
static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS])
{
/* The first 4 color/index entries match what the PS4 assigns */
static const __u8 color_code[7][3] = {
/* Blue */ { 0x00, 0x00, 0x01 },
/* Red */ { 0x01, 0x00, 0x00 },
/* Green */ { 0x00, 0x01, 0x00 },
/* Pink */ { 0x02, 0x00, 0x01 },
/* Orange */ { 0x02, 0x01, 0x00 },
/* Teal */ { 0x00, 0x01, 0x01 },
/* White */ { 0x01, 0x01, 0x01 }
};
BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
if (id < 0)
return;
id %= 7;
memcpy(values, color_code[id], sizeof(color_code[id]));
}
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
{
struct list_head *report_list =
......@@ -1066,19 +1147,18 @@ static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count)
{
struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
BUG_ON(count > MAX_LEDS);
if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
buzz_set_leds(hdev, leds);
if (sc->quirks & BUZZ_CONTROLLER && count == 4) {
buzz_set_leds(sc->hdev, leds);
} else {
for (n = 0; n < count; n++)
drv_data->led_state[n] = leds[n];
schedule_work(&drv_data->state_worker);
sc->led_state[n] = leds[n];
schedule_work(&sc->state_worker);
}
}
......@@ -1090,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
struct sony_sc *drv_data;
int n;
int force_update;
drv_data = hid_get_drvdata(hdev);
if (!drv_data) {
......@@ -1097,12 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led,
return;
}
/*
* The Sixaxis on USB will override any LED settings sent to it
* and keep flashing all of the LEDs until the PS button is pressed.
* Updates, even if redundant, must be always be sent to the
* controller to avoid having to toggle the state of an LED just to
* stop the flashing later on.
*/
force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB);
for (n = 0; n < drv_data->led_count; n++) {
if (led == drv_data->leds[n]) {
if (value != drv_data->led_state[n]) {
drv_data->led_state[n] = value;
sony_set_leds(hdev, drv_data->led_state, drv_data->led_count);
}
if (led == drv_data->leds[n] && (force_update ||
(value != drv_data->led_state[n] ||
drv_data->led_delay_on[n] ||
drv_data->led_delay_off[n]))) {
drv_data->led_state[n] = value;
/* Setting the brightness stops the blinking */
drv_data->led_delay_on[n] = 0;
drv_data->led_delay_off[n] = 0;
sony_set_leds(drv_data, drv_data->led_state,
drv_data->led_count);
break;
}
}
......@@ -1130,63 +1228,112 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
return LED_OFF;
}
static void sony_leds_remove(struct hid_device *hdev)
static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
unsigned long *delay_off)
{
struct sony_sc *drv_data;
struct led_classdev *led;
struct device *dev = led->dev->parent;
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
__u8 new_on, new_off;
drv_data = hid_get_drvdata(hdev);
BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
if (!drv_data) {
hid_err(hdev, "No device data\n");
return -EINVAL;
}
/* Max delay is 255 deciseconds or 2550 milliseconds */
if (*delay_on > 2550)
*delay_on = 2550;
if (*delay_off > 2550)
*delay_off = 2550;
/* Blink at 1 Hz if both values are zero */
if (!*delay_on && !*delay_off)
*delay_on = *delay_off = 500;
new_on = *delay_on / 10;
new_off = *delay_off / 10;
for (n = 0; n < drv_data->led_count; n++) {
led = drv_data->leds[n];
drv_data->leds[n] = NULL;
if (led == drv_data->leds[n])
break;
}
/* This LED is not registered on this device */
if (n >= drv_data->led_count)
return -EINVAL;
/* Don't schedule work if the values didn't change */
if (new_on != drv_data->led_delay_on[n] ||
new_off != drv_data->led_delay_off[n]) {
drv_data->led_delay_on[n] = new_on;
drv_data->led_delay_off[n] = new_off;
schedule_work(&drv_data->state_worker);
}
return 0;
}
static void sony_leds_remove(struct sony_sc *sc)
{
struct led_classdev *led;
int n;
BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
for (n = 0; n < sc->led_count; n++) {
led = sc->leds[n];
sc->leds[n] = NULL;
if (!led)
continue;
led_classdev_unregister(led);
kfree(led);
}
drv_data->led_count = 0;
sc->led_count = 0;
}
static int sony_leds_init(struct hid_device *hdev)
static int sony_leds_init(struct sony_sc *sc)
{
struct sony_sc *drv_data;
struct hid_device *hdev = sc->hdev;
int n, ret = 0;
int max_brightness;
int use_colors;
int use_ds4_names;
struct led_classdev *led;
size_t name_sz;
char *name;
size_t name_len;
const char *name_fmt;
static const char * const color_str[] = { "red", "green", "blue" };
static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
static const char * const ds4_name_str[] = { "red", "green", "blue",
"global" };
__u8 initial_values[MAX_LEDS] = { 0 };
__u8 max_brightness[MAX_LEDS] = { 1 };
__u8 use_hw_blink[MAX_LEDS] = { 0 };
drv_data = hid_get_drvdata(hdev);
BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
if (drv_data->quirks & BUZZ_CONTROLLER) {
drv_data->led_count = 4;
max_brightness = 1;
use_colors = 0;
if (sc->quirks & BUZZ_CONTROLLER) {
sc->led_count = 4;
use_ds4_names = 0;
name_len = strlen("::buzz#");
name_fmt = "%s::buzz%d";
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
} else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
drv_data->led_count = 3;
max_brightness = 255;
use_colors = 1;
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
dualshock4_set_leds_from_id(sc->device_id, initial_values);
initial_values[3] = 1;
sc->led_count = 4;
memset(max_brightness, 255, 3);
use_hw_blink[3] = 1;
use_ds4_names = 1;
name_len = 0;
name_fmt = "%s:%s";
} else {
drv_data->led_count = 4;
max_brightness = 1;
use_colors = 0;
sixaxis_set_leds_from_id(sc->device_id, initial_values);
sc->led_count = 4;
memset(use_hw_blink, 1, 4);
use_ds4_names = 0;
name_len = strlen("::sony#");
name_fmt = "%s::sony%d";
}
......@@ -1196,14 +1343,14 @@ static int sony_leds_init(struct hid_device *hdev)
* only relevant if the driver is loaded after somebody actively set the
* LEDs to on
*/
sony_set_leds(hdev, initial_values, drv_data->led_count);
sony_set_leds(sc, initial_values, sc->led_count);
name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
for (n = 0; n < drv_data->led_count; n++) {
for (n = 0; n < sc->led_count; n++) {
if (use_colors)
name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2;
if (use_ds4_names)
name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2;
led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
if (!led) {
......@@ -1213,30 +1360,35 @@ static int sony_leds_init(struct hid_device *hdev)
}
name = (void *)(&led[1]);
if (use_colors)
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]);
if (use_ds4_names)
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev),
ds4_name_str[n]);
else
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
led->name = name;
led->brightness = 0;
led->max_brightness = max_brightness;
led->brightness = initial_values[n];
led->max_brightness = max_brightness[n];
led->brightness_get = sony_led_get_brightness;
led->brightness_set = sony_led_set_brightness;
if (use_hw_blink[n])
led->blink_set = sony_led_blink_set;
sc->leds[n] = led;
ret = led_classdev_register(&hdev->dev, led);
if (ret) {
hid_err(hdev, "Failed to register LED %d\n", n);
sc->leds[n] = NULL;
kfree(led);
goto error_leds;
}
drv_data->leds[n] = led;
}
return ret;
error_leds:
sony_leds_remove(hdev);
sony_leds_remove(sc);
return ret;
}
......@@ -1244,29 +1396,52 @@ static int sony_leds_init(struct hid_device *hdev)
static void sixaxis_state_worker(struct work_struct *work)
{
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
unsigned char buf[] = {
0x01,
0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
int n;
union sixaxis_output_report_01 report = {
.buf = {
0x01,
0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
}
};
#ifdef CONFIG_SONY_FF
buf[3] = sc->right ? 1 : 0;
buf[5] = sc->left;
report.data.rumble.right_motor_on = sc->right ? 1 : 0;
report.data.rumble.left_motor_force = sc->left;
#endif
buf[10] |= sc->led_state[0] << 1;
buf[10] |= sc->led_state[1] << 2;
buf[10] |= sc->led_state[2] << 3;
buf[10] |= sc->led_state[3] << 4;
report.data.leds_bitmap |= sc->led_state[0] << 1;
report.data.leds_bitmap |= sc->led_state[1] << 2;
report.data.leds_bitmap |= sc->led_state[2] << 3;
report.data.leds_bitmap |= sc->led_state[3] << 4;
/* Set flag for all leds off, required for 3rd party INTEC controller */
if ((report.data.leds_bitmap & 0x1E) == 0)
report.data.leds_bitmap |= 0x20;
hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
HID_REQ_SET_REPORT);
/*
* The LEDs in the report are indexed in reverse order to their
* corresponding light on the controller.
* Index 0 = LED 4, index 1 = LED 3, etc...
*
* In the case of both delay values being zero (blinking disabled) the
* default report values should be used or the controller LED will be
* always off.
*/
for (n = 0; n < 4; n++) {
if (sc->led_delay_on[n] || sc->led_delay_off[n]) {
report.data.led[3 - n].duty_off = sc->led_delay_off[n];
report.data.led[3 - n].duty_on = sc->led_delay_on[n];
}
}
hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf,
sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
static void dualshock4_state_worker(struct work_struct *work)
......@@ -1279,7 +1454,7 @@ static void dualshock4_state_worker(struct work_struct *work)
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
buf[0] = 0x05;
buf[1] = 0x03;
buf[1] = 0xFF;
offset = 4;
} else {
buf[0] = 0x11;
......@@ -1295,9 +1470,18 @@ static void dualshock4_state_worker(struct work_struct *work)
offset += 2;
#endif
buf[offset++] = sc->led_state[0];
buf[offset++] = sc->led_state[1];
buf[offset++] = sc->led_state[2];
/* LED 3 is the global control */
if (sc->led_state[3]) {
buf[offset++] = sc->led_state[0];
buf[offset++] = sc->led_state[1];
buf[offset++] = sc->led_state[2];
} else {
offset += 3;
}
/* If both delay values are zero the DualShock 4 disables blinking. */
buf[offset++] = sc->led_delay_on[3];
buf[offset++] = sc->led_delay_off[3];
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
hid_hw_output_report(hdev, buf, 32);
......@@ -1323,9 +1507,9 @@ static int sony_play_effect(struct input_dev *dev, void *data,
return 0;
}
static int sony_init_ff(struct hid_device *hdev)
static int sony_init_ff(struct sony_sc *sc)
{
struct hid_input *hidinput = list_entry(hdev->inputs.next,
struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
......@@ -1334,7 +1518,7 @@ static int sony_init_ff(struct hid_device *hdev)
}
#else
static int sony_init_ff(struct hid_device *hdev)
static int sony_init_ff(struct sony_sc *sc)
{
return 0;
}
......@@ -1384,8 +1568,6 @@ static int sony_battery_get_property(struct power_supply *psy,
static int sony_battery_probe(struct sony_sc *sc)
{
static atomic_t power_id_seq = ATOMIC_INIT(0);
unsigned long power_id;
struct hid_device *hdev = sc->hdev;
int ret;
......@@ -1395,15 +1577,13 @@ static int sony_battery_probe(struct sony_sc *sc)
*/
sc->battery_capacity = 100;
power_id = (unsigned long)atomic_inc_return(&power_id_seq);
sc->battery.properties = sony_battery_props;
sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
sc->battery.get_property = sony_battery_get_property;
sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
sc->battery.use_for_apm = 0;
sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
power_id);
sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR",
sc->mac_address);
if (!sc->battery.name)
return -ENOMEM;
......@@ -1578,6 +1758,52 @@ static int sony_check_add(struct sony_sc *sc)
return sony_check_add_dev_list(sc);
}
static int sony_set_device_id(struct sony_sc *sc)
{
int ret;
/*
* Only DualShock 4 or Sixaxis controllers get an id.
* All others are set to -1.
*/
if ((sc->quirks & SIXAXIS_CONTROLLER) ||
(sc->quirks & DUALSHOCK4_CONTROLLER)) {
ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
GFP_KERNEL);
if (ret < 0) {
sc->device_id = -1;
return ret;
}
sc->device_id = ret;
} else {
sc->device_id = -1;
}
return 0;
}
static void sony_release_device_id(struct sony_sc *sc)
{
if (sc->device_id >= 0) {
ida_simple_remove(&sony_device_id_allocator, sc->device_id);
sc->device_id = -1;
}
}
static inline void sony_init_work(struct sony_sc *sc,
void (*worker)(struct work_struct *))
{
if (!sc->worker_initialized)
INIT_WORK(&sc->state_worker, worker);
sc->worker_initialized = 1;
}
static inline void sony_cancel_work_sync(struct sony_sc *sc)
{
if (sc->worker_initialized)
cancel_work_sync(&sc->state_worker);
}
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
......@@ -1615,6 +1841,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
ret = sony_set_device_id(sc);
if (ret < 0) {
hid_err(hdev, "failed to allocate the device id\n");
goto err_stop;
}
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
/*
* The Sony Sixaxis does not handle HID Output Reports on the
......@@ -1629,8 +1861,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
/*
* The Sixaxis wants output reports sent on the ctrl endpoint
......@@ -1638,8 +1869,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
/*
......@@ -1661,8 +1891,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
sc->worker_initialized = 1;
INIT_WORK(&sc->state_worker, dualshock4_state_worker);
sony_init_work(sc, dualshock4_state_worker);
} else {
ret = 0;
}
......@@ -1675,7 +1904,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
if (sc->quirks & SONY_LED_SUPPORT) {
ret = sony_leds_init(hdev);
ret = sony_leds_init(sc);
if (ret < 0)
goto err_stop;
}
......@@ -1694,7 +1923,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SONY_FF_SUPPORT) {
ret = sony_init_ff(hdev);
ret = sony_init_ff(sc);
if (ret < 0)
goto err_close;
}
......@@ -1704,12 +1933,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT)
sony_battery_remove(sc);
if (sc->worker_initialized)
cancel_work_sync(&sc->state_worker);
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
sony_release_device_id(sc);
hid_hw_stop(hdev);
return ret;
}
......@@ -1719,18 +1948,19 @@ static void sony_remove(struct hid_device *hdev)
struct sony_sc *sc = hid_get_drvdata(hdev);
if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(hdev);
sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT) {
hid_hw_close(hdev);
sony_battery_remove(sc);
}
if (sc->worker_initialized)
cancel_work_sync(&sc->state_worker);
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
sony_release_device_id(sc);
hid_hw_stop(hdev);
}
......@@ -1775,6 +2005,22 @@ static struct hid_driver sony_driver = {
.report_fixup = sony_report_fixup,
.raw_event = sony_raw_event
};
module_hid_driver(sony_driver);
static int __init sony_init(void)
{
dbg_hid("Sony:%s\n", __func__);
return hid_register_driver(&sony_driver);
}
static void __exit sony_exit(void)
{
dbg_hid("Sony:%s\n", __func__);
ida_destroy(&sony_device_id_allocator);
hid_unregister_driver(&sony_driver);
}
module_init(sony_init);
module_exit(sony_exit);
MODULE_LICENSE("GPL");
/*
* ThingM blink(1) USB RGB LED driver
*
* Copyright 2013 Savoir-faire Linux Inc.
* Copyright 2013-2014 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or
......@@ -10,244 +10,285 @@
*/
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include "hid-ids.h"
#define BLINK1_CMD_SIZE 9
#define REPORT_ID 1
#define REPORT_SIZE 9
#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16)
#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8)
#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0)
/* Firmware major number of supported devices */
#define THINGM_MAJOR_MK1 '1'
#define THINGM_MAJOR_MK2 '2'
/**
* struct blink1_data - blink(1) device specific data
* @hdev: HID device.
* @led_cdev: LED class instance.
* @rgb: 8-bit per channel RGB notation.
* @fade: fade time in hundredths of a second.
* @brightness: brightness coefficient.
* @play: play/pause in-memory patterns.
*/
struct blink1_data {
struct thingm_fwinfo {
char major;
unsigned numrgb;
unsigned first;
};
static const struct thingm_fwinfo thingm_fwinfo[] = {
{
.major = THINGM_MAJOR_MK1,
.numrgb = 1,
.first = 0,
}, {
.major = THINGM_MAJOR_MK2,
.numrgb = 2,
.first = 1,
}
};
/* A red, green or blue channel, part of an RGB chip */
struct thingm_led {
struct thingm_rgb *rgb;
struct led_classdev ldev;
char name[32];
};
/* Basically a WS2812 5050 RGB LED chip */
struct thingm_rgb {
struct thingm_device *tdev;
struct thingm_led red;
struct thingm_led green;
struct thingm_led blue;
struct work_struct work;
u8 num;
};
struct thingm_device {
struct hid_device *hdev;
struct led_classdev led_cdev;
u32 rgb;
u16 fade;
u8 brightness;
bool play;
struct {
char major;
char minor;
} version;
const struct thingm_fwinfo *fwinfo;
struct mutex lock;
struct thingm_rgb *rgb;
};
static int blink1_send_command(struct blink1_data *data,
u8 buf[BLINK1_CMD_SIZE])
static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
int ret;
hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
static int blink1_update_color(struct blink1_data *data)
static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
if (data->brightness) {
unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
int ret;
buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
}
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0)
return ret;
if (data->fade) {
buf[1] = 'c';
buf[5] = (data->fade & 0xFF00) >> 8;
buf[6] = (data->fade & 0x00FF);
}
hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
return blink1_send_command(data, buf);
return 0;
}
static void blink1_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
static int thingm_version(struct thingm_device *tdev)
{
struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
int err;
data->brightness = brightness;
if (blink1_update_color(data))
hid_err(data->hdev, "failed to update color\n");
}
err = thingm_send(tdev, buf);
if (err)
return err;
static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
{
struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
err = thingm_recv(tdev, buf);
if (err)
return err;
return data->brightness;
tdev->version.major = buf[3];
tdev->version.minor = buf[4];
return 0;
}
static ssize_t blink1_show_rgb(struct device *dev,
struct device_attribute *attr, char *buf)
static int thingm_write_color(struct thingm_rgb *rgb)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
return sprintf(buf, "%.6X\n", data->rgb);
buf[2] = rgb->red.ldev.brightness;
buf[3] = rgb->green.ldev.brightness;
buf[4] = rgb->blue.ldev.brightness;
return thingm_send(rgb->tdev, buf);
}
static ssize_t blink1_store_rgb(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
static void thingm_work(struct work_struct *work)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
long unsigned int rgb;
int ret;
struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
ret = kstrtoul(buf, 16, &rgb);
if (ret)
return ret;
/* RGB triplet notation is 24-bit hexadecimal */
if (rgb > 0xFFFFFF)
return -EINVAL;
mutex_lock(&rgb->tdev->lock);
data->rgb = rgb;
ret = blink1_update_color(data);
if (thingm_write_color(rgb))
hid_err(rgb->tdev->hdev, "failed to write color\n");
return ret ? ret : count;
mutex_unlock(&rgb->tdev->lock);
}
static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
static ssize_t blink1_show_fade(struct device *dev,
struct device_attribute *attr, char *buf)
static void thingm_led_set(struct led_classdev *ldev,
enum led_brightness brightness)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
return sprintf(buf, "%d\n", data->fade * 10);
/* the ledclass has already stored the brightness value */
schedule_work(&led->rgb->work);
}
static ssize_t blink1_store_fade(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
static int thingm_init_rgb(struct thingm_rgb *rgb)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
long unsigned int fade;
int ret;
const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
int err;
/* Register the red diode */
snprintf(rgb->red.name, sizeof(rgb->red.name),
"thingm%d:red:led%d", minor, rgb->num);
rgb->red.ldev.name = rgb->red.name;
rgb->red.ldev.max_brightness = 255;
rgb->red.ldev.brightness_set = thingm_led_set;
rgb->red.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev);
if (err)
return err;
/* Register the green diode */
snprintf(rgb->green.name, sizeof(rgb->green.name),
"thingm%d:green:led%d", minor, rgb->num);
rgb->green.ldev.name = rgb->green.name;
rgb->green.ldev.max_brightness = 255;
rgb->green.ldev.brightness_set = thingm_led_set;
rgb->green.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev);
if (err)
goto unregister_red;
/* Register the blue diode */
snprintf(rgb->blue.name, sizeof(rgb->blue.name),
"thingm%d:blue:led%d", minor, rgb->num);
rgb->blue.ldev.name = rgb->blue.name;
rgb->blue.ldev.max_brightness = 255;
rgb->blue.ldev.brightness_set = thingm_led_set;
rgb->blue.rgb = rgb;
err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev);
if (err)
goto unregister_green;
INIT_WORK(&rgb->work, thingm_work);
ret = kstrtoul(buf, 10, &fade);
if (ret)
return ret;
return 0;
/* blink(1) accepts 16-bit fade time, number of 10ms ticks */
fade = DIV_ROUND_CLOSEST(fade, 10);
if (fade > 65535)
return -EINVAL;
unregister_green:
led_classdev_unregister(&rgb->green.ldev);
data->fade = fade;
unregister_red:
led_classdev_unregister(&rgb->red.ldev);
return count;
return err;
}
static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
blink1_show_fade, blink1_store_fade);
static ssize_t blink1_show_play(struct device *dev,
struct device_attribute *attr, char *buf)
static void thingm_remove_rgb(struct thingm_rgb *rgb)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
return sprintf(buf, "%d\n", data->play);
flush_work(&rgb->work);
led_classdev_unregister(&rgb->red.ldev);
led_classdev_unregister(&rgb->green.ldev);
led_classdev_unregister(&rgb->blue.ldev);
}
static ssize_t blink1_store_play(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct blink1_data *data = dev_get_drvdata(dev->parent);
u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
long unsigned int play;
int ret;
struct thingm_device *tdev;
int i, err;
ret = kstrtoul(buf, 10, &play);
if (ret)
return ret;
tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
GFP_KERNEL);
if (!tdev)
return -ENOMEM;
data->play = !!play;
cmd[2] = data->play;
ret = blink1_send_command(data, cmd);
tdev->hdev = hdev;
hid_set_drvdata(hdev, tdev);
return ret ? ret : count;
}
static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
blink1_show_play, blink1_store_play);
err = hid_parse(hdev);
if (err)
goto error;
static const struct attribute_group blink1_sysfs_group = {
.attrs = (struct attribute *[]) {
&dev_attr_rgb.attr,
&dev_attr_fade.attr,
&dev_attr_play.attr,
NULL
},
};
err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (err)
goto error;
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct blink1_data *data;
struct led_classdev *led;
char led_name[13];
int ret;
mutex_init(&tdev->lock);
data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
err = thingm_version(tdev);
if (err)
goto stop;
hid_set_drvdata(hdev, data);
data->hdev = hdev;
data->rgb = 0xFFFFFF; /* set a default white color */
hid_dbg(hdev, "firmware version: %c.%c\n",
tdev->version.major, tdev->version.minor);
ret = hid_parse(hdev);
if (ret)
goto error;
for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
if (thingm_fwinfo[i].major == tdev->version.major)
tdev->fwinfo = &thingm_fwinfo[i];
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret)
goto error;
if (!tdev->fwinfo) {
hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
goto stop;
}
/* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
led = &data->led_cdev;
snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
led->name = led_name;
led->brightness_set = blink1_led_set;
led->brightness_get = blink1_led_get;
ret = led_classdev_register(&hdev->dev, led);
if (ret)
tdev->rgb = devm_kzalloc(&hdev->dev,
sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
GFP_KERNEL);
if (!tdev->rgb) {
err = -ENOMEM;
goto stop;
}
ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
if (ret)
goto remove_led;
for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
struct thingm_rgb *rgb = tdev->rgb + i;
rgb->tdev = tdev;
rgb->num = tdev->fwinfo->first + i;
err = thingm_init_rgb(rgb);
if (err) {
while (--i >= 0)
thingm_remove_rgb(tdev->rgb + i);
goto stop;
}
}
return 0;
remove_led:
led_classdev_unregister(led);
stop:
hid_hw_stop(hdev);
error:
return ret;
return err;
}
static void thingm_remove(struct hid_device *hdev)
{
struct blink1_data *data = hid_get_drvdata(hdev);
struct led_classdev *led = &data->led_cdev;
struct thingm_device *tdev = hid_get_drvdata(hdev);
int i;
for (i = 0; i < tdev->fwinfo->numrgb; ++i)
thingm_remove_rgb(tdev->rgb + i);
sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
led_classdev_unregister(led);
hid_hw_stop(hdev);
}
......
......@@ -807,34 +807,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
unsigned int dsize;
int ret;
/* Fetch the length of HID description, retrieve the 4 first bytes:
* bytes 0-1 -> length
* bytes 2-3 -> bcdVersion (has to be 1.00) */
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
ihid->hdesc_buffer);
/* i2c hid fetch using a fixed descriptor size (30 bytes) */
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
sizeof(struct i2c_hid_desc));
if (ret) {
dev_err(&client->dev,
"unable to fetch the size of HID descriptor (ret=%d)\n",
ret);
return -ENODEV;
}
dsize = le16_to_cpu(hdesc->wHIDDescLength);
/*
* the size of the HID descriptor should at least contain
* its size and the bcdVersion (4 bytes), and should not be greater
* than sizeof(struct i2c_hid_desc) as we directly fill this struct
* through i2c_hid_command.
*/
if (dsize < 4 || dsize > sizeof(struct i2c_hid_desc)) {
dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
dsize);
dev_err(&client->dev, "hid_descr_cmd failed\n");
return -ENODEV;
}
/* Validate the length of HID descriptor, the 4 first bytes:
* bytes 0-1 -> length
* bytes 2-3 -> bcdVersion (has to be 1.00) */
/* check bcdVersion == 1.0 */
if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
dev_err(&client->dev,
......@@ -843,17 +827,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
return -ENODEV;
}
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
dsize);
if (ret) {
dev_err(&client->dev, "hid_descr_cmd Fail\n");
/* Descriptor length should be 30 bytes as per the specification */
dsize = le16_to_cpu(hdesc->wHIDDescLength);
if (dsize != sizeof(struct i2c_hid_desc)) {
dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
dsize);
return -ENODEV;
}
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
return 0;
}
......
......@@ -441,12 +441,11 @@ static int uhid_dev_create2(struct uhid_device *uhid,
if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL;
uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
uhid->rd_data = kmemdup(ev->u.create2.rd_data, uhid->rd_size,
GFP_KERNEL);
if (!uhid->rd_data)
return -ENOMEM;
memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
......
......@@ -115,6 +115,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
......
......@@ -479,6 +479,8 @@ config LEDS_OT200
This option enables support for the LEDs on the Bachmann OT200.
Say Y to enable LEDs on the Bachmann OT200.
comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
config LEDS_BLINKM
tristate "LED support for the BlinkM I2C RGB LED"
depends on LEDS_CLASS
......
......@@ -233,11 +233,6 @@ struct hid_item {
#define HID_DG_BARRELSWITCH 0x000d0044
#define HID_DG_ERASER 0x000d0045
#define HID_DG_TABLETPICK 0x000d0046
/*
* as of May 20, 2009 the usages below are not yet in the official USB spec
* but are being pushed by Microsft as described in their paper "Digitizer
* Drivers for Windows Touch and Pen-Based Computers"
*/
#define HID_DG_CONFIDENCE 0x000d0047
#define HID_DG_WIDTH 0x000d0048
#define HID_DG_HEIGHT 0x000d0049
......@@ -246,6 +241,8 @@ struct hid_item {
#define HID_DG_DEVICEINDEX 0x000d0053
#define HID_DG_CONTACTCOUNT 0x000d0054
#define HID_DG_CONTACTMAX 0x000d0055
#define HID_DG_BARRELSWITCH2 0x000d005a
#define HID_DG_TOOLSERIALNUMBER 0x000d005b
/*
* HID report types --- Ouch! HID spec says 1 2 3!
......@@ -299,12 +296,20 @@ struct hid_item {
/*
* HID device groups
*
* Note: HID_GROUP_ANY is declared in linux/mod_devicetable.h
* and has a value of 0x0000
*/
#define HID_GROUP_GENERIC 0x0001
#define HID_GROUP_MULTITOUCH 0x0002
#define HID_GROUP_SENSOR_HUB 0x0003
#define HID_GROUP_MULTITOUCH_WIN_8 0x0004
/*
* Vendor specific HID device groups
*/
#define HID_GROUP_RMI 0x0100
/*
* This is the global environment of the parser. This information is
* persistent for main-items. The global environment can be saved and
......@@ -570,6 +575,8 @@ struct hid_descriptor {
.bus = BUS_USB, .vendor = (ven), .product = (prod)
#define HID_BLUETOOTH_DEVICE(ven, prod) \
.bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod)
#define HID_I2C_DEVICE(ven, prod) \
.bus = BUS_I2C, .vendor = (ven), .product = (prod)
#define HID_REPORT_ID(rep) \
.report_type = (rep)
......
......@@ -462,7 +462,10 @@ struct input_keymap_entry {
#define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous video source */
#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */
#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
brightness control is off,
rely on ambient */
#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
......@@ -632,6 +635,7 @@ struct input_keymap_entry {
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */
......@@ -723,6 +727,17 @@ struct input_keymap_entry {
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册