0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/device.h>
0010 #include <linux/hid.h>
0011 #include <linux/module.h>
0012 #include "hid-ids.h"
0013
0014 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
0015 MODULE_DESCRIPTION("HID Creative SB0540 receiver");
0016 MODULE_LICENSE("GPL");
0017
0018 static const unsigned short creative_sb0540_key_table[] = {
0019 KEY_POWER,
0020 KEY_RESERVED,
0021 KEY_RESERVED,
0022 KEY_RESERVED,
0023 KEY_RESERVED,
0024 KEY_RESERVED,
0025 KEY_RESERVED,
0026 KEY_RESERVED,
0027 KEY_RESERVED,
0028 KEY_RESERVED,
0029 KEY_RESERVED,
0030 KEY_RESERVED,
0031 KEY_RESERVED,
0032 KEY_MUTE,
0033 KEY_VOLUMEUP,
0034 KEY_VOLUMEDOWN,
0035 KEY_UP,
0036 KEY_LEFT,
0037 KEY_RIGHT,
0038 KEY_REWIND,
0039 KEY_OK,
0040 KEY_FASTFORWARD,
0041 KEY_DOWN,
0042 KEY_AGAIN,
0043 KEY_PLAY,
0044 KEY_ESC,
0045 KEY_RECORD,
0046 KEY_OPTION,
0047 KEY_MENU,
0048 KEY_PREVIOUS,
0049 KEY_PLAYPAUSE,
0050 KEY_NEXT,
0051 KEY_SLOW,
0052 KEY_STOP,
0053 KEY_NUMERIC_1,
0054 KEY_NUMERIC_2,
0055 KEY_NUMERIC_3,
0056 KEY_NUMERIC_4,
0057 KEY_NUMERIC_5,
0058 KEY_NUMERIC_6,
0059 KEY_NUMERIC_7,
0060 KEY_NUMERIC_8,
0061 KEY_NUMERIC_9,
0062 KEY_NUMERIC_0
0063 };
0064
0065
0066
0067
0068
0069
0070 static const unsigned short creative_sb0540_codes[] = {
0071 0x619E,
0072 0x916E,
0073 0x926D,
0074 0x936C,
0075 0x718E,
0076 0x946B,
0077 0x956A,
0078 0x8C73,
0079 0x9669,
0080 0x9768,
0081 0x9867,
0082 0x9966,
0083 0x9A65,
0084 0x6E91,
0085 0x629D,
0086 0x639C,
0087 0x7B84,
0088 0x6B94,
0089 0x728D,
0090 0x8778,
0091 0x817E,
0092 0x758A,
0093 0x8D72,
0094 0x8E71,
0095 0x8877,
0096 0x7C83,
0097 0x738C,
0098 0x827D,
0099 0x7689,
0100 0x7F80,
0101 0x7986,
0102 0x7A85,
0103 0x7D82,
0104 0x857A,
0105 0x8B74,
0106 0x8F70,
0107 0x906F,
0108 0x8A75,
0109 0x847B,
0110 0x7887,
0111 0x8976,
0112 0x837C,
0113 0x7788,
0114 0x807F
0115 };
0116
0117 struct creative_sb0540 {
0118 struct input_dev *input_dev;
0119 struct hid_device *hid;
0120 unsigned short keymap[ARRAY_SIZE(creative_sb0540_key_table)];
0121 };
0122
0123 static inline u64 reverse(u64 data, int bits)
0124 {
0125 int i;
0126 u64 c;
0127
0128 c = 0;
0129 for (i = 0; i < bits; i++) {
0130 c |= (u64) (((data & (((u64) 1) << i)) ? 1 : 0))
0131 << (bits - 1 - i);
0132 }
0133 return (c);
0134 }
0135
0136 static int get_key(struct creative_sb0540 *creative_sb0540, u64 keycode)
0137 {
0138 int i;
0139
0140 for (i = 0; i < ARRAY_SIZE(creative_sb0540_codes); i++) {
0141 if (creative_sb0540_codes[i] == keycode)
0142 return creative_sb0540->keymap[i];
0143 }
0144
0145 return 0;
0146
0147 }
0148
0149 static int creative_sb0540_raw_event(struct hid_device *hid,
0150 struct hid_report *report, u8 *data, int len)
0151 {
0152 struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
0153 u64 code, main_code;
0154 int key;
0155
0156 if (len != 6)
0157 return 0;
0158
0159
0160 code = reverse(data[5], 8);
0161 main_code = (code << 8) + ((~code) & 0xff);
0162
0163
0164
0165
0166
0167 main_code = ((main_code & 0xff) << 8) +
0168 ((main_code & 0xff00) >> 8);
0169
0170 key = get_key(creative_sb0540, main_code);
0171 if (key == 0 || key == KEY_RESERVED) {
0172 hid_err(hid, "Could not get a key for main_code %llX\n",
0173 main_code);
0174 return 0;
0175 }
0176
0177 input_report_key(creative_sb0540->input_dev, key, 1);
0178 input_report_key(creative_sb0540->input_dev, key, 0);
0179 input_sync(creative_sb0540->input_dev);
0180
0181
0182 return 0;
0183 }
0184
0185 static int creative_sb0540_input_configured(struct hid_device *hid,
0186 struct hid_input *hidinput)
0187 {
0188 struct input_dev *input_dev = hidinput->input;
0189 struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
0190 int i;
0191
0192 creative_sb0540->input_dev = input_dev;
0193
0194 input_dev->keycode = creative_sb0540->keymap;
0195 input_dev->keycodesize = sizeof(unsigned short);
0196 input_dev->keycodemax = ARRAY_SIZE(creative_sb0540->keymap);
0197
0198 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
0199
0200 memcpy(creative_sb0540->keymap, creative_sb0540_key_table,
0201 sizeof(creative_sb0540->keymap));
0202 for (i = 0; i < ARRAY_SIZE(creative_sb0540_key_table); i++)
0203 set_bit(creative_sb0540->keymap[i], input_dev->keybit);
0204 clear_bit(KEY_RESERVED, input_dev->keybit);
0205
0206 return 0;
0207 }
0208
0209 static int creative_sb0540_input_mapping(struct hid_device *hid,
0210 struct hid_input *hi, struct hid_field *field,
0211 struct hid_usage *usage, unsigned long **bit, int *max)
0212 {
0213
0214
0215
0216
0217 return -1;
0218 }
0219
0220 static int creative_sb0540_probe(struct hid_device *hid,
0221 const struct hid_device_id *id)
0222 {
0223 int ret;
0224 struct creative_sb0540 *creative_sb0540;
0225
0226 creative_sb0540 = devm_kzalloc(&hid->dev,
0227 sizeof(struct creative_sb0540), GFP_KERNEL);
0228
0229 if (!creative_sb0540)
0230 return -ENOMEM;
0231
0232 creative_sb0540->hid = hid;
0233
0234
0235 hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
0236
0237 hid_set_drvdata(hid, creative_sb0540);
0238
0239 ret = hid_parse(hid);
0240 if (ret) {
0241 hid_err(hid, "parse failed\n");
0242 return ret;
0243 }
0244
0245 ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
0246 if (ret) {
0247 hid_err(hid, "hw start failed\n");
0248 return ret;
0249 }
0250
0251 return ret;
0252 }
0253
0254 static const struct hid_device_id creative_sb0540_devices[] = {
0255 { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB0540) },
0256 { }
0257 };
0258 MODULE_DEVICE_TABLE(hid, creative_sb0540_devices);
0259
0260 static struct hid_driver creative_sb0540_driver = {
0261 .name = "creative-sb0540",
0262 .id_table = creative_sb0540_devices,
0263 .raw_event = creative_sb0540_raw_event,
0264 .input_configured = creative_sb0540_input_configured,
0265 .probe = creative_sb0540_probe,
0266 .input_mapping = creative_sb0540_input_mapping,
0267 };
0268 module_hid_driver(creative_sb0540_driver);