Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0d69a3c7
Commit
0d69a3c7
authored
Feb 21, 2013
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branches 'for-3.9/sony' and 'for-3.9/steelseries' into for-linus
Conflicts: drivers/hid/hid-core.c
parents
73759518
99d24902
7e415762
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
469 additions
and
3 deletions
+469
-3
Documentation/ABI/testing/sysfs-driver-hid-srws1
Documentation/ABI/testing/sysfs-driver-hid-srws1
+21
-0
drivers/hid/Kconfig
drivers/hid/Kconfig
+6
-0
drivers/hid/Makefile
drivers/hid/Makefile
+1
-0
drivers/hid/hid-core.c
drivers/hid/hid-core.c
+1
-0
drivers/hid/hid-ids.h
drivers/hid/hid-ids.h
+4
-0
drivers/hid/hid-sony.c
drivers/hid/hid-sony.c
+43
-3
drivers/hid/hid-steelseries.c
drivers/hid/hid-steelseries.c
+393
-0
No files found.
Documentation/ABI/testing/sysfs-driver-hid-srws1
0 → 100644
View file @
0d69a3c7
What: /sys/class/leds/SRWS1::<serial>::RPM1
What: /sys/class/leds/SRWS1::<serial>::RPM2
What: /sys/class/leds/SRWS1::<serial>::RPM3
What: /sys/class/leds/SRWS1::<serial>::RPM4
What: /sys/class/leds/SRWS1::<serial>::RPM5
What: /sys/class/leds/SRWS1::<serial>::RPM6
What: /sys/class/leds/SRWS1::<serial>::RPM7
What: /sys/class/leds/SRWS1::<serial>::RPM8
What: /sys/class/leds/SRWS1::<serial>::RPM9
What: /sys/class/leds/SRWS1::<serial>::RPM10
What: /sys/class/leds/SRWS1::<serial>::RPM11
What: /sys/class/leds/SRWS1::<serial>::RPM12
What: /sys/class/leds/SRWS1::<serial>::RPM13
What: /sys/class/leds/SRWS1::<serial>::RPM14
What: /sys/class/leds/SRWS1::<serial>::RPM15
What: /sys/class/leds/SRWS1::<serial>::RPMALL
Date: Jan 2013
KernelVersion: 3.9
Contact: Simon Wood <simon@mungewell.org>
Description: Provides a control for turning on/off the LEDs which form
an RPM meter on the front of the controller
drivers/hid/Kconfig
View file @
0d69a3c7
...
...
@@ -596,6 +596,12 @@ config HID_SPEEDLINK
---help---
Support for Speedlink Vicious and Divine Cezanne mouse.
config HID_STEELSERIES
tristate "Steelseries SRW-S1 steering wheel support"
depends on USB_HID
---help---
Support for Steelseries SRW-S1 steering wheel
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
depends on USB_HID
...
...
drivers/hid/Makefile
View file @
0d69a3c7
...
...
@@ -101,6 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS)
+=
hid-sjoy.o
obj-$(CONFIG_HID_SONY)
+=
hid-sony.o
obj-$(CONFIG_HID_SPEEDLINK)
+=
hid-speedlink.o
obj-$(CONFIG_HID_STEELSERIES)
+=
hid-steelseries.o
obj-$(CONFIG_HID_SUNPLUS)
+=
hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA)
+=
hid-gaff.o
obj-$(CONFIG_HID_THINGM)
+=
hid-thingm.o
...
...
drivers/hid/hid-core.c
View file @
0d69a3c7
...
...
@@ -1702,6 +1702,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER
)
},
{
HID_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_PS3_CONTROLLER
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_STEELSERIES
,
USB_DEVICE_ID_STEELSERIES_SRWS1
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SUNPLUS
,
USB_DEVICE_ID_SUNPLUS_WDESKTOP
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_THINGM
,
USB_DEVICE_ID_BLINK1
)
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_THRUSTMASTER
,
0xb300
)
},
...
...
drivers/hid/hid-ids.h
View file @
0d69a3c7
...
...
@@ -715,6 +715,7 @@
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
#define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
...
...
@@ -732,6 +733,9 @@
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
#define USB_VENDOR_ID_STEELSERIES 0x1038
#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
...
...
drivers/hid/hid-sony.c
View file @
0d69a3c7
...
...
@@ -33,6 +33,28 @@ static const u8 sixaxis_rdesc_fixup[] = {
0x03
,
0x46
,
0xFF
,
0x03
,
0x09
,
0x01
,
0x81
,
0x02
};
static
const
u8
sixaxis_rdesc_fixup2
[]
=
{
0x05
,
0x01
,
0x09
,
0x04
,
0xa1
,
0x01
,
0xa1
,
0x02
,
0x85
,
0x01
,
0x75
,
0x08
,
0x95
,
0x01
,
0x15
,
0x00
,
0x26
,
0xff
,
0x00
,
0x81
,
0x03
,
0x75
,
0x01
,
0x95
,
0x13
,
0x15
,
0x00
,
0x25
,
0x01
,
0x35
,
0x00
,
0x45
,
0x01
,
0x05
,
0x09
,
0x19
,
0x01
,
0x29
,
0x13
,
0x81
,
0x02
,
0x75
,
0x01
,
0x95
,
0x0d
,
0x06
,
0x00
,
0xff
,
0x81
,
0x03
,
0x15
,
0x00
,
0x26
,
0xff
,
0x00
,
0x05
,
0x01
,
0x09
,
0x01
,
0xa1
,
0x00
,
0x75
,
0x08
,
0x95
,
0x04
,
0x35
,
0x00
,
0x46
,
0xff
,
0x00
,
0x09
,
0x30
,
0x09
,
0x31
,
0x09
,
0x32
,
0x09
,
0x35
,
0x81
,
0x02
,
0xc0
,
0x05
,
0x01
,
0x95
,
0x13
,
0x09
,
0x01
,
0x81
,
0x02
,
0x95
,
0x0c
,
0x81
,
0x01
,
0x75
,
0x10
,
0x95
,
0x04
,
0x26
,
0xff
,
0x03
,
0x46
,
0xff
,
0x03
,
0x09
,
0x01
,
0x81
,
0x02
,
0xc0
,
0xa1
,
0x02
,
0x85
,
0x02
,
0x75
,
0x08
,
0x95
,
0x30
,
0x09
,
0x01
,
0xb1
,
0x02
,
0xc0
,
0xa1
,
0x02
,
0x85
,
0xee
,
0x75
,
0x08
,
0x95
,
0x30
,
0x09
,
0x01
,
0xb1
,
0x02
,
0xc0
,
0xa1
,
0x02
,
0x85
,
0xef
,
0x75
,
0x08
,
0x95
,
0x30
,
0x09
,
0x01
,
0xb1
,
0x02
,
0xc0
,
0xc0
,
};
struct
sony_sc
{
unsigned
long
quirks
;
};
...
...
@@ -43,9 +65,19 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
if
((
sc
->
quirks
&
VAIO_RDESC_CONSTANT
)
&&
*
rsize
>=
56
&&
rdesc
[
54
]
==
0x81
&&
rdesc
[
55
]
==
0x07
)
{
hid_info
(
hdev
,
"Fixing up Sony Vaio VGX report descriptor
\n
"
);
/*
* Some Sony RF receivers wrongly declare the mouse pointer as a
* a constant non-data variable.
*/
if
((
sc
->
quirks
&
VAIO_RDESC_CONSTANT
)
&&
*
rsize
>=
56
&&
/* usage page: generic desktop controls */
/* rdesc[0] == 0x05 && rdesc[1] == 0x01 && */
/* usage: mouse */
rdesc
[
2
]
==
0x09
&&
rdesc
[
3
]
==
0x02
&&
/* input (usage page for x,y axes): constant, variable, relative */
rdesc
[
54
]
==
0x81
&&
rdesc
[
55
]
==
0x07
)
{
hid_info
(
hdev
,
"Fixing up Sony RF Receiver report descriptor
\n
"
);
/* input: data, variable, relative */
rdesc
[
55
]
=
0x06
;
}
...
...
@@ -56,6 +88,12 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info
(
hdev
,
"Fixing up Sony Sixaxis report descriptor
\n
"
);
memcpy
((
void
*
)
&
rdesc
[
83
],
(
void
*
)
&
sixaxis_rdesc_fixup
,
sizeof
(
sixaxis_rdesc_fixup
));
}
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
&&
*
rsize
>
sizeof
(
sixaxis_rdesc_fixup2
))
{
hid_info
(
hdev
,
"Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)
\n
"
,
*
rsize
,
(
int
)
sizeof
(
sixaxis_rdesc_fixup2
));
*
rsize
=
sizeof
(
sixaxis_rdesc_fixup2
);
memcpy
(
rdesc
,
&
sixaxis_rdesc_fixup2
,
*
rsize
);
}
return
rdesc
;
}
...
...
@@ -217,6 +255,8 @@ static const struct hid_device_id sony_devices[] = {
.
driver_data
=
SIXAXIS_CONTROLLER_BT
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE
),
.
driver_data
=
VAIO_RDESC_CONSTANT
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE
),
.
driver_data
=
VAIO_RDESC_CONSTANT
},
{
}
};
MODULE_DEVICE_TABLE
(
hid
,
sony_devices
);
...
...
drivers/hid/hid-steelseries.c
0 → 100644
View file @
0d69a3c7
/*
* HID driver for Steelseries SRW-S1
*
* Copyright (c) 2013 Simon Wood
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
#define SRWS1_NUMBER_LEDS 15
struct
steelseries_srws1_data
{
__u16
led_state
;
/* the last element is used for setting all leds simultaneously */
struct
led_classdev
*
led
[
SRWS1_NUMBER_LEDS
+
1
];
};
#endif
/* Fixed report descriptor for Steelseries SRW-S1 wheel controller
*
* The original descriptor hides the sensitivity and assists dials
* a custom vendor usage page. This inserts a patch to make them
* appear in the 'Generic Desktop' usage.
*/
static
__u8
steelseries_srws1_rdesc_fixed
[]
=
{
0x05
,
0x01
,
/* Usage Page (Desktop) */
0x09
,
0x08
,
/* Usage (MultiAxis), Changed */
0xA1
,
0x01
,
/* Collection (Application), */
0xA1
,
0x02
,
/* Collection (Logical), */
0x95
,
0x01
,
/* Report Count (1), */
0x05
,
0x01
,
/* Changed Usage Page (Desktop), */
0x09
,
0x30
,
/* Changed Usage (X), */
0x16
,
0xF8
,
0xF8
,
/* Logical Minimum (-1800), */
0x26
,
0x08
,
0x07
,
/* Logical Maximum (1800), */
0x65
,
0x14
,
/* Unit (Degrees), */
0x55
,
0x0F
,
/* Unit Exponent (15), */
0x75
,
0x10
,
/* Report Size (16), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x31
,
/* Changed Usage (Y), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x03
,
/* Logical Maximum (1023), */
0x75
,
0x0C
,
/* Report Size (12), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x32
,
/* Changed Usage (Z), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x03
,
/* Logical Maximum (1023), */
0x75
,
0x0C
,
/* Report Size (12), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x39
,
/* Usage (Hat Switch), */
0x25
,
0x07
,
/* Logical Maximum (7), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x46
,
0x3B
,
0x01
,
/* Physical Maximum (315), */
0x65
,
0x14
,
/* Unit (Degrees), */
0x75
,
0x04
,
/* Report Size (4), */
0x95
,
0x01
,
/* Report Count (1), */
0x81
,
0x02
,
/* Input (Variable), */
0x25
,
0x01
,
/* Logical Maximum (1), */
0x45
,
0x01
,
/* Physical Maximum (1), */
0x65
,
0x00
,
/* Unit, */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x01
,
/* Input (Constant), */
0x05
,
0x09
,
/* Usage Page (Button), */
0x19
,
0x01
,
/* Usage Minimum (01h), */
0x29
,
0x11
,
/* Usage Maximum (11h), */
0x95
,
0x11
,
/* Report Count (17), */
0x81
,
0x02
,
/* Input (Variable), */
/* ---- Dial patch starts here ---- */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x33
,
/* Usage (RX), */
0x75
,
0x04
,
/* Report Size (4), */
0x95
,
0x02
,
/* Report Count (2), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x0b
,
/* Logical Maximum (b), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x35
,
/* Usage (RZ), */
0x75
,
0x04
,
/* Report Size (4), */
0x95
,
0x01
,
/* Report Count (1), */
0x25
,
0x03
,
/* Logical Maximum (3), */
0x81
,
0x02
,
/* Input (Variable), */
/* ---- Dial patch ends here ---- */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x01
,
/* Usage (01h), */
0x75
,
0x04
,
/* Changed Report Size (4), */
0x95
,
0x0D
,
/* Changed Report Count (13), */
0x81
,
0x02
,
/* Input (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x09
,
0x02
,
/* Usage (02h), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x10
,
/* Report Count (16), */
0x91
,
0x02
,
/* Output (Variable), */
0xC0
,
/* End Collection, */
0xC0
/* End Collection */
};
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
static
void
steelseries_srws1_set_leds
(
struct
hid_device
*
hdev
,
__u16
leds
)
{
struct
list_head
*
report_list
=
&
hdev
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
struct
hid_report
*
report
=
list_entry
(
report_list
->
next
,
struct
hid_report
,
list
);
__s32
*
value
=
report
->
field
[
0
]
->
value
;
value
[
0
]
=
0x40
;
value
[
1
]
=
leds
&
0xFF
;
value
[
2
]
=
leds
>>
8
;
value
[
3
]
=
0x00
;
value
[
4
]
=
0x00
;
value
[
5
]
=
0x00
;
value
[
6
]
=
0x00
;
value
[
7
]
=
0x00
;
value
[
8
]
=
0x00
;
value
[
9
]
=
0x00
;
value
[
10
]
=
0x00
;
value
[
11
]
=
0x00
;
value
[
12
]
=
0x00
;
value
[
13
]
=
0x00
;
value
[
14
]
=
0x00
;
value
[
15
]
=
0x00
;
usbhid_submit_report
(
hdev
,
report
,
USB_DIR_OUT
);
/* Note: LED change does not show on device until the device is read/polled */
}
static
void
steelseries_srws1_led_all_set_brightness
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
steelseries_srws1_data
*
drv_data
=
hid_get_drvdata
(
hid
);
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
;
}
if
(
value
==
LED_OFF
)
drv_data
->
led_state
=
0
;
else
drv_data
->
led_state
=
(
1
<<
(
SRWS1_NUMBER_LEDS
+
1
))
-
1
;
steelseries_srws1_set_leds
(
hid
,
drv_data
->
led_state
);
}
static
enum
led_brightness
steelseries_srws1_led_all_get_brightness
(
struct
led_classdev
*
led_cdev
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
steelseries_srws1_data
*
drv_data
;
drv_data
=
hid_get_drvdata
(
hid
);
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
LED_OFF
;
}
return
(
drv_data
->
led_state
>>
SRWS1_NUMBER_LEDS
)
?
LED_FULL
:
LED_OFF
;
}
static
void
steelseries_srws1_led_set_brightness
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
steelseries_srws1_data
*
drv_data
=
hid_get_drvdata
(
hid
);
int
i
,
state
=
0
;
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
;
}
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
;
i
++
)
{
if
(
led_cdev
!=
drv_data
->
led
[
i
])
continue
;
state
=
(
drv_data
->
led_state
>>
i
)
&
1
;
if
(
value
==
LED_OFF
&&
state
)
{
drv_data
->
led_state
&=
~
(
1
<<
i
);
steelseries_srws1_set_leds
(
hid
,
drv_data
->
led_state
);
}
else
if
(
value
!=
LED_OFF
&&
!
state
)
{
drv_data
->
led_state
|=
1
<<
i
;
steelseries_srws1_set_leds
(
hid
,
drv_data
->
led_state
);
}
break
;
}
}
static
enum
led_brightness
steelseries_srws1_led_get_brightness
(
struct
led_classdev
*
led_cdev
)
{
struct
device
*
dev
=
led_cdev
->
dev
->
parent
;
struct
hid_device
*
hid
=
container_of
(
dev
,
struct
hid_device
,
dev
);
struct
steelseries_srws1_data
*
drv_data
;
int
i
,
value
=
0
;
drv_data
=
hid_get_drvdata
(
hid
);
if
(
!
drv_data
)
{
hid_err
(
hid
,
"Device data not found."
);
return
LED_OFF
;
}
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
;
i
++
)
if
(
led_cdev
==
drv_data
->
led
[
i
])
{
value
=
(
drv_data
->
led_state
>>
i
)
&
1
;
break
;
}
return
value
?
LED_FULL
:
LED_OFF
;
}
static
int
steelseries_srws1_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
int
ret
,
i
;
struct
led_classdev
*
led
;
size_t
name_sz
;
char
*
name
;
struct
steelseries_srws1_data
*
drv_data
=
kzalloc
(
sizeof
(
*
drv_data
),
GFP_KERNEL
);
if
(
drv_data
==
NULL
)
{
hid_err
(
hdev
,
"can't alloc SRW-S1 memory
\n
"
);
return
-
ENOMEM
;
}
hid_set_drvdata
(
hdev
,
drv_data
);
ret
=
hid_parse
(
hdev
);
if
(
ret
)
{
hid_err
(
hdev
,
"parse failed
\n
"
);
goto
err_free
;
}
ret
=
hid_hw_start
(
hdev
,
HID_CONNECT_DEFAULT
);
if
(
ret
)
{
hid_err
(
hdev
,
"hw start failed
\n
"
);
goto
err_free
;
}
/* register led subsystem */
drv_data
->
led_state
=
0
;
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
+
1
;
i
++
)
drv_data
->
led
[
i
]
=
NULL
;
steelseries_srws1_set_leds
(
hdev
,
0
);
name_sz
=
strlen
(
hdev
->
uniq
)
+
16
;
/* 'ALL', for setting all LEDs simultaneously */
led
=
kzalloc
(
sizeof
(
struct
led_classdev
)
+
name_sz
,
GFP_KERNEL
);
if
(
!
led
)
{
hid_err
(
hdev
,
"can't allocate memory for LED ALL
\n
"
);
goto
err_led
;
}
name
=
(
void
*
)(
&
led
[
1
]);
snprintf
(
name
,
name_sz
,
"SRWS1::%s::RPMALL"
,
hdev
->
uniq
);
led
->
name
=
name
;
led
->
brightness
=
0
;
led
->
max_brightness
=
1
;
led
->
brightness_get
=
steelseries_srws1_led_all_get_brightness
;
led
->
brightness_set
=
steelseries_srws1_led_all_set_brightness
;
drv_data
->
led
[
SRWS1_NUMBER_LEDS
]
=
led
;
ret
=
led_classdev_register
(
&
hdev
->
dev
,
led
);
if
(
ret
)
goto
err_led
;
/* Each individual LED */
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
;
i
++
)
{
led
=
kzalloc
(
sizeof
(
struct
led_classdev
)
+
name_sz
,
GFP_KERNEL
);
if
(
!
led
)
{
hid_err
(
hdev
,
"can't allocate memory for LED %d
\n
"
,
i
);
goto
err_led
;
}
name
=
(
void
*
)(
&
led
[
1
]);
snprintf
(
name
,
name_sz
,
"SRWS1::%s::RPM%d"
,
hdev
->
uniq
,
i
+
1
);
led
->
name
=
name
;
led
->
brightness
=
0
;
led
->
max_brightness
=
1
;
led
->
brightness_get
=
steelseries_srws1_led_get_brightness
;
led
->
brightness_set
=
steelseries_srws1_led_set_brightness
;
drv_data
->
led
[
i
]
=
led
;
ret
=
led_classdev_register
(
&
hdev
->
dev
,
led
);
if
(
ret
)
{
hid_err
(
hdev
,
"failed to register LED %d. Aborting.
\n
"
,
i
);
err_led:
/* Deregister all LEDs (if any) */
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
+
1
;
i
++
)
{
led
=
drv_data
->
led
[
i
];
drv_data
->
led
[
i
]
=
NULL
;
if
(
!
led
)
continue
;
led_classdev_unregister
(
led
);
kfree
(
led
);
}
goto
out
;
/* but let the driver continue without LEDs */
}
}
out:
return
0
;
err_free:
kfree
(
drv_data
);
return
ret
;
}
static
void
steelseries_srws1_remove
(
struct
hid_device
*
hdev
)
{
int
i
;
struct
led_classdev
*
led
;
struct
steelseries_srws1_data
*
drv_data
=
hid_get_drvdata
(
hdev
);
if
(
drv_data
)
{
/* Deregister LEDs (if any) */
for
(
i
=
0
;
i
<
SRWS1_NUMBER_LEDS
+
1
;
i
++
)
{
led
=
drv_data
->
led
[
i
];
drv_data
->
led
[
i
]
=
NULL
;
if
(
!
led
)
continue
;
led_classdev_unregister
(
led
);
kfree
(
led
);
}
}
hid_hw_stop
(
hdev
);
kfree
(
drv_data
);
return
;
}
#endif
static
__u8
*
steelseries_srws1_report_fixup
(
struct
hid_device
*
hdev
,
__u8
*
rdesc
,
unsigned
int
*
rsize
)
{
if
(
*
rsize
>=
115
&&
rdesc
[
11
]
==
0x02
&&
rdesc
[
13
]
==
0xc8
&&
rdesc
[
29
]
==
0xbb
&&
rdesc
[
40
]
==
0xc5
)
{
hid_info
(
hdev
,
"Fixing up Steelseries SRW-S1 report descriptor
\n
"
);
rdesc
=
steelseries_srws1_rdesc_fixed
;
*
rsize
=
sizeof
(
steelseries_srws1_rdesc_fixed
);
}
return
rdesc
;
}
static
const
struct
hid_device_id
steelseries_srws1_devices
[]
=
{
{
HID_USB_DEVICE
(
USB_VENDOR_ID_STEELSERIES
,
USB_DEVICE_ID_STEELSERIES_SRWS1
)
},
{
}
};
MODULE_DEVICE_TABLE
(
hid
,
steelseries_srws1_devices
);
static
struct
hid_driver
steelseries_srws1_driver
=
{
.
name
=
"steelseries_srws1"
,
.
id_table
=
steelseries_srws1_devices
,
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
.
probe
=
steelseries_srws1_probe
,
.
remove
=
steelseries_srws1_remove
,
#endif
.
report_fixup
=
steelseries_srws1_report_fixup
};
static
int
__init
steelseries_srws1_init
(
void
)
{
return
hid_register_driver
(
&
steelseries_srws1_driver
);
}
static
void
__exit
steelseries_srws1_exit
(
void
)
{
hid_unregister_driver
(
&
steelseries_srws1_driver
);
}
module_init
(
steelseries_srws1_init
);
module_exit
(
steelseries_srws1_exit
);
MODULE_LICENSE
(
"GPL"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment