Commit 7a324b3f authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:

 - touch_max detection improvements and quirk handling fixes in wacom
   driver from Jason Gerecke and Ping Cheng

 - Palm rejection from Dmitry Torokhov and _dial support from Benjamin
   Tissoires for hid-multitouch driver

 - Low voltage support for i2c-hid driver from Stephen Boyd

 - Guitar-Hero support from Nicolas Adenis-Lamarre

 - other assorted small fixes and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (40 commits)
  HID: intel_ish-hid: tx_buf memory leak on probe/remove
  HID: intel-ish-hid: Prevent loading of driver on Mehlow
  HID: cougar: Add support for the Cougar 500k Gaming Keyboard
  HID: cougar: make compare_device_paths reusable
  HID: intel-ish-hid: remove redundant variable num_frags
  HID: multitouch: handle palm for touchscreens
  HID: multitouch: touchscreens also use confidence reports
  HID: multitouch: report MT_TOOL_PALM for non-confident touches
  HID: microsoft: support the Surface Dial
  HID: core: do not upper bound the collection stack
  HID: input: enable Totem on the Dell Canvas 27
  HID: multitouch: remove one copy of values
  HID: multitouch: ditch mt_report_id
  HID: multitouch: store a per application quirks value
  HID: multitouch: Store per collection multitouch data
  HID: multitouch: make sure the static list of class is not changed
  input: add MT_TOOL_DIAL
  HID: elan: Add support for touchpad on the Toshiba Click Mini L9W
  HID: elan: Add USB-id for HP x2 10-n000nd touchpad
  HID: elan: Add a flag for selecting if the touchpad has a LED
  ...
