提交 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 ...@@ -608,7 +608,10 @@ config HID_SAITEK
Support for Saitek devices that are not fully compliant with the Support for Saitek devices that are not fully compliant with the
HID standard. 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 config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards" tristate "Samsung InfraRed remote control or keyboards"
...@@ -657,6 +660,14 @@ config HID_SUNPLUS ...@@ -657,6 +660,14 @@ config HID_SUNPLUS
---help--- ---help---
Support for Sunplus wireless desktop. 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 config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support" tristate "GreenAsia (Product ID 0x12) game controller support"
depends on HID depends on HID
......
...@@ -97,6 +97,7 @@ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ ...@@ -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-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.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 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_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
......
...@@ -779,6 +779,14 @@ static int hid_scan_report(struct hid_device *hid) ...@@ -779,6 +779,14 @@ static int hid_scan_report(struct hid_device *hid)
(hid->group == HID_GROUP_MULTITOUCH)) (hid->group == HID_GROUP_MULTITOUCH))
hid->group = HID_GROUP_MULTITOUCH_WIN_8; 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); vfree(parser);
return 0; return 0;
} }
...@@ -842,7 +850,17 @@ struct hid_report *hid_validate_values(struct hid_device *hid, ...@@ -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 * ->numbered being checked, which may not always be the case when
* drivers go to access report values. * 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) { if (!report) {
hid_err(hid, "missing %s %u\n", hid_report_names[type], id); hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
return NULL; return NULL;
...@@ -1868,7 +1886,11 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -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_RYOS_MK_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
#endif #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_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_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
......
...@@ -165,6 +165,8 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -165,6 +165,8 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x53, "DeviceIndex"}, {0, 0x53, "DeviceIndex"},
{0, 0x54, "ContactCount"}, {0, 0x54, "ContactCount"},
{0, 0x55, "ContactMaximumNumber"}, {0, 0x55, "ContactMaximumNumber"},
{0, 0x5A, "SecondaryBarrelSwitch"},
{0, 0x5B, "TransducerSerialNumber"},
{ 15, 0, "PhysicalInterfaceDevice" }, { 15, 0, "PhysicalInterfaceDevice" },
{0, 0x00, "Undefined"}, {0, 0x00, "Undefined"},
{0, 0x01, "Physical_Interface_Device"}, {0, 0x01, "Physical_Interface_Device"},
...@@ -272,6 +274,85 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -272,6 +274,85 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0xAA, "Shared_Parameter_Blocks"}, {0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"}, {0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"}, {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, 0, "Power Device" },
{ 0x84, 0x02, "PresentStatus" }, { 0x84, 0x02, "PresentStatus" },
{ 0x84, 0x03, "ChangeStatus" }, { 0x84, 0x03, "ChangeStatus" },
...@@ -855,6 +936,16 @@ static const char *keys[KEY_MAX + 1] = { ...@@ -855,6 +936,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDILLUMDOWN] = "KbdIlluminationDown", [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
[KEY_KBDILLUMUP] = "KbdIlluminationUp", [KEY_KBDILLUMUP] = "KbdIlluminationUp",
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", [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] = { static const char *relatives[REL_MAX + 1] = {
......
...@@ -463,6 +463,7 @@ ...@@ -463,6 +463,7 @@
#define USB_VENDOR_ID_STM_0 0x0483 #define USB_VENDOR_ID_STM_0 0x0483
#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1 #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_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132 #define USB_DEVICE_ID_ICADE 0x0132
...@@ -633,6 +634,9 @@ ...@@ -633,6 +634,9 @@
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c #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_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
...@@ -764,11 +768,16 @@ ...@@ -764,11 +768,16 @@
#define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
#define USB_DEVICE_ID_SAITEK_PS1000 0x0621 #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_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 #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_VENDOR_ID_SENNHEISER 0x1395
#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c #define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c
......
...@@ -684,9 +684,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -684,9 +684,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break; break;
case 0x46: /* TabletPick */ case 0x46: /* TabletPick */
case 0x5a: /* SecondaryBarrelSwitch */
map_key_clear(BTN_STYLUS2); map_key_clear(BTN_STYLUS2);
break; break;
case 0x5b: /* TransducerSerialNumber */
set_bit(MSC_SERIAL, input->mscbit);
break;
default: goto unknown; default: goto unknown;
} }
break; break;
...@@ -721,6 +726,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -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 0x06c: map_key_clear(KEY_YELLOW); break;
case 0x06d: map_key_clear(KEY_ZOOM); 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 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
case 0x083: map_key_clear(KEY_LAST); break; case 0x083: map_key_clear(KEY_LAST); break;
case 0x084: map_key_clear(KEY_ENTER); 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 ...@@ -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 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); 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 0x0e0: map_abs_clear(ABS_VOLUME); break;
case 0x0e2: map_key_clear(KEY_MUTE); break; case 0x0e2: map_key_clear(KEY_MUTE); break;
case 0x0e5: map_key_clear(KEY_BASSBOOST); 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 ...@@ -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 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x0f5: map_key_clear(KEY_SLOW); 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 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break; case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); 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 ...@@ -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 0x18c: map_key_clear(KEY_VOICEMAIL); break;
case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
case 0x18e: map_key_clear(KEY_CALENDAR); 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 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break; case 0x192: map_key_clear(KEY_CALC); break;
case 0x193: map_key_clear(KEY_PLAYER); 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 ...@@ -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 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); 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 0x1a3: map_key_clear(KEY_NEXT); break;
case 0x1a4: map_key_clear(KEY_PREVIOUS); break; case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); 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 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break; case 0x1b7: map_key_clear(KEY_AUDIO); break;
......
此差异已折叠。
/* /*
* 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 * 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. * clearing the constant bit on the input reports for buttons and d-pad.
* (This module is based on "hid-ortek".) * (This module is based on "hid-ortek".)
*
* Copyright (c) 2012 Andreas Hübner * 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 @@ ...@@ -21,12 +28,57 @@
#include "hid-ids.h" #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, static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33 struct saitek_sc *ssc = hid_get_drvdata(hdev);
&& rdesc[94] == 0x81 && rdesc[95] == 0x03
&& rdesc[110] == 0x81 && rdesc[111] == 0x03) { 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"); 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, ...@@ -42,8 +94,93 @@ static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return 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[] = { 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); ...@@ -52,7 +189,10 @@ MODULE_DEVICE_TABLE(hid, saitek_devices);
static struct hid_driver saitek_driver = { static struct hid_driver saitek_driver = {
.name = "saitek", .name = "saitek",
.id_table = saitek_devices, .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); module_hid_driver(saitek_driver);
......
...@@ -705,8 +705,17 @@ static const struct hid_device_id sensor_hub_devices[] = { ...@@ -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, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
USB_DEVICE_ID_INTEL_HID_SENSOR_1), USB_DEVICE_ID_INTEL_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, .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, { 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}, .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS,
USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA), USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA),
......
此差异已折叠。
/* /*
* ThingM blink(1) USB RGB LED driver * 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> * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -10,244 +10,285 @@ ...@@ -10,244 +10,285 @@
*/ */
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include "hid-ids.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) /* Firmware major number of supported devices */
#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8) #define THINGM_MAJOR_MK1 '1'
#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0) #define THINGM_MAJOR_MK2 '2'
/** struct thingm_fwinfo {
* struct blink1_data - blink(1) device specific data char major;
* @hdev: HID device. unsigned numrgb;
* @led_cdev: LED class instance. unsigned first;
* @rgb: 8-bit per channel RGB notation. };
* @fade: fade time in hundredths of a second.
* @brightness: brightness coefficient. static const struct thingm_fwinfo thingm_fwinfo[] = {
* @play: play/pause in-memory patterns. {
*/ .major = THINGM_MAJOR_MK1,
struct blink1_data { .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 hid_device *hdev;
struct led_classdev led_cdev; struct {
u32 rgb; char major;
u16 fade; char minor;
u8 brightness; } version;
bool play; const struct thingm_fwinfo *fwinfo;
struct mutex lock;
struct thingm_rgb *rgb;
}; };
static int blink1_send_command(struct blink1_data *data, static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
u8 buf[BLINK1_CMD_SIZE])
{ {
int ret; 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[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]); buf[5], buf[6], buf[7], buf[8]);
ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE, ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0; 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 }; int ret;
if (data->brightness) {
unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef); ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef); HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef); if (ret < 0)
} return ret;
if (data->fade) { hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[1] = 'c'; buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5] = (data->fade & 0xFF00) >> 8; buf[5], buf[6], buf[7], buf[8]);
buf[6] = (data->fade & 0x00FF);
}
return blink1_send_command(data, buf); return 0;
} }
static void blink1_led_set(struct led_classdev *led_cdev, static int thingm_version(struct thingm_device *tdev)
enum led_brightness brightness)
{ {
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; err = thingm_send(tdev, buf);
if (blink1_update_color(data)) if (err)
hid_err(data->hdev, "failed to update color\n"); return err;
}
static enum led_brightness blink1_led_get(struct led_classdev *led_cdev) err = thingm_recv(tdev, buf);
{ if (err)
struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent); 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, static int thingm_write_color(struct thingm_rgb *rgb)
struct device_attribute *attr, char *buf)
{ {
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, static void thingm_work(struct work_struct *work)
struct device_attribute *attr, const char *buf, size_t count)
{ {
struct blink1_data *data = dev_get_drvdata(dev->parent); struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
long unsigned int rgb;
int ret;
ret = kstrtoul(buf, 16, &rgb); mutex_lock(&rgb->tdev->lock);
if (ret)
return ret;
/* RGB triplet notation is 24-bit hexadecimal */
if (rgb > 0xFFFFFF)
return -EINVAL;
data->rgb = rgb; if (thingm_write_color(rgb))
ret = blink1_update_color(data); 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 void thingm_led_set(struct led_classdev *ldev,
enum led_brightness brightness)
static ssize_t blink1_show_fade(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
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, static int thingm_init_rgb(struct thingm_rgb *rgb)
struct device_attribute *attr, const char *buf, size_t count)
{ {
struct blink1_data *data = dev_get_drvdata(dev->parent); const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
long unsigned int fade; int err;
int ret;
/* 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); return 0;
if (ret)
return ret;
/* blink(1) accepts 16-bit fade time, number of 10ms ticks */ unregister_green:
fade = DIV_ROUND_CLOSEST(fade, 10); led_classdev_unregister(&rgb->green.ldev);
if (fade > 65535)
return -EINVAL;
data->fade = fade; unregister_red:
led_classdev_unregister(&rgb->red.ldev);
return count; return err;
} }
static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR, static void thingm_remove_rgb(struct thingm_rgb *rgb)
blink1_show_fade, blink1_store_fade);
static ssize_t blink1_show_play(struct device *dev,
struct device_attribute *attr, char *buf)
{ {
struct blink1_data *data = dev_get_drvdata(dev->parent); flush_work(&rgb->work);
led_classdev_unregister(&rgb->red.ldev);
return sprintf(buf, "%d\n", data->play); led_classdev_unregister(&rgb->green.ldev);
led_classdev_unregister(&rgb->blue.ldev);
} }
static ssize_t blink1_store_play(struct device *dev, static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct device_attribute *attr, const char *buf, size_t count)
{ {
struct blink1_data *data = dev_get_drvdata(dev->parent); struct thingm_device *tdev;
u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 }; int i, err;
long unsigned int play;
int ret;
ret = kstrtoul(buf, 10, &play); tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
if (ret) GFP_KERNEL);
return ret; if (!tdev)
return -ENOMEM;
data->play = !!play; tdev->hdev = hdev;
cmd[2] = data->play; hid_set_drvdata(hdev, tdev);
ret = blink1_send_command(data, cmd);
return ret ? ret : count; err = hid_parse(hdev);
} if (err)
goto error;
static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
blink1_show_play, blink1_store_play);
static const struct attribute_group blink1_sysfs_group = { err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
.attrs = (struct attribute *[]) { if (err)
&dev_attr_rgb.attr, goto error;
&dev_attr_fade.attr,
&dev_attr_play.attr,
NULL
},
};
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) mutex_init(&tdev->lock);
{
struct blink1_data *data;
struct led_classdev *led;
char led_name[13];
int ret;
data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL); err = thingm_version(tdev);
if (!data) if (err)
return -ENOMEM; goto stop;
hid_set_drvdata(hdev, data); hid_dbg(hdev, "firmware version: %c.%c\n",
data->hdev = hdev; tdev->version.major, tdev->version.minor);
data->rgb = 0xFFFFFF; /* set a default white color */
ret = hid_parse(hdev); for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
if (ret) if (thingm_fwinfo[i].major == tdev->version.major)
goto error; tdev->fwinfo = &thingm_fwinfo[i];
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); if (!tdev->fwinfo) {
if (ret) hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
goto error; goto stop;
}
/* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */ tdev->rgb = devm_kzalloc(&hdev->dev,
led = &data->led_cdev; sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4); GFP_KERNEL);
led->name = led_name; if (!tdev->rgb) {
led->brightness_set = blink1_led_set; err = -ENOMEM;
led->brightness_get = blink1_led_get;
ret = led_classdev_register(&hdev->dev, led);
if (ret)
goto stop; goto stop;
}
ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group); for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
if (ret) struct thingm_rgb *rgb = tdev->rgb + i;
goto remove_led;
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; return 0;
remove_led:
led_classdev_unregister(led);
stop: stop:
hid_hw_stop(hdev); hid_hw_stop(hdev);
error: error:
return ret; return err;
} }
static void thingm_remove(struct hid_device *hdev) static void thingm_remove(struct hid_device *hdev)
{ {
struct blink1_data *data = hid_get_drvdata(hdev); struct thingm_device *tdev = hid_get_drvdata(hdev);
struct led_classdev *led = &data->led_cdev; 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); hid_hw_stop(hdev);
} }
......
...@@ -807,34 +807,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ...@@ -807,34 +807,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
unsigned int dsize; unsigned int dsize;
int ret; int ret;
/* Fetch the length of HID description, retrieve the 4 first bytes: /* i2c hid fetch using a fixed descriptor size (30 bytes) */
* bytes 0-1 -> length i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
* bytes 2-3 -> bcdVersion (has to be 1.00) */ ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4); sizeof(struct i2c_hid_desc));
i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
ihid->hdesc_buffer);
if (ret) { if (ret) {
dev_err(&client->dev, dev_err(&client->dev, "hid_descr_cmd failed\n");
"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);
return -ENODEV; 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 */ /* check bcdVersion == 1.0 */
if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) { if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
dev_err(&client->dev, dev_err(&client->dev,
...@@ -843,17 +827,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ...@@ -843,17 +827,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
return -ENODEV; return -ENODEV;
} }
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n"); /* Descriptor length should be 30 bytes as per the specification */
dsize = le16_to_cpu(hdesc->wHIDDescLength);
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, if (dsize != sizeof(struct i2c_hid_desc)) {
dsize); dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
if (ret) { dsize);
dev_err(&client->dev, "hid_descr_cmd Fail\n");
return -ENODEV; return -ENODEV;
} }
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer); i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
return 0; return 0;
} }
......
...@@ -441,12 +441,11 @@ static int uhid_dev_create2(struct uhid_device *uhid, ...@@ -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) if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL; 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) if (!uhid->rd_data)
return -ENOMEM; return -ENOMEM;
memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
hid = hid_allocate_device(); hid = hid_allocate_device();
if (IS_ERR(hid)) { if (IS_ERR(hid)) {
ret = PTR_ERR(hid); ret = PTR_ERR(hid);
......
...@@ -115,6 +115,7 @@ static const struct hid_blacklist { ...@@ -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_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, 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_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_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_LTS2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, 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 ...@@ -479,6 +479,8 @@ config LEDS_OT200
This option enables support for the LEDs on the Bachmann OT200. This option enables support for the LEDs on the Bachmann OT200.
Say Y to enable 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 config LEDS_BLINKM
tristate "LED support for the BlinkM I2C RGB LED" tristate "LED support for the BlinkM I2C RGB LED"
depends on LEDS_CLASS depends on LEDS_CLASS
......
...@@ -233,11 +233,6 @@ struct hid_item { ...@@ -233,11 +233,6 @@ struct hid_item {
#define HID_DG_BARRELSWITCH 0x000d0044 #define HID_DG_BARRELSWITCH 0x000d0044
#define HID_DG_ERASER 0x000d0045 #define HID_DG_ERASER 0x000d0045
#define HID_DG_TABLETPICK 0x000d0046 #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_CONFIDENCE 0x000d0047
#define HID_DG_WIDTH 0x000d0048 #define HID_DG_WIDTH 0x000d0048
#define HID_DG_HEIGHT 0x000d0049 #define HID_DG_HEIGHT 0x000d0049
...@@ -246,6 +241,8 @@ struct hid_item { ...@@ -246,6 +241,8 @@ struct hid_item {
#define HID_DG_DEVICEINDEX 0x000d0053 #define HID_DG_DEVICEINDEX 0x000d0053
#define HID_DG_CONTACTCOUNT 0x000d0054 #define HID_DG_CONTACTCOUNT 0x000d0054
#define HID_DG_CONTACTMAX 0x000d0055 #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! * HID report types --- Ouch! HID spec says 1 2 3!
...@@ -299,12 +296,20 @@ struct hid_item { ...@@ -299,12 +296,20 @@ struct hid_item {
/* /*
* HID device groups * 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_GENERIC 0x0001
#define HID_GROUP_MULTITOUCH 0x0002 #define HID_GROUP_MULTITOUCH 0x0002
#define HID_GROUP_SENSOR_HUB 0x0003 #define HID_GROUP_SENSOR_HUB 0x0003
#define HID_GROUP_MULTITOUCH_WIN_8 0x0004 #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 * This is the global environment of the parser. This information is
* persistent for main-items. The global environment can be saved and * persistent for main-items. The global environment can be saved and
...@@ -570,6 +575,8 @@ struct hid_descriptor { ...@@ -570,6 +575,8 @@ struct hid_descriptor {
.bus = BUS_USB, .vendor = (ven), .product = (prod) .bus = BUS_USB, .vendor = (ven), .product = (prod)
#define HID_BLUETOOTH_DEVICE(ven, prod) \ #define HID_BLUETOOTH_DEVICE(ven, prod) \
.bus = BUS_BLUETOOTH, .vendor = (ven), .product = (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) \ #define HID_REPORT_ID(rep) \
.report_type = (rep) .report_type = (rep)
......
...@@ -462,7 +462,10 @@ struct input_keymap_entry { ...@@ -462,7 +462,10 @@ struct input_keymap_entry {
#define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_NEXT 241 /* drive next video source */
#define KEY_VIDEO_PREV 242 /* drive previous 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_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_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ #define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
...@@ -632,6 +635,7 @@ struct input_keymap_entry { ...@@ -632,6 +635,7 @@ struct input_keymap_entry {
#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ #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_SPELLCHECK 0x1b0 /* AL Spell Check */
#define KEY_LOGOFF 0x1b1 /* AL Logoff */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */
...@@ -723,6 +727,17 @@ struct input_keymap_entry { ...@@ -723,6 +727,17 @@ struct input_keymap_entry {
#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ #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_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1 #define BTN_TRIGGER_HAPPY2 0x2c1
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册