diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-picolcd.c | 2763 | ||||
-rw-r--r-- | drivers/hid/hid-quanta.c | 261 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.c | 578 |
3 files changed, 3602 insertions, 0 deletions
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c new file mode 100644 index 00000000000..9d8710f8bc7 --- /dev/null +++ b/drivers/hid/hid-picolcd.c | |||
@@ -0,0 +1,2763 @@ | |||
1 | /*************************************************************************** | ||
2 | * Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org> * | ||
3 | * * | ||
4 | * Based on Logitech G13 driver (v0.4) * | ||
5 | * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * | ||
6 | * * | ||
7 | * This program is free software: you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation, version 2 of the License. * | ||
10 | * * | ||
11 | * This driver is distributed in the hope that it will be useful, but * | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * | ||
14 | * General Public License for more details. * | ||
15 | * * | ||
16 | * You should have received a copy of the GNU General Public License * | ||
17 | * along with this software. If not see <http://www.gnu.org/licenses/>. * | ||
18 | ***************************************************************************/ | ||
19 | |||
20 | #include <linux/hid.h> | ||
21 | #include <linux/hid-debug.h> | ||
22 | #include <linux/input.h> | ||
23 | #include "hid-ids.h" | ||
24 | #include "usbhid/usbhid.h" | ||
25 | #include <linux/usb.h> | ||
26 | |||
27 | #include <linux/fb.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/backlight.h> | ||
30 | #include <linux/lcd.h> | ||
31 | |||
32 | #include <linux/leds.h> | ||
33 | |||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/debugfs.h> | ||
36 | |||
37 | #include <linux/completion.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | |||
40 | #define PICOLCD_NAME "PicoLCD (graphic)" | ||
41 | |||
42 | /* Report numbers */ | ||
43 | #define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */ | ||
44 | #define ERR_SUCCESS 0x00 | ||
45 | #define ERR_PARAMETER_MISSING 0x01 | ||
46 | #define ERR_DATA_MISSING 0x02 | ||
47 | #define ERR_BLOCK_READ_ONLY 0x03 | ||
48 | #define ERR_BLOCK_NOT_ERASABLE 0x04 | ||
49 | #define ERR_BLOCK_TOO_BIG 0x05 | ||
50 | #define ERR_SECTION_OVERFLOW 0x06 | ||
51 | #define ERR_INVALID_CMD_LEN 0x07 | ||
52 | #define ERR_INVALID_DATA_LEN 0x08 | ||
53 | #define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */ | ||
54 | #define REPORT_IR_DATA 0x21 /* LCD: IN[63] */ | ||
55 | #define REPORT_EE_DATA 0x32 /* LCD: IN[63] */ | ||
56 | #define REPORT_MEMORY 0x41 /* LCD: IN[63] */ | ||
57 | #define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */ | ||
58 | #define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */ | ||
59 | #define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */ | ||
60 | #define REPORT_RESET 0x93 /* LCD: OUT[2] */ | ||
61 | #define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */ | ||
62 | #define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */ | ||
63 | #define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */ | ||
64 | #define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */ | ||
65 | #define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */ | ||
66 | #define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */ | ||
67 | #define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */ | ||
68 | #define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */ | ||
69 | #define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */ | ||
70 | #define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */ | ||
71 | #define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */ | ||
72 | #define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */ | ||
73 | #define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */ | ||
74 | #define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */ | ||
75 | #define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */ | ||
76 | #define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */ | ||
77 | #define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */ | ||
78 | #define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */ | ||
79 | |||
80 | #ifdef CONFIG_HID_PICOLCD_FB | ||
81 | /* Framebuffer | ||
82 | * | ||
83 | * The PicoLCD use a Topway LCD module of 256x64 pixel | ||
84 | * This display area is tiled over 4 controllers with 8 tiles | ||
85 | * each. Each tile has 8x64 pixel, each data byte representing | ||
86 | * a 1-bit wide vertical line of the tile. | ||
87 | * | ||
88 | * The display can be updated at a tile granularity. | ||
89 | * | ||
90 | * Chip 1 Chip 2 Chip 3 Chip 4 | ||
91 | * +----------------+----------------+----------------+----------------+ | ||
92 | * | Tile 1 | Tile 1 | Tile 1 | Tile 1 | | ||
93 | * +----------------+----------------+----------------+----------------+ | ||
94 | * | Tile 2 | Tile 2 | Tile 2 | Tile 2 | | ||
95 | * +----------------+----------------+----------------+----------------+ | ||
96 | * ... | ||
97 | * +----------------+----------------+----------------+----------------+ | ||
98 | * | Tile 8 | Tile 8 | Tile 8 | Tile 8 | | ||
99 | * +----------------+----------------+----------------+----------------+ | ||
100 | */ | ||
101 | #define PICOLCDFB_NAME "picolcdfb" | ||
102 | #define PICOLCDFB_WIDTH (256) | ||
103 | #define PICOLCDFB_HEIGHT (64) | ||
104 | #define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8) | ||
105 | |||
106 | #define PICOLCDFB_UPDATE_RATE_LIMIT 10 | ||
107 | #define PICOLCDFB_UPDATE_RATE_DEFAULT 2 | ||
108 | |||
109 | /* Framebuffer visual structures */ | ||
110 | static const struct fb_fix_screeninfo picolcdfb_fix = { | ||
111 | .id = PICOLCDFB_NAME, | ||
112 | .type = FB_TYPE_PACKED_PIXELS, | ||
113 | .visual = FB_VISUAL_MONO01, | ||
114 | .xpanstep = 0, | ||
115 | .ypanstep = 0, | ||
116 | .ywrapstep = 0, | ||
117 | .line_length = PICOLCDFB_WIDTH / 8, | ||
118 | .accel = FB_ACCEL_NONE, | ||
119 | }; | ||
120 | |||
121 | static const struct fb_var_screeninfo picolcdfb_var = { | ||
122 | .xres = PICOLCDFB_WIDTH, | ||
123 | .yres = PICOLCDFB_HEIGHT, | ||
124 | .xres_virtual = PICOLCDFB_WIDTH, | ||
125 | .yres_virtual = PICOLCDFB_HEIGHT, | ||
126 | .width = 103, | ||
127 | .height = 26, | ||
128 | .bits_per_pixel = 1, | ||
129 | .grayscale = 1, | ||
130 | .red = { | ||
131 | .offset = 0, | ||
132 | .length = 1, | ||
133 | .msb_right = 0, | ||
134 | }, | ||
135 | .green = { | ||
136 | .offset = 0, | ||
137 | .length = 1, | ||
138 | .msb_right = 0, | ||
139 | }, | ||
140 | .blue = { | ||
141 | .offset = 0, | ||
142 | .length = 1, | ||
143 | .msb_right = 0, | ||
144 | }, | ||
145 | .transp = { | ||
146 | .offset = 0, | ||
147 | .length = 0, | ||
148 | .msb_right = 0, | ||
149 | }, | ||
150 | }; | ||
151 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
152 | |||
153 | /* Input device | ||
154 | * | ||
155 | * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys | ||
156 | * and header for 4x4 key matrix. The built-in keys are part of the matrix. | ||
157 | */ | ||
158 | static const unsigned short def_keymap[] = { | ||
159 | KEY_RESERVED, /* none */ | ||
160 | KEY_BACK, /* col 4 + row 1 */ | ||
161 | KEY_HOMEPAGE, /* col 3 + row 1 */ | ||
162 | KEY_RESERVED, /* col 2 + row 1 */ | ||
163 | KEY_RESERVED, /* col 1 + row 1 */ | ||
164 | KEY_SCROLLUP, /* col 4 + row 2 */ | ||
165 | KEY_OK, /* col 3 + row 2 */ | ||
166 | KEY_SCROLLDOWN, /* col 2 + row 2 */ | ||
167 | KEY_RESERVED, /* col 1 + row 2 */ | ||
168 | KEY_RESERVED, /* col 4 + row 3 */ | ||
169 | KEY_RESERVED, /* col 3 + row 3 */ | ||
170 | KEY_RESERVED, /* col 2 + row 3 */ | ||
171 | KEY_RESERVED, /* col 1 + row 3 */ | ||
172 | KEY_RESERVED, /* col 4 + row 4 */ | ||
173 | KEY_RESERVED, /* col 3 + row 4 */ | ||
174 | KEY_RESERVED, /* col 2 + row 4 */ | ||
175 | KEY_RESERVED, /* col 1 + row 4 */ | ||
176 | }; | ||
177 | #define PICOLCD_KEYS ARRAY_SIZE(def_keymap) | ||
178 | |||
179 | /* Description of in-progress IO operation, used for operations | ||
180 | * that trigger response from device */ | ||
181 | struct picolcd_pending { | ||
182 | struct hid_report *out_report; | ||
183 | struct hid_report *in_report; | ||
184 | struct completion ready; | ||
185 | int raw_size; | ||
186 | u8 raw_data[64]; | ||
187 | }; | ||
188 | |||
189 | /* Per device data structure */ | ||
190 | struct picolcd_data { | ||
191 | struct hid_device *hdev; | ||
192 | #ifdef CONFIG_DEBUG_FS | ||
193 | struct dentry *debug_reset; | ||
194 | struct dentry *debug_eeprom; | ||
195 | struct dentry *debug_flash; | ||
196 | struct mutex mutex_flash; | ||
197 | int addr_sz; | ||
198 | #endif | ||
199 | u8 version[2]; | ||
200 | unsigned short opmode_delay; | ||
201 | /* input stuff */ | ||
202 | u8 pressed_keys[2]; | ||
203 | struct input_dev *input_keys; | ||
204 | struct input_dev *input_cir; | ||
205 | unsigned short keycode[PICOLCD_KEYS]; | ||
206 | |||
207 | #ifdef CONFIG_HID_PICOLCD_FB | ||
208 | /* Framebuffer stuff */ | ||
209 | u8 fb_update_rate; | ||
210 | u8 fb_bpp; | ||
211 | u8 fb_force; | ||
212 | u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ | ||
213 | u8 *fb_bitmap; /* framebuffer */ | ||
214 | struct fb_info *fb_info; | ||
215 | struct fb_deferred_io fb_defio; | ||
216 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
217 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
218 | struct lcd_device *lcd; | ||
219 | u8 lcd_contrast; | ||
220 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
221 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
222 | struct backlight_device *backlight; | ||
223 | u8 lcd_brightness; | ||
224 | u8 lcd_power; | ||
225 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
226 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
227 | /* LED stuff */ | ||
228 | u8 led_state; | ||
229 | struct led_classdev *led[8]; | ||
230 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
231 | |||
232 | /* Housekeeping stuff */ | ||
233 | spinlock_t lock; | ||
234 | struct mutex mutex; | ||
235 | struct picolcd_pending *pending; | ||
236 | int status; | ||
237 | #define PICOLCD_BOOTLOADER 1 | ||
238 | #define PICOLCD_FAILED 2 | ||
239 | #define PICOLCD_READY_FB 4 | ||
240 | }; | ||
241 | |||
242 | |||
243 | /* Find a given report */ | ||
244 | #define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT) | ||
245 | #define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT) | ||
246 | |||
247 | static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir) | ||
248 | { | ||
249 | struct list_head *feature_report_list = &hdev->report_enum[dir].report_list; | ||
250 | struct hid_report *report = NULL; | ||
251 | |||
252 | list_for_each_entry(report, feature_report_list, list) { | ||
253 | if (report->id == id) | ||
254 | return report; | ||
255 | } | ||
256 | hid_warn(hdev, "No report with id 0x%x found\n", id); | ||
257 | return NULL; | ||
258 | } | ||
259 | |||
260 | #ifdef CONFIG_DEBUG_FS | ||
261 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
262 | struct hid_device *hdev, struct hid_report *report); | ||
263 | #define usbhid_submit_report(a, b, c) \ | ||
264 | do { \ | ||
265 | picolcd_debug_out_report(hid_get_drvdata(a), a, b); \ | ||
266 | usbhid_submit_report(a, b, c); \ | ||
267 | } while (0) | ||
268 | #endif | ||
269 | |||
270 | /* Submit a report and wait for a reply from device - if device fades away | ||
271 | * or does not respond in time, return NULL */ | ||
272 | static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev, | ||
273 | int report_id, const u8 *raw_data, int size) | ||
274 | { | ||
275 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
276 | struct picolcd_pending *work; | ||
277 | struct hid_report *report = picolcd_out_report(report_id, hdev); | ||
278 | unsigned long flags; | ||
279 | int i, j, k; | ||
280 | |||
281 | if (!report || !data) | ||
282 | return NULL; | ||
283 | if (data->status & PICOLCD_FAILED) | ||
284 | return NULL; | ||
285 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
286 | if (!work) | ||
287 | return NULL; | ||
288 | |||
289 | init_completion(&work->ready); | ||
290 | work->out_report = report; | ||
291 | work->in_report = NULL; | ||
292 | work->raw_size = 0; | ||
293 | |||
294 | mutex_lock(&data->mutex); | ||
295 | spin_lock_irqsave(&data->lock, flags); | ||
296 | for (i = k = 0; i < report->maxfield; i++) | ||
297 | for (j = 0; j < report->field[i]->report_count; j++) { | ||
298 | hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0); | ||
299 | k++; | ||
300 | } | ||
301 | data->pending = work; | ||
302 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
303 | spin_unlock_irqrestore(&data->lock, flags); | ||
304 | wait_for_completion_interruptible_timeout(&work->ready, HZ*2); | ||
305 | spin_lock_irqsave(&data->lock, flags); | ||
306 | data->pending = NULL; | ||
307 | spin_unlock_irqrestore(&data->lock, flags); | ||
308 | mutex_unlock(&data->mutex); | ||
309 | return work; | ||
310 | } | ||
311 | |||
312 | #ifdef CONFIG_HID_PICOLCD_FB | ||
313 | /* Send a given tile to PicoLCD */ | ||
314 | static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile) | ||
315 | { | ||
316 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
317 | struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev); | ||
318 | struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev); | ||
319 | unsigned long flags; | ||
320 | u8 *tdata; | ||
321 | int i; | ||
322 | |||
323 | if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1) | ||
324 | return -ENODEV; | ||
325 | |||
326 | spin_lock_irqsave(&data->lock, flags); | ||
327 | hid_set_field(report1->field[0], 0, chip << 2); | ||
328 | hid_set_field(report1->field[0], 1, 0x02); | ||
329 | hid_set_field(report1->field[0], 2, 0x00); | ||
330 | hid_set_field(report1->field[0], 3, 0x00); | ||
331 | hid_set_field(report1->field[0], 4, 0xb8 | tile); | ||
332 | hid_set_field(report1->field[0], 5, 0x00); | ||
333 | hid_set_field(report1->field[0], 6, 0x00); | ||
334 | hid_set_field(report1->field[0], 7, 0x40); | ||
335 | hid_set_field(report1->field[0], 8, 0x00); | ||
336 | hid_set_field(report1->field[0], 9, 0x00); | ||
337 | hid_set_field(report1->field[0], 10, 32); | ||
338 | |||
339 | hid_set_field(report2->field[0], 0, (chip << 2) | 0x01); | ||
340 | hid_set_field(report2->field[0], 1, 0x00); | ||
341 | hid_set_field(report2->field[0], 2, 0x00); | ||
342 | hid_set_field(report2->field[0], 3, 32); | ||
343 | |||
344 | tdata = data->fb_vbitmap + (tile * 4 + chip) * 64; | ||
345 | for (i = 0; i < 64; i++) | ||
346 | if (i < 32) | ||
347 | hid_set_field(report1->field[0], 11 + i, tdata[i]); | ||
348 | else | ||
349 | hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); | ||
350 | |||
351 | usbhid_submit_report(data->hdev, report1, USB_DIR_OUT); | ||
352 | usbhid_submit_report(data->hdev, report2, USB_DIR_OUT); | ||
353 | spin_unlock_irqrestore(&data->lock, flags); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* Translate a single tile*/ | ||
358 | static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, | ||
359 | int chip, int tile) | ||
360 | { | ||
361 | int i, b, changed = 0; | ||
362 | u8 tdata[64]; | ||
363 | u8 *vdata = vbitmap + (tile * 4 + chip) * 64; | ||
364 | |||
365 | if (bpp == 1) { | ||
366 | for (b = 7; b >= 0; b--) { | ||
367 | const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; | ||
368 | for (i = 0; i < 64; i++) { | ||
369 | tdata[i] <<= 1; | ||
370 | tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01; | ||
371 | } | ||
372 | } | ||
373 | } else if (bpp == 8) { | ||
374 | for (b = 7; b >= 0; b--) { | ||
375 | const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8; | ||
376 | for (i = 0; i < 64; i++) { | ||
377 | tdata[i] <<= 1; | ||
378 | tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00; | ||
379 | } | ||
380 | } | ||
381 | } else { | ||
382 | /* Oops, we should never get here! */ | ||
383 | WARN_ON(1); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | for (i = 0; i < 64; i++) | ||
388 | if (tdata[i] != vdata[i]) { | ||
389 | changed = 1; | ||
390 | vdata[i] = tdata[i]; | ||
391 | } | ||
392 | return changed; | ||
393 | } | ||
394 | |||
395 | /* Reconfigure LCD display */ | ||
396 | static int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
397 | { | ||
398 | struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev); | ||
399 | int i, j; | ||
400 | unsigned long flags; | ||
401 | static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 }; | ||
402 | |||
403 | if (!report || report->maxfield != 1) | ||
404 | return -ENODEV; | ||
405 | |||
406 | spin_lock_irqsave(&data->lock, flags); | ||
407 | for (i = 0; i < 4; i++) { | ||
408 | for (j = 0; j < report->field[0]->maxusage; j++) | ||
409 | if (j == 0) | ||
410 | hid_set_field(report->field[0], j, i << 2); | ||
411 | else if (j < sizeof(mapcmd)) | ||
412 | hid_set_field(report->field[0], j, mapcmd[j]); | ||
413 | else | ||
414 | hid_set_field(report->field[0], j, 0); | ||
415 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
416 | } | ||
417 | |||
418 | data->status |= PICOLCD_READY_FB; | ||
419 | spin_unlock_irqrestore(&data->lock, flags); | ||
420 | |||
421 | if (data->fb_bitmap) { | ||
422 | if (clear) { | ||
423 | memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE); | ||
424 | memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); | ||
425 | } | ||
426 | data->fb_force = 1; | ||
427 | } | ||
428 | |||
429 | /* schedule first output of framebuffer */ | ||
430 | if (data->fb_info) | ||
431 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* Update fb_vbitmap from the screen_base and send changed tiles to device */ | ||
437 | static void picolcd_fb_update(struct picolcd_data *data) | ||
438 | { | ||
439 | int chip, tile, n; | ||
440 | unsigned long flags; | ||
441 | |||
442 | if (!data) | ||
443 | return; | ||
444 | |||
445 | spin_lock_irqsave(&data->lock, flags); | ||
446 | if (!(data->status & PICOLCD_READY_FB)) { | ||
447 | spin_unlock_irqrestore(&data->lock, flags); | ||
448 | picolcd_fb_reset(data, 0); | ||
449 | } else { | ||
450 | spin_unlock_irqrestore(&data->lock, flags); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Translate the framebuffer into the format needed by the PicoLCD. | ||
455 | * See display layout above. | ||
456 | * Do this one tile after the other and push those tiles that changed. | ||
457 | * | ||
458 | * Wait for our IO to complete as otherwise we might flood the queue! | ||
459 | */ | ||
460 | n = 0; | ||
461 | for (chip = 0; chip < 4; chip++) | ||
462 | for (tile = 0; tile < 8; tile++) | ||
463 | if (picolcd_fb_update_tile(data->fb_vbitmap, | ||
464 | data->fb_bitmap, data->fb_bpp, chip, tile) || | ||
465 | data->fb_force) { | ||
466 | n += 2; | ||
467 | if (!data->fb_info->par) | ||
468 | return; /* device lost! */ | ||
469 | if (n >= HID_OUTPUT_FIFO_SIZE / 2) { | ||
470 | usbhid_wait_io(data->hdev); | ||
471 | n = 0; | ||
472 | } | ||
473 | picolcd_fb_send_tile(data->hdev, chip, tile); | ||
474 | } | ||
475 | data->fb_force = false; | ||
476 | if (n) | ||
477 | usbhid_wait_io(data->hdev); | ||
478 | } | ||
479 | |||
480 | /* Stub to call the system default and update the image on the picoLCD */ | ||
481 | static void picolcd_fb_fillrect(struct fb_info *info, | ||
482 | const struct fb_fillrect *rect) | ||
483 | { | ||
484 | if (!info->par) | ||
485 | return; | ||
486 | sys_fillrect(info, rect); | ||
487 | |||
488 | schedule_delayed_work(&info->deferred_work, 0); | ||
489 | } | ||
490 | |||
491 | /* Stub to call the system default and update the image on the picoLCD */ | ||
492 | static void picolcd_fb_copyarea(struct fb_info *info, | ||
493 | const struct fb_copyarea *area) | ||
494 | { | ||
495 | if (!info->par) | ||
496 | return; | ||
497 | sys_copyarea(info, area); | ||
498 | |||
499 | schedule_delayed_work(&info->deferred_work, 0); | ||
500 | } | ||
501 | |||
502 | /* Stub to call the system default and update the image on the picoLCD */ | ||
503 | static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
504 | { | ||
505 | if (!info->par) | ||
506 | return; | ||
507 | sys_imageblit(info, image); | ||
508 | |||
509 | schedule_delayed_work(&info->deferred_work, 0); | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * this is the slow path from userspace. they can seek and write to | ||
514 | * the fb. it's inefficient to do anything less than a full screen draw | ||
515 | */ | ||
516 | static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf, | ||
517 | size_t count, loff_t *ppos) | ||
518 | { | ||
519 | ssize_t ret; | ||
520 | if (!info->par) | ||
521 | return -ENODEV; | ||
522 | ret = fb_sys_write(info, buf, count, ppos); | ||
523 | if (ret >= 0) | ||
524 | schedule_delayed_work(&info->deferred_work, 0); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int picolcd_fb_blank(int blank, struct fb_info *info) | ||
529 | { | ||
530 | if (!info->par) | ||
531 | return -ENODEV; | ||
532 | /* We let fb notification do this for us via lcd/backlight device */ | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static void picolcd_fb_destroy(struct fb_info *info) | ||
537 | { | ||
538 | struct picolcd_data *data = info->par; | ||
539 | u32 *ref_cnt = info->pseudo_palette; | ||
540 | int may_release; | ||
541 | |||
542 | info->par = NULL; | ||
543 | if (data) | ||
544 | data->fb_info = NULL; | ||
545 | fb_deferred_io_cleanup(info); | ||
546 | |||
547 | ref_cnt--; | ||
548 | mutex_lock(&info->lock); | ||
549 | (*ref_cnt)--; | ||
550 | may_release = !*ref_cnt; | ||
551 | mutex_unlock(&info->lock); | ||
552 | if (may_release) { | ||
553 | vfree((u8 *)info->fix.smem_start); | ||
554 | framebuffer_release(info); | ||
555 | } | ||
556 | } | ||
557 | |||
558 | static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
559 | { | ||
560 | __u32 bpp = var->bits_per_pixel; | ||
561 | __u32 activate = var->activate; | ||
562 | |||
563 | /* only allow 1/8 bit depth (8-bit is grayscale) */ | ||
564 | *var = picolcdfb_var; | ||
565 | var->activate = activate; | ||
566 | if (bpp >= 8) { | ||
567 | var->bits_per_pixel = 8; | ||
568 | var->red.length = 8; | ||
569 | var->green.length = 8; | ||
570 | var->blue.length = 8; | ||
571 | } else { | ||
572 | var->bits_per_pixel = 1; | ||
573 | var->red.length = 1; | ||
574 | var->green.length = 1; | ||
575 | var->blue.length = 1; | ||
576 | } | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int picolcd_set_par(struct fb_info *info) | ||
581 | { | ||
582 | struct picolcd_data *data = info->par; | ||
583 | u8 *tmp_fb, *o_fb; | ||
584 | if (!data) | ||
585 | return -ENODEV; | ||
586 | if (info->var.bits_per_pixel == data->fb_bpp) | ||
587 | return 0; | ||
588 | /* switch between 1/8 bit depths */ | ||
589 | if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) | ||
590 | return -EINVAL; | ||
591 | |||
592 | o_fb = data->fb_bitmap; | ||
593 | tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); | ||
594 | if (!tmp_fb) | ||
595 | return -ENOMEM; | ||
596 | |||
597 | /* translate FB content to new bits-per-pixel */ | ||
598 | if (info->var.bits_per_pixel == 1) { | ||
599 | int i, b; | ||
600 | for (i = 0; i < PICOLCDFB_SIZE; i++) { | ||
601 | u8 p = 0; | ||
602 | for (b = 0; b < 8; b++) { | ||
603 | p <<= 1; | ||
604 | p |= o_fb[i*8+b] ? 0x01 : 0x00; | ||
605 | } | ||
606 | tmp_fb[i] = p; | ||
607 | } | ||
608 | memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE); | ||
609 | info->fix.visual = FB_VISUAL_MONO01; | ||
610 | info->fix.line_length = PICOLCDFB_WIDTH / 8; | ||
611 | } else { | ||
612 | int i; | ||
613 | memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE); | ||
614 | for (i = 0; i < PICOLCDFB_SIZE * 8; i++) | ||
615 | o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; | ||
616 | info->fix.visual = FB_VISUAL_DIRECTCOLOR; | ||
617 | info->fix.line_length = PICOLCDFB_WIDTH; | ||
618 | } | ||
619 | |||
620 | kfree(tmp_fb); | ||
621 | data->fb_bpp = info->var.bits_per_pixel; | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | /* Do refcounting on our FB and cleanup per worker if FB is | ||
626 | * closed after unplug of our device | ||
627 | * (fb_release holds info->lock and still touches info after | ||
628 | * we return so we can't release it immediately. | ||
629 | */ | ||
630 | struct picolcd_fb_cleanup_item { | ||
631 | struct fb_info *info; | ||
632 | struct picolcd_fb_cleanup_item *next; | ||
633 | }; | ||
634 | static struct picolcd_fb_cleanup_item *fb_pending; | ||
635 | DEFINE_SPINLOCK(fb_pending_lock); | ||
636 | |||
637 | static void picolcd_fb_do_cleanup(struct work_struct *data) | ||
638 | { | ||
639 | struct picolcd_fb_cleanup_item *item; | ||
640 | unsigned long flags; | ||
641 | |||
642 | do { | ||
643 | spin_lock_irqsave(&fb_pending_lock, flags); | ||
644 | item = fb_pending; | ||
645 | fb_pending = item ? item->next : NULL; | ||
646 | spin_unlock_irqrestore(&fb_pending_lock, flags); | ||
647 | |||
648 | if (item) { | ||
649 | u8 *fb = (u8 *)item->info->fix.smem_start; | ||
650 | /* make sure we do not race against fb core when | ||
651 | * releasing */ | ||
652 | mutex_lock(&item->info->lock); | ||
653 | mutex_unlock(&item->info->lock); | ||
654 | framebuffer_release(item->info); | ||
655 | vfree(fb); | ||
656 | } | ||
657 | } while (item); | ||
658 | } | ||
659 | |||
660 | DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup); | ||
661 | |||
662 | static int picolcd_fb_open(struct fb_info *info, int u) | ||
663 | { | ||
664 | u32 *ref_cnt = info->pseudo_palette; | ||
665 | ref_cnt--; | ||
666 | |||
667 | (*ref_cnt)++; | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int picolcd_fb_release(struct fb_info *info, int u) | ||
672 | { | ||
673 | u32 *ref_cnt = info->pseudo_palette; | ||
674 | ref_cnt--; | ||
675 | |||
676 | (*ref_cnt)++; | ||
677 | if (!*ref_cnt) { | ||
678 | unsigned long flags; | ||
679 | struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt; | ||
680 | item--; | ||
681 | spin_lock_irqsave(&fb_pending_lock, flags); | ||
682 | item->next = fb_pending; | ||
683 | fb_pending = item; | ||
684 | spin_unlock_irqrestore(&fb_pending_lock, flags); | ||
685 | schedule_work(&picolcd_fb_cleanup); | ||
686 | } | ||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | /* Note this can't be const because of struct fb_info definition */ | ||
691 | static struct fb_ops picolcdfb_ops = { | ||
692 | .owner = THIS_MODULE, | ||
693 | .fb_destroy = picolcd_fb_destroy, | ||
694 | .fb_open = picolcd_fb_open, | ||
695 | .fb_release = picolcd_fb_release, | ||
696 | .fb_read = fb_sys_read, | ||
697 | .fb_write = picolcd_fb_write, | ||
698 | .fb_blank = picolcd_fb_blank, | ||
699 | .fb_fillrect = picolcd_fb_fillrect, | ||
700 | .fb_copyarea = picolcd_fb_copyarea, | ||
701 | .fb_imageblit = picolcd_fb_imageblit, | ||
702 | .fb_check_var = picolcd_fb_check_var, | ||
703 | .fb_set_par = picolcd_set_par, | ||
704 | }; | ||
705 | |||
706 | |||
707 | /* Callback from deferred IO workqueue */ | ||
708 | static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist) | ||
709 | { | ||
710 | picolcd_fb_update(info->par); | ||
711 | } | ||
712 | |||
713 | static const struct fb_deferred_io picolcd_fb_defio = { | ||
714 | .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT, | ||
715 | .deferred_io = picolcd_fb_deferred_io, | ||
716 | }; | ||
717 | |||
718 | |||
719 | /* | ||
720 | * The "fb_update_rate" sysfs attribute | ||
721 | */ | ||
722 | static ssize_t picolcd_fb_update_rate_show(struct device *dev, | ||
723 | struct device_attribute *attr, char *buf) | ||
724 | { | ||
725 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
726 | unsigned i, fb_update_rate = data->fb_update_rate; | ||
727 | size_t ret = 0; | ||
728 | |||
729 | for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++) | ||
730 | if (ret >= PAGE_SIZE) | ||
731 | break; | ||
732 | else if (i == fb_update_rate) | ||
733 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i); | ||
734 | else | ||
735 | ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i); | ||
736 | if (ret > 0) | ||
737 | buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n'; | ||
738 | return ret; | ||
739 | } | ||
740 | |||
741 | static ssize_t picolcd_fb_update_rate_store(struct device *dev, | ||
742 | struct device_attribute *attr, const char *buf, size_t count) | ||
743 | { | ||
744 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
745 | int i; | ||
746 | unsigned u; | ||
747 | |||
748 | if (count < 1 || count > 10) | ||
749 | return -EINVAL; | ||
750 | |||
751 | i = sscanf(buf, "%u", &u); | ||
752 | if (i != 1) | ||
753 | return -EINVAL; | ||
754 | |||
755 | if (u > PICOLCDFB_UPDATE_RATE_LIMIT) | ||
756 | return -ERANGE; | ||
757 | else if (u == 0) | ||
758 | u = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
759 | |||
760 | data->fb_update_rate = u; | ||
761 | data->fb_defio.delay = HZ / data->fb_update_rate; | ||
762 | return count; | ||
763 | } | ||
764 | |||
765 | static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show, | ||
766 | picolcd_fb_update_rate_store); | ||
767 | |||
768 | /* initialize Framebuffer device */ | ||
769 | static int picolcd_init_framebuffer(struct picolcd_data *data) | ||
770 | { | ||
771 | struct device *dev = &data->hdev->dev; | ||
772 | struct fb_info *info = NULL; | ||
773 | int i, error = -ENOMEM; | ||
774 | u8 *fb_vbitmap = NULL; | ||
775 | u8 *fb_bitmap = NULL; | ||
776 | u32 *palette; | ||
777 | |||
778 | fb_bitmap = vmalloc(PICOLCDFB_SIZE*8); | ||
779 | if (fb_bitmap == NULL) { | ||
780 | dev_err(dev, "can't get a free page for framebuffer\n"); | ||
781 | goto err_nomem; | ||
782 | } | ||
783 | |||
784 | fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL); | ||
785 | if (fb_vbitmap == NULL) { | ||
786 | dev_err(dev, "can't alloc vbitmap image buffer\n"); | ||
787 | goto err_nomem; | ||
788 | } | ||
789 | |||
790 | data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; | ||
791 | data->fb_defio = picolcd_fb_defio; | ||
792 | /* The extra memory is: | ||
793 | * - struct picolcd_fb_cleanup_item | ||
794 | * - u32 for ref_count | ||
795 | * - 256*u32 for pseudo_palette | ||
796 | */ | ||
797 | info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev); | ||
798 | if (info == NULL) { | ||
799 | dev_err(dev, "failed to allocate a framebuffer\n"); | ||
800 | goto err_nomem; | ||
801 | } | ||
802 | |||
803 | palette = info->par + sizeof(struct picolcd_fb_cleanup_item); | ||
804 | *palette = 1; | ||
805 | palette++; | ||
806 | for (i = 0; i < 256; i++) | ||
807 | palette[i] = i > 0 && i < 16 ? 0xff : 0; | ||
808 | info->pseudo_palette = palette; | ||
809 | info->fbdefio = &data->fb_defio; | ||
810 | info->screen_base = (char __force __iomem *)fb_bitmap; | ||
811 | info->fbops = &picolcdfb_ops; | ||
812 | info->var = picolcdfb_var; | ||
813 | info->fix = picolcdfb_fix; | ||
814 | info->fix.smem_len = PICOLCDFB_SIZE*8; | ||
815 | info->fix.smem_start = (unsigned long)fb_bitmap; | ||
816 | info->par = data; | ||
817 | info->flags = FBINFO_FLAG_DEFAULT; | ||
818 | |||
819 | data->fb_vbitmap = fb_vbitmap; | ||
820 | data->fb_bitmap = fb_bitmap; | ||
821 | data->fb_bpp = picolcdfb_var.bits_per_pixel; | ||
822 | error = picolcd_fb_reset(data, 1); | ||
823 | if (error) { | ||
824 | dev_err(dev, "failed to configure display\n"); | ||
825 | goto err_cleanup; | ||
826 | } | ||
827 | error = device_create_file(dev, &dev_attr_fb_update_rate); | ||
828 | if (error) { | ||
829 | dev_err(dev, "failed to create sysfs attributes\n"); | ||
830 | goto err_cleanup; | ||
831 | } | ||
832 | fb_deferred_io_init(info); | ||
833 | data->fb_info = info; | ||
834 | error = register_framebuffer(info); | ||
835 | if (error) { | ||
836 | dev_err(dev, "failed to register framebuffer\n"); | ||
837 | goto err_sysfs; | ||
838 | } | ||
839 | /* schedule first output of framebuffer */ | ||
840 | data->fb_force = 1; | ||
841 | schedule_delayed_work(&info->deferred_work, 0); | ||
842 | return 0; | ||
843 | |||
844 | err_sysfs: | ||
845 | fb_deferred_io_cleanup(info); | ||
846 | device_remove_file(dev, &dev_attr_fb_update_rate); | ||
847 | err_cleanup: | ||
848 | data->fb_vbitmap = NULL; | ||
849 | data->fb_bitmap = NULL; | ||
850 | data->fb_bpp = 0; | ||
851 | data->fb_info = NULL; | ||
852 | |||
853 | err_nomem: | ||
854 | framebuffer_release(info); | ||
855 | vfree(fb_bitmap); | ||
856 | kfree(fb_vbitmap); | ||
857 | return error; | ||
858 | } | ||
859 | |||
860 | static void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
861 | { | ||
862 | struct fb_info *info = data->fb_info; | ||
863 | u8 *fb_vbitmap = data->fb_vbitmap; | ||
864 | |||
865 | if (!info) | ||
866 | return; | ||
867 | |||
868 | info->par = NULL; | ||
869 | device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); | ||
870 | unregister_framebuffer(info); | ||
871 | data->fb_vbitmap = NULL; | ||
872 | data->fb_bitmap = NULL; | ||
873 | data->fb_bpp = 0; | ||
874 | data->fb_info = NULL; | ||
875 | kfree(fb_vbitmap); | ||
876 | } | ||
877 | |||
878 | #define picolcd_fbinfo(d) ((d)->fb_info) | ||
879 | #else | ||
880 | static inline int picolcd_fb_reset(struct picolcd_data *data, int clear) | ||
881 | { | ||
882 | return 0; | ||
883 | } | ||
884 | static inline int picolcd_init_framebuffer(struct picolcd_data *data) | ||
885 | { | ||
886 | return 0; | ||
887 | } | ||
888 | static inline void picolcd_exit_framebuffer(struct picolcd_data *data) | ||
889 | { | ||
890 | } | ||
891 | #define picolcd_fbinfo(d) NULL | ||
892 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
893 | |||
894 | #ifdef CONFIG_HID_PICOLCD_BACKLIGHT | ||
895 | /* | ||
896 | * backlight class device | ||
897 | */ | ||
898 | static int picolcd_get_brightness(struct backlight_device *bdev) | ||
899 | { | ||
900 | struct picolcd_data *data = bl_get_data(bdev); | ||
901 | return data->lcd_brightness; | ||
902 | } | ||
903 | |||
904 | static int picolcd_set_brightness(struct backlight_device *bdev) | ||
905 | { | ||
906 | struct picolcd_data *data = bl_get_data(bdev); | ||
907 | struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev); | ||
908 | unsigned long flags; | ||
909 | |||
910 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
911 | return -ENODEV; | ||
912 | |||
913 | data->lcd_brightness = bdev->props.brightness & 0x0ff; | ||
914 | data->lcd_power = bdev->props.power; | ||
915 | spin_lock_irqsave(&data->lock, flags); | ||
916 | hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); | ||
917 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
918 | spin_unlock_irqrestore(&data->lock, flags); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb) | ||
923 | { | ||
924 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev)); | ||
925 | } | ||
926 | |||
927 | static const struct backlight_ops picolcd_blops = { | ||
928 | .update_status = picolcd_set_brightness, | ||
929 | .get_brightness = picolcd_get_brightness, | ||
930 | .check_fb = picolcd_check_bl_fb, | ||
931 | }; | ||
932 | |||
933 | static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report) | ||
934 | { | ||
935 | struct device *dev = &data->hdev->dev; | ||
936 | struct backlight_device *bdev; | ||
937 | struct backlight_properties props; | ||
938 | if (!report) | ||
939 | return -ENODEV; | ||
940 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
941 | report->field[0]->report_size != 8) { | ||
942 | dev_err(dev, "unsupported BRIGHTNESS report"); | ||
943 | return -EINVAL; | ||
944 | } | ||
945 | |||
946 | memset(&props, 0, sizeof(props)); | ||
947 | props.type = BACKLIGHT_RAW; | ||
948 | props.max_brightness = 0xff; | ||
949 | bdev = backlight_device_register(dev_name(dev), dev, data, | ||
950 | &picolcd_blops, &props); | ||
951 | if (IS_ERR(bdev)) { | ||
952 | dev_err(dev, "failed to register backlight\n"); | ||
953 | return PTR_ERR(bdev); | ||
954 | } | ||
955 | bdev->props.brightness = 0xff; | ||
956 | data->lcd_brightness = 0xff; | ||
957 | data->backlight = bdev; | ||
958 | picolcd_set_brightness(bdev); | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static void picolcd_exit_backlight(struct picolcd_data *data) | ||
963 | { | ||
964 | struct backlight_device *bdev = data->backlight; | ||
965 | |||
966 | data->backlight = NULL; | ||
967 | if (bdev) | ||
968 | backlight_device_unregister(bdev); | ||
969 | } | ||
970 | |||
971 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
972 | { | ||
973 | if (!data->backlight) | ||
974 | return 0; | ||
975 | return picolcd_set_brightness(data->backlight); | ||
976 | } | ||
977 | |||
978 | #ifdef CONFIG_PM | ||
979 | static void picolcd_suspend_backlight(struct picolcd_data *data) | ||
980 | { | ||
981 | int bl_power = data->lcd_power; | ||
982 | if (!data->backlight) | ||
983 | return; | ||
984 | |||
985 | data->backlight->props.power = FB_BLANK_POWERDOWN; | ||
986 | picolcd_set_brightness(data->backlight); | ||
987 | data->lcd_power = data->backlight->props.power = bl_power; | ||
988 | } | ||
989 | #endif /* CONFIG_PM */ | ||
990 | #else | ||
991 | static inline int picolcd_init_backlight(struct picolcd_data *data, | ||
992 | struct hid_report *report) | ||
993 | { | ||
994 | return 0; | ||
995 | } | ||
996 | static inline void picolcd_exit_backlight(struct picolcd_data *data) | ||
997 | { | ||
998 | } | ||
999 | static inline int picolcd_resume_backlight(struct picolcd_data *data) | ||
1000 | { | ||
1001 | return 0; | ||
1002 | } | ||
1003 | static inline void picolcd_suspend_backlight(struct picolcd_data *data) | ||
1004 | { | ||
1005 | } | ||
1006 | #endif /* CONFIG_HID_PICOLCD_BACKLIGHT */ | ||
1007 | |||
1008 | #ifdef CONFIG_HID_PICOLCD_LCD | ||
1009 | /* | ||
1010 | * lcd class device | ||
1011 | */ | ||
1012 | static int picolcd_get_contrast(struct lcd_device *ldev) | ||
1013 | { | ||
1014 | struct picolcd_data *data = lcd_get_data(ldev); | ||
1015 | return data->lcd_contrast; | ||
1016 | } | ||
1017 | |||
1018 | static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) | ||
1019 | { | ||
1020 | struct picolcd_data *data = lcd_get_data(ldev); | ||
1021 | struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev); | ||
1022 | unsigned long flags; | ||
1023 | |||
1024 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
1025 | return -ENODEV; | ||
1026 | |||
1027 | data->lcd_contrast = contrast & 0x0ff; | ||
1028 | spin_lock_irqsave(&data->lock, flags); | ||
1029 | hid_set_field(report->field[0], 0, data->lcd_contrast); | ||
1030 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
1031 | spin_unlock_irqrestore(&data->lock, flags); | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) | ||
1036 | { | ||
1037 | return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); | ||
1038 | } | ||
1039 | |||
1040 | static struct lcd_ops picolcd_lcdops = { | ||
1041 | .get_contrast = picolcd_get_contrast, | ||
1042 | .set_contrast = picolcd_set_contrast, | ||
1043 | .check_fb = picolcd_check_lcd_fb, | ||
1044 | }; | ||
1045 | |||
1046 | static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) | ||
1047 | { | ||
1048 | struct device *dev = &data->hdev->dev; | ||
1049 | struct lcd_device *ldev; | ||
1050 | |||
1051 | if (!report) | ||
1052 | return -ENODEV; | ||
1053 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
1054 | report->field[0]->report_size != 8) { | ||
1055 | dev_err(dev, "unsupported CONTRAST report"); | ||
1056 | return -EINVAL; | ||
1057 | } | ||
1058 | |||
1059 | ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops); | ||
1060 | if (IS_ERR(ldev)) { | ||
1061 | dev_err(dev, "failed to register LCD\n"); | ||
1062 | return PTR_ERR(ldev); | ||
1063 | } | ||
1064 | ldev->props.max_contrast = 0x0ff; | ||
1065 | data->lcd_contrast = 0xe5; | ||
1066 | data->lcd = ldev; | ||
1067 | picolcd_set_contrast(ldev, 0xe5); | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static void picolcd_exit_lcd(struct picolcd_data *data) | ||
1072 | { | ||
1073 | struct lcd_device *ldev = data->lcd; | ||
1074 | |||
1075 | data->lcd = NULL; | ||
1076 | if (ldev) | ||
1077 | lcd_device_unregister(ldev); | ||
1078 | } | ||
1079 | |||
1080 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
1081 | { | ||
1082 | if (!data->lcd) | ||
1083 | return 0; | ||
1084 | return picolcd_set_contrast(data->lcd, data->lcd_contrast); | ||
1085 | } | ||
1086 | #else | ||
1087 | static inline int picolcd_init_lcd(struct picolcd_data *data, | ||
1088 | struct hid_report *report) | ||
1089 | { | ||
1090 | return 0; | ||
1091 | } | ||
1092 | static inline void picolcd_exit_lcd(struct picolcd_data *data) | ||
1093 | { | ||
1094 | } | ||
1095 | static inline int picolcd_resume_lcd(struct picolcd_data *data) | ||
1096 | { | ||
1097 | return 0; | ||
1098 | } | ||
1099 | #endif /* CONFIG_HID_PICOLCD_LCD */ | ||
1100 | |||
1101 | #ifdef CONFIG_HID_PICOLCD_LEDS | ||
1102 | /** | ||
1103 | * LED class device | ||
1104 | */ | ||
1105 | static void picolcd_leds_set(struct picolcd_data *data) | ||
1106 | { | ||
1107 | struct hid_report *report; | ||
1108 | unsigned long flags; | ||
1109 | |||
1110 | if (!data->led[0]) | ||
1111 | return; | ||
1112 | report = picolcd_out_report(REPORT_LED_STATE, data->hdev); | ||
1113 | if (!report || report->maxfield != 1 || report->field[0]->report_count != 1) | ||
1114 | return; | ||
1115 | |||
1116 | spin_lock_irqsave(&data->lock, flags); | ||
1117 | hid_set_field(report->field[0], 0, data->led_state); | ||
1118 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
1119 | spin_unlock_irqrestore(&data->lock, flags); | ||
1120 | } | ||
1121 | |||
1122 | static void picolcd_led_set_brightness(struct led_classdev *led_cdev, | ||
1123 | enum led_brightness value) | ||
1124 | { | ||
1125 | struct device *dev; | ||
1126 | struct hid_device *hdev; | ||
1127 | struct picolcd_data *data; | ||
1128 | int i, state = 0; | ||
1129 | |||
1130 | dev = led_cdev->dev->parent; | ||
1131 | hdev = container_of(dev, struct hid_device, dev); | ||
1132 | data = hid_get_drvdata(hdev); | ||
1133 | for (i = 0; i < 8; i++) { | ||
1134 | if (led_cdev != data->led[i]) | ||
1135 | continue; | ||
1136 | state = (data->led_state >> i) & 1; | ||
1137 | if (value == LED_OFF && state) { | ||
1138 | data->led_state &= ~(1 << i); | ||
1139 | picolcd_leds_set(data); | ||
1140 | } else if (value != LED_OFF && !state) { | ||
1141 | data->led_state |= 1 << i; | ||
1142 | picolcd_leds_set(data); | ||
1143 | } | ||
1144 | break; | ||
1145 | } | ||
1146 | } | ||
1147 | |||
1148 | static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev) | ||
1149 | { | ||
1150 | struct device *dev; | ||
1151 | struct hid_device *hdev; | ||
1152 | struct picolcd_data *data; | ||
1153 | int i, value = 0; | ||
1154 | |||
1155 | dev = led_cdev->dev->parent; | ||
1156 | hdev = container_of(dev, struct hid_device, dev); | ||
1157 | data = hid_get_drvdata(hdev); | ||
1158 | for (i = 0; i < 8; i++) | ||
1159 | if (led_cdev == data->led[i]) { | ||
1160 | value = (data->led_state >> i) & 1; | ||
1161 | break; | ||
1162 | } | ||
1163 | return value ? LED_FULL : LED_OFF; | ||
1164 | } | ||
1165 | |||
1166 | static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report) | ||
1167 | { | ||
1168 | struct device *dev = &data->hdev->dev; | ||
1169 | struct led_classdev *led; | ||
1170 | size_t name_sz = strlen(dev_name(dev)) + 8; | ||
1171 | char *name; | ||
1172 | int i, ret = 0; | ||
1173 | |||
1174 | if (!report) | ||
1175 | return -ENODEV; | ||
1176 | if (report->maxfield != 1 || report->field[0]->report_count != 1 || | ||
1177 | report->field[0]->report_size != 8) { | ||
1178 | dev_err(dev, "unsupported LED_STATE report"); | ||
1179 | return -EINVAL; | ||
1180 | } | ||
1181 | |||
1182 | for (i = 0; i < 8; i++) { | ||
1183 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | ||
1184 | if (!led) { | ||
1185 | dev_err(dev, "can't allocate memory for LED %d\n", i); | ||
1186 | ret = -ENOMEM; | ||
1187 | goto err; | ||
1188 | } | ||
1189 | name = (void *)(&led[1]); | ||
1190 | snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i); | ||
1191 | led->name = name; | ||
1192 | led->brightness = 0; | ||
1193 | led->max_brightness = 1; | ||
1194 | led->brightness_get = picolcd_led_get_brightness; | ||
1195 | led->brightness_set = picolcd_led_set_brightness; | ||
1196 | |||
1197 | data->led[i] = led; | ||
1198 | ret = led_classdev_register(dev, data->led[i]); | ||
1199 | if (ret) { | ||
1200 | data->led[i] = NULL; | ||
1201 | kfree(led); | ||
1202 | dev_err(dev, "can't register LED %d\n", i); | ||
1203 | goto err; | ||
1204 | } | ||
1205 | } | ||
1206 | return 0; | ||
1207 | err: | ||
1208 | for (i = 0; i < 8; i++) | ||
1209 | if (data->led[i]) { | ||
1210 | led = data->led[i]; | ||
1211 | data->led[i] = NULL; | ||
1212 | led_classdev_unregister(led); | ||
1213 | kfree(led); | ||
1214 | } | ||
1215 | return ret; | ||
1216 | } | ||
1217 | |||
1218 | static void picolcd_exit_leds(struct picolcd_data *data) | ||
1219 | { | ||
1220 | struct led_classdev *led; | ||
1221 | int i; | ||
1222 | |||
1223 | for (i = 0; i < 8; i++) { | ||
1224 | led = data->led[i]; | ||
1225 | data->led[i] = NULL; | ||
1226 | if (!led) | ||
1227 | continue; | ||
1228 | led_classdev_unregister(led); | ||
1229 | kfree(led); | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | #else | ||
1234 | static inline int picolcd_init_leds(struct picolcd_data *data, | ||
1235 | struct hid_report *report) | ||
1236 | { | ||
1237 | return 0; | ||
1238 | } | ||
1239 | static inline void picolcd_exit_leds(struct picolcd_data *data) | ||
1240 | { | ||
1241 | } | ||
1242 | static inline int picolcd_leds_set(struct picolcd_data *data) | ||
1243 | { | ||
1244 | return 0; | ||
1245 | } | ||
1246 | #endif /* CONFIG_HID_PICOLCD_LEDS */ | ||
1247 | |||
1248 | /* | ||
1249 | * input class device | ||
1250 | */ | ||
1251 | static int picolcd_raw_keypad(struct picolcd_data *data, | ||
1252 | struct hid_report *report, u8 *raw_data, int size) | ||
1253 | { | ||
1254 | /* | ||
1255 | * Keypad event | ||
1256 | * First and second data bytes list currently pressed keys, | ||
1257 | * 0x00 means no key and at most 2 keys may be pressed at same time | ||
1258 | */ | ||
1259 | int i, j; | ||
1260 | |||
1261 | /* determine newly pressed keys */ | ||
1262 | for (i = 0; i < size; i++) { | ||
1263 | unsigned int key_code; | ||
1264 | if (raw_data[i] == 0) | ||
1265 | continue; | ||
1266 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
1267 | if (data->pressed_keys[j] == raw_data[i]) | ||
1268 | goto key_already_down; | ||
1269 | for (j = 0; j < sizeof(data->pressed_keys); j++) | ||
1270 | if (data->pressed_keys[j] == 0) { | ||
1271 | data->pressed_keys[j] = raw_data[i]; | ||
1272 | break; | ||
1273 | } | ||
1274 | input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]); | ||
1275 | if (raw_data[i] < PICOLCD_KEYS) | ||
1276 | key_code = data->keycode[raw_data[i]]; | ||
1277 | else | ||
1278 | key_code = KEY_UNKNOWN; | ||
1279 | if (key_code != KEY_UNKNOWN) { | ||
1280 | dbg_hid(PICOLCD_NAME " got key press for %u:%d", | ||
1281 | raw_data[i], key_code); | ||
1282 | input_report_key(data->input_keys, key_code, 1); | ||
1283 | } | ||
1284 | input_sync(data->input_keys); | ||
1285 | key_already_down: | ||
1286 | continue; | ||
1287 | } | ||
1288 | |||
1289 | /* determine newly released keys */ | ||
1290 | for (j = 0; j < sizeof(data->pressed_keys); j++) { | ||
1291 | unsigned int key_code; | ||
1292 | if (data->pressed_keys[j] == 0) | ||
1293 | continue; | ||
1294 | for (i = 0; i < size; i++) | ||
1295 | if (data->pressed_keys[j] == raw_data[i]) | ||
1296 | goto key_still_down; | ||
1297 | input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]); | ||
1298 | if (data->pressed_keys[j] < PICOLCD_KEYS) | ||
1299 | key_code = data->keycode[data->pressed_keys[j]]; | ||
1300 | else | ||
1301 | key_code = KEY_UNKNOWN; | ||
1302 | if (key_code != KEY_UNKNOWN) { | ||
1303 | dbg_hid(PICOLCD_NAME " got key release for %u:%d", | ||
1304 | data->pressed_keys[j], key_code); | ||
1305 | input_report_key(data->input_keys, key_code, 0); | ||
1306 | } | ||
1307 | input_sync(data->input_keys); | ||
1308 | data->pressed_keys[j] = 0; | ||
1309 | key_still_down: | ||
1310 | continue; | ||
1311 | } | ||
1312 | return 1; | ||
1313 | } | ||
1314 | |||
1315 | static int picolcd_raw_cir(struct picolcd_data *data, | ||
1316 | struct hid_report *report, u8 *raw_data, int size) | ||
1317 | { | ||
1318 | /* Need understanding of CIR data format to implement ... */ | ||
1319 | return 1; | ||
1320 | } | ||
1321 | |||
1322 | static int picolcd_check_version(struct hid_device *hdev) | ||
1323 | { | ||
1324 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
1325 | struct picolcd_pending *verinfo; | ||
1326 | int ret = 0; | ||
1327 | |||
1328 | if (!data) | ||
1329 | return -ENODEV; | ||
1330 | |||
1331 | verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0); | ||
1332 | if (!verinfo) { | ||
1333 | hid_err(hdev, "no version response from PicoLCD\n"); | ||
1334 | return -ENODEV; | ||
1335 | } | ||
1336 | |||
1337 | if (verinfo->raw_size == 2) { | ||
1338 | data->version[0] = verinfo->raw_data[1]; | ||
1339 | data->version[1] = verinfo->raw_data[0]; | ||
1340 | if (data->status & PICOLCD_BOOTLOADER) { | ||
1341 | hid_info(hdev, "PicoLCD, bootloader version %d.%d\n", | ||
1342 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
1343 | } else { | ||
1344 | hid_info(hdev, "PicoLCD, firmware version %d.%d\n", | ||
1345 | verinfo->raw_data[1], verinfo->raw_data[0]); | ||
1346 | } | ||
1347 | } else { | ||
1348 | hid_err(hdev, "confused, got unexpected version response from PicoLCD\n"); | ||
1349 | ret = -EINVAL; | ||
1350 | } | ||
1351 | kfree(verinfo); | ||
1352 | return ret; | ||
1353 | } | ||
1354 | |||
1355 | /* | ||
1356 | * Reset our device and wait for answer to VERSION request | ||
1357 | */ | ||
1358 | static int picolcd_reset(struct hid_device *hdev) | ||
1359 | { | ||
1360 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
1361 | struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev); | ||
1362 | unsigned long flags; | ||
1363 | int error; | ||
1364 | |||
1365 | if (!data || !report || report->maxfield != 1) | ||
1366 | return -ENODEV; | ||
1367 | |||
1368 | spin_lock_irqsave(&data->lock, flags); | ||
1369 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
1370 | data->status |= PICOLCD_BOOTLOADER; | ||
1371 | |||
1372 | /* perform the reset */ | ||
1373 | hid_set_field(report->field[0], 0, 1); | ||
1374 | usbhid_submit_report(hdev, report, USB_DIR_OUT); | ||
1375 | spin_unlock_irqrestore(&data->lock, flags); | ||
1376 | |||
1377 | error = picolcd_check_version(hdev); | ||
1378 | if (error) | ||
1379 | return error; | ||
1380 | |||
1381 | picolcd_resume_lcd(data); | ||
1382 | picolcd_resume_backlight(data); | ||
1383 | #ifdef CONFIG_HID_PICOLCD_FB | ||
1384 | if (data->fb_info) | ||
1385 | schedule_delayed_work(&data->fb_info->deferred_work, 0); | ||
1386 | #endif /* CONFIG_HID_PICOLCD_FB */ | ||
1387 | |||
1388 | picolcd_leds_set(data); | ||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | /* | ||
1393 | * The "operation_mode" sysfs attribute | ||
1394 | */ | ||
1395 | static ssize_t picolcd_operation_mode_show(struct device *dev, | ||
1396 | struct device_attribute *attr, char *buf) | ||
1397 | { | ||
1398 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1399 | |||
1400 | if (data->status & PICOLCD_BOOTLOADER) | ||
1401 | return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n"); | ||
1402 | else | ||
1403 | return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n"); | ||
1404 | } | ||
1405 | |||
1406 | static ssize_t picolcd_operation_mode_store(struct device *dev, | ||
1407 | struct device_attribute *attr, const char *buf, size_t count) | ||
1408 | { | ||
1409 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1410 | struct hid_report *report = NULL; | ||
1411 | size_t cnt = count; | ||
1412 | int timeout = data->opmode_delay; | ||
1413 | unsigned long flags; | ||
1414 | |||
1415 | if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { | ||
1416 | if (data->status & PICOLCD_BOOTLOADER) | ||
1417 | report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); | ||
1418 | buf += 3; | ||
1419 | cnt -= 3; | ||
1420 | } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) { | ||
1421 | if (!(data->status & PICOLCD_BOOTLOADER)) | ||
1422 | report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); | ||
1423 | buf += 10; | ||
1424 | cnt -= 10; | ||
1425 | } | ||
1426 | if (!report) | ||
1427 | return -EINVAL; | ||
1428 | |||
1429 | while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) | ||
1430 | cnt--; | ||
1431 | if (cnt != 0) | ||
1432 | return -EINVAL; | ||
1433 | |||
1434 | spin_lock_irqsave(&data->lock, flags); | ||
1435 | hid_set_field(report->field[0], 0, timeout & 0xff); | ||
1436 | hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); | ||
1437 | usbhid_submit_report(data->hdev, report, USB_DIR_OUT); | ||
1438 | spin_unlock_irqrestore(&data->lock, flags); | ||
1439 | return count; | ||
1440 | } | ||
1441 | |||
1442 | static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show, | ||
1443 | picolcd_operation_mode_store); | ||
1444 | |||
1445 | /* | ||
1446 | * The "operation_mode_delay" sysfs attribute | ||
1447 | */ | ||
1448 | static ssize_t picolcd_operation_mode_delay_show(struct device *dev, | ||
1449 | struct device_attribute *attr, char *buf) | ||
1450 | { | ||
1451 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1452 | |||
1453 | return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay); | ||
1454 | } | ||
1455 | |||
1456 | static ssize_t picolcd_operation_mode_delay_store(struct device *dev, | ||
1457 | struct device_attribute *attr, const char *buf, size_t count) | ||
1458 | { | ||
1459 | struct picolcd_data *data = dev_get_drvdata(dev); | ||
1460 | unsigned u; | ||
1461 | if (sscanf(buf, "%u", &u) != 1) | ||
1462 | return -EINVAL; | ||
1463 | if (u > 30000) | ||
1464 | return -EINVAL; | ||
1465 | else | ||
1466 | data->opmode_delay = u; | ||
1467 | return count; | ||
1468 | } | ||
1469 | |||
1470 | static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show, | ||
1471 | picolcd_operation_mode_delay_store); | ||
1472 | |||
1473 | |||
1474 | #ifdef CONFIG_DEBUG_FS | ||
1475 | /* | ||
1476 | * The "reset" file | ||
1477 | */ | ||
1478 | static int picolcd_debug_reset_show(struct seq_file *f, void *p) | ||
1479 | { | ||
1480 | if (picolcd_fbinfo((struct picolcd_data *)f->private)) | ||
1481 | seq_printf(f, "all fb\n"); | ||
1482 | else | ||
1483 | seq_printf(f, "all\n"); | ||
1484 | return 0; | ||
1485 | } | ||
1486 | |||
1487 | static int picolcd_debug_reset_open(struct inode *inode, struct file *f) | ||
1488 | { | ||
1489 | return single_open(f, picolcd_debug_reset_show, inode->i_private); | ||
1490 | } | ||
1491 | |||
1492 | static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf, | ||
1493 | size_t count, loff_t *ppos) | ||
1494 | { | ||
1495 | struct picolcd_data *data = ((struct seq_file *)f->private_data)->private; | ||
1496 | char buf[32]; | ||
1497 | size_t cnt = min(count, sizeof(buf)-1); | ||
1498 | if (copy_from_user(buf, user_buf, cnt)) | ||
1499 | return -EFAULT; | ||
1500 | |||
1501 | while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n')) | ||
1502 | cnt--; | ||
1503 | buf[cnt] = '\0'; | ||
1504 | if (strcmp(buf, "all") == 0) { | ||
1505 | picolcd_reset(data->hdev); | ||
1506 | picolcd_fb_reset(data, 1); | ||
1507 | } else if (strcmp(buf, "fb") == 0) { | ||
1508 | picolcd_fb_reset(data, 1); | ||
1509 | } else { | ||
1510 | return -EINVAL; | ||
1511 | } | ||
1512 | return count; | ||
1513 | } | ||
1514 | |||
1515 | static const struct file_operations picolcd_debug_reset_fops = { | ||
1516 | .owner = THIS_MODULE, | ||
1517 | .open = picolcd_debug_reset_open, | ||
1518 | .read = seq_read, | ||
1519 | .llseek = seq_lseek, | ||
1520 | .write = picolcd_debug_reset_write, | ||
1521 | .release = single_release, | ||
1522 | }; | ||
1523 | |||
1524 | /* | ||
1525 | * The "eeprom" file | ||
1526 | */ | ||
1527 | static int picolcd_debug_eeprom_open(struct inode *i, struct file *f) | ||
1528 | { | ||
1529 | f->private_data = i->i_private; | ||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u, | ||
1534 | size_t s, loff_t *off) | ||
1535 | { | ||
1536 | struct picolcd_data *data = f->private_data; | ||
1537 | struct picolcd_pending *resp; | ||
1538 | u8 raw_data[3]; | ||
1539 | ssize_t ret = -EIO; | ||
1540 | |||
1541 | if (s == 0) | ||
1542 | return -EINVAL; | ||
1543 | if (*off > 0x0ff) | ||
1544 | return 0; | ||
1545 | |||
1546 | /* prepare buffer with info about what we want to read (addr & len) */ | ||
1547 | raw_data[0] = *off & 0xff; | ||
1548 | raw_data[1] = (*off >> 8) & 0xff; | ||
1549 | raw_data[2] = s < 20 ? s : 20; | ||
1550 | if (*off + raw_data[2] > 0xff) | ||
1551 | raw_data[2] = 0x100 - *off; | ||
1552 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data, | ||
1553 | sizeof(raw_data)); | ||
1554 | if (!resp) | ||
1555 | return -EIO; | ||
1556 | |||
1557 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
1558 | /* successful read :) */ | ||
1559 | ret = resp->raw_data[2]; | ||
1560 | if (ret > s) | ||
1561 | ret = s; | ||
1562 | if (copy_to_user(u, resp->raw_data+3, ret)) | ||
1563 | ret = -EFAULT; | ||
1564 | else | ||
1565 | *off += ret; | ||
1566 | } /* anything else is some kind of IO error */ | ||
1567 | |||
1568 | kfree(resp); | ||
1569 | return ret; | ||
1570 | } | ||
1571 | |||
1572 | static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, | ||
1573 | size_t s, loff_t *off) | ||
1574 | { | ||
1575 | struct picolcd_data *data = f->private_data; | ||
1576 | struct picolcd_pending *resp; | ||
1577 | ssize_t ret = -EIO; | ||
1578 | u8 raw_data[23]; | ||
1579 | |||
1580 | if (s == 0) | ||
1581 | return -EINVAL; | ||
1582 | if (*off > 0x0ff) | ||
1583 | return -ENOSPC; | ||
1584 | |||
1585 | memset(raw_data, 0, sizeof(raw_data)); | ||
1586 | raw_data[0] = *off & 0xff; | ||
1587 | raw_data[1] = (*off >> 8) & 0xff; | ||
1588 | raw_data[2] = min((size_t)20, s); | ||
1589 | if (*off + raw_data[2] > 0xff) | ||
1590 | raw_data[2] = 0x100 - *off; | ||
1591 | |||
1592 | if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2]))) | ||
1593 | return -EFAULT; | ||
1594 | resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data, | ||
1595 | sizeof(raw_data)); | ||
1596 | |||
1597 | if (!resp) | ||
1598 | return -EIO; | ||
1599 | |||
1600 | if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) { | ||
1601 | /* check if written data matches */ | ||
1602 | if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) { | ||
1603 | *off += raw_data[2]; | ||
1604 | ret = raw_data[2]; | ||
1605 | } | ||
1606 | } | ||
1607 | kfree(resp); | ||
1608 | return ret; | ||
1609 | } | ||
1610 | |||
1611 | /* | ||
1612 | * Notes: | ||
1613 | * - read/write happens in chunks of at most 20 bytes, it's up to userspace | ||
1614 | * to loop in order to get more data. | ||
1615 | * - on write errors on otherwise correct write request the bytes | ||
1616 | * that should have been written are in undefined state. | ||
1617 | */ | ||
1618 | static const struct file_operations picolcd_debug_eeprom_fops = { | ||
1619 | .owner = THIS_MODULE, | ||
1620 | .open = picolcd_debug_eeprom_open, | ||
1621 | .read = picolcd_debug_eeprom_read, | ||
1622 | .write = picolcd_debug_eeprom_write, | ||
1623 | .llseek = generic_file_llseek, | ||
1624 | }; | ||
1625 | |||
1626 | /* | ||
1627 | * The "flash" file | ||
1628 | */ | ||
1629 | static int picolcd_debug_flash_open(struct inode *i, struct file *f) | ||
1630 | { | ||
1631 | f->private_data = i->i_private; | ||
1632 | return 0; | ||
1633 | } | ||
1634 | |||
1635 | /* record a flash address to buf (bounds check to be done by caller) */ | ||
1636 | static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off) | ||
1637 | { | ||
1638 | buf[0] = off & 0xff; | ||
1639 | buf[1] = (off >> 8) & 0xff; | ||
1640 | if (data->addr_sz == 3) | ||
1641 | buf[2] = (off >> 16) & 0xff; | ||
1642 | return data->addr_sz == 2 ? 2 : 3; | ||
1643 | } | ||
1644 | |||
1645 | /* read a given size of data (bounds check to be done by caller) */ | ||
1646 | static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id, | ||
1647 | char __user *u, size_t s, loff_t *off) | ||
1648 | { | ||
1649 | struct picolcd_pending *resp; | ||
1650 | u8 raw_data[4]; | ||
1651 | ssize_t ret = 0; | ||
1652 | int len_off, err = -EIO; | ||
1653 | |||
1654 | while (s > 0) { | ||
1655 | err = -EIO; | ||
1656 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1657 | raw_data[len_off] = s > 32 ? 32 : s; | ||
1658 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1); | ||
1659 | if (!resp || !resp->in_report) | ||
1660 | goto skip; | ||
1661 | if (resp->in_report->id == REPORT_MEMORY || | ||
1662 | resp->in_report->id == REPORT_BL_READ_MEMORY) { | ||
1663 | if (memcmp(raw_data, resp->raw_data, len_off+1) != 0) | ||
1664 | goto skip; | ||
1665 | if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) { | ||
1666 | err = -EFAULT; | ||
1667 | goto skip; | ||
1668 | } | ||
1669 | *off += raw_data[len_off]; | ||
1670 | s -= raw_data[len_off]; | ||
1671 | ret += raw_data[len_off]; | ||
1672 | err = 0; | ||
1673 | } | ||
1674 | skip: | ||
1675 | kfree(resp); | ||
1676 | if (err) | ||
1677 | return ret > 0 ? ret : err; | ||
1678 | } | ||
1679 | return ret; | ||
1680 | } | ||
1681 | |||
1682 | static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u, | ||
1683 | size_t s, loff_t *off) | ||
1684 | { | ||
1685 | struct picolcd_data *data = f->private_data; | ||
1686 | |||
1687 | if (s == 0) | ||
1688 | return -EINVAL; | ||
1689 | if (*off > 0x05fff) | ||
1690 | return 0; | ||
1691 | if (*off + s > 0x05fff) | ||
1692 | s = 0x06000 - *off; | ||
1693 | |||
1694 | if (data->status & PICOLCD_BOOTLOADER) | ||
1695 | return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off); | ||
1696 | else | ||
1697 | return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off); | ||
1698 | } | ||
1699 | |||
1700 | /* erase block aligned to 64bytes boundary */ | ||
1701 | static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id, | ||
1702 | loff_t *off) | ||
1703 | { | ||
1704 | struct picolcd_pending *resp; | ||
1705 | u8 raw_data[3]; | ||
1706 | int len_off; | ||
1707 | ssize_t ret = -EIO; | ||
1708 | |||
1709 | if (*off & 0x3f) | ||
1710 | return -EINVAL; | ||
1711 | |||
1712 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1713 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off); | ||
1714 | if (!resp || !resp->in_report) | ||
1715 | goto skip; | ||
1716 | if (resp->in_report->id == REPORT_MEMORY || | ||
1717 | resp->in_report->id == REPORT_BL_ERASE_MEMORY) { | ||
1718 | if (memcmp(raw_data, resp->raw_data, len_off) != 0) | ||
1719 | goto skip; | ||
1720 | ret = 0; | ||
1721 | } | ||
1722 | skip: | ||
1723 | kfree(resp); | ||
1724 | return ret; | ||
1725 | } | ||
1726 | |||
1727 | /* write a given size of data (bounds check to be done by caller) */ | ||
1728 | static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id, | ||
1729 | const char __user *u, size_t s, loff_t *off) | ||
1730 | { | ||
1731 | struct picolcd_pending *resp; | ||
1732 | u8 raw_data[36]; | ||
1733 | ssize_t ret = 0; | ||
1734 | int len_off, err = -EIO; | ||
1735 | |||
1736 | while (s > 0) { | ||
1737 | err = -EIO; | ||
1738 | len_off = _picolcd_flash_setaddr(data, raw_data, *off); | ||
1739 | raw_data[len_off] = s > 32 ? 32 : s; | ||
1740 | if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) { | ||
1741 | err = -EFAULT; | ||
1742 | break; | ||
1743 | } | ||
1744 | resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, | ||
1745 | len_off+1+raw_data[len_off]); | ||
1746 | if (!resp || !resp->in_report) | ||
1747 | goto skip; | ||
1748 | if (resp->in_report->id == REPORT_MEMORY || | ||
1749 | resp->in_report->id == REPORT_BL_WRITE_MEMORY) { | ||
1750 | if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0) | ||
1751 | goto skip; | ||
1752 | *off += raw_data[len_off]; | ||
1753 | s -= raw_data[len_off]; | ||
1754 | ret += raw_data[len_off]; | ||
1755 | err = 0; | ||
1756 | } | ||
1757 | skip: | ||
1758 | kfree(resp); | ||
1759 | if (err) | ||
1760 | break; | ||
1761 | } | ||
1762 | return ret > 0 ? ret : err; | ||
1763 | } | ||
1764 | |||
1765 | static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, | ||
1766 | size_t s, loff_t *off) | ||
1767 | { | ||
1768 | struct picolcd_data *data = f->private_data; | ||
1769 | ssize_t err, ret = 0; | ||
1770 | int report_erase, report_write; | ||
1771 | |||
1772 | if (s == 0) | ||
1773 | return -EINVAL; | ||
1774 | if (*off > 0x5fff) | ||
1775 | return -ENOSPC; | ||
1776 | if (s & 0x3f) | ||
1777 | return -EINVAL; | ||
1778 | if (*off & 0x3f) | ||
1779 | return -EINVAL; | ||
1780 | |||
1781 | if (data->status & PICOLCD_BOOTLOADER) { | ||
1782 | report_erase = REPORT_BL_ERASE_MEMORY; | ||
1783 | report_write = REPORT_BL_WRITE_MEMORY; | ||
1784 | } else { | ||
1785 | report_erase = REPORT_ERASE_MEMORY; | ||
1786 | report_write = REPORT_WRITE_MEMORY; | ||
1787 | } | ||
1788 | mutex_lock(&data->mutex_flash); | ||
1789 | while (s > 0) { | ||
1790 | err = _picolcd_flash_erase64(data, report_erase, off); | ||
1791 | if (err) | ||
1792 | break; | ||
1793 | err = _picolcd_flash_write(data, report_write, u, 64, off); | ||
1794 | if (err < 0) | ||
1795 | break; | ||
1796 | ret += err; | ||
1797 | *off += err; | ||
1798 | s -= err; | ||
1799 | if (err != 64) | ||
1800 | break; | ||
1801 | } | ||
1802 | mutex_unlock(&data->mutex_flash); | ||
1803 | return ret > 0 ? ret : err; | ||
1804 | } | ||
1805 | |||
1806 | /* | ||
1807 | * Notes: | ||
1808 | * - concurrent writing is prevented by mutex and all writes must be | ||
1809 | * n*64 bytes and 64-byte aligned, each write being preceded by an | ||
1810 | * ERASE which erases a 64byte block. | ||
1811 | * If less than requested was written or an error is returned for an | ||
1812 | * otherwise correct write request the next 64-byte block which should | ||
1813 | * have been written is in undefined state (mostly: original, erased, | ||
1814 | * (half-)written with write error) | ||
1815 | * - reading can happen without special restriction | ||
1816 | */ | ||
1817 | static const struct file_operations picolcd_debug_flash_fops = { | ||
1818 | .owner = THIS_MODULE, | ||
1819 | .open = picolcd_debug_flash_open, | ||
1820 | .read = picolcd_debug_flash_read, | ||
1821 | .write = picolcd_debug_flash_write, | ||
1822 | .llseek = generic_file_llseek, | ||
1823 | }; | ||
1824 | |||
1825 | |||
1826 | /* | ||
1827 | * Helper code for HID report level dumping/debugging | ||
1828 | */ | ||
1829 | static const char *error_codes[] = { | ||
1830 | "success", "parameter missing", "data_missing", "block readonly", | ||
1831 | "block not erasable", "block too big", "section overflow", | ||
1832 | "invalid command length", "invalid data length", | ||
1833 | }; | ||
1834 | |||
1835 | static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data, | ||
1836 | const size_t data_len) | ||
1837 | { | ||
1838 | int i, j; | ||
1839 | for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) { | ||
1840 | dst[j++] = hex_asc[(data[i] >> 4) & 0x0f]; | ||
1841 | dst[j++] = hex_asc[data[i] & 0x0f]; | ||
1842 | dst[j++] = ' '; | ||
1843 | } | ||
1844 | if (j < dst_sz) { | ||
1845 | dst[j--] = '\0'; | ||
1846 | dst[j] = '\n'; | ||
1847 | } else | ||
1848 | dst[j] = '\0'; | ||
1849 | } | ||
1850 | |||
1851 | static void picolcd_debug_out_report(struct picolcd_data *data, | ||
1852 | struct hid_device *hdev, struct hid_report *report) | ||
1853 | { | ||
1854 | u8 raw_data[70]; | ||
1855 | int raw_size = (report->size >> 3) + 1; | ||
1856 | char *buff; | ||
1857 | #define BUFF_SZ 256 | ||
1858 | |||
1859 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
1860 | if (!hdev->debug_events) | ||
1861 | return; | ||
1862 | |||
1863 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
1864 | if (!buff) | ||
1865 | return; | ||
1866 | |||
1867 | snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ", | ||
1868 | report->id, raw_size); | ||
1869 | hid_debug_event(hdev, buff); | ||
1870 | if (raw_size + 5 > sizeof(raw_data)) { | ||
1871 | kfree(buff); | ||
1872 | hid_debug_event(hdev, " TOO BIG\n"); | ||
1873 | return; | ||
1874 | } else { | ||
1875 | raw_data[0] = report->id; | ||
1876 | hid_output_report(report, raw_data); | ||
1877 | dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size); | ||
1878 | hid_debug_event(hdev, buff); | ||
1879 | } | ||
1880 | |||
1881 | switch (report->id) { | ||
1882 | case REPORT_LED_STATE: | ||
1883 | /* 1 data byte with GPO state */ | ||
1884 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1885 | "REPORT_LED_STATE", report->id, raw_size-1); | ||
1886 | hid_debug_event(hdev, buff); | ||
1887 | snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]); | ||
1888 | hid_debug_event(hdev, buff); | ||
1889 | break; | ||
1890 | case REPORT_BRIGHTNESS: | ||
1891 | /* 1 data byte with brightness */ | ||
1892 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1893 | "REPORT_BRIGHTNESS", report->id, raw_size-1); | ||
1894 | hid_debug_event(hdev, buff); | ||
1895 | snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]); | ||
1896 | hid_debug_event(hdev, buff); | ||
1897 | break; | ||
1898 | case REPORT_CONTRAST: | ||
1899 | /* 1 data byte with contrast */ | ||
1900 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1901 | "REPORT_CONTRAST", report->id, raw_size-1); | ||
1902 | hid_debug_event(hdev, buff); | ||
1903 | snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]); | ||
1904 | hid_debug_event(hdev, buff); | ||
1905 | break; | ||
1906 | case REPORT_RESET: | ||
1907 | /* 2 data bytes with reset duration in ms */ | ||
1908 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1909 | "REPORT_RESET", report->id, raw_size-1); | ||
1910 | hid_debug_event(hdev, buff); | ||
1911 | snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n", | ||
1912 | raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]); | ||
1913 | hid_debug_event(hdev, buff); | ||
1914 | break; | ||
1915 | case REPORT_LCD_CMD: | ||
1916 | /* 63 data bytes with LCD commands */ | ||
1917 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1918 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1919 | hid_debug_event(hdev, buff); | ||
1920 | /* TODO: format decoding */ | ||
1921 | break; | ||
1922 | case REPORT_LCD_DATA: | ||
1923 | /* 63 data bytes with LCD data */ | ||
1924 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1925 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1926 | /* TODO: format decoding */ | ||
1927 | hid_debug_event(hdev, buff); | ||
1928 | break; | ||
1929 | case REPORT_LCD_CMD_DATA: | ||
1930 | /* 63 data bytes with LCD commands and data */ | ||
1931 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1932 | "REPORT_LCD_CMD", report->id, raw_size-1); | ||
1933 | /* TODO: format decoding */ | ||
1934 | hid_debug_event(hdev, buff); | ||
1935 | break; | ||
1936 | case REPORT_EE_READ: | ||
1937 | /* 3 data bytes with read area description */ | ||
1938 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1939 | "REPORT_EE_READ", report->id, raw_size-1); | ||
1940 | hid_debug_event(hdev, buff); | ||
1941 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1942 | raw_data[2], raw_data[1]); | ||
1943 | hid_debug_event(hdev, buff); | ||
1944 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1945 | hid_debug_event(hdev, buff); | ||
1946 | break; | ||
1947 | case REPORT_EE_WRITE: | ||
1948 | /* 3+1..20 data bytes with write area description */ | ||
1949 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1950 | "REPORT_EE_WRITE", report->id, raw_size-1); | ||
1951 | hid_debug_event(hdev, buff); | ||
1952 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1953 | raw_data[2], raw_data[1]); | ||
1954 | hid_debug_event(hdev, buff); | ||
1955 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
1956 | hid_debug_event(hdev, buff); | ||
1957 | if (raw_data[3] == 0) { | ||
1958 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
1959 | } else if (raw_data[3] + 4 <= raw_size) { | ||
1960 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
1961 | hid_debug_event(hdev, buff); | ||
1962 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
1963 | } else { | ||
1964 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
1965 | } | ||
1966 | hid_debug_event(hdev, buff); | ||
1967 | break; | ||
1968 | case REPORT_ERASE_MEMORY: | ||
1969 | case REPORT_BL_ERASE_MEMORY: | ||
1970 | /* 3 data bytes with pointer inside erase block */ | ||
1971 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1972 | "REPORT_ERASE_MEMORY", report->id, raw_size-1); | ||
1973 | hid_debug_event(hdev, buff); | ||
1974 | switch (data->addr_sz) { | ||
1975 | case 2: | ||
1976 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n", | ||
1977 | raw_data[2], raw_data[1]); | ||
1978 | break; | ||
1979 | case 3: | ||
1980 | snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n", | ||
1981 | raw_data[3], raw_data[2], raw_data[1]); | ||
1982 | break; | ||
1983 | default: | ||
1984 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
1985 | } | ||
1986 | hid_debug_event(hdev, buff); | ||
1987 | break; | ||
1988 | case REPORT_READ_MEMORY: | ||
1989 | case REPORT_BL_READ_MEMORY: | ||
1990 | /* 4 data bytes with read area description */ | ||
1991 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
1992 | "REPORT_READ_MEMORY", report->id, raw_size-1); | ||
1993 | hid_debug_event(hdev, buff); | ||
1994 | switch (data->addr_sz) { | ||
1995 | case 2: | ||
1996 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
1997 | raw_data[2], raw_data[1]); | ||
1998 | hid_debug_event(hdev, buff); | ||
1999 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2000 | break; | ||
2001 | case 3: | ||
2002 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
2003 | raw_data[3], raw_data[2], raw_data[1]); | ||
2004 | hid_debug_event(hdev, buff); | ||
2005 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
2006 | break; | ||
2007 | default: | ||
2008 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
2009 | } | ||
2010 | hid_debug_event(hdev, buff); | ||
2011 | break; | ||
2012 | case REPORT_WRITE_MEMORY: | ||
2013 | case REPORT_BL_WRITE_MEMORY: | ||
2014 | /* 4+1..32 data bytes with write adrea description */ | ||
2015 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2016 | "REPORT_WRITE_MEMORY", report->id, raw_size-1); | ||
2017 | hid_debug_event(hdev, buff); | ||
2018 | switch (data->addr_sz) { | ||
2019 | case 2: | ||
2020 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
2021 | raw_data[2], raw_data[1]); | ||
2022 | hid_debug_event(hdev, buff); | ||
2023 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2024 | hid_debug_event(hdev, buff); | ||
2025 | if (raw_data[3] == 0) { | ||
2026 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2027 | } else if (raw_data[3] + 4 <= raw_size) { | ||
2028 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2029 | hid_debug_event(hdev, buff); | ||
2030 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
2031 | } else { | ||
2032 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2033 | } | ||
2034 | break; | ||
2035 | case 3: | ||
2036 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
2037 | raw_data[3], raw_data[2], raw_data[1]); | ||
2038 | hid_debug_event(hdev, buff); | ||
2039 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
2040 | hid_debug_event(hdev, buff); | ||
2041 | if (raw_data[4] == 0) { | ||
2042 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2043 | } else if (raw_data[4] + 5 <= raw_size) { | ||
2044 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2045 | hid_debug_event(hdev, buff); | ||
2046 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
2047 | } else { | ||
2048 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2049 | } | ||
2050 | break; | ||
2051 | default: | ||
2052 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
2053 | } | ||
2054 | hid_debug_event(hdev, buff); | ||
2055 | break; | ||
2056 | case REPORT_SPLASH_RESTART: | ||
2057 | /* TODO */ | ||
2058 | break; | ||
2059 | case REPORT_EXIT_KEYBOARD: | ||
2060 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2061 | "REPORT_EXIT_KEYBOARD", report->id, raw_size-1); | ||
2062 | hid_debug_event(hdev, buff); | ||
2063 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
2064 | raw_data[1] | (raw_data[2] << 8), | ||
2065 | raw_data[2], raw_data[1]); | ||
2066 | hid_debug_event(hdev, buff); | ||
2067 | break; | ||
2068 | case REPORT_VERSION: | ||
2069 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2070 | "REPORT_VERSION", report->id, raw_size-1); | ||
2071 | hid_debug_event(hdev, buff); | ||
2072 | break; | ||
2073 | case REPORT_DEVID: | ||
2074 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2075 | "REPORT_DEVID", report->id, raw_size-1); | ||
2076 | hid_debug_event(hdev, buff); | ||
2077 | break; | ||
2078 | case REPORT_SPLASH_SIZE: | ||
2079 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2080 | "REPORT_SPLASH_SIZE", report->id, raw_size-1); | ||
2081 | hid_debug_event(hdev, buff); | ||
2082 | break; | ||
2083 | case REPORT_HOOK_VERSION: | ||
2084 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2085 | "REPORT_HOOK_VERSION", report->id, raw_size-1); | ||
2086 | hid_debug_event(hdev, buff); | ||
2087 | break; | ||
2088 | case REPORT_EXIT_FLASHER: | ||
2089 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2090 | "REPORT_VERSION", report->id, raw_size-1); | ||
2091 | hid_debug_event(hdev, buff); | ||
2092 | snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n", | ||
2093 | raw_data[1] | (raw_data[2] << 8), | ||
2094 | raw_data[2], raw_data[1]); | ||
2095 | hid_debug_event(hdev, buff); | ||
2096 | break; | ||
2097 | default: | ||
2098 | snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n", | ||
2099 | "<unknown>", report->id, raw_size-1); | ||
2100 | hid_debug_event(hdev, buff); | ||
2101 | break; | ||
2102 | } | ||
2103 | wake_up_interruptible(&hdev->debug_wait); | ||
2104 | kfree(buff); | ||
2105 | } | ||
2106 | |||
2107 | static void picolcd_debug_raw_event(struct picolcd_data *data, | ||
2108 | struct hid_device *hdev, struct hid_report *report, | ||
2109 | u8 *raw_data, int size) | ||
2110 | { | ||
2111 | char *buff; | ||
2112 | |||
2113 | #define BUFF_SZ 256 | ||
2114 | /* Avoid unnecessary overhead if debugfs is disabled */ | ||
2115 | if (!hdev->debug_events) | ||
2116 | return; | ||
2117 | |||
2118 | buff = kmalloc(BUFF_SZ, GFP_ATOMIC); | ||
2119 | if (!buff) | ||
2120 | return; | ||
2121 | |||
2122 | switch (report->id) { | ||
2123 | case REPORT_ERROR_CODE: | ||
2124 | /* 2 data bytes with affected report and error code */ | ||
2125 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2126 | "REPORT_ERROR_CODE", report->id, size-1); | ||
2127 | hid_debug_event(hdev, buff); | ||
2128 | if (raw_data[2] < ARRAY_SIZE(error_codes)) | ||
2129 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n", | ||
2130 | raw_data[2], error_codes[raw_data[2]], raw_data[1]); | ||
2131 | else | ||
2132 | snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n", | ||
2133 | raw_data[2], raw_data[1]); | ||
2134 | hid_debug_event(hdev, buff); | ||
2135 | break; | ||
2136 | case REPORT_KEY_STATE: | ||
2137 | /* 2 data bytes with key state */ | ||
2138 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2139 | "REPORT_KEY_STATE", report->id, size-1); | ||
2140 | hid_debug_event(hdev, buff); | ||
2141 | if (raw_data[1] == 0) | ||
2142 | snprintf(buff, BUFF_SZ, "\tNo key pressed\n"); | ||
2143 | else if (raw_data[2] == 0) | ||
2144 | snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n", | ||
2145 | raw_data[1], raw_data[1]); | ||
2146 | else | ||
2147 | snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n", | ||
2148 | raw_data[1], raw_data[1], raw_data[2], raw_data[2]); | ||
2149 | hid_debug_event(hdev, buff); | ||
2150 | break; | ||
2151 | case REPORT_IR_DATA: | ||
2152 | /* Up to 20 byes of IR scancode data */ | ||
2153 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2154 | "REPORT_IR_DATA", report->id, size-1); | ||
2155 | hid_debug_event(hdev, buff); | ||
2156 | if (raw_data[1] == 0) { | ||
2157 | snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n"); | ||
2158 | hid_debug_event(hdev, buff); | ||
2159 | } else if (raw_data[1] + 1 <= size) { | ||
2160 | snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ", | ||
2161 | raw_data[1]-1); | ||
2162 | hid_debug_event(hdev, buff); | ||
2163 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1); | ||
2164 | hid_debug_event(hdev, buff); | ||
2165 | } else { | ||
2166 | snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n", | ||
2167 | raw_data[1]-1); | ||
2168 | hid_debug_event(hdev, buff); | ||
2169 | } | ||
2170 | break; | ||
2171 | case REPORT_EE_DATA: | ||
2172 | /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */ | ||
2173 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2174 | "REPORT_EE_DATA", report->id, size-1); | ||
2175 | hid_debug_event(hdev, buff); | ||
2176 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
2177 | raw_data[2], raw_data[1]); | ||
2178 | hid_debug_event(hdev, buff); | ||
2179 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2180 | hid_debug_event(hdev, buff); | ||
2181 | if (raw_data[3] == 0) { | ||
2182 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2183 | hid_debug_event(hdev, buff); | ||
2184 | } else if (raw_data[3] + 4 <= size) { | ||
2185 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2186 | hid_debug_event(hdev, buff); | ||
2187 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
2188 | hid_debug_event(hdev, buff); | ||
2189 | } else { | ||
2190 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2191 | hid_debug_event(hdev, buff); | ||
2192 | } | ||
2193 | break; | ||
2194 | case REPORT_MEMORY: | ||
2195 | /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */ | ||
2196 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2197 | "REPORT_MEMORY", report->id, size-1); | ||
2198 | hid_debug_event(hdev, buff); | ||
2199 | switch (data->addr_sz) { | ||
2200 | case 2: | ||
2201 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n", | ||
2202 | raw_data[2], raw_data[1]); | ||
2203 | hid_debug_event(hdev, buff); | ||
2204 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]); | ||
2205 | hid_debug_event(hdev, buff); | ||
2206 | if (raw_data[3] == 0) { | ||
2207 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2208 | } else if (raw_data[3] + 4 <= size) { | ||
2209 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2210 | hid_debug_event(hdev, buff); | ||
2211 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]); | ||
2212 | } else { | ||
2213 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2214 | } | ||
2215 | break; | ||
2216 | case 3: | ||
2217 | snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n", | ||
2218 | raw_data[3], raw_data[2], raw_data[1]); | ||
2219 | hid_debug_event(hdev, buff); | ||
2220 | snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]); | ||
2221 | hid_debug_event(hdev, buff); | ||
2222 | if (raw_data[4] == 0) { | ||
2223 | snprintf(buff, BUFF_SZ, "\tNo data\n"); | ||
2224 | } else if (raw_data[4] + 5 <= size) { | ||
2225 | snprintf(buff, BUFF_SZ, "\tData: "); | ||
2226 | hid_debug_event(hdev, buff); | ||
2227 | dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]); | ||
2228 | } else { | ||
2229 | snprintf(buff, BUFF_SZ, "\tData overflowed\n"); | ||
2230 | } | ||
2231 | break; | ||
2232 | default: | ||
2233 | snprintf(buff, BUFF_SZ, "\tNot supported\n"); | ||
2234 | } | ||
2235 | hid_debug_event(hdev, buff); | ||
2236 | break; | ||
2237 | case REPORT_VERSION: | ||
2238 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2239 | "REPORT_VERSION", report->id, size-1); | ||
2240 | hid_debug_event(hdev, buff); | ||
2241 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
2242 | raw_data[2], raw_data[1]); | ||
2243 | hid_debug_event(hdev, buff); | ||
2244 | break; | ||
2245 | case REPORT_BL_ERASE_MEMORY: | ||
2246 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2247 | "REPORT_BL_ERASE_MEMORY", report->id, size-1); | ||
2248 | hid_debug_event(hdev, buff); | ||
2249 | /* TODO */ | ||
2250 | break; | ||
2251 | case REPORT_BL_READ_MEMORY: | ||
2252 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2253 | "REPORT_BL_READ_MEMORY", report->id, size-1); | ||
2254 | hid_debug_event(hdev, buff); | ||
2255 | /* TODO */ | ||
2256 | break; | ||
2257 | case REPORT_BL_WRITE_MEMORY: | ||
2258 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2259 | "REPORT_BL_WRITE_MEMORY", report->id, size-1); | ||
2260 | hid_debug_event(hdev, buff); | ||
2261 | /* TODO */ | ||
2262 | break; | ||
2263 | case REPORT_DEVID: | ||
2264 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2265 | "REPORT_DEVID", report->id, size-1); | ||
2266 | hid_debug_event(hdev, buff); | ||
2267 | snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n", | ||
2268 | raw_data[1], raw_data[2], raw_data[3], raw_data[4]); | ||
2269 | hid_debug_event(hdev, buff); | ||
2270 | snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n", | ||
2271 | raw_data[5]); | ||
2272 | hid_debug_event(hdev, buff); | ||
2273 | break; | ||
2274 | case REPORT_SPLASH_SIZE: | ||
2275 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2276 | "REPORT_SPLASH_SIZE", report->id, size-1); | ||
2277 | hid_debug_event(hdev, buff); | ||
2278 | snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n", | ||
2279 | (raw_data[2] << 8) | raw_data[1]); | ||
2280 | hid_debug_event(hdev, buff); | ||
2281 | snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n", | ||
2282 | (raw_data[4] << 8) | raw_data[3]); | ||
2283 | hid_debug_event(hdev, buff); | ||
2284 | break; | ||
2285 | case REPORT_HOOK_VERSION: | ||
2286 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2287 | "REPORT_HOOK_VERSION", report->id, size-1); | ||
2288 | hid_debug_event(hdev, buff); | ||
2289 | snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n", | ||
2290 | raw_data[1], raw_data[2]); | ||
2291 | hid_debug_event(hdev, buff); | ||
2292 | break; | ||
2293 | default: | ||
2294 | snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n", | ||
2295 | "<unknown>", report->id, size-1); | ||
2296 | hid_debug_event(hdev, buff); | ||
2297 | break; | ||
2298 | } | ||
2299 | wake_up_interruptible(&hdev->debug_wait); | ||
2300 | kfree(buff); | ||
2301 | } | ||
2302 | |||
2303 | static void picolcd_init_devfs(struct picolcd_data *data, | ||
2304 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
2305 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
2306 | struct hid_report *reset) | ||
2307 | { | ||
2308 | struct hid_device *hdev = data->hdev; | ||
2309 | |||
2310 | mutex_init(&data->mutex_flash); | ||
2311 | |||
2312 | /* reset */ | ||
2313 | if (reset) | ||
2314 | data->debug_reset = debugfs_create_file("reset", 0600, | ||
2315 | hdev->debug_dir, data, &picolcd_debug_reset_fops); | ||
2316 | |||
2317 | /* eeprom */ | ||
2318 | if (eeprom_r || eeprom_w) | ||
2319 | data->debug_eeprom = debugfs_create_file("eeprom", | ||
2320 | (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0), | ||
2321 | hdev->debug_dir, data, &picolcd_debug_eeprom_fops); | ||
2322 | |||
2323 | /* flash */ | ||
2324 | if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8) | ||
2325 | data->addr_sz = flash_r->field[0]->report_count - 1; | ||
2326 | else | ||
2327 | data->addr_sz = -1; | ||
2328 | if (data->addr_sz == 2 || data->addr_sz == 3) { | ||
2329 | data->debug_flash = debugfs_create_file("flash", | ||
2330 | (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0), | ||
2331 | hdev->debug_dir, data, &picolcd_debug_flash_fops); | ||
2332 | } else if (flash_r || flash_w) | ||
2333 | hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n"); | ||
2334 | } | ||
2335 | |||
2336 | static void picolcd_exit_devfs(struct picolcd_data *data) | ||
2337 | { | ||
2338 | struct dentry *dent; | ||
2339 | |||
2340 | dent = data->debug_reset; | ||
2341 | data->debug_reset = NULL; | ||
2342 | if (dent) | ||
2343 | debugfs_remove(dent); | ||
2344 | dent = data->debug_eeprom; | ||
2345 | data->debug_eeprom = NULL; | ||
2346 | if (dent) | ||
2347 | debugfs_remove(dent); | ||
2348 | dent = data->debug_flash; | ||
2349 | data->debug_flash = NULL; | ||
2350 | if (dent) | ||
2351 | debugfs_remove(dent); | ||
2352 | mutex_destroy(&data->mutex_flash); | ||
2353 | } | ||
2354 | #else | ||
2355 | static inline void picolcd_debug_raw_event(struct picolcd_data *data, | ||
2356 | struct hid_device *hdev, struct hid_report *report, | ||
2357 | u8 *raw_data, int size) | ||
2358 | { | ||
2359 | } | ||
2360 | static inline void picolcd_init_devfs(struct picolcd_data *data, | ||
2361 | struct hid_report *eeprom_r, struct hid_report *eeprom_w, | ||
2362 | struct hid_report *flash_r, struct hid_report *flash_w, | ||
2363 | struct hid_report *reset) | ||
2364 | { | ||
2365 | } | ||
2366 | static inline void picolcd_exit_devfs(struct picolcd_data *data) | ||
2367 | { | ||
2368 | } | ||
2369 | #endif /* CONFIG_DEBUG_FS */ | ||
2370 | |||
2371 | /* | ||
2372 | * Handle raw report as sent by device | ||
2373 | */ | ||
2374 | static int picolcd_raw_event(struct hid_device *hdev, | ||
2375 | struct hid_report *report, u8 *raw_data, int size) | ||
2376 | { | ||
2377 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
2378 | unsigned long flags; | ||
2379 | int ret = 0; | ||
2380 | |||
2381 | if (!data) | ||
2382 | return 1; | ||
2383 | |||
2384 | if (report->id == REPORT_KEY_STATE) { | ||
2385 | if (data->input_keys) | ||
2386 | ret = picolcd_raw_keypad(data, report, raw_data+1, size-1); | ||
2387 | } else if (report->id == REPORT_IR_DATA) { | ||
2388 | if (data->input_cir) | ||
2389 | ret = picolcd_raw_cir(data, report, raw_data+1, size-1); | ||
2390 | } else { | ||
2391 | spin_lock_irqsave(&data->lock, flags); | ||
2392 | /* | ||
2393 | * We let the caller of picolcd_send_and_wait() check if the | ||
2394 | * report we got is one of the expected ones or not. | ||
2395 | */ | ||
2396 | if (data->pending) { | ||
2397 | memcpy(data->pending->raw_data, raw_data+1, size-1); | ||
2398 | data->pending->raw_size = size-1; | ||
2399 | data->pending->in_report = report; | ||
2400 | complete(&data->pending->ready); | ||
2401 | } | ||
2402 | spin_unlock_irqrestore(&data->lock, flags); | ||
2403 | } | ||
2404 | |||
2405 | picolcd_debug_raw_event(data, hdev, report, raw_data, size); | ||
2406 | return 1; | ||
2407 | } | ||
2408 | |||
2409 | #ifdef CONFIG_PM | ||
2410 | static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) | ||
2411 | { | ||
2412 | if (message.event & PM_EVENT_AUTO) | ||
2413 | return 0; | ||
2414 | |||
2415 | picolcd_suspend_backlight(hid_get_drvdata(hdev)); | ||
2416 | dbg_hid(PICOLCD_NAME " device ready for suspend\n"); | ||
2417 | return 0; | ||
2418 | } | ||
2419 | |||
2420 | static int picolcd_resume(struct hid_device *hdev) | ||
2421 | { | ||
2422 | int ret; | ||
2423 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
2424 | if (ret) | ||
2425 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | static int picolcd_reset_resume(struct hid_device *hdev) | ||
2430 | { | ||
2431 | int ret; | ||
2432 | ret = picolcd_reset(hdev); | ||
2433 | if (ret) | ||
2434 | dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret); | ||
2435 | ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0); | ||
2436 | if (ret) | ||
2437 | dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret); | ||
2438 | ret = picolcd_resume_lcd(hid_get_drvdata(hdev)); | ||
2439 | if (ret) | ||
2440 | dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret); | ||
2441 | ret = picolcd_resume_backlight(hid_get_drvdata(hdev)); | ||
2442 | if (ret) | ||
2443 | dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret); | ||
2444 | picolcd_leds_set(hid_get_drvdata(hdev)); | ||
2445 | return 0; | ||
2446 | } | ||
2447 | #endif | ||
2448 | |||
2449 | /* initialize keypad input device */ | ||
2450 | static int picolcd_init_keys(struct picolcd_data *data, | ||
2451 | struct hid_report *report) | ||
2452 | { | ||
2453 | struct hid_device *hdev = data->hdev; | ||
2454 | struct input_dev *idev; | ||
2455 | int error, i; | ||
2456 | |||
2457 | if (!report) | ||
2458 | return -ENODEV; | ||
2459 | if (report->maxfield != 1 || report->field[0]->report_count != 2 || | ||
2460 | report->field[0]->report_size != 8) { | ||
2461 | hid_err(hdev, "unsupported KEY_STATE report\n"); | ||
2462 | return -EINVAL; | ||
2463 | } | ||
2464 | |||
2465 | idev = input_allocate_device(); | ||
2466 | if (idev == NULL) { | ||
2467 | hid_err(hdev, "failed to allocate input device\n"); | ||
2468 | return -ENOMEM; | ||
2469 | } | ||
2470 | input_set_drvdata(idev, hdev); | ||
2471 | memcpy(data->keycode, def_keymap, sizeof(def_keymap)); | ||
2472 | idev->name = hdev->name; | ||
2473 | idev->phys = hdev->phys; | ||
2474 | idev->uniq = hdev->uniq; | ||
2475 | idev->id.bustype = hdev->bus; | ||
2476 | idev->id.vendor = hdev->vendor; | ||
2477 | idev->id.product = hdev->product; | ||
2478 | idev->id.version = hdev->version; | ||
2479 | idev->dev.parent = hdev->dev.parent; | ||
2480 | idev->keycode = &data->keycode; | ||
2481 | idev->keycodemax = PICOLCD_KEYS; | ||
2482 | idev->keycodesize = sizeof(data->keycode[0]); | ||
2483 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
2484 | set_bit(EV_REP, idev->evbit); | ||
2485 | for (i = 0; i < PICOLCD_KEYS; i++) | ||
2486 | input_set_capability(idev, EV_KEY, data->keycode[i]); | ||
2487 | error = input_register_device(idev); | ||
2488 | if (error) { | ||
2489 | hid_err(hdev, "error registering the input device\n"); | ||
2490 | input_free_device(idev); | ||
2491 | return error; | ||
2492 | } | ||
2493 | data->input_keys = idev; | ||
2494 | return 0; | ||
2495 | } | ||
2496 | |||
2497 | static void picolcd_exit_keys(struct picolcd_data *data) | ||
2498 | { | ||
2499 | struct input_dev *idev = data->input_keys; | ||
2500 | |||
2501 | data->input_keys = NULL; | ||
2502 | if (idev) | ||
2503 | input_unregister_device(idev); | ||
2504 | } | ||
2505 | |||
2506 | /* initialize CIR input device */ | ||
2507 | static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) | ||
2508 | { | ||
2509 | /* support not implemented yet */ | ||
2510 | return 0; | ||
2511 | } | ||
2512 | |||
2513 | static inline void picolcd_exit_cir(struct picolcd_data *data) | ||
2514 | { | ||
2515 | } | ||
2516 | |||
2517 | static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data) | ||
2518 | { | ||
2519 | int error; | ||
2520 | |||
2521 | error = picolcd_check_version(hdev); | ||
2522 | if (error) | ||
2523 | return error; | ||
2524 | |||
2525 | if (data->version[0] != 0 && data->version[1] != 3) | ||
2526 | hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
2527 | dev_name(&hdev->dev)); | ||
2528 | |||
2529 | /* Setup keypad input device */ | ||
2530 | error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev)); | ||
2531 | if (error) | ||
2532 | goto err; | ||
2533 | |||
2534 | /* Setup CIR input device */ | ||
2535 | error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev)); | ||
2536 | if (error) | ||
2537 | goto err; | ||
2538 | |||
2539 | /* Set up the framebuffer device */ | ||
2540 | error = picolcd_init_framebuffer(data); | ||
2541 | if (error) | ||
2542 | goto err; | ||
2543 | |||
2544 | /* Setup lcd class device */ | ||
2545 | error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev)); | ||
2546 | if (error) | ||
2547 | goto err; | ||
2548 | |||
2549 | /* Setup backlight class device */ | ||
2550 | error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev)); | ||
2551 | if (error) | ||
2552 | goto err; | ||
2553 | |||
2554 | /* Setup the LED class devices */ | ||
2555 | error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev)); | ||
2556 | if (error) | ||
2557 | goto err; | ||
2558 | |||
2559 | picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev), | ||
2560 | picolcd_out_report(REPORT_EE_WRITE, hdev), | ||
2561 | picolcd_out_report(REPORT_READ_MEMORY, hdev), | ||
2562 | picolcd_out_report(REPORT_WRITE_MEMORY, hdev), | ||
2563 | picolcd_out_report(REPORT_RESET, hdev)); | ||
2564 | return 0; | ||
2565 | err: | ||
2566 | picolcd_exit_leds(data); | ||
2567 | picolcd_exit_backlight(data); | ||
2568 | picolcd_exit_lcd(data); | ||
2569 | picolcd_exit_framebuffer(data); | ||
2570 | picolcd_exit_cir(data); | ||
2571 | picolcd_exit_keys(data); | ||
2572 | return error; | ||
2573 | } | ||
2574 | |||
2575 | static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data) | ||
2576 | { | ||
2577 | int error; | ||
2578 | |||
2579 | error = picolcd_check_version(hdev); | ||
2580 | if (error) | ||
2581 | return error; | ||
2582 | |||
2583 | if (data->version[0] != 1 && data->version[1] != 0) | ||
2584 | hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n", | ||
2585 | dev_name(&hdev->dev)); | ||
2586 | |||
2587 | picolcd_init_devfs(data, NULL, NULL, | ||
2588 | picolcd_out_report(REPORT_BL_READ_MEMORY, hdev), | ||
2589 | picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL); | ||
2590 | return 0; | ||
2591 | } | ||
2592 | |||
2593 | static int picolcd_probe(struct hid_device *hdev, | ||
2594 | const struct hid_device_id *id) | ||
2595 | { | ||
2596 | struct picolcd_data *data; | ||
2597 | int error = -ENOMEM; | ||
2598 | |||
2599 | dbg_hid(PICOLCD_NAME " hardware probe...\n"); | ||
2600 | |||
2601 | /* | ||
2602 | * Let's allocate the picolcd data structure, set some reasonable | ||
2603 | * defaults, and associate it with the device | ||
2604 | */ | ||
2605 | data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); | ||
2606 | if (data == NULL) { | ||
2607 | hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); | ||
2608 | error = -ENOMEM; | ||
2609 | goto err_no_cleanup; | ||
2610 | } | ||
2611 | |||
2612 | spin_lock_init(&data->lock); | ||
2613 | mutex_init(&data->mutex); | ||
2614 | data->hdev = hdev; | ||
2615 | data->opmode_delay = 5000; | ||
2616 | if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER) | ||
2617 | data->status |= PICOLCD_BOOTLOADER; | ||
2618 | hid_set_drvdata(hdev, data); | ||
2619 | |||
2620 | /* Parse the device reports and start it up */ | ||
2621 | error = hid_parse(hdev); | ||
2622 | if (error) { | ||
2623 | hid_err(hdev, "device report parse failed\n"); | ||
2624 | goto err_cleanup_data; | ||
2625 | } | ||
2626 | |||
2627 | /* We don't use hidinput but hid_hw_start() fails if nothing is | ||
2628 | * claimed. So spoof claimed input. */ | ||
2629 | hdev->claimed = HID_CLAIMED_INPUT; | ||
2630 | error = hid_hw_start(hdev, 0); | ||
2631 | hdev->claimed = 0; | ||
2632 | if (error) { | ||
2633 | hid_err(hdev, "hardware start failed\n"); | ||
2634 | goto err_cleanup_data; | ||
2635 | } | ||
2636 | |||
2637 | error = hid_hw_open(hdev); | ||
2638 | if (error) { | ||
2639 | hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n"); | ||
2640 | goto err_cleanup_hid_hw; | ||
2641 | } | ||
2642 | |||
2643 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2644 | if (error) { | ||
2645 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
2646 | goto err_cleanup_hid_ll; | ||
2647 | } | ||
2648 | |||
2649 | error = device_create_file(&hdev->dev, &dev_attr_operation_mode); | ||
2650 | if (error) { | ||
2651 | hid_err(hdev, "failed to create sysfs attributes\n"); | ||
2652 | goto err_cleanup_sysfs1; | ||
2653 | } | ||
2654 | |||
2655 | if (data->status & PICOLCD_BOOTLOADER) | ||
2656 | error = picolcd_probe_bootloader(hdev, data); | ||
2657 | else | ||
2658 | error = picolcd_probe_lcd(hdev, data); | ||
2659 | if (error) | ||
2660 | goto err_cleanup_sysfs2; | ||
2661 | |||
2662 | dbg_hid(PICOLCD_NAME " activated and initialized\n"); | ||
2663 | return 0; | ||
2664 | |||
2665 | err_cleanup_sysfs2: | ||
2666 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
2667 | err_cleanup_sysfs1: | ||
2668 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2669 | err_cleanup_hid_ll: | ||
2670 | hid_hw_close(hdev); | ||
2671 | err_cleanup_hid_hw: | ||
2672 | hid_hw_stop(hdev); | ||
2673 | err_cleanup_data: | ||
2674 | kfree(data); | ||
2675 | err_no_cleanup: | ||
2676 | hid_set_drvdata(hdev, NULL); | ||
2677 | |||
2678 | return error; | ||
2679 | } | ||
2680 | |||
2681 | static void picolcd_remove(struct hid_device *hdev) | ||
2682 | { | ||
2683 | struct picolcd_data *data = hid_get_drvdata(hdev); | ||
2684 | unsigned long flags; | ||
2685 | |||
2686 | dbg_hid(PICOLCD_NAME " hardware remove...\n"); | ||
2687 | spin_lock_irqsave(&data->lock, flags); | ||
2688 | data->status |= PICOLCD_FAILED; | ||
2689 | spin_unlock_irqrestore(&data->lock, flags); | ||
2690 | #ifdef CONFIG_HID_PICOLCD_FB | ||
2691 | /* short-circuit FB as early as possible in order to | ||
2692 | * avoid long delays if we host console. | ||
2693 | */ | ||
2694 | if (data->fb_info) | ||
2695 | data->fb_info->par = NULL; | ||
2696 | #endif | ||
2697 | |||
2698 | picolcd_exit_devfs(data); | ||
2699 | device_remove_file(&hdev->dev, &dev_attr_operation_mode); | ||
2700 | device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay); | ||
2701 | hid_hw_close(hdev); | ||
2702 | hid_hw_stop(hdev); | ||
2703 | hid_set_drvdata(hdev, NULL); | ||
2704 | |||
2705 | /* Shortcut potential pending reply that will never arrive */ | ||
2706 | spin_lock_irqsave(&data->lock, flags); | ||
2707 | if (data->pending) | ||
2708 | complete(&data->pending->ready); | ||
2709 | spin_unlock_irqrestore(&data->lock, flags); | ||
2710 | |||
2711 | /* Cleanup LED */ | ||
2712 | picolcd_exit_leds(data); | ||
2713 | /* Clean up the framebuffer */ | ||
2714 | picolcd_exit_backlight(data); | ||
2715 | picolcd_exit_lcd(data); | ||
2716 | picolcd_exit_framebuffer(data); | ||
2717 | /* Cleanup input */ | ||
2718 | picolcd_exit_cir(data); | ||
2719 | picolcd_exit_keys(data); | ||
2720 | |||
2721 | mutex_destroy(&data->mutex); | ||
2722 | /* Finally, clean up the picolcd data itself */ | ||
2723 | kfree(data); | ||
2724 | } | ||
2725 | |||
2726 | static const struct hid_device_id picolcd_devices[] = { | ||
2727 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, | ||
2728 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, | ||
2729 | { } | ||
2730 | }; | ||
2731 | MODULE_DEVICE_TABLE(hid, picolcd_devices); | ||
2732 | |||
2733 | static struct hid_driver picolcd_driver = { | ||
2734 | .name = "hid-picolcd", | ||
2735 | .id_table = picolcd_devices, | ||
2736 | .probe = picolcd_probe, | ||
2737 | .remove = picolcd_remove, | ||
2738 | .raw_event = picolcd_raw_event, | ||
2739 | #ifdef CONFIG_PM | ||
2740 | .suspend = picolcd_suspend, | ||
2741 | .resume = picolcd_resume, | ||
2742 | .reset_resume = picolcd_reset_resume, | ||
2743 | #endif | ||
2744 | }; | ||
2745 | |||
2746 | static int __init picolcd_init(void) | ||
2747 | { | ||
2748 | return hid_register_driver(&picolcd_driver); | ||
2749 | } | ||
2750 | |||
2751 | static void __exit picolcd_exit(void) | ||
2752 | { | ||
2753 | hid_unregister_driver(&picolcd_driver); | ||
2754 | #ifdef CONFIG_HID_PICOLCD_FB | ||
2755 | flush_work_sync(&picolcd_fb_cleanup); | ||
2756 | WARN_ON(fb_pending); | ||
2757 | #endif | ||
2758 | } | ||
2759 | |||
2760 | module_init(picolcd_init); | ||
2761 | module_exit(picolcd_exit); | ||
2762 | MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver"); | ||
2763 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c new file mode 100644 index 00000000000..87a54df4d4a --- /dev/null +++ b/drivers/hid/hid-quanta.c | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * HID driver for Quanta Optical Touch dual-touch panels | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the Free | ||
11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
12 | * any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/hid.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | |||
20 | MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | ||
21 | MODULE_DESCRIPTION("Quanta dual-touch panel"); | ||
22 | MODULE_LICENSE("GPL"); | ||
23 | |||
24 | #include "hid-ids.h" | ||
25 | |||
26 | struct quanta_data { | ||
27 | __u16 x, y; | ||
28 | __u8 id; | ||
29 | bool valid; /* valid finger data, or just placeholder? */ | ||
30 | bool first; /* is this the first finger in this frame? */ | ||
31 | bool activity_now; /* at least one active finger in this frame? */ | ||
32 | bool activity; /* at least one active finger previously? */ | ||
33 | }; | ||
34 | |||
35 | static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
36 | struct hid_field *field, struct hid_usage *usage, | ||
37 | unsigned long **bit, int *max) | ||
38 | { | ||
39 | switch (usage->hid & HID_USAGE_PAGE) { | ||
40 | |||
41 | case HID_UP_GENDESK: | ||
42 | switch (usage->hid) { | ||
43 | case HID_GD_X: | ||
44 | hid_map_usage(hi, usage, bit, max, | ||
45 | EV_ABS, ABS_MT_POSITION_X); | ||
46 | /* touchscreen emulation */ | ||
47 | input_set_abs_params(hi->input, ABS_X, | ||
48 | field->logical_minimum, | ||
49 | field->logical_maximum, 0, 0); | ||
50 | return 1; | ||
51 | case HID_GD_Y: | ||
52 | hid_map_usage(hi, usage, bit, max, | ||
53 | EV_ABS, ABS_MT_POSITION_Y); | ||
54 | /* touchscreen emulation */ | ||
55 | input_set_abs_params(hi->input, ABS_Y, | ||
56 | field->logical_minimum, | ||
57 | field->logical_maximum, 0, 0); | ||
58 | return 1; | ||
59 | } | ||
60 | return 0; | ||
61 | |||
62 | case HID_UP_DIGITIZER: | ||
63 | switch (usage->hid) { | ||
64 | case HID_DG_CONFIDENCE: | ||
65 | case HID_DG_TIPSWITCH: | ||
66 | case HID_DG_INPUTMODE: | ||
67 | case HID_DG_DEVICEINDEX: | ||
68 | case HID_DG_CONTACTCOUNT: | ||
69 | case HID_DG_CONTACTMAX: | ||
70 | case HID_DG_TIPPRESSURE: | ||
71 | case HID_DG_WIDTH: | ||
72 | case HID_DG_HEIGHT: | ||
73 | return -1; | ||
74 | case HID_DG_INRANGE: | ||
75 | /* touchscreen emulation */ | ||
76 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | ||
77 | return 1; | ||
78 | case HID_DG_CONTACTID: | ||
79 | hid_map_usage(hi, usage, bit, max, | ||
80 | EV_ABS, ABS_MT_TRACKING_ID); | ||
81 | return 1; | ||
82 | } | ||
83 | return 0; | ||
84 | |||
85 | case 0xff000000: | ||
86 | /* ignore vendor-specific features */ | ||
87 | return -1; | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi, | ||
94 | struct hid_field *field, struct hid_usage *usage, | ||
95 | unsigned long **bit, int *max) | ||
96 | { | ||
97 | if (usage->type == EV_KEY || usage->type == EV_ABS) | ||
98 | clear_bit(usage->code, *bit); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * this function is called when a whole finger has been parsed, | ||
105 | * so that it can decide what to send to the input layer. | ||
106 | */ | ||
107 | static void quanta_filter_event(struct quanta_data *td, struct input_dev *input) | ||
108 | { | ||
109 | |||
110 | td->first = !td->first; /* touchscreen emulation */ | ||
111 | |||
112 | if (!td->valid) { | ||
113 | /* | ||
114 | * touchscreen emulation: if no finger in this frame is valid | ||
115 | * and there previously was finger activity, this is a release | ||
116 | */ | ||
117 | if (!td->first && !td->activity_now && td->activity) { | ||
118 | input_event(input, EV_KEY, BTN_TOUCH, 0); | ||
119 | td->activity = false; | ||
120 | } | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); | ||
125 | input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); | ||
126 | input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); | ||
127 | |||
128 | input_mt_sync(input); | ||
129 | td->valid = false; | ||
130 | |||
131 | /* touchscreen emulation: if first active finger in this frame... */ | ||
132 | if (!td->activity_now) { | ||
133 | /* if there was no previous activity, emit touch event */ | ||
134 | if (!td->activity) { | ||
135 | input_event(input, EV_KEY, BTN_TOUCH, 1); | ||
136 | td->activity = true; | ||
137 | } | ||
138 | td->activity_now = true; | ||
139 | /* and in any case this is our preferred finger */ | ||
140 | input_event(input, EV_ABS, ABS_X, td->x); | ||
141 | input_event(input, EV_ABS, ABS_Y, td->y); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | |||
146 | static int quanta_event(struct hid_device *hid, struct hid_field *field, | ||
147 | struct hid_usage *usage, __s32 value) | ||
148 | { | ||
149 | struct quanta_data *td = hid_get_drvdata(hid); | ||
150 | |||
151 | if (hid->claimed & HID_CLAIMED_INPUT) { | ||
152 | struct input_dev *input = field->hidinput->input; | ||
153 | |||
154 | switch (usage->hid) { | ||
155 | case HID_DG_INRANGE: | ||
156 | td->valid = !!value; | ||
157 | break; | ||
158 | case HID_GD_X: | ||
159 | td->x = value; | ||
160 | break; | ||
161 | case HID_GD_Y: | ||
162 | td->y = value; | ||
163 | quanta_filter_event(td, input); | ||
164 | break; | ||
165 | case HID_DG_CONTACTID: | ||
166 | td->id = value; | ||
167 | break; | ||
168 | case HID_DG_CONTACTCOUNT: | ||
169 | /* touch emulation: this is the last field in a frame */ | ||
170 | td->first = false; | ||
171 | td->activity_now = false; | ||
172 | break; | ||
173 | case HID_DG_CONFIDENCE: | ||
174 | case HID_DG_TIPSWITCH: | ||
175 | /* avoid interference from generic hidinput handling */ | ||
176 | break; | ||
177 | |||
178 | default: | ||
179 | /* fallback to the generic hidinput handling */ | ||
180 | return 0; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* we have handled the hidinput part, now remains hiddev */ | ||
185 | if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) | ||
186 | hid->hiddev_hid_event(hid, field, usage, value); | ||
187 | |||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
192 | { | ||
193 | int ret; | ||
194 | struct quanta_data *td; | ||
195 | |||
196 | td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL); | ||
197 | if (!td) { | ||
198 | hid_err(hdev, "cannot allocate Quanta Touch data\n"); | ||
199 | return -ENOMEM; | ||
200 | } | ||
201 | td->valid = false; | ||
202 | td->activity = false; | ||
203 | td->activity_now = false; | ||
204 | td->first = false; | ||
205 | hid_set_drvdata(hdev, td); | ||
206 | |||
207 | ret = hid_parse(hdev); | ||
208 | if (!ret) | ||
209 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | ||
210 | |||
211 | if (ret) | ||
212 | kfree(td); | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static void quanta_remove(struct hid_device *hdev) | ||
218 | { | ||
219 | hid_hw_stop(hdev); | ||
220 | kfree(hid_get_drvdata(hdev)); | ||
221 | hid_set_drvdata(hdev, NULL); | ||
222 | } | ||
223 | |||
224 | static const struct hid_device_id quanta_devices[] = { | ||
225 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, | ||
226 | USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, | ||
227 | { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, | ||
228 | USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, | ||
229 | { } | ||
230 | }; | ||
231 | MODULE_DEVICE_TABLE(hid, quanta_devices); | ||
232 | |||
233 | static const struct hid_usage_id quanta_grabbed_usages[] = { | ||
234 | { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, | ||
235 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
236 | }; | ||
237 | |||
238 | static struct hid_driver quanta_driver = { | ||
239 | .name = "quanta-touch", | ||
240 | .id_table = quanta_devices, | ||
241 | .probe = quanta_probe, | ||
242 | .remove = quanta_remove, | ||
243 | .input_mapping = quanta_input_mapping, | ||
244 | .input_mapped = quanta_input_mapped, | ||
245 | .usage_table = quanta_grabbed_usages, | ||
246 | .event = quanta_event, | ||
247 | }; | ||
248 | |||
249 | static int __init quanta_init(void) | ||
250 | { | ||
251 | return hid_register_driver(&quanta_driver); | ||
252 | } | ||
253 | |||
254 | static void __exit quanta_exit(void) | ||
255 | { | ||
256 | hid_unregister_driver(&quanta_driver); | ||
257 | } | ||
258 | |||
259 | module_init(quanta_init); | ||
260 | module_exit(quanta_exit); | ||
261 | |||
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c new file mode 100644 index 00000000000..85a02e5f9fe --- /dev/null +++ b/drivers/hid/hid-wiimote.c | |||
@@ -0,0 +1,578 @@ | |||
1 | /* | ||
2 | * HID driver for Nintendo Wiimote devices | ||
3 | * Copyright (c) 2011 David Herrmann | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the Free | ||
9 | * Software Foundation; either version 2 of the License, or (at your option) | ||
10 | * any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/hid.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/leds.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include "hid-ids.h" | ||
20 | |||
21 | #define WIIMOTE_VERSION "0.1" | ||
22 | #define WIIMOTE_NAME "Nintendo Wii Remote" | ||
23 | #define WIIMOTE_BUFSIZE 32 | ||
24 | |||
25 | struct wiimote_buf { | ||
26 | __u8 data[HID_MAX_BUFFER_SIZE]; | ||
27 | size_t size; | ||
28 | }; | ||
29 | |||
30 | struct wiimote_state { | ||
31 | spinlock_t lock; | ||
32 | __u8 flags; | ||
33 | }; | ||
34 | |||
35 | struct wiimote_data { | ||
36 | struct hid_device *hdev; | ||
37 | struct input_dev *input; | ||
38 | struct led_classdev *leds[4]; | ||
39 | |||
40 | spinlock_t qlock; | ||
41 | __u8 head; | ||
42 | __u8 tail; | ||
43 | struct wiimote_buf outq[WIIMOTE_BUFSIZE]; | ||
44 | struct work_struct worker; | ||
45 | |||
46 | struct wiimote_state state; | ||
47 | }; | ||
48 | |||
49 | #define WIIPROTO_FLAG_LED1 0x01 | ||
50 | #define WIIPROTO_FLAG_LED2 0x02 | ||
51 | #define WIIPROTO_FLAG_LED3 0x04 | ||
52 | #define WIIPROTO_FLAG_LED4 0x08 | ||
53 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ | ||
54 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) | ||
55 | |||
56 | /* return flag for led \num */ | ||
57 | #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) | ||
58 | |||
59 | enum wiiproto_reqs { | ||
60 | WIIPROTO_REQ_NULL = 0x0, | ||
61 | WIIPROTO_REQ_LED = 0x11, | ||
62 | WIIPROTO_REQ_DRM = 0x12, | ||
63 | WIIPROTO_REQ_STATUS = 0x20, | ||
64 | WIIPROTO_REQ_RETURN = 0x22, | ||
65 | WIIPROTO_REQ_DRM_K = 0x30, | ||
66 | }; | ||
67 | |||
68 | enum wiiproto_keys { | ||
69 | WIIPROTO_KEY_LEFT, | ||
70 | WIIPROTO_KEY_RIGHT, | ||
71 | WIIPROTO_KEY_UP, | ||
72 | WIIPROTO_KEY_DOWN, | ||
73 | WIIPROTO_KEY_PLUS, | ||
74 | WIIPROTO_KEY_MINUS, | ||
75 | WIIPROTO_KEY_ONE, | ||
76 | WIIPROTO_KEY_TWO, | ||
77 | WIIPROTO_KEY_A, | ||
78 | WIIPROTO_KEY_B, | ||
79 | WIIPROTO_KEY_HOME, | ||
80 | WIIPROTO_KEY_COUNT | ||
81 | }; | ||
82 | |||
83 | static __u16 wiiproto_keymap[] = { | ||
84 | KEY_LEFT, /* WIIPROTO_KEY_LEFT */ | ||
85 | KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ | ||
86 | KEY_UP, /* WIIPROTO_KEY_UP */ | ||
87 | KEY_DOWN, /* WIIPROTO_KEY_DOWN */ | ||
88 | KEY_NEXT, /* WIIPROTO_KEY_PLUS */ | ||
89 | KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ | ||
90 | BTN_1, /* WIIPROTO_KEY_ONE */ | ||
91 | BTN_2, /* WIIPROTO_KEY_TWO */ | ||
92 | BTN_A, /* WIIPROTO_KEY_A */ | ||
93 | BTN_B, /* WIIPROTO_KEY_B */ | ||
94 | BTN_MODE, /* WIIPROTO_KEY_HOME */ | ||
95 | }; | ||
96 | |||
97 | static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, | ||
98 | size_t count) | ||
99 | { | ||
100 | __u8 *buf; | ||
101 | ssize_t ret; | ||
102 | |||
103 | if (!hdev->hid_output_raw_report) | ||
104 | return -ENODEV; | ||
105 | |||
106 | buf = kmemdup(buffer, count, GFP_KERNEL); | ||
107 | if (!buf) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT); | ||
111 | |||
112 | kfree(buf); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static void wiimote_worker(struct work_struct *work) | ||
117 | { | ||
118 | struct wiimote_data *wdata = container_of(work, struct wiimote_data, | ||
119 | worker); | ||
120 | unsigned long flags; | ||
121 | |||
122 | spin_lock_irqsave(&wdata->qlock, flags); | ||
123 | |||
124 | while (wdata->head != wdata->tail) { | ||
125 | spin_unlock_irqrestore(&wdata->qlock, flags); | ||
126 | wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data, | ||
127 | wdata->outq[wdata->tail].size); | ||
128 | spin_lock_irqsave(&wdata->qlock, flags); | ||
129 | |||
130 | wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE; | ||
131 | } | ||
132 | |||
133 | spin_unlock_irqrestore(&wdata->qlock, flags); | ||
134 | } | ||
135 | |||
136 | static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer, | ||
137 | size_t count) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | __u8 newhead; | ||
141 | |||
142 | if (count > HID_MAX_BUFFER_SIZE) { | ||
143 | hid_warn(wdata->hdev, "Sending too large output report\n"); | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Copy new request into our output queue and check whether the | ||
149 | * queue is full. If it is full, discard this request. | ||
150 | * If it is empty we need to start a new worker that will | ||
151 | * send out the buffer to the hid device. | ||
152 | * If the queue is not empty, then there must be a worker | ||
153 | * that is currently sending out our buffer and this worker | ||
154 | * will reschedule itself until the queue is empty. | ||
155 | */ | ||
156 | |||
157 | spin_lock_irqsave(&wdata->qlock, flags); | ||
158 | |||
159 | memcpy(wdata->outq[wdata->head].data, buffer, count); | ||
160 | wdata->outq[wdata->head].size = count; | ||
161 | newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE; | ||
162 | |||
163 | if (wdata->head == wdata->tail) { | ||
164 | wdata->head = newhead; | ||
165 | schedule_work(&wdata->worker); | ||
166 | } else if (newhead != wdata->tail) { | ||
167 | wdata->head = newhead; | ||
168 | } else { | ||
169 | hid_warn(wdata->hdev, "Output queue is full"); | ||
170 | } | ||
171 | |||
172 | spin_unlock_irqrestore(&wdata->qlock, flags); | ||
173 | } | ||
174 | |||
175 | static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) | ||
176 | { | ||
177 | __u8 cmd[2]; | ||
178 | |||
179 | leds &= WIIPROTO_FLAGS_LEDS; | ||
180 | if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds) | ||
181 | return; | ||
182 | wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds; | ||
183 | |||
184 | cmd[0] = WIIPROTO_REQ_LED; | ||
185 | cmd[1] = 0; | ||
186 | |||
187 | if (leds & WIIPROTO_FLAG_LED1) | ||
188 | cmd[1] |= 0x10; | ||
189 | if (leds & WIIPROTO_FLAG_LED2) | ||
190 | cmd[1] |= 0x20; | ||
191 | if (leds & WIIPROTO_FLAG_LED3) | ||
192 | cmd[1] |= 0x40; | ||
193 | if (leds & WIIPROTO_FLAG_LED4) | ||
194 | cmd[1] |= 0x80; | ||
195 | |||
196 | wiimote_queue(wdata, cmd, sizeof(cmd)); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Check what peripherals of the wiimote are currently | ||
201 | * active and select a proper DRM that supports all of | ||
202 | * the requested data inputs. | ||
203 | */ | ||
204 | static __u8 select_drm(struct wiimote_data *wdata) | ||
205 | { | ||
206 | return WIIPROTO_REQ_DRM_K; | ||
207 | } | ||
208 | |||
209 | static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm) | ||
210 | { | ||
211 | __u8 cmd[3]; | ||
212 | |||
213 | if (drm == WIIPROTO_REQ_NULL) | ||
214 | drm = select_drm(wdata); | ||
215 | |||
216 | cmd[0] = WIIPROTO_REQ_DRM; | ||
217 | cmd[1] = 0; | ||
218 | cmd[2] = drm; | ||
219 | |||
220 | wiimote_queue(wdata, cmd, sizeof(cmd)); | ||
221 | } | ||
222 | |||
223 | static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev) | ||
224 | { | ||
225 | struct wiimote_data *wdata; | ||
226 | struct device *dev = led_dev->dev->parent; | ||
227 | int i; | ||
228 | unsigned long flags; | ||
229 | bool value = false; | ||
230 | |||
231 | wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); | ||
232 | |||
233 | for (i = 0; i < 4; ++i) { | ||
234 | if (wdata->leds[i] == led_dev) { | ||
235 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
236 | value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1); | ||
237 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
238 | break; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return value ? LED_FULL : LED_OFF; | ||
243 | } | ||
244 | |||
245 | static void wiimote_leds_set(struct led_classdev *led_dev, | ||
246 | enum led_brightness value) | ||
247 | { | ||
248 | struct wiimote_data *wdata; | ||
249 | struct device *dev = led_dev->dev->parent; | ||
250 | int i; | ||
251 | unsigned long flags; | ||
252 | __u8 state, flag; | ||
253 | |||
254 | wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); | ||
255 | |||
256 | for (i = 0; i < 4; ++i) { | ||
257 | if (wdata->leds[i] == led_dev) { | ||
258 | flag = WIIPROTO_FLAG_LED(i + 1); | ||
259 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
260 | state = wdata->state.flags; | ||
261 | if (value == LED_OFF) | ||
262 | wiiproto_req_leds(wdata, state & ~flag); | ||
263 | else | ||
264 | wiiproto_req_leds(wdata, state | flag); | ||
265 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
266 | break; | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static int wiimote_input_event(struct input_dev *dev, unsigned int type, | ||
272 | unsigned int code, int value) | ||
273 | { | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int wiimote_input_open(struct input_dev *dev) | ||
278 | { | ||
279 | struct wiimote_data *wdata = input_get_drvdata(dev); | ||
280 | |||
281 | return hid_hw_open(wdata->hdev); | ||
282 | } | ||
283 | |||
284 | static void wiimote_input_close(struct input_dev *dev) | ||
285 | { | ||
286 | struct wiimote_data *wdata = input_get_drvdata(dev); | ||
287 | |||
288 | hid_hw_close(wdata->hdev); | ||
289 | } | ||
290 | |||
291 | static void handler_keys(struct wiimote_data *wdata, const __u8 *payload) | ||
292 | { | ||
293 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT], | ||
294 | !!(payload[0] & 0x01)); | ||
295 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT], | ||
296 | !!(payload[0] & 0x02)); | ||
297 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN], | ||
298 | !!(payload[0] & 0x04)); | ||
299 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP], | ||
300 | !!(payload[0] & 0x08)); | ||
301 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS], | ||
302 | !!(payload[0] & 0x10)); | ||
303 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO], | ||
304 | !!(payload[1] & 0x01)); | ||
305 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE], | ||
306 | !!(payload[1] & 0x02)); | ||
307 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B], | ||
308 | !!(payload[1] & 0x04)); | ||
309 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A], | ||
310 | !!(payload[1] & 0x08)); | ||
311 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS], | ||
312 | !!(payload[1] & 0x10)); | ||
313 | input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME], | ||
314 | !!(payload[1] & 0x80)); | ||
315 | input_sync(wdata->input); | ||
316 | } | ||
317 | |||
318 | static void handler_status(struct wiimote_data *wdata, const __u8 *payload) | ||
319 | { | ||
320 | handler_keys(wdata, payload); | ||
321 | |||
322 | /* on status reports the drm is reset so we need to resend the drm */ | ||
323 | wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); | ||
324 | } | ||
325 | |||
326 | static void handler_return(struct wiimote_data *wdata, const __u8 *payload) | ||
327 | { | ||
328 | __u8 err = payload[3]; | ||
329 | __u8 cmd = payload[2]; | ||
330 | |||
331 | handler_keys(wdata, payload); | ||
332 | |||
333 | if (err) | ||
334 | hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err, | ||
335 | cmd); | ||
336 | } | ||
337 | |||
338 | struct wiiproto_handler { | ||
339 | __u8 id; | ||
340 | size_t size; | ||
341 | void (*func)(struct wiimote_data *wdata, const __u8 *payload); | ||
342 | }; | ||
343 | |||
344 | static struct wiiproto_handler handlers[] = { | ||
345 | { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status }, | ||
346 | { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return }, | ||
347 | { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, | ||
348 | { .id = 0 } | ||
349 | }; | ||
350 | |||
351 | static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, | ||
352 | u8 *raw_data, int size) | ||
353 | { | ||
354 | struct wiimote_data *wdata = hid_get_drvdata(hdev); | ||
355 | struct wiiproto_handler *h; | ||
356 | int i; | ||
357 | unsigned long flags; | ||
358 | |||
359 | if (size < 1) | ||
360 | return -EINVAL; | ||
361 | |||
362 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
363 | |||
364 | for (i = 0; handlers[i].id; ++i) { | ||
365 | h = &handlers[i]; | ||
366 | if (h->id == raw_data[0] && h->size < size) | ||
367 | h->func(wdata, &raw_data[1]); | ||
368 | } | ||
369 | |||
370 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static void wiimote_leds_destroy(struct wiimote_data *wdata) | ||
376 | { | ||
377 | int i; | ||
378 | struct led_classdev *led; | ||
379 | |||
380 | for (i = 0; i < 4; ++i) { | ||
381 | if (wdata->leds[i]) { | ||
382 | led = wdata->leds[i]; | ||
383 | wdata->leds[i] = NULL; | ||
384 | led_classdev_unregister(led); | ||
385 | kfree(led); | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | static int wiimote_leds_create(struct wiimote_data *wdata) | ||
391 | { | ||
392 | int i, ret; | ||
393 | struct device *dev = &wdata->hdev->dev; | ||
394 | size_t namesz = strlen(dev_name(dev)) + 9; | ||
395 | struct led_classdev *led; | ||
396 | char *name; | ||
397 | |||
398 | for (i = 0; i < 4; ++i) { | ||
399 | led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); | ||
400 | if (!led) { | ||
401 | ret = -ENOMEM; | ||
402 | goto err; | ||
403 | } | ||
404 | name = (void*)&led[1]; | ||
405 | snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i); | ||
406 | led->name = name; | ||
407 | led->brightness = 0; | ||
408 | led->max_brightness = 1; | ||
409 | led->brightness_get = wiimote_leds_get; | ||
410 | led->brightness_set = wiimote_leds_set; | ||
411 | |||
412 | ret = led_classdev_register(dev, led); | ||
413 | if (ret) { | ||
414 | kfree(led); | ||
415 | goto err; | ||
416 | } | ||
417 | wdata->leds[i] = led; | ||
418 | } | ||
419 | |||
420 | return 0; | ||
421 | |||
422 | err: | ||
423 | wiimote_leds_destroy(wdata); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static struct wiimote_data *wiimote_create(struct hid_device *hdev) | ||
428 | { | ||
429 | struct wiimote_data *wdata; | ||
430 | int i; | ||
431 | |||
432 | wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); | ||
433 | if (!wdata) | ||
434 | return NULL; | ||
435 | |||
436 | wdata->input = input_allocate_device(); | ||
437 | if (!wdata->input) { | ||
438 | kfree(wdata); | ||
439 | return NULL; | ||
440 | } | ||
441 | |||
442 | wdata->hdev = hdev; | ||
443 | hid_set_drvdata(hdev, wdata); | ||
444 | |||
445 | input_set_drvdata(wdata->input, wdata); | ||
446 | wdata->input->event = wiimote_input_event; | ||
447 | wdata->input->open = wiimote_input_open; | ||
448 | wdata->input->close = wiimote_input_close; | ||
449 | wdata->input->dev.parent = &wdata->hdev->dev; | ||
450 | wdata->input->id.bustype = wdata->hdev->bus; | ||
451 | wdata->input->id.vendor = wdata->hdev->vendor; | ||
452 | wdata->input->id.product = wdata->hdev->product; | ||
453 | wdata->input->id.version = wdata->hdev->version; | ||
454 | wdata->input->name = WIIMOTE_NAME; | ||
455 | |||
456 | set_bit(EV_KEY, wdata->input->evbit); | ||
457 | for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) | ||
458 | set_bit(wiiproto_keymap[i], wdata->input->keybit); | ||
459 | |||
460 | spin_lock_init(&wdata->qlock); | ||
461 | INIT_WORK(&wdata->worker, wiimote_worker); | ||
462 | |||
463 | spin_lock_init(&wdata->state.lock); | ||
464 | |||
465 | return wdata; | ||
466 | } | ||
467 | |||
468 | static void wiimote_destroy(struct wiimote_data *wdata) | ||
469 | { | ||
470 | wiimote_leds_destroy(wdata); | ||
471 | |||
472 | input_unregister_device(wdata->input); | ||
473 | cancel_work_sync(&wdata->worker); | ||
474 | hid_hw_stop(wdata->hdev); | ||
475 | |||
476 | kfree(wdata); | ||
477 | } | ||
478 | |||
479 | static int wiimote_hid_probe(struct hid_device *hdev, | ||
480 | const struct hid_device_id *id) | ||
481 | { | ||
482 | struct wiimote_data *wdata; | ||
483 | int ret; | ||
484 | |||
485 | wdata = wiimote_create(hdev); | ||
486 | if (!wdata) { | ||
487 | hid_err(hdev, "Can't alloc device\n"); | ||
488 | return -ENOMEM; | ||
489 | } | ||
490 | |||
491 | ret = hid_parse(hdev); | ||
492 | if (ret) { | ||
493 | hid_err(hdev, "HID parse failed\n"); | ||
494 | goto err; | ||
495 | } | ||
496 | |||
497 | ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); | ||
498 | if (ret) { | ||
499 | hid_err(hdev, "HW start failed\n"); | ||
500 | goto err; | ||
501 | } | ||
502 | |||
503 | ret = input_register_device(wdata->input); | ||
504 | if (ret) { | ||
505 | hid_err(hdev, "Cannot register input device\n"); | ||
506 | goto err_stop; | ||
507 | } | ||
508 | |||
509 | ret = wiimote_leds_create(wdata); | ||
510 | if (ret) | ||
511 | goto err_free; | ||
512 | |||
513 | hid_info(hdev, "New device registered\n"); | ||
514 | |||
515 | /* by default set led1 after device initialization */ | ||
516 | spin_lock_irq(&wdata->state.lock); | ||
517 | wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); | ||
518 | spin_unlock_irq(&wdata->state.lock); | ||
519 | |||
520 | return 0; | ||
521 | |||
522 | err_free: | ||
523 | wiimote_destroy(wdata); | ||
524 | return ret; | ||
525 | |||
526 | err_stop: | ||
527 | hid_hw_stop(hdev); | ||
528 | err: | ||
529 | input_free_device(wdata->input); | ||
530 | kfree(wdata); | ||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | static void wiimote_hid_remove(struct hid_device *hdev) | ||
535 | { | ||
536 | struct wiimote_data *wdata = hid_get_drvdata(hdev); | ||
537 | |||
538 | hid_info(hdev, "Device removed\n"); | ||
539 | wiimote_destroy(wdata); | ||
540 | } | ||
541 | |||
542 | static const struct hid_device_id wiimote_hid_devices[] = { | ||
543 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, | ||
544 | USB_DEVICE_ID_NINTENDO_WIIMOTE) }, | ||
545 | { } | ||
546 | }; | ||
547 | MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); | ||
548 | |||
549 | static struct hid_driver wiimote_hid_driver = { | ||
550 | .name = "wiimote", | ||
551 | .id_table = wiimote_hid_devices, | ||
552 | .probe = wiimote_hid_probe, | ||
553 | .remove = wiimote_hid_remove, | ||
554 | .raw_event = wiimote_hid_event, | ||
555 | }; | ||
556 | |||
557 | static int __init wiimote_init(void) | ||
558 | { | ||
559 | int ret; | ||
560 | |||
561 | ret = hid_register_driver(&wiimote_hid_driver); | ||
562 | if (ret) | ||
563 | pr_err("Can't register wiimote hid driver\n"); | ||
564 | |||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | static void __exit wiimote_exit(void) | ||
569 | { | ||
570 | hid_unregister_driver(&wiimote_hid_driver); | ||
571 | } | ||
572 | |||
573 | module_init(wiimote_init); | ||
574 | module_exit(wiimote_exit); | ||
575 | MODULE_LICENSE("GPL"); | ||
576 | MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>"); | ||
577 | MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver"); | ||
578 | MODULE_VERSION(WIIMOTE_VERSION); | ||