parents 61c4fc1e 1429b47b
......@@ -25,7 +25,8 @@ device-specific compatible properties, which should be used in addition to the
- compatible:
* "wacom,w9013" (Wacom W9013 digitizer). Supports:
- vdd-supply
- vdd-supply (3.3V)
- vddl-supply (1.8V)
- post-power-on-delay-ms
- vdd-supply: phandle of the regulator that provides the supply voltage.
......
......@@ -310,12 +310,12 @@ ABS_MT_TOOL_Y
ABS_MT_TOOL_TYPE
The type of approaching tool. A lot of kernel drivers cannot distinguish
between different tool types, such as a finger or a pen. In such cases, the
event should be omitted. The protocol currently supports MT_TOOL_FINGER,
MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_. For type B devices, this event is
handled by input core; drivers should instead use
input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may change over
time while still touching the device, because the firmware may not be able
to determine which tool is being used when it first appears.
event should be omitted. The protocol currently mainly supports
MT_TOOL_FINGER, MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_.
For type B devices, this event is handled by input core; drivers should
instead use input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may
change over time while still touching the device, because the firmware may
not be able to determine which tool is being used when it first appears.
ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped
......
......@@ -207,6 +207,16 @@ config HID_CORSAIR
- Vengeance K90
- Scimitar PRO RGB
config HID_COUGAR
tristate "Cougar devices"
depends on HID
help
Support for Cougar devices that are not fully compliant with the
HID standard.
Supported devices:
- Cougar 500k Gaming Keyboard
config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support"
depends on HID && SND
......
......@@ -35,6 +35,7 @@ obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o
obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o
obj-$(CONFIG_HID_COUGAR) += hid-cougar.o
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
......
......@@ -128,9 +128,19 @@ static int open_collection(struct hid_parser *parser, unsigned type)
usage = parser->local.usage[0];
if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
hid_err(parser->device, "collection stack overflow\n");
return -EINVAL;
if (parser->collection_stack_ptr == parser->collection_stack_size) {
unsigned int *collection_stack;
unsigned int new_size = parser->collection_stack_size +
HID_COLLECTION_STACK_SIZE;
collection_stack = krealloc(parser->collection_stack,
new_size * sizeof(unsigned int),
GFP_KERNEL);
if (!collection_stack)
return -ENOMEM;
parser->collection_stack = collection_stack;
parser->collection_stack_size = new_size;
}
if (parser->device->maxcollection == parser->device->collection_size) {
......@@ -840,6 +850,7 @@ static int hid_scan_report(struct hid_device *hid)
break;
}
kfree(parser->collection_stack);
vfree(parser);
return 0;
}
......@@ -1939,6 +1950,29 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
return hid_match_device(hdev, hdrv) != NULL;
}
/**
* hid_compare_device_paths - check if both devices share the same path
* @hdev_a: hid device
* @hdev_b: hid device
* @separator: char to use as separator
*
* Check if two devices share the same path up to the last occurrence of
* the separator char. Both paths must exist (i.e., zero-length paths
* don't match).
*/
bool hid_compare_device_paths(struct hid_device *hdev_a,
struct hid_device *hdev_b, char separator)
{
int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys;
int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys;
if (n1 != n2 || n1 <= 0 || n2 <= 0)
return false;
return !strncmp(hdev_a->phys, hdev_b->phys, n1);
}
EXPORT_SYMBOL_GPL(hid_compare_device_paths);
static int hid_device_probe(struct device *dev)
{
struct hid_driver *hdrv = to_hid_driver(dev->driver);
......
// SPDX-License-Identifier: GPL-2.0+
/*
* HID driver for Cougar 500k Gaming Keyboard
*
* Copyright (c) 2018 Daniel M. Lambea <dmlambea@gmail.com>
*/
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("Daniel M. Lambea <dmlambea@gmail.com>");
MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard");
MODULE_LICENSE("GPL");
MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18");
static int cougar_g6_is_space = 1;
module_param_named(g6_is_space, cougar_g6_is_space, int, 0600);
MODULE_PARM_DESC(g6_is_space,
"If set, G6 programmable key sends SPACE instead of F18 (0=off, 1=on) (default=1)");
#define COUGAR_VENDOR_USAGE 0xff00ff00
#define COUGAR_FIELD_CODE 1
#define COUGAR_FIELD_ACTION 2
#define COUGAR_KEY_G1 0x83
#define COUGAR_KEY_G2 0x84
#define COUGAR_KEY_G3 0x85
#define COUGAR_KEY_G4 0x86
#define COUGAR_KEY_G5 0x87
#define COUGAR_KEY_G6 0x78
#define COUGAR_KEY_FN 0x0d
#define COUGAR_KEY_MR 0x6f
#define COUGAR_KEY_M1 0x80
#define COUGAR_KEY_M2 0x81
#define COUGAR_KEY_M3 0x82
#define COUGAR_KEY_LEDS 0x67
#define COUGAR_KEY_LOCK 0x6e
/* Default key mappings. The special key COUGAR_KEY_G6 is defined first
* because it is more frequent to use the spacebar rather than any other
* special keys. Depending on the value of the parameter 'g6_is_space',
* the mapping will be updated in the probe function.
*/
static unsigned char cougar_mapping[][2] = {
{ COUGAR_KEY_G6, KEY_SPACE },
{ COUGAR_KEY_G1, KEY_F13 },
{ COUGAR_KEY_G2, KEY_F14 },
{ COUGAR_KEY_G3, KEY_F15 },
{ COUGAR_KEY_G4, KEY_F16 },
{ COUGAR_KEY_G5, KEY_F17 },
{ COUGAR_KEY_LOCK, KEY_SCREENLOCK },
/* The following keys are handled by the hardware itself, so no special
* treatment is required:
{ COUGAR_KEY_FN, KEY_RESERVED },
{ COUGAR_KEY_MR, KEY_RESERVED },
{ COUGAR_KEY_M1, KEY_RESERVED },
{ COUGAR_KEY_M2, KEY_RESERVED },
{ COUGAR_KEY_M3, KEY_RESERVED },
{ COUGAR_KEY_LEDS, KEY_RESERVED },
*/
{ 0, 0 },
};
struct cougar_shared {
struct list_head list;
struct kref kref;
bool enabled;
struct hid_device *dev;
struct input_dev *input;
};
struct cougar {
bool special_intf;
struct cougar_shared *shared;
};
static LIST_HEAD(cougar_udev_list);
static DEFINE_MUTEX(cougar_udev_list_lock);
static void cougar_fix_g6_mapping(struct hid_device *hdev)
{
int i;
for (i = 0; cougar_mapping[i][0]; i++) {
if (cougar_mapping[i][0] == COUGAR_KEY_G6) {
cougar_mapping[i][1] =
cougar_g6_is_space ? KEY_SPACE : KEY_F18;
hid_info(hdev, "G6 mapped to %s\n",
cougar_g6_is_space ? "space" : "F18");
return;
}
}
hid_warn(hdev, "no mapping defined for G6/spacebar");
}
/*
* Constant-friendly rdesc fixup for mouse interface
*/
static __u8 *cougar_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (rdesc[2] == 0x09 && rdesc[3] == 0x02 &&
(rdesc[115] | rdesc[116] << 8) >= HID_MAX_USAGES) {
hid_info(hdev,
"usage count exceeds max: fixing up report descriptor\n");
rdesc[115] = ((HID_MAX_USAGES-1) & 0xff);
rdesc[116] = ((HID_MAX_USAGES-1) >> 8);
}
return rdesc;
}
static struct cougar_shared *cougar_get_shared_data(struct hid_device *hdev)
{
struct cougar_shared *shared;
/* Try to find an already-probed interface from the same device */
list_for_each_entry(shared, &cougar_udev_list, list) {
if (hid_compare_device_paths(hdev, shared->dev, '/')) {
kref_get(&shared->kref);
return shared;
}
}
return NULL;
}
static void cougar_release_shared_data(struct kref *kref)
{
struct cougar_shared *shared = container_of(kref,
struct cougar_shared, kref);
mutex_lock(&cougar_udev_list_lock);
list_del(&shared->list);
mutex_unlock(&cougar_udev_list_lock);
kfree(shared);
}
static void cougar_remove_shared_data(void *resource)
{
struct cougar *cougar = resource;
if (cougar->shared) {
kref_put(&cougar->shared->kref, cougar_release_shared_data);
cougar->shared = NULL;
}
}
/*
* Bind the device group's shared data to this cougar struct.
* If no shared data exists for this group, create and initialize it.
*/
static int cougar_bind_shared_data(struct hid_device *hdev, struct cougar *cougar)
{
struct cougar_shared *shared;
int error = 0;
mutex_lock(&cougar_udev_list_lock);
shared = cougar_get_shared_data(hdev);
if (!shared) {
shared = kzalloc(sizeof(*shared), GFP_KERNEL);
if (!shared) {
error = -ENOMEM;
goto out;
}
kref_init(&shared->kref);
shared->dev = hdev;
list_add_tail(&shared->list, &cougar_udev_list);
}
cougar->shared = shared;
error = devm_add_action(&hdev->dev, cougar_remove_shared_data, cougar);
if (error) {
mutex_unlock(&cougar_udev_list_lock);
cougar_remove_shared_data(cougar);
return error;
}
out:
mutex_unlock(&cougar_udev_list_lock);
return error;
}
static int cougar_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct cougar *cougar;
struct hid_input *next, *hidinput = NULL;
unsigned int connect_mask;
int error;
cougar = devm_kzalloc(&hdev->dev, sizeof(*cougar), GFP_KERNEL);
if (!cougar)
return -ENOMEM;
hid_set_drvdata(hdev, cougar);
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
goto fail;
}
if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
cougar->special_intf = true;
connect_mask = HID_CONNECT_HIDRAW;
} else
connect_mask = HID_CONNECT_DEFAULT;
error = hid_hw_start(hdev, connect_mask);
if (error) {
hid_err(hdev, "hw start failed\n");
goto fail;
}
error = cougar_bind_shared_data(hdev, cougar);
if (error)
goto fail_stop_and_cleanup;
/* The custom vendor interface will use the hid_input registered
* for the keyboard interface, in order to send translated key codes
* to it.
*/
if (hdev->collection->usage == HID_GD_KEYBOARD) {
cougar_fix_g6_mapping(hdev);
list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) {
if (hidinput->registered && hidinput->input != NULL) {
cougar->shared->input = hidinput->input;
cougar->shared->enabled = true;
break;
}
}
} else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
error = hid_hw_open(hdev);
if (error)
goto fail_stop_and_cleanup;
}
return 0;
fail_stop_and_cleanup:
hid_hw_stop(hdev);
fail:
hid_set_drvdata(hdev, NULL);
return error;
}
/*
* Convert events from vendor intf to input key events
*/
static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct cougar *cougar;
unsigned char code, action;
int i;
cougar = hid_get_drvdata(hdev);
if (!cougar->special_intf || !cougar->shared ||
!cougar->shared->input || !cougar->shared->enabled)
return 0;
code = data[COUGAR_FIELD_CODE];
action = data[COUGAR_FIELD_ACTION];
for (i = 0; cougar_mapping[i][0]; i++) {
if (code == cougar_mapping[i][0]) {
input_event(cougar->shared->input, EV_KEY,
cougar_mapping[i][1], action);
input_sync(cougar->shared->input);
return 0;
}
}
hid_warn(hdev, "unmapped special key code %x: ignoring\n", code);
return 0;
}
static void cougar_remove(struct hid_device *hdev)
{
struct cougar *cougar = hid_get_drvdata(hdev);
if (cougar) {
/* Stop the vendor intf to process more events */
if (cougar->shared)
cougar->shared->enabled = false;
if (cougar->special_intf)
hid_hw_close(hdev);
}
hid_hw_stop(hdev);
}
static struct hid_device_id cougar_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
{}
};
MODULE_DEVICE_TABLE(hid, cougar_id_table);
static struct hid_driver cougar_driver = {
.name = "cougar",
.id_table = cougar_id_table,
.report_fixup = cougar_report_fixup,
.probe = cougar_probe,
.remove = cougar_remove,
.raw_event = cougar_raw_event,
};
module_hid_driver(cougar_driver);
This diff is collapsed.
......@@ -369,6 +369,8 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
#define USB_VENDOR_ID_ELAN 0x04f3
#define USB_DEVICE_ID_TOSHIBA_CLICK_L9W 0x0401
#define USB_DEVICE_ID_HP_X2 0x074d
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
#define USB_VENDOR_ID_ELECOM 0x056e
......@@ -1001,6 +1003,9 @@
#define USB_VENDOR_ID_SINO_LITE 0x1345
#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008
#define USB_VENDOR_ID_SOLID_YEAR 0x060b
#define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046
......
......@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
case HID_GD_WIRELESS_RADIO_CTLS:
suffix = "Wireless Radio Control";
break;
case HID_GD_SYSTEM_MULTIAXIS:
suffix = "System Multi Axis";
break;
default:
break;
}
......
......@@ -22,12 +22,13 @@
#include "hid-ids.h"
#define MS_HIDINPUT 0x01
#define MS_ERGONOMY 0x02
#define MS_PRESENTER 0x04
#define MS_RDESC 0x08
#define MS_NOGET 0x10
#define MS_DUPLICATE_USAGES 0x20
#define MS_HIDINPUT BIT(0)
#define MS_ERGONOMY BIT(1)
#define MS_PRESENTER BIT(2)
#define MS_RDESC BIT(3)
#define MS_NOGET BIT(4)
#define MS_DUPLICATE_USAGES BIT(5)
#define MS_SURFACE_DIAL BIT(6)
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
......@@ -130,6 +131,30 @@ static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
return 1;
}
static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case 0xff070000:
/* fall-through */
case HID_UP_DIGITIZER:
/* ignore those axis */
return -1;
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
/* fall-through */
case HID_GD_Y:
/* fall-through */
case HID_GD_RFKILL_BTN:
/* ignore those axis */
return -1;
}
}
return 0;
}
static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
......@@ -146,6 +171,13 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ms_presenter_8k_quirk(hi, usage, bit, max))
return 1;
if (quirks & MS_SURFACE_DIAL) {
int ret = ms_surface_dial_quirk(hi, field, usage, bit, max);
if (ret)
return ret;
}
return 0;
}
......@@ -229,6 +261,9 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (quirks & MS_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
if (quirks & MS_SURFACE_DIAL)
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
......@@ -281,6 +316,8 @@ static const struct hid_device_id ms_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
.driver_data = MS_SURFACE_DIAL },
{ }
};
MODULE_DEVICE_TABLE(hid, ms_devices);
......
This diff is collapsed.
......@@ -955,6 +955,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = sysfs_create_group(&hdev->dev.kobj,
&ntrig_attribute_group);
if (ret)
hid_err(hdev, "cannot create sysfs group\n");
return 0;
err_free:
......
......@@ -44,29 +44,6 @@ static __u8 *redragon_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
static int redragon_probe(struct hid_device *dev,
const struct hid_device_id *id)
{
int ret;
ret = hid_parse(dev);
if (ret) {
hid_err(dev, "parse failed\n");
return ret;
}
/* do not register unused input device */
if (dev->maxapplication == 1)
return 0;
ret = hid_hw_start(dev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(dev, "hw start failed\n");
return ret;
}
return 0;
}
static const struct hid_device_id redragon_devices[] = {
{HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_REDRAGON_ASURA)},
{}
......@@ -77,8 +54,7 @@ MODULE_DEVICE_TABLE(hid, redragon_devices);
static struct hid_driver redragon_driver = {
.name = "redragon",
.id_table = redragon_devices,
.report_fixup = redragon_report_fixup,
.probe = redragon_probe
.report_fixup = redragon_report_fixup
};
module_hid_driver(redragon_driver);
......
......@@ -1353,7 +1353,7 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
char *name;
int ret;
sc->touchpad = input_allocate_device();
sc->touchpad = devm_input_allocate_device(&sc->hdev->dev);
if (!sc->touchpad)
return -ENOMEM;
......@@ -1370,11 +1370,9 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
* DS4 compatible non-Sony devices with different names.
*/
name_sz = strlen(sc->hdev->name) + sizeof(DS4_TOUCHPAD_SUFFIX);
name = kzalloc(name_sz, GFP_KERNEL);
if (!name) {
ret = -ENOMEM;
goto err;
}
name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL);
if (!name)
return -ENOMEM;
snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name);
sc->touchpad->name = name;
......@@ -1403,34 +1401,13 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER);
if (ret < 0)
goto err;
return ret;
ret = input_register_device(sc->touchpad);
if (ret < 0)
goto err;
return ret;
return 0;
err:
kfree(sc->touchpad->name);
sc->touchpad->name = NULL;
input_free_device(sc->touchpad);
sc->touchpad = NULL;
return ret;
}
static void sony_unregister_touchpad(struct sony_sc *sc)
{
if (!sc->touchpad)
return;
kfree(sc->touchpad->name);
sc->touchpad->name = NULL;
input_unregister_device(sc->touchpad);
sc->touchpad = NULL;
}
static int sony_register_sensors(struct sony_sc *sc)
......@@ -1440,7 +1417,7 @@ static int sony_register_sensors(struct sony_sc *sc)
int ret;
int range;
sc->sensor_dev = input_allocate_device();
sc->sensor_dev = devm_input_allocate_device(&sc->hdev->dev);
if (!sc->sensor_dev)
return -ENOMEM;
......@@ -1457,11 +1434,9 @@ static int sony_register_sensors(struct sony_sc *sc)
* DS4 compatible non-Sony devices with different names.
*/
name_sz = strlen(sc->hdev->name) + sizeof(SENSOR_SUFFIX);
name = kzalloc(name_sz, GFP_KERNEL);
if (!name) {
ret = -ENOMEM;
goto err;
}
name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL);
if (!name)
return -ENOMEM;
snprintf(name, name_sz, "%s" SENSOR_SUFFIX, sc->hdev->name);
sc->sensor_dev->name = name;
......@@ -1503,33 +1478,11 @@ static int sony_register_sensors(struct sony_sc *sc)
ret = input_register_device(sc->sensor_dev);
if (ret < 0)
goto err;
return ret;
return 0;
err:
kfree(sc->sensor_dev->name);
sc->sensor_dev->name = NULL;
input_free_device(sc->sensor_dev);
sc->sensor_dev = NULL;
return ret;
}
static void sony_unregister_sensors(struct sony_sc *sc)
{
if (!sc->sensor_dev)
return;
kfree(sc->sensor_dev->name);
sc->sensor_dev->name = NULL;
input_unregister_device(sc->sensor_dev);
sc->sensor_dev = NULL;
}
/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any
......@@ -1987,25 +1940,6 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
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);
}
sc->led_count = 0; <