Skip to content

Commit 7af0f83

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.4/sb0540' into for-linus
- support for Creative SB0540 IR receivers, from Bastien Nocera Signed-off-by: Jiri Kosina <[email protected]>
2 parents 67fe00d + f7c4f73 commit 7af0f83

File tree

5 files changed

+285
-0
lines changed

5 files changed

+285
-0
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4308,6 +4308,12 @@ S: Maintained
43084308
F: Documentation/filesystems/cramfs.txt
43094309
F: fs/cramfs/
43104310

4311+
CREATIVE SB0540
4312+
M: Bastien Nocera <[email protected]>
4313+
4314+
S: Maintained
4315+
F: drivers/hid/hid-creative-sb0540.c
4316+
43114317
CRYPTO API
43124318
M: Herbert Xu <[email protected]>
43134319
M: "David S. Miller" <[email protected]>

drivers/hid/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,15 @@ config HID_CP2112
273273
and gpiochip to expose these functions of the CP2112. The
274274
customizable USB descriptor fields are exposed as sysfs attributes.
275275

276+
config HID_CREATIVE_SB0540
277+
tristate "Creative SB0540 infrared receiver"
278+
depends on USB_HID
279+
help
280+
Support for Creative infrared SB0540-compatible remote controls, such
281+
as the RM-1500 and RM-1800 remotes.
282+
283+
Say Y here if you want support for Creative SB0540 infrared receiver.
284+
276285
config HID_CYPRESS
277286
tristate "Cypress mouse and barcode readers"
278287
depends on HID

drivers/hid/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
2727
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
2828
obj-$(CONFIG_HID_APPLE) += hid-apple.o
2929
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
30+
obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
3031
obj-$(CONFIG_HID_ASUS) += hid-asus.o
3132
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
3233
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o

drivers/hid/hid-creative-sb0540.c

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* HID driver for the Creative SB0540 receiver
4+
*
5+
* Copyright (C) 2019 Red Hat Inc. All Rights Reserved
6+
*
7+
*/
8+
9+
#include <linux/device.h>
10+
#include <linux/hid.h>
11+
#include <linux/module.h>
12+
#include "hid-ids.h"
13+
14+
MODULE_AUTHOR("Bastien Nocera <[email protected]>");
15+
MODULE_DESCRIPTION("HID Creative SB0540 receiver");
16+
MODULE_LICENSE("GPL");
17+
18+
static const unsigned short creative_sb0540_key_table[] = {
19+
KEY_POWER,
20+
KEY_RESERVED, /* text: 24bit */
21+
KEY_RESERVED, /* 24bit wheel up */
22+
KEY_RESERVED, /* 24bit wheel down */
23+
KEY_RESERVED, /* text: CMSS */
24+
KEY_RESERVED, /* CMSS wheel Up */
25+
KEY_RESERVED, /* CMSS wheel Down */
26+
KEY_RESERVED, /* text: EAX */
27+
KEY_RESERVED, /* EAX wheel up */
28+
KEY_RESERVED, /* EAX wheel down */
29+
KEY_RESERVED, /* text: 3D Midi */
30+
KEY_RESERVED, /* 3D Midi wheel up */
31+
KEY_RESERVED, /* 3D Midi wheel down */
32+
KEY_MUTE,
33+
KEY_VOLUMEUP,
34+
KEY_VOLUMEDOWN,
35+
KEY_UP,
36+
KEY_LEFT,
37+
KEY_RIGHT,
38+
KEY_REWIND,
39+
KEY_OK,
40+
KEY_FASTFORWARD,
41+
KEY_DOWN,
42+
KEY_AGAIN, /* text: Return, symbol: Jump to */
43+
KEY_PLAY, /* text: Start */
44+
KEY_ESC, /* text: Cancel */
45+
KEY_RECORD,
46+
KEY_OPTION,
47+
KEY_MENU, /* text: Display */
48+
KEY_PREVIOUS,
49+
KEY_PLAYPAUSE,
50+
KEY_NEXT,
51+
KEY_SLOW,
52+
KEY_STOP,
53+
KEY_NUMERIC_1,
54+
KEY_NUMERIC_2,
55+
KEY_NUMERIC_3,
56+
KEY_NUMERIC_4,
57+
KEY_NUMERIC_5,
58+
KEY_NUMERIC_6,
59+
KEY_NUMERIC_7,
60+
KEY_NUMERIC_8,
61+
KEY_NUMERIC_9,
62+
KEY_NUMERIC_0
63+
};
64+
65+
/*
66+
* Codes and keys from lirc's
67+
* remotes/creative/lircd.conf.alsa_usb
68+
* order and size must match creative_sb0540_key_table[] above
69+
*/
70+
static const unsigned short creative_sb0540_codes[] = {
71+
0x619E,
72+
0x916E,
73+
0x926D,
74+
0x936C,
75+
0x718E,
76+
0x946B,
77+
0x956A,
78+
0x8C73,
79+
0x9669,
80+
0x9768,
81+
0x9867,
82+
0x9966,
83+
0x9A65,
84+
0x6E91,
85+
0x629D,
86+
0x639C,
87+
0x7B84,
88+
0x6B94,
89+
0x728D,
90+
0x8778,
91+
0x817E,
92+
0x758A,
93+
0x8D72,
94+
0x8E71,
95+
0x8877,
96+
0x7C83,
97+
0x738C,
98+
0x827D,
99+
0x7689,
100+
0x7F80,
101+
0x7986,
102+
0x7A85,
103+
0x7D82,
104+
0x857A,
105+
0x8B74,
106+
0x8F70,
107+
0x906F,
108+
0x8A75,
109+
0x847B,
110+
0x7887,
111+
0x8976,
112+
0x837C,
113+
0x7788,
114+
0x807F
115+
};
116+
117+
struct creative_sb0540 {
118+
struct input_dev *input_dev;
119+
struct hid_device *hid;
120+
unsigned short keymap[ARRAY_SIZE(creative_sb0540_key_table)];
121+
};
122+
123+
static inline u64 reverse(u64 data, int bits)
124+
{
125+
int i;
126+
u64 c;
127+
128+
c = 0;
129+
for (i = 0; i < bits; i++) {
130+
c |= (u64) (((data & (((u64) 1) << i)) ? 1 : 0))
131+
<< (bits - 1 - i);
132+
}
133+
return (c);
134+
}
135+
136+
static int get_key(struct creative_sb0540 *creative_sb0540, u64 keycode)
137+
{
138+
int i;
139+
140+
for (i = 0; i < ARRAY_SIZE(creative_sb0540_codes); i++) {
141+
if (creative_sb0540_codes[i] == keycode)
142+
return creative_sb0540->keymap[i];
143+
}
144+
145+
return 0;
146+
147+
}
148+
149+
static int creative_sb0540_raw_event(struct hid_device *hid,
150+
struct hid_report *report, u8 *data, int len)
151+
{
152+
struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
153+
u64 code, main_code;
154+
int key;
155+
156+
if (len != 6)
157+
return 0;
158+
159+
/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
160+
code = reverse(data[5], 8);
161+
main_code = (code << 8) + ((~code) & 0xff);
162+
163+
/*
164+
* Flip to get values in the same format as
165+
* remotes/creative/lircd.conf.alsa_usb in lirc
166+
*/
167+
main_code = ((main_code & 0xff) << 8) +
168+
((main_code & 0xff00) >> 8);
169+
170+
key = get_key(creative_sb0540, main_code);
171+
if (key == 0 || key == KEY_RESERVED) {
172+
hid_err(hid, "Could not get a key for main_code %llX\n",
173+
main_code);
174+
return 0;
175+
}
176+
177+
input_report_key(creative_sb0540->input_dev, key, 1);
178+
input_report_key(creative_sb0540->input_dev, key, 0);
179+
input_sync(creative_sb0540->input_dev);
180+
181+
/* let hidraw and hiddev handle the report */
182+
return 0;
183+
}
184+
185+
static int creative_sb0540_input_configured(struct hid_device *hid,
186+
struct hid_input *hidinput)
187+
{
188+
struct input_dev *input_dev = hidinput->input;
189+
struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
190+
int i;
191+
192+
creative_sb0540->input_dev = input_dev;
193+
194+
input_dev->keycode = creative_sb0540->keymap;
195+
input_dev->keycodesize = sizeof(unsigned short);
196+
input_dev->keycodemax = ARRAY_SIZE(creative_sb0540->keymap);
197+
198+
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
199+
200+
memcpy(creative_sb0540->keymap, creative_sb0540_key_table,
201+
sizeof(creative_sb0540->keymap));
202+
for (i = 0; i < ARRAY_SIZE(creative_sb0540_key_table); i++)
203+
set_bit(creative_sb0540->keymap[i], input_dev->keybit);
204+
clear_bit(KEY_RESERVED, input_dev->keybit);
205+
206+
return 0;
207+
}
208+
209+
static int creative_sb0540_input_mapping(struct hid_device *hid,
210+
struct hid_input *hi, struct hid_field *field,
211+
struct hid_usage *usage, unsigned long **bit, int *max)
212+
{
213+
/*
214+
* We are remapping the keys ourselves, so ignore the hid-input
215+
* keymap processing.
216+
*/
217+
return -1;
218+
}
219+
220+
static int creative_sb0540_probe(struct hid_device *hid,
221+
const struct hid_device_id *id)
222+
{
223+
int ret;
224+
struct creative_sb0540 *creative_sb0540;
225+
226+
creative_sb0540 = devm_kzalloc(&hid->dev,
227+
sizeof(struct creative_sb0540), GFP_KERNEL);
228+
229+
if (!creative_sb0540)
230+
return -ENOMEM;
231+
232+
creative_sb0540->hid = hid;
233+
234+
/* force input as some remotes bypass the input registration */
235+
hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
236+
237+
hid_set_drvdata(hid, creative_sb0540);
238+
239+
ret = hid_parse(hid);
240+
if (ret) {
241+
hid_err(hid, "parse failed\n");
242+
return ret;
243+
}
244+
245+
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
246+
if (ret) {
247+
hid_err(hid, "hw start failed\n");
248+
return ret;
249+
}
250+
251+
return ret;
252+
}
253+
254+
static const struct hid_device_id creative_sb0540_devices[] = {
255+
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB0540) },
256+
{ }
257+
};
258+
MODULE_DEVICE_TABLE(hid, creative_sb0540_devices);
259+
260+
static struct hid_driver creative_sb0540_driver = {
261+
.name = "creative-sb0540",
262+
.id_table = creative_sb0540_devices,
263+
.raw_event = creative_sb0540_raw_event,
264+
.input_configured = creative_sb0540_input_configured,
265+
.probe = creative_sb0540_probe,
266+
.input_mapping = creative_sb0540_input_mapping,
267+
};
268+
module_hid_driver(creative_sb0540_driver);

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
#define USB_VENDOR_ID_CREATIVELABS 0x041e
315315
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
316316
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
317+
#define USB_DEVICE_ID_CREATIVE_SB0540 0x3100
317318

318319
#define USB_VENDOR_ID_CVTOUCH 0x1ff7
319320
#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013

0 commit comments

Comments
 (0)