diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-07 17:31:32 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-05-08 01:41:29 -0400 |
commit | ba0acb5ee318901646f82c134cca2e4de0c43934 (patch) | |
tree | 862d0d2b5d06332dce642571f625431c313d04ea /drivers/input/misc | |
parent | b5da20f8f7652e7a9648401a1942b7aac3b9ab9d (diff) |
Input: move USB miscellaneous devices under drivers/input/misc
This will allow concentrating all input devices in one place
in {menu|x|q}config.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/input/misc')
-rw-r--r-- | drivers/input/misc/Kconfig | 88 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 9 | ||||
-rw-r--r-- | drivers/input/misc/ati_remote.c | 862 | ||||
-rw-r--r-- | drivers/input/misc/ati_remote2.c | 543 | ||||
-rw-r--r-- | drivers/input/misc/keyspan_remote.c | 592 | ||||
-rw-r--r-- | drivers/input/misc/map_to_7segment.h | 189 | ||||
-rw-r--r-- | drivers/input/misc/powermate.c | 463 | ||||
-rw-r--r-- | drivers/input/misc/yealink.c | 1004 | ||||
-rw-r--r-- | drivers/input/misc/yealink.h | 220 |
9 files changed, 3961 insertions, 9 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1d0d3e765db6..6013ace94d98 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -40,6 +40,18 @@ config INPUT_M68K_BEEP | |||
40 | tristate "M68k Beeper support" | 40 | tristate "M68k Beeper support" |
41 | depends on M68K | 41 | depends on M68K |
42 | 42 | ||
43 | config INPUT_IXP4XX_BEEPER | ||
44 | tristate "IXP4XX Beeper support" | ||
45 | depends on ARCH_IXP4XX | ||
46 | help | ||
47 | If you say yes here, you can connect a beeper to the | ||
48 | ixp4xx gpio pins. This is used by the LinkSys NSLU2. | ||
49 | |||
50 | If unsure, say Y. | ||
51 | |||
52 | To compile this driver as a module, choose M here: the | ||
53 | module will be called ixp4xx-beeper. | ||
54 | |||
43 | config INPUT_COBALT_BTNS | 55 | config INPUT_COBALT_BTNS |
44 | tristate "Cobalt button interface" | 56 | tristate "Cobalt button interface" |
45 | depends on MIPS_COBALT | 57 | depends on MIPS_COBALT |
@@ -70,17 +82,79 @@ config INPUT_ATLAS_BTNS | |||
70 | To compile this driver as a module, choose M here: the module will | 82 | To compile this driver as a module, choose M here: the module will |
71 | be called atlas_btns. | 83 | be called atlas_btns. |
72 | 84 | ||
73 | config INPUT_IXP4XX_BEEPER | 85 | config INPUT_ATI_REMOTE |
74 | tristate "IXP4XX Beeper support" | 86 | tristate "ATI / X10 USB RF remote control" |
75 | depends on ARCH_IXP4XX | 87 | select USB |
76 | help | 88 | help |
77 | If you say yes here, you can connect a beeper to the | 89 | Say Y here if you want to use an ATI or X10 "Lola" USB remote control. |
78 | ixp4xx gpio pins. This is used by the LinkSys NSLU2. | 90 | These are RF remotes with USB receivers. |
91 | The ATI remote comes with many of ATI's All-In-Wonder video cards. | ||
92 | The X10 "Lola" remote is available at: | ||
93 | <http://www.x10.com/products/lola_sg1.htm> | ||
94 | This driver provides mouse pointer, left and right mouse buttons, | ||
95 | and maps all the other remote buttons to keypress events. | ||
96 | |||
97 | To compile this driver as a module, choose M here: the module will be | ||
98 | called ati_remote. | ||
99 | |||
100 | config INPUT_ATI_REMOTE2 | ||
101 | tristate "ATI / Philips USB RF remote control" | ||
102 | select USB | ||
103 | help | ||
104 | Say Y here if you want to use an ATI or Philips USB RF remote control. | ||
105 | These are RF remotes with USB receivers. | ||
106 | ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards | ||
107 | and is also available as a separate product. | ||
108 | This driver provides mouse pointer, left and right mouse buttons, | ||
109 | and maps all the other remote buttons to keypress events. | ||
110 | |||
111 | To compile this driver as a module, choose M here: the module will be | ||
112 | called ati_remote2. | ||
113 | |||
114 | config INPUT_KEYSPAN_REMOTE | ||
115 | tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" | ||
116 | depends on EXPERIMENTAL | ||
117 | select USB | ||
118 | help | ||
119 | Say Y here if you want to use a Keyspan DMR USB remote control. | ||
120 | Currently only the UIA-11 type of receiver has been tested. The tag | ||
121 | on the receiver that connects to the USB port should have a P/N that | ||
122 | will tell you what type of DMR you have. The UIA-10 type is not | ||
123 | supported at this time. This driver maps all buttons to keypress | ||
124 | events. | ||
79 | 125 | ||
80 | If unsure, say Y. | 126 | To compile this driver as a module, choose M here: the module will |
127 | be called keyspan_remote. | ||
128 | |||
129 | config INPUT_POWERMATE | ||
130 | tristate "Griffin PowerMate and Contour Jog support" | ||
131 | select USB | ||
132 | help | ||
133 | Say Y here if you want to use Griffin PowerMate or Contour Jog devices. | ||
134 | These are aluminum dials which can measure clockwise and anticlockwise | ||
135 | rotation. The dial also acts as a pushbutton. The base contains an LED | ||
136 | which can be instructed to pulse or to switch to a particular intensity. | ||
137 | |||
138 | You can download userspace tools from | ||
139 | <http://sowerbutts.com/powermate/>. | ||
81 | 140 | ||
82 | To compile this driver as a module, choose M here: the | 141 | To compile this driver as a module, choose M here: the |
83 | module will be called ixp4xx-beeper. | 142 | module will be called powermate. |
143 | |||
144 | config INPUT_YEALINK | ||
145 | tristate "Yealink usb-p1k voip phone" | ||
146 | depends EXPERIMENTAL | ||
147 | select USB | ||
148 | help | ||
149 | Say Y here if you want to enable keyboard and LCD functions of the | ||
150 | Yealink usb-p1k usb phones. The audio part is enabled by the generic | ||
151 | usb sound driver, so you might want to enable that as well. | ||
152 | |||
153 | For information about how to use these additional functions, see | ||
154 | <file:Documentation/input/yealink.txt>. | ||
155 | |||
156 | To compile this driver as a module, choose M here: the module will be | ||
157 | called yealink. | ||
84 | 158 | ||
85 | config INPUT_UINPUT | 159 | config INPUT_UINPUT |
86 | tristate "User level driver support" | 160 | tristate "User level driver support" |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 21e3cca0d33e..8b2f7799e25c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -8,9 +8,14 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o | |||
8 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o | 8 | obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o |
9 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o | 9 | obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o |
10 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 10 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
11 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o | 11 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
12 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | 12 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
13 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | 13 | obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o |
14 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | 14 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
15 | obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o | ||
16 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | ||
17 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | ||
18 | obj-$(CONFIG_INPUT_POWERMATE) += powermate.o | ||
19 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o | ||
15 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 20 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
16 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 21 | obj-$(CONFIG_INPUT_UINPUT) += uinput.o |
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c new file mode 100644 index 000000000000..471aab206443 --- /dev/null +++ b/drivers/input/misc/ati_remote.c | |||
@@ -0,0 +1,862 @@ | |||
1 | /* | ||
2 | * USB ATI Remote support | ||
3 | * | ||
4 | * Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net> | ||
5 | * Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev | ||
6 | * | ||
7 | * This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including | ||
8 | * porting to the 2.6 kernel interfaces, along with other modification | ||
9 | * to better match the style of the existing usb/input drivers. However, the | ||
10 | * protocol and hardware handling is essentially unchanged from 2.1.1. | ||
11 | * | ||
12 | * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by | ||
13 | * Vojtech Pavlik. | ||
14 | * | ||
15 | * Changes: | ||
16 | * | ||
17 | * Feb 2004: Torrey Hoffman <thoffman@arnor.net> | ||
18 | * Version 2.2.0 | ||
19 | * Jun 2004: Torrey Hoffman <thoffman@arnor.net> | ||
20 | * Version 2.2.1 | ||
21 | * Added key repeat support contributed by: | ||
22 | * Vincent Vanackere <vanackere@lif.univ-mrs.fr> | ||
23 | * Added support for the "Lola" remote contributed by: | ||
24 | * Seth Cohn <sethcohn@yahoo.com> | ||
25 | * | ||
26 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
27 | * | ||
28 | * This program is free software; you can redistribute it and/or modify | ||
29 | * it under the terms of the GNU General Public License as published by | ||
30 | * the Free Software Foundation; either version 2 of the License, or | ||
31 | * (at your option) any later version. | ||
32 | * | ||
33 | * This program is distributed in the hope that it will be useful, | ||
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
36 | * GNU General Public License for more details. | ||
37 | * | ||
38 | * You should have received a copy of the GNU General Public License | ||
39 | * along with this program; if not, write to the Free Software | ||
40 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
41 | * | ||
42 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
43 | * | ||
44 | * Hardware & software notes | ||
45 | * | ||
46 | * These remote controls are distributed by ATI as part of their | ||
47 | * "All-In-Wonder" video card packages. The receiver self-identifies as a | ||
48 | * "USB Receiver" with manufacturer "X10 Wireless Technology Inc". | ||
49 | * | ||
50 | * The "Lola" remote is available from X10. See: | ||
51 | * http://www.x10.com/products/lola_sg1.htm | ||
52 | * The Lola is similar to the ATI remote but has no mouse support, and slightly | ||
53 | * different keys. | ||
54 | * | ||
55 | * It is possible to use multiple receivers and remotes on multiple computers | ||
56 | * simultaneously by configuring them to use specific channels. | ||
57 | * | ||
58 | * The RF protocol used by the remote supports 16 distinct channels, 1 to 16. | ||
59 | * Actually, it may even support more, at least in some revisions of the | ||
60 | * hardware. | ||
61 | * | ||
62 | * Each remote can be configured to transmit on one channel as follows: | ||
63 | * - Press and hold the "hand icon" button. | ||
64 | * - When the red LED starts to blink, let go of the "hand icon" button. | ||
65 | * - When it stops blinking, input the channel code as two digits, from 01 | ||
66 | * to 16, and press the hand icon again. | ||
67 | * | ||
68 | * The timing can be a little tricky. Try loading the module with debug=1 | ||
69 | * to have the kernel print out messages about the remote control number | ||
70 | * and mask. Note: debugging prints remote numbers as zero-based hexadecimal. | ||
71 | * | ||
72 | * The driver has a "channel_mask" parameter. This bitmask specifies which | ||
73 | * channels will be ignored by the module. To mask out channels, just add | ||
74 | * all the 2^channel_number values together. | ||
75 | * | ||
76 | * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote | ||
77 | * ignore signals coming from remote controls transmitting on channel 4, but | ||
78 | * accept all other channels. | ||
79 | * | ||
80 | * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be | ||
81 | * ignored. | ||
82 | * | ||
83 | * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this | ||
84 | * parameter are unused. | ||
85 | * | ||
86 | */ | ||
87 | |||
88 | #include <linux/kernel.h> | ||
89 | #include <linux/errno.h> | ||
90 | #include <linux/init.h> | ||
91 | #include <linux/slab.h> | ||
92 | #include <linux/module.h> | ||
93 | #include <linux/moduleparam.h> | ||
94 | #include <linux/usb/input.h> | ||
95 | #include <linux/wait.h> | ||
96 | #include <linux/jiffies.h> | ||
97 | |||
98 | /* | ||
99 | * Module and Version Information, Module Parameters | ||
100 | */ | ||
101 | |||
102 | #define ATI_REMOTE_VENDOR_ID 0x0bc7 | ||
103 | #define ATI_REMOTE_PRODUCT_ID 0x004 | ||
104 | #define LOLA_REMOTE_PRODUCT_ID 0x002 | ||
105 | #define MEDION_REMOTE_PRODUCT_ID 0x006 | ||
106 | |||
107 | #define DRIVER_VERSION "2.2.1" | ||
108 | #define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>" | ||
109 | #define DRIVER_DESC "ATI/X10 RF USB Remote Control" | ||
110 | |||
111 | #define NAME_BUFSIZE 80 /* size of product name, path buffers */ | ||
112 | #define DATA_BUFSIZE 63 /* size of URB data buffers */ | ||
113 | |||
114 | /* | ||
115 | * Duplicate event filtering time. | ||
116 | * Sequential, identical KIND_FILTERED inputs with less than | ||
117 | * FILTER_TIME milliseconds between them are considered as repeat | ||
118 | * events. The hardware generates 5 events for the first keypress | ||
119 | * and we have to take this into account for an accurate repeat | ||
120 | * behaviour. | ||
121 | */ | ||
122 | #define FILTER_TIME 60 /* msec */ | ||
123 | #define REPEAT_DELAY 500 /* msec */ | ||
124 | |||
125 | static unsigned long channel_mask; | ||
126 | module_param(channel_mask, ulong, 0644); | ||
127 | MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); | ||
128 | |||
129 | static int debug; | ||
130 | module_param(debug, int, 0644); | ||
131 | MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); | ||
132 | |||
133 | static int repeat_filter = FILTER_TIME; | ||
134 | module_param(repeat_filter, int, 0644); | ||
135 | MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec"); | ||
136 | |||
137 | static int repeat_delay = REPEAT_DELAY; | ||
138 | module_param(repeat_delay, int, 0644); | ||
139 | MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec"); | ||
140 | |||
141 | #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) | ||
142 | #undef err | ||
143 | #define err(format, arg...) printk(KERN_ERR format , ## arg) | ||
144 | |||
145 | static struct usb_device_id ati_remote_table[] = { | ||
146 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, | ||
147 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, | ||
148 | { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, | ||
149 | {} /* Terminating entry */ | ||
150 | }; | ||
151 | |||
152 | MODULE_DEVICE_TABLE(usb, ati_remote_table); | ||
153 | |||
154 | /* Get hi and low bytes of a 16-bits int */ | ||
155 | #define HI(a) ((unsigned char)((a) >> 8)) | ||
156 | #define LO(a) ((unsigned char)((a) & 0xff)) | ||
157 | |||
158 | #define SEND_FLAG_IN_PROGRESS 1 | ||
159 | #define SEND_FLAG_COMPLETE 2 | ||
160 | |||
161 | /* Device initialization strings */ | ||
162 | static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; | ||
163 | static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; | ||
164 | |||
165 | struct ati_remote { | ||
166 | struct input_dev *idev; | ||
167 | struct usb_device *udev; | ||
168 | struct usb_interface *interface; | ||
169 | |||
170 | struct urb *irq_urb; | ||
171 | struct urb *out_urb; | ||
172 | struct usb_endpoint_descriptor *endpoint_in; | ||
173 | struct usb_endpoint_descriptor *endpoint_out; | ||
174 | unsigned char *inbuf; | ||
175 | unsigned char *outbuf; | ||
176 | dma_addr_t inbuf_dma; | ||
177 | dma_addr_t outbuf_dma; | ||
178 | |||
179 | unsigned char old_data[2]; /* Detect duplicate events */ | ||
180 | unsigned long old_jiffies; | ||
181 | unsigned long acc_jiffies; /* handle acceleration */ | ||
182 | unsigned long first_jiffies; | ||
183 | |||
184 | unsigned int repeat_count; | ||
185 | |||
186 | char name[NAME_BUFSIZE]; | ||
187 | char phys[NAME_BUFSIZE]; | ||
188 | |||
189 | wait_queue_head_t wait; | ||
190 | int send_flags; | ||
191 | }; | ||
192 | |||
193 | /* "Kinds" of messages sent from the hardware to the driver. */ | ||
194 | #define KIND_END 0 | ||
195 | #define KIND_LITERAL 1 /* Simply pass to input system */ | ||
196 | #define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */ | ||
197 | #define KIND_LU 3 /* Directional keypad diagonals - left up, */ | ||
198 | #define KIND_RU 4 /* right up, */ | ||
199 | #define KIND_LD 5 /* left down, */ | ||
200 | #define KIND_RD 6 /* right down */ | ||
201 | #define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/ | ||
202 | |||
203 | /* Translation table from hardware messages to input events. */ | ||
204 | static const struct { | ||
205 | short kind; | ||
206 | unsigned char data1, data2; | ||
207 | int type; | ||
208 | unsigned int code; | ||
209 | int value; | ||
210 | } ati_remote_tbl[] = { | ||
211 | /* Directional control pad axes */ | ||
212 | {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ | ||
213 | {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ | ||
214 | {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ | ||
215 | {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ | ||
216 | /* Directional control pad diagonals */ | ||
217 | {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ | ||
218 | {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ | ||
219 | {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ | ||
220 | {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ | ||
221 | |||
222 | /* "Mouse button" buttons */ | ||
223 | {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ | ||
224 | {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ | ||
225 | {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ | ||
226 | {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ | ||
227 | |||
228 | /* Artificial "doubleclick" events are generated by the hardware. | ||
229 | * They are mapped to the "side" and "extra" mouse buttons here. */ | ||
230 | {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ | ||
231 | {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ | ||
232 | |||
233 | /* keyboard. */ | ||
234 | {KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1}, | ||
235 | {KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1}, | ||
236 | {KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1}, | ||
237 | {KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1}, | ||
238 | {KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1}, | ||
239 | {KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1}, | ||
240 | {KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1}, | ||
241 | {KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1}, | ||
242 | {KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1}, | ||
243 | {KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1}, | ||
244 | {KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1}, | ||
245 | {KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1}, | ||
246 | {KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1}, | ||
247 | {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1}, | ||
248 | {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1}, | ||
249 | {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, | ||
250 | |||
251 | /* "special" keys */ | ||
252 | {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1}, /* "check" */ | ||
253 | {KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1}, /* "menu" */ | ||
254 | {KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1}, /* Power */ | ||
255 | {KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1}, /* TV */ | ||
256 | {KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1}, /* DVD */ | ||
257 | {KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* WEB */ | ||
258 | {KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* "book" */ | ||
259 | {KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1}, /* "hand" */ | ||
260 | {KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1}, /* "timer" */ | ||
261 | {KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1}, /* "max" */ | ||
262 | {KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* left */ | ||
263 | {KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* right */ | ||
264 | {KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* down */ | ||
265 | {KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* up */ | ||
266 | {KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1}, /* "OK" */ | ||
267 | {KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */ | ||
268 | {KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1}, /* VOL - */ | ||
269 | {KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1}, /* MUTE */ | ||
270 | {KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1}, /* CH + */ | ||
271 | {KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */ | ||
272 | {KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1}, /* ( o) red */ | ||
273 | {KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */ | ||
274 | {KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */ | ||
275 | {KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */ | ||
276 | {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */ | ||
277 | {KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */ | ||
278 | {KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */ | ||
279 | {KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */ | ||
280 | {KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */ | ||
281 | {KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */ | ||
282 | {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */ | ||
283 | {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */ | ||
284 | |||
285 | {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} | ||
286 | }; | ||
287 | |||
288 | /* Local function prototypes */ | ||
289 | static void ati_remote_dump (unsigned char *data, unsigned int actual_length); | ||
290 | static int ati_remote_open (struct input_dev *inputdev); | ||
291 | static void ati_remote_close (struct input_dev *inputdev); | ||
292 | static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data); | ||
293 | static void ati_remote_irq_out (struct urb *urb); | ||
294 | static void ati_remote_irq_in (struct urb *urb); | ||
295 | static void ati_remote_input_report (struct urb *urb); | ||
296 | static int ati_remote_initialize (struct ati_remote *ati_remote); | ||
297 | static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id); | ||
298 | static void ati_remote_disconnect (struct usb_interface *interface); | ||
299 | |||
300 | /* usb specific object to register with the usb subsystem */ | ||
301 | static struct usb_driver ati_remote_driver = { | ||
302 | .name = "ati_remote", | ||
303 | .probe = ati_remote_probe, | ||
304 | .disconnect = ati_remote_disconnect, | ||
305 | .id_table = ati_remote_table, | ||
306 | }; | ||
307 | |||
308 | /* | ||
309 | * ati_remote_dump_input | ||
310 | */ | ||
311 | static void ati_remote_dump(unsigned char *data, unsigned int len) | ||
312 | { | ||
313 | if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) | ||
314 | warn("Weird byte 0x%02x", data[0]); | ||
315 | else if (len == 4) | ||
316 | warn("Weird key %02x %02x %02x %02x", | ||
317 | data[0], data[1], data[2], data[3]); | ||
318 | else | ||
319 | warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", | ||
320 | len, data[0], data[1], data[2], data[3], data[4], data[5]); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * ati_remote_open | ||
325 | */ | ||
326 | static int ati_remote_open(struct input_dev *inputdev) | ||
327 | { | ||
328 | struct ati_remote *ati_remote = input_get_drvdata(inputdev); | ||
329 | |||
330 | /* On first open, submit the read urb which was set up previously. */ | ||
331 | ati_remote->irq_urb->dev = ati_remote->udev; | ||
332 | if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) { | ||
333 | dev_err(&ati_remote->interface->dev, | ||
334 | "%s: usb_submit_urb failed!\n", __FUNCTION__); | ||
335 | return -EIO; | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * ati_remote_close | ||
343 | */ | ||
344 | static void ati_remote_close(struct input_dev *inputdev) | ||
345 | { | ||
346 | struct ati_remote *ati_remote = input_get_drvdata(inputdev); | ||
347 | |||
348 | usb_kill_urb(ati_remote->irq_urb); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * ati_remote_irq_out | ||
353 | */ | ||
354 | static void ati_remote_irq_out(struct urb *urb) | ||
355 | { | ||
356 | struct ati_remote *ati_remote = urb->context; | ||
357 | |||
358 | if (urb->status) { | ||
359 | dev_dbg(&ati_remote->interface->dev, "%s: status %d\n", | ||
360 | __FUNCTION__, urb->status); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | ati_remote->send_flags |= SEND_FLAG_COMPLETE; | ||
365 | wmb(); | ||
366 | wake_up(&ati_remote->wait); | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * ati_remote_sendpacket | ||
371 | * | ||
372 | * Used to send device initialization strings | ||
373 | */ | ||
374 | static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data) | ||
375 | { | ||
376 | int retval = 0; | ||
377 | |||
378 | /* Set up out_urb */ | ||
379 | memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd)); | ||
380 | ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd); | ||
381 | |||
382 | ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1; | ||
383 | ati_remote->out_urb->dev = ati_remote->udev; | ||
384 | ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; | ||
385 | |||
386 | retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); | ||
387 | if (retval) { | ||
388 | dev_dbg(&ati_remote->interface->dev, | ||
389 | "sendpacket: usb_submit_urb failed: %d\n", retval); | ||
390 | return retval; | ||
391 | } | ||
392 | |||
393 | wait_event_timeout(ati_remote->wait, | ||
394 | ((ati_remote->out_urb->status != -EINPROGRESS) || | ||
395 | (ati_remote->send_flags & SEND_FLAG_COMPLETE)), | ||
396 | HZ); | ||
397 | usb_kill_urb(ati_remote->out_urb); | ||
398 | |||
399 | return retval; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * ati_remote_event_lookup | ||
404 | */ | ||
405 | static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) | ||
406 | { | ||
407 | int i; | ||
408 | |||
409 | for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { | ||
410 | /* | ||
411 | * Decide if the table entry matches the remote input. | ||
412 | */ | ||
413 | if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) && | ||
414 | ((((ati_remote_tbl[i].data1 >> 4) - | ||
415 | (d1 >> 4) + rem) & 0x0f) == 0x0f) && | ||
416 | (ati_remote_tbl[i].data2 == d2)) | ||
417 | return i; | ||
418 | |||
419 | } | ||
420 | return -1; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * ati_remote_compute_accel | ||
425 | * | ||
426 | * Implements acceleration curve for directional control pad | ||
427 | * If elapsed time since last event is > 1/4 second, user "stopped", | ||
428 | * so reset acceleration. Otherwise, user is probably holding the control | ||
429 | * pad down, so we increase acceleration, ramping up over two seconds to | ||
430 | * a maximum speed. | ||
431 | */ | ||
432 | static int ati_remote_compute_accel(struct ati_remote *ati_remote) | ||
433 | { | ||
434 | static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 }; | ||
435 | unsigned long now = jiffies; | ||
436 | int acc; | ||
437 | |||
438 | if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) { | ||
439 | acc = 1; | ||
440 | ati_remote->acc_jiffies = now; | ||
441 | } | ||
442 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125))) | ||
443 | acc = accel[0]; | ||
444 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250))) | ||
445 | acc = accel[1]; | ||
446 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500))) | ||
447 | acc = accel[2]; | ||
448 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000))) | ||
449 | acc = accel[3]; | ||
450 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500))) | ||
451 | acc = accel[4]; | ||
452 | else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000))) | ||
453 | acc = accel[5]; | ||
454 | else | ||
455 | acc = accel[6]; | ||
456 | |||
457 | return acc; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * ati_remote_report_input | ||
462 | */ | ||
463 | static void ati_remote_input_report(struct urb *urb) | ||
464 | { | ||
465 | struct ati_remote *ati_remote = urb->context; | ||
466 | unsigned char *data= ati_remote->inbuf; | ||
467 | struct input_dev *dev = ati_remote->idev; | ||
468 | int index, acc; | ||
469 | int remote_num; | ||
470 | |||
471 | /* Deal with strange looking inputs */ | ||
472 | if ( (urb->actual_length != 4) || (data[0] != 0x14) || | ||
473 | ((data[3] & 0x0f) != 0x00) ) { | ||
474 | ati_remote_dump(data, urb->actual_length); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | /* Mask unwanted remote channels. */ | ||
479 | /* note: remote_num is 0-based, channel 1 on remote == 0 here */ | ||
480 | remote_num = (data[3] >> 4) & 0x0f; | ||
481 | if (channel_mask & (1 << (remote_num + 1))) { | ||
482 | dbginfo(&ati_remote->interface->dev, | ||
483 | "Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n", | ||
484 | remote_num, data[1], data[2], channel_mask); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | /* Look up event code index in translation table */ | ||
489 | index = ati_remote_event_lookup(remote_num, data[1], data[2]); | ||
490 | if (index < 0) { | ||
491 | dev_warn(&ati_remote->interface->dev, | ||
492 | "Unknown input from channel 0x%02x: data %02x,%02x\n", | ||
493 | remote_num, data[1], data[2]); | ||
494 | return; | ||
495 | } | ||
496 | dbginfo(&ati_remote->interface->dev, | ||
497 | "channel 0x%02x; data %02x,%02x; index %d; keycode %d\n", | ||
498 | remote_num, data[1], data[2], index, ati_remote_tbl[index].code); | ||
499 | |||
500 | if (ati_remote_tbl[index].kind == KIND_LITERAL) { | ||
501 | input_event(dev, ati_remote_tbl[index].type, | ||
502 | ati_remote_tbl[index].code, | ||
503 | ati_remote_tbl[index].value); | ||
504 | input_sync(dev); | ||
505 | |||
506 | ati_remote->old_jiffies = jiffies; | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | if (ati_remote_tbl[index].kind == KIND_FILTERED) { | ||
511 | unsigned long now = jiffies; | ||
512 | |||
513 | /* Filter duplicate events which happen "too close" together. */ | ||
514 | if (ati_remote->old_data[0] == data[1] && | ||
515 | ati_remote->old_data[1] == data[2] && | ||
516 | time_before(now, ati_remote->old_jiffies + | ||
517 | msecs_to_jiffies(repeat_filter))) { | ||
518 | ati_remote->repeat_count++; | ||
519 | } else { | ||
520 | ati_remote->repeat_count = 0; | ||
521 | ati_remote->first_jiffies = now; | ||
522 | } | ||
523 | |||
524 | ati_remote->old_data[0] = data[1]; | ||
525 | ati_remote->old_data[1] = data[2]; | ||
526 | ati_remote->old_jiffies = now; | ||
527 | |||
528 | /* Ensure we skip at least the 4 first duplicate events (generated | ||
529 | * by a single keypress), and continue skipping until repeat_delay | ||
530 | * msecs have passed | ||
531 | */ | ||
532 | if (ati_remote->repeat_count > 0 && | ||
533 | (ati_remote->repeat_count < 5 || | ||
534 | time_before(now, ati_remote->first_jiffies + | ||
535 | msecs_to_jiffies(repeat_delay)))) | ||
536 | return; | ||
537 | |||
538 | |||
539 | input_event(dev, ati_remote_tbl[index].type, | ||
540 | ati_remote_tbl[index].code, 1); | ||
541 | input_sync(dev); | ||
542 | input_event(dev, ati_remote_tbl[index].type, | ||
543 | ati_remote_tbl[index].code, 0); | ||
544 | input_sync(dev); | ||
545 | |||
546 | } else { | ||
547 | |||
548 | /* | ||
549 | * Other event kinds are from the directional control pad, and have an | ||
550 | * acceleration factor applied to them. Without this acceleration, the | ||
551 | * control pad is mostly unusable. | ||
552 | */ | ||
553 | acc = ati_remote_compute_accel(ati_remote); | ||
554 | |||
555 | switch (ati_remote_tbl[index].kind) { | ||
556 | case KIND_ACCEL: | ||
557 | input_event(dev, ati_remote_tbl[index].type, | ||
558 | ati_remote_tbl[index].code, | ||
559 | ati_remote_tbl[index].value * acc); | ||
560 | break; | ||
561 | case KIND_LU: | ||
562 | input_report_rel(dev, REL_X, -acc); | ||
563 | input_report_rel(dev, REL_Y, -acc); | ||
564 | break; | ||
565 | case KIND_RU: | ||
566 | input_report_rel(dev, REL_X, acc); | ||
567 | input_report_rel(dev, REL_Y, -acc); | ||
568 | break; | ||
569 | case KIND_LD: | ||
570 | input_report_rel(dev, REL_X, -acc); | ||
571 | input_report_rel(dev, REL_Y, acc); | ||
572 | break; | ||
573 | case KIND_RD: | ||
574 | input_report_rel(dev, REL_X, acc); | ||
575 | input_report_rel(dev, REL_Y, acc); | ||
576 | break; | ||
577 | default: | ||
578 | dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", | ||
579 | ati_remote_tbl[index].kind); | ||
580 | } | ||
581 | input_sync(dev); | ||
582 | |||
583 | ati_remote->old_jiffies = jiffies; | ||
584 | ati_remote->old_data[0] = data[1]; | ||
585 | ati_remote->old_data[1] = data[2]; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * ati_remote_irq_in | ||
591 | */ | ||
592 | static void ati_remote_irq_in(struct urb *urb) | ||
593 | { | ||
594 | struct ati_remote *ati_remote = urb->context; | ||
595 | int retval; | ||
596 | |||
597 | switch (urb->status) { | ||
598 | case 0: /* success */ | ||
599 | ati_remote_input_report(urb); | ||
600 | break; | ||
601 | case -ECONNRESET: /* unlink */ | ||
602 | case -ENOENT: | ||
603 | case -ESHUTDOWN: | ||
604 | dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n", | ||
605 | __FUNCTION__); | ||
606 | return; | ||
607 | default: /* error */ | ||
608 | dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n", | ||
609 | __FUNCTION__, urb->status); | ||
610 | } | ||
611 | |||
612 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
613 | if (retval) | ||
614 | dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", | ||
615 | __FUNCTION__, retval); | ||
616 | } | ||
617 | |||
618 | /* | ||
619 | * ati_remote_alloc_buffers | ||
620 | */ | ||
621 | static int ati_remote_alloc_buffers(struct usb_device *udev, | ||
622 | struct ati_remote *ati_remote) | ||
623 | { | ||
624 | ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, | ||
625 | &ati_remote->inbuf_dma); | ||
626 | if (!ati_remote->inbuf) | ||
627 | return -1; | ||
628 | |||
629 | ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, | ||
630 | &ati_remote->outbuf_dma); | ||
631 | if (!ati_remote->outbuf) | ||
632 | return -1; | ||
633 | |||
634 | ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
635 | if (!ati_remote->irq_urb) | ||
636 | return -1; | ||
637 | |||
638 | ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
639 | if (!ati_remote->out_urb) | ||
640 | return -1; | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * ati_remote_free_buffers | ||
647 | */ | ||
648 | static void ati_remote_free_buffers(struct ati_remote *ati_remote) | ||
649 | { | ||
650 | usb_free_urb(ati_remote->irq_urb); | ||
651 | usb_free_urb(ati_remote->out_urb); | ||
652 | |||
653 | usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, | ||
654 | ati_remote->inbuf, ati_remote->inbuf_dma); | ||
655 | |||
656 | usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, | ||
657 | ati_remote->outbuf, ati_remote->outbuf_dma); | ||
658 | } | ||
659 | |||
660 | static void ati_remote_input_init(struct ati_remote *ati_remote) | ||
661 | { | ||
662 | struct input_dev *idev = ati_remote->idev; | ||
663 | int i; | ||
664 | |||
665 | idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
666 | idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) | | ||
667 | BIT(BTN_SIDE) | BIT(BTN_EXTRA) ); | ||
668 | idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
669 | for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) | ||
670 | if (ati_remote_tbl[i].type == EV_KEY) | ||
671 | set_bit(ati_remote_tbl[i].code, idev->keybit); | ||
672 | |||
673 | input_set_drvdata(idev, ati_remote); | ||
674 | |||
675 | idev->open = ati_remote_open; | ||
676 | idev->close = ati_remote_close; | ||
677 | |||
678 | idev->name = ati_remote->name; | ||
679 | idev->phys = ati_remote->phys; | ||
680 | |||
681 | usb_to_input_id(ati_remote->udev, &idev->id); | ||
682 | idev->dev.parent = &ati_remote->udev->dev; | ||
683 | } | ||
684 | |||
685 | static int ati_remote_initialize(struct ati_remote *ati_remote) | ||
686 | { | ||
687 | struct usb_device *udev = ati_remote->udev; | ||
688 | int pipe, maxp; | ||
689 | |||
690 | init_waitqueue_head(&ati_remote->wait); | ||
691 | |||
692 | /* Set up irq_urb */ | ||
693 | pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress); | ||
694 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
695 | maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; | ||
696 | |||
697 | usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf, | ||
698 | maxp, ati_remote_irq_in, ati_remote, | ||
699 | ati_remote->endpoint_in->bInterval); | ||
700 | ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma; | ||
701 | ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
702 | |||
703 | /* Set up out_urb */ | ||
704 | pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress); | ||
705 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
706 | maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp; | ||
707 | |||
708 | usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf, | ||
709 | maxp, ati_remote_irq_out, ati_remote, | ||
710 | ati_remote->endpoint_out->bInterval); | ||
711 | ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma; | ||
712 | ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
713 | |||
714 | /* send initialization strings */ | ||
715 | if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) || | ||
716 | (ati_remote_sendpacket(ati_remote, 0x8007, init2))) { | ||
717 | dev_err(&ati_remote->interface->dev, | ||
718 | "Initializing ati_remote hardware failed.\n"); | ||
719 | return -EIO; | ||
720 | } | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | /* | ||
726 | * ati_remote_probe | ||
727 | */ | ||
728 | static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id) | ||
729 | { | ||
730 | struct usb_device *udev = interface_to_usbdev(interface); | ||
731 | struct usb_host_interface *iface_host = interface->cur_altsetting; | ||
732 | struct usb_endpoint_descriptor *endpoint_in, *endpoint_out; | ||
733 | struct ati_remote *ati_remote; | ||
734 | struct input_dev *input_dev; | ||
735 | int err = -ENOMEM; | ||
736 | |||
737 | if (iface_host->desc.bNumEndpoints != 2) { | ||
738 | err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__); | ||
739 | return -ENODEV; | ||
740 | } | ||
741 | |||
742 | endpoint_in = &iface_host->endpoint[0].desc; | ||
743 | endpoint_out = &iface_host->endpoint[1].desc; | ||
744 | |||
745 | if (!usb_endpoint_is_int_in(endpoint_in)) { | ||
746 | err("%s: Unexpected endpoint_in\n", __FUNCTION__); | ||
747 | return -ENODEV; | ||
748 | } | ||
749 | if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { | ||
750 | err("%s: endpoint_in message size==0? \n", __FUNCTION__); | ||
751 | return -ENODEV; | ||
752 | } | ||
753 | |||
754 | ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); | ||
755 | input_dev = input_allocate_device(); | ||
756 | if (!ati_remote || !input_dev) | ||
757 | goto fail1; | ||
758 | |||
759 | /* Allocate URB buffers, URBs */ | ||
760 | if (ati_remote_alloc_buffers(udev, ati_remote)) | ||
761 | goto fail2; | ||
762 | |||
763 | ati_remote->endpoint_in = endpoint_in; | ||
764 | ati_remote->endpoint_out = endpoint_out; | ||
765 | ati_remote->udev = udev; | ||
766 | ati_remote->idev = input_dev; | ||
767 | ati_remote->interface = interface; | ||
768 | |||
769 | usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys)); | ||
770 | strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys)); | ||
771 | |||
772 | if (udev->manufacturer) | ||
773 | strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name)); | ||
774 | |||
775 | if (udev->product) | ||
776 | snprintf(ati_remote->name, sizeof(ati_remote->name), | ||
777 | "%s %s", ati_remote->name, udev->product); | ||
778 | |||
779 | if (!strlen(ati_remote->name)) | ||
780 | snprintf(ati_remote->name, sizeof(ati_remote->name), | ||
781 | DRIVER_DESC "(%04x,%04x)", | ||
782 | le16_to_cpu(ati_remote->udev->descriptor.idVendor), | ||
783 | le16_to_cpu(ati_remote->udev->descriptor.idProduct)); | ||
784 | |||
785 | ati_remote_input_init(ati_remote); | ||
786 | |||
787 | /* Device Hardware Initialization - fills in ati_remote->idev from udev. */ | ||
788 | err = ati_remote_initialize(ati_remote); | ||
789 | if (err) | ||
790 | goto fail3; | ||
791 | |||
792 | /* Set up and register input device */ | ||
793 | err = input_register_device(ati_remote->idev); | ||
794 | if (err) | ||
795 | goto fail3; | ||
796 | |||
797 | usb_set_intfdata(interface, ati_remote); | ||
798 | return 0; | ||
799 | |||
800 | fail3: usb_kill_urb(ati_remote->irq_urb); | ||
801 | usb_kill_urb(ati_remote->out_urb); | ||
802 | fail2: ati_remote_free_buffers(ati_remote); | ||
803 | fail1: input_free_device(input_dev); | ||
804 | kfree(ati_remote); | ||
805 | return err; | ||
806 | } | ||
807 | |||
808 | /* | ||
809 | * ati_remote_disconnect | ||
810 | */ | ||
811 | static void ati_remote_disconnect(struct usb_interface *interface) | ||
812 | { | ||
813 | struct ati_remote *ati_remote; | ||
814 | |||
815 | ati_remote = usb_get_intfdata(interface); | ||
816 | usb_set_intfdata(interface, NULL); | ||
817 | if (!ati_remote) { | ||
818 | warn("%s - null device?\n", __FUNCTION__); | ||
819 | return; | ||
820 | } | ||
821 | |||
822 | usb_kill_urb(ati_remote->irq_urb); | ||
823 | usb_kill_urb(ati_remote->out_urb); | ||
824 | input_unregister_device(ati_remote->idev); | ||
825 | ati_remote_free_buffers(ati_remote); | ||
826 | kfree(ati_remote); | ||
827 | } | ||
828 | |||
829 | /* | ||
830 | * ati_remote_init | ||
831 | */ | ||
832 | static int __init ati_remote_init(void) | ||
833 | { | ||
834 | int result; | ||
835 | |||
836 | result = usb_register(&ati_remote_driver); | ||
837 | if (result) | ||
838 | err("usb_register error #%d\n", result); | ||
839 | else | ||
840 | info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION); | ||
841 | |||
842 | return result; | ||
843 | } | ||
844 | |||
845 | /* | ||
846 | * ati_remote_exit | ||
847 | */ | ||
848 | static void __exit ati_remote_exit(void) | ||
849 | { | ||
850 | usb_deregister(&ati_remote_driver); | ||
851 | } | ||
852 | |||
853 | /* | ||
854 | * module specification | ||
855 | */ | ||
856 | |||
857 | module_init(ati_remote_init); | ||
858 | module_exit(ati_remote_exit); | ||
859 | |||
860 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
861 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
862 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c new file mode 100644 index 000000000000..1031543e5c3f --- /dev/null +++ b/drivers/input/misc/ati_remote2.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * ati_remote2 - ATI/Philips USB RF remote driver | ||
3 | * | ||
4 | * Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi> | ||
5 | * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk> | ||
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 version 2 | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/usb/input.h> | ||
13 | |||
14 | #define DRIVER_DESC "ATI/Philips USB RF remote driver" | ||
15 | #define DRIVER_VERSION "0.2" | ||
16 | |||
17 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
18 | MODULE_VERSION(DRIVER_VERSION); | ||
19 | MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | |||
22 | /* | ||
23 | * ATI Remote Wonder II Channel Configuration | ||
24 | * | ||
25 | * The remote control can by assigned one of sixteen "channels" in order to facilitate | ||
26 | * the use of multiple remote controls within range of each other. | ||
27 | * A remote's "channel" may be altered by pressing and holding the "PC" button for | ||
28 | * approximately 3 seconds, after which the button will slowly flash the count of the | ||
29 | * currently configured "channel", using the numeric keypad enter a number between 1 and | ||
30 | * 16 and then the "PC" button again, the button will slowly flash the count of the | ||
31 | * newly configured "channel". | ||
32 | */ | ||
33 | |||
34 | static unsigned int channel_mask = 0xFFFF; | ||
35 | module_param(channel_mask, uint, 0644); | ||
36 | MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>"); | ||
37 | |||
38 | static unsigned int mode_mask = 0x1F; | ||
39 | module_param(mode_mask, uint, 0644); | ||
40 | MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>"); | ||
41 | |||
42 | static struct usb_device_id ati_remote2_id_table[] = { | ||
43 | { USB_DEVICE(0x0471, 0x0602) }, /* ATI Remote Wonder II */ | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(usb, ati_remote2_id_table); | ||
47 | |||
48 | static struct { | ||
49 | int hw_code; | ||
50 | int key_code; | ||
51 | } ati_remote2_key_table[] = { | ||
52 | { 0x00, KEY_0 }, | ||
53 | { 0x01, KEY_1 }, | ||
54 | { 0x02, KEY_2 }, | ||
55 | { 0x03, KEY_3 }, | ||
56 | { 0x04, KEY_4 }, | ||
57 | { 0x05, KEY_5 }, | ||
58 | { 0x06, KEY_6 }, | ||
59 | { 0x07, KEY_7 }, | ||
60 | { 0x08, KEY_8 }, | ||
61 | { 0x09, KEY_9 }, | ||
62 | { 0x0c, KEY_POWER }, | ||
63 | { 0x0d, KEY_MUTE }, | ||
64 | { 0x10, KEY_VOLUMEUP }, | ||
65 | { 0x11, KEY_VOLUMEDOWN }, | ||
66 | { 0x20, KEY_CHANNELUP }, | ||
67 | { 0x21, KEY_CHANNELDOWN }, | ||
68 | { 0x28, KEY_FORWARD }, | ||
69 | { 0x29, KEY_REWIND }, | ||
70 | { 0x2c, KEY_PLAY }, | ||
71 | { 0x30, KEY_PAUSE }, | ||
72 | { 0x31, KEY_STOP }, | ||
73 | { 0x37, KEY_RECORD }, | ||
74 | { 0x38, KEY_DVD }, | ||
75 | { 0x39, KEY_TV }, | ||
76 | { 0x54, KEY_MENU }, | ||
77 | { 0x58, KEY_UP }, | ||
78 | { 0x59, KEY_DOWN }, | ||
79 | { 0x5a, KEY_LEFT }, | ||
80 | { 0x5b, KEY_RIGHT }, | ||
81 | { 0x5c, KEY_OK }, | ||
82 | { 0x78, KEY_A }, | ||
83 | { 0x79, KEY_B }, | ||
84 | { 0x7a, KEY_C }, | ||
85 | { 0x7b, KEY_D }, | ||
86 | { 0x7c, KEY_E }, | ||
87 | { 0x7d, KEY_F }, | ||
88 | { 0x82, KEY_ENTER }, | ||
89 | { 0x8e, KEY_VENDOR }, | ||
90 | { 0x96, KEY_COFFEE }, | ||
91 | { 0xa9, BTN_LEFT }, | ||
92 | { 0xaa, BTN_RIGHT }, | ||
93 | { 0xbe, KEY_QUESTION }, | ||
94 | { 0xd5, KEY_FRONT }, | ||
95 | { 0xd0, KEY_EDIT }, | ||
96 | { 0xf9, KEY_INFO }, | ||
97 | { (0x00 << 8) | 0x3f, KEY_PROG1 }, | ||
98 | { (0x01 << 8) | 0x3f, KEY_PROG2 }, | ||
99 | { (0x02 << 8) | 0x3f, KEY_PROG3 }, | ||
100 | { (0x03 << 8) | 0x3f, KEY_PROG4 }, | ||
101 | { (0x04 << 8) | 0x3f, KEY_PC }, | ||
102 | { 0, KEY_RESERVED } | ||
103 | }; | ||
104 | |||
105 | struct ati_remote2 { | ||
106 | struct input_dev *idev; | ||
107 | struct usb_device *udev; | ||
108 | |||
109 | struct usb_interface *intf[2]; | ||
110 | struct usb_endpoint_descriptor *ep[2]; | ||
111 | struct urb *urb[2]; | ||
112 | void *buf[2]; | ||
113 | dma_addr_t buf_dma[2]; | ||
114 | |||
115 | unsigned long jiffies; | ||
116 | int mode; | ||
117 | |||
118 | char name[64]; | ||
119 | char phys[64]; | ||
120 | }; | ||
121 | |||
122 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id); | ||
123 | static void ati_remote2_disconnect(struct usb_interface *interface); | ||
124 | |||
125 | static struct usb_driver ati_remote2_driver = { | ||
126 | .name = "ati_remote2", | ||
127 | .probe = ati_remote2_probe, | ||
128 | .disconnect = ati_remote2_disconnect, | ||
129 | .id_table = ati_remote2_id_table, | ||
130 | }; | ||
131 | |||
132 | static int ati_remote2_open(struct input_dev *idev) | ||
133 | { | ||
134 | struct ati_remote2 *ar2 = input_get_drvdata(idev); | ||
135 | int r; | ||
136 | |||
137 | r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); | ||
138 | if (r) { | ||
139 | dev_err(&ar2->intf[0]->dev, | ||
140 | "%s: usb_submit_urb() = %d\n", __FUNCTION__, r); | ||
141 | return r; | ||
142 | } | ||
143 | r = usb_submit_urb(ar2->urb[1], GFP_KERNEL); | ||
144 | if (r) { | ||
145 | usb_kill_urb(ar2->urb[0]); | ||
146 | dev_err(&ar2->intf[1]->dev, | ||
147 | "%s: usb_submit_urb() = %d\n", __FUNCTION__, r); | ||
148 | return r; | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static void ati_remote2_close(struct input_dev *idev) | ||
155 | { | ||
156 | struct ati_remote2 *ar2 = input_get_drvdata(idev); | ||
157 | |||
158 | usb_kill_urb(ar2->urb[0]); | ||
159 | usb_kill_urb(ar2->urb[1]); | ||
160 | } | ||
161 | |||
162 | static void ati_remote2_input_mouse(struct ati_remote2 *ar2) | ||
163 | { | ||
164 | struct input_dev *idev = ar2->idev; | ||
165 | u8 *data = ar2->buf[0]; | ||
166 | int channel, mode; | ||
167 | |||
168 | channel = data[0] >> 4; | ||
169 | |||
170 | if (!((1 << channel) & channel_mask)) | ||
171 | return; | ||
172 | |||
173 | mode = data[0] & 0x0F; | ||
174 | |||
175 | if (mode > 4) { | ||
176 | dev_err(&ar2->intf[0]->dev, | ||
177 | "Unknown mode byte (%02x %02x %02x %02x)\n", | ||
178 | data[3], data[2], data[1], data[0]); | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | if (!((1 << mode) & mode_mask)) | ||
183 | return; | ||
184 | |||
185 | input_event(idev, EV_REL, REL_X, (s8) data[1]); | ||
186 | input_event(idev, EV_REL, REL_Y, (s8) data[2]); | ||
187 | input_sync(idev); | ||
188 | } | ||
189 | |||
190 | static int ati_remote2_lookup(unsigned int hw_code) | ||
191 | { | ||
192 | int i; | ||
193 | |||
194 | for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++) | ||
195 | if (ati_remote2_key_table[i].hw_code == hw_code) | ||
196 | return i; | ||
197 | |||
198 | return -1; | ||
199 | } | ||
200 | |||
201 | static void ati_remote2_input_key(struct ati_remote2 *ar2) | ||
202 | { | ||
203 | struct input_dev *idev = ar2->idev; | ||
204 | u8 *data = ar2->buf[1]; | ||
205 | int channel, mode, hw_code, index; | ||
206 | |||
207 | channel = data[0] >> 4; | ||
208 | |||
209 | if (!((1 << channel) & channel_mask)) | ||
210 | return; | ||
211 | |||
212 | mode = data[0] & 0x0F; | ||
213 | |||
214 | if (mode > 4) { | ||
215 | dev_err(&ar2->intf[1]->dev, | ||
216 | "Unknown mode byte (%02x %02x %02x %02x)\n", | ||
217 | data[3], data[2], data[1], data[0]); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | hw_code = data[2]; | ||
222 | /* | ||
223 | * Mode keys (AUX1-AUX4, PC) all generate the same code byte. | ||
224 | * Use the mode byte to figure out which one was pressed. | ||
225 | */ | ||
226 | if (hw_code == 0x3f) { | ||
227 | /* | ||
228 | * For some incomprehensible reason the mouse pad generates | ||
229 | * events which look identical to the events from the last | ||
230 | * pressed mode key. Naturally we don't want to generate key | ||
231 | * events for the mouse pad so we filter out any subsequent | ||
232 | * events from the same mode key. | ||
233 | */ | ||
234 | if (ar2->mode == mode) | ||
235 | return; | ||
236 | |||
237 | if (data[1] == 0) | ||
238 | ar2->mode = mode; | ||
239 | |||
240 | hw_code |= mode << 8; | ||
241 | } | ||
242 | |||
243 | if (!((1 << mode) & mode_mask)) | ||
244 | return; | ||
245 | |||
246 | index = ati_remote2_lookup(hw_code); | ||
247 | if (index < 0) { | ||
248 | dev_err(&ar2->intf[1]->dev, | ||
249 | "Unknown code byte (%02x %02x %02x %02x)\n", | ||
250 | data[3], data[2], data[1], data[0]); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | switch (data[1]) { | ||
255 | case 0: /* release */ | ||
256 | break; | ||
257 | case 1: /* press */ | ||
258 | ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]); | ||
259 | break; | ||
260 | case 2: /* repeat */ | ||
261 | |||
262 | /* No repeat for mouse buttons. */ | ||
263 | if (ati_remote2_key_table[index].key_code == BTN_LEFT || | ||
264 | ati_remote2_key_table[index].key_code == BTN_RIGHT) | ||
265 | return; | ||
266 | |||
267 | if (!time_after_eq(jiffies, ar2->jiffies)) | ||
268 | return; | ||
269 | |||
270 | ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]); | ||
271 | break; | ||
272 | default: | ||
273 | dev_err(&ar2->intf[1]->dev, | ||
274 | "Unknown state byte (%02x %02x %02x %02x)\n", | ||
275 | data[3], data[2], data[1], data[0]); | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]); | ||
280 | input_sync(idev); | ||
281 | } | ||
282 | |||
283 | static void ati_remote2_complete_mouse(struct urb *urb) | ||
284 | { | ||
285 | struct ati_remote2 *ar2 = urb->context; | ||
286 | int r; | ||
287 | |||
288 | switch (urb->status) { | ||
289 | case 0: | ||
290 | ati_remote2_input_mouse(ar2); | ||
291 | break; | ||
292 | case -ENOENT: | ||
293 | case -EILSEQ: | ||
294 | case -ECONNRESET: | ||
295 | case -ESHUTDOWN: | ||
296 | dev_dbg(&ar2->intf[0]->dev, | ||
297 | "%s(): urb status = %d\n", __FUNCTION__, urb->status); | ||
298 | return; | ||
299 | default: | ||
300 | dev_err(&ar2->intf[0]->dev, | ||
301 | "%s(): urb status = %d\n", __FUNCTION__, urb->status); | ||
302 | } | ||
303 | |||
304 | r = usb_submit_urb(urb, GFP_ATOMIC); | ||
305 | if (r) | ||
306 | dev_err(&ar2->intf[0]->dev, | ||
307 | "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r); | ||
308 | } | ||
309 | |||
310 | static void ati_remote2_complete_key(struct urb *urb) | ||
311 | { | ||
312 | struct ati_remote2 *ar2 = urb->context; | ||
313 | int r; | ||
314 | |||
315 | switch (urb->status) { | ||
316 | case 0: | ||
317 | ati_remote2_input_key(ar2); | ||
318 | break; | ||
319 | case -ENOENT: | ||
320 | case -EILSEQ: | ||
321 | case -ECONNRESET: | ||
322 | case -ESHUTDOWN: | ||
323 | dev_dbg(&ar2->intf[1]->dev, | ||
324 | "%s(): urb status = %d\n", __FUNCTION__, urb->status); | ||
325 | return; | ||
326 | default: | ||
327 | dev_err(&ar2->intf[1]->dev, | ||
328 | "%s(): urb status = %d\n", __FUNCTION__, urb->status); | ||
329 | } | ||
330 | |||
331 | r = usb_submit_urb(urb, GFP_ATOMIC); | ||
332 | if (r) | ||
333 | dev_err(&ar2->intf[1]->dev, | ||
334 | "%s(): usb_submit_urb() = %d\n", __FUNCTION__, r); | ||
335 | } | ||
336 | |||
337 | static int ati_remote2_input_init(struct ati_remote2 *ar2) | ||
338 | { | ||
339 | struct input_dev *idev; | ||
340 | int i, retval; | ||
341 | |||
342 | idev = input_allocate_device(); | ||
343 | if (!idev) | ||
344 | return -ENOMEM; | ||
345 | |||
346 | ar2->idev = idev; | ||
347 | input_set_drvdata(idev, ar2); | ||
348 | |||
349 | idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL); | ||
350 | idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); | ||
351 | idev->relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
352 | for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++) | ||
353 | set_bit(ati_remote2_key_table[i].key_code, idev->keybit); | ||
354 | |||
355 | idev->rep[REP_DELAY] = 250; | ||
356 | idev->rep[REP_PERIOD] = 33; | ||
357 | |||
358 | idev->open = ati_remote2_open; | ||
359 | idev->close = ati_remote2_close; | ||
360 | |||
361 | idev->name = ar2->name; | ||
362 | idev->phys = ar2->phys; | ||
363 | |||
364 | usb_to_input_id(ar2->udev, &idev->id); | ||
365 | idev->dev.parent = &ar2->udev->dev; | ||
366 | |||
367 | retval = input_register_device(idev); | ||
368 | if (retval) | ||
369 | input_free_device(idev); | ||
370 | |||
371 | return retval; | ||
372 | } | ||
373 | |||
374 | static int ati_remote2_urb_init(struct ati_remote2 *ar2) | ||
375 | { | ||
376 | struct usb_device *udev = ar2->udev; | ||
377 | int i, pipe, maxp; | ||
378 | |||
379 | for (i = 0; i < 2; i++) { | ||
380 | ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]); | ||
381 | if (!ar2->buf[i]) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL); | ||
385 | if (!ar2->urb[i]) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress); | ||
389 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
390 | maxp = maxp > 4 ? 4 : maxp; | ||
391 | |||
392 | usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp, | ||
393 | i ? ati_remote2_complete_key : ati_remote2_complete_mouse, | ||
394 | ar2, ar2->ep[i]->bInterval); | ||
395 | ar2->urb[i]->transfer_dma = ar2->buf_dma[i]; | ||
396 | ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
397 | } | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2) | ||
403 | { | ||
404 | int i; | ||
405 | |||
406 | for (i = 0; i < 2; i++) { | ||
407 | usb_free_urb(ar2->urb[i]); | ||
408 | usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | static int ati_remote2_setup(struct ati_remote2 *ar2) | ||
413 | { | ||
414 | int r, i, channel; | ||
415 | |||
416 | /* | ||
417 | * Configure receiver to only accept input from remote "channel" | ||
418 | * channel == 0 -> Accept input from any remote channel | ||
419 | * channel == 1 -> Only accept input from remote channel 1 | ||
420 | * channel == 2 -> Only accept input from remote channel 2 | ||
421 | * ... | ||
422 | * channel == 16 -> Only accept input from remote channel 16 | ||
423 | */ | ||
424 | |||
425 | channel = 0; | ||
426 | for (i = 0; i < 16; i++) { | ||
427 | if ((1 << i) & channel_mask) { | ||
428 | if (!(~(1 << i) & 0xFFFF & channel_mask)) | ||
429 | channel = i + 1; | ||
430 | break; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0), | ||
435 | 0x20, | ||
436 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, | ||
437 | channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
438 | if (r) { | ||
439 | dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n", | ||
440 | __FUNCTION__, r); | ||
441 | return r; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id) | ||
448 | { | ||
449 | struct usb_device *udev = interface_to_usbdev(interface); | ||
450 | struct usb_host_interface *alt = interface->cur_altsetting; | ||
451 | struct ati_remote2 *ar2; | ||
452 | int r; | ||
453 | |||
454 | if (alt->desc.bInterfaceNumber) | ||
455 | return -ENODEV; | ||
456 | |||
457 | ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL); | ||
458 | if (!ar2) | ||
459 | return -ENOMEM; | ||
460 | |||
461 | ar2->udev = udev; | ||
462 | |||
463 | ar2->intf[0] = interface; | ||
464 | ar2->ep[0] = &alt->endpoint[0].desc; | ||
465 | |||
466 | ar2->intf[1] = usb_ifnum_to_if(udev, 1); | ||
467 | r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2); | ||
468 | if (r) | ||
469 | goto fail1; | ||
470 | alt = ar2->intf[1]->cur_altsetting; | ||
471 | ar2->ep[1] = &alt->endpoint[0].desc; | ||
472 | |||
473 | r = ati_remote2_urb_init(ar2); | ||
474 | if (r) | ||
475 | goto fail2; | ||
476 | |||
477 | r = ati_remote2_setup(ar2); | ||
478 | if (r) | ||
479 | goto fail2; | ||
480 | |||
481 | usb_make_path(udev, ar2->phys, sizeof(ar2->phys)); | ||
482 | strlcat(ar2->phys, "/input0", sizeof(ar2->phys)); | ||
483 | |||
484 | strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name)); | ||
485 | |||
486 | r = ati_remote2_input_init(ar2); | ||
487 | if (r) | ||
488 | goto fail2; | ||
489 | |||
490 | usb_set_intfdata(interface, ar2); | ||
491 | |||
492 | return 0; | ||
493 | |||
494 | fail2: | ||
495 | ati_remote2_urb_cleanup(ar2); | ||
496 | |||
497 | usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); | ||
498 | fail1: | ||
499 | kfree(ar2); | ||
500 | |||
501 | return r; | ||
502 | } | ||
503 | |||
504 | static void ati_remote2_disconnect(struct usb_interface *interface) | ||
505 | { | ||
506 | struct ati_remote2 *ar2; | ||
507 | struct usb_host_interface *alt = interface->cur_altsetting; | ||
508 | |||
509 | if (alt->desc.bInterfaceNumber) | ||
510 | return; | ||
511 | |||
512 | ar2 = usb_get_intfdata(interface); | ||
513 | usb_set_intfdata(interface, NULL); | ||
514 | |||
515 | input_unregister_device(ar2->idev); | ||
516 | |||
517 | ati_remote2_urb_cleanup(ar2); | ||
518 | |||
519 | usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]); | ||
520 | |||
521 | kfree(ar2); | ||
522 | } | ||
523 | |||
524 | static int __init ati_remote2_init(void) | ||
525 | { | ||
526 | int r; | ||
527 | |||
528 | r = usb_register(&ati_remote2_driver); | ||
529 | if (r) | ||
530 | printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r); | ||
531 | else | ||
532 | printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n"); | ||
533 | |||
534 | return r; | ||
535 | } | ||
536 | |||
537 | static void __exit ati_remote2_exit(void) | ||
538 | { | ||
539 | usb_deregister(&ati_remote2_driver); | ||
540 | } | ||
541 | |||
542 | module_init(ati_remote2_init); | ||
543 | module_exit(ati_remote2_exit); | ||
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c new file mode 100644 index 000000000000..1bffc9fa98c2 --- /dev/null +++ b/drivers/input/misc/keyspan_remote.c | |||
@@ -0,0 +1,592 @@ | |||
1 | /* | ||
2 | * keyspan_remote: USB driver for the Keyspan DMR | ||
3 | * | ||
4 | * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | * | ||
10 | * This driver has been put together with the support of Innosys, Inc. | ||
11 | * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/usb/input.h> | ||
21 | |||
22 | #define DRIVER_VERSION "v0.1" | ||
23 | #define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>" | ||
24 | #define DRIVER_DESC "Driver for the USB Keyspan remote control." | ||
25 | #define DRIVER_LICENSE "GPL" | ||
26 | |||
27 | /* Parameters that can be passed to the driver. */ | ||
28 | static int debug; | ||
29 | module_param(debug, int, 0444); | ||
30 | MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); | ||
31 | |||
32 | /* Vendor and product ids */ | ||
33 | #define USB_KEYSPAN_VENDOR_ID 0x06CD | ||
34 | #define USB_KEYSPAN_PRODUCT_UIA11 0x0202 | ||
35 | |||
36 | /* Defines for converting the data from the remote. */ | ||
37 | #define ZERO 0x18 | ||
38 | #define ZERO_MASK 0x1F /* 5 bits for a 0 */ | ||
39 | #define ONE 0x3C | ||
40 | #define ONE_MASK 0x3F /* 6 bits for a 1 */ | ||
41 | #define SYNC 0x3F80 | ||
42 | #define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */ | ||
43 | #define STOP 0x00 | ||
44 | #define STOP_MASK 0x1F /* 5 bits for the STOP sequence */ | ||
45 | #define GAP 0xFF | ||
46 | |||
47 | #define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */ | ||
48 | |||
49 | /* table of devices that work with this driver */ | ||
50 | static struct usb_device_id keyspan_table[] = { | ||
51 | { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) }, | ||
52 | { } /* Terminating entry */ | ||
53 | }; | ||
54 | |||
55 | /* Structure to store all the real stuff that a remote sends to us. */ | ||
56 | struct keyspan_message { | ||
57 | u16 system; | ||
58 | u8 button; | ||
59 | u8 toggle; | ||
60 | }; | ||
61 | |||
62 | /* Structure used for all the bit testing magic needed to be done. */ | ||
63 | struct bit_tester { | ||
64 | u32 tester; | ||
65 | int len; | ||
66 | int pos; | ||
67 | int bits_left; | ||
68 | u8 buffer[32]; | ||
69 | }; | ||
70 | |||
71 | /* Structure to hold all of our driver specific stuff */ | ||
72 | struct usb_keyspan { | ||
73 | char name[128]; | ||
74 | char phys[64]; | ||
75 | struct usb_device* udev; | ||
76 | struct input_dev *input; | ||
77 | struct usb_interface* interface; | ||
78 | struct usb_endpoint_descriptor* in_endpoint; | ||
79 | struct urb* irq_urb; | ||
80 | int open; | ||
81 | dma_addr_t in_dma; | ||
82 | unsigned char* in_buffer; | ||
83 | |||
84 | /* variables used to parse messages from remote. */ | ||
85 | struct bit_tester data; | ||
86 | int stage; | ||
87 | int toggle; | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Table that maps the 31 possible keycodes to input keys. | ||
92 | * Currently there are 15 and 17 button models so RESERVED codes | ||
93 | * are blank areas in the mapping. | ||
94 | */ | ||
95 | static const int keyspan_key_table[] = { | ||
96 | KEY_RESERVED, /* 0 is just a place holder. */ | ||
97 | KEY_RESERVED, | ||
98 | KEY_STOP, | ||
99 | KEY_PLAYCD, | ||
100 | KEY_RESERVED, | ||
101 | KEY_PREVIOUSSONG, | ||
102 | KEY_REWIND, | ||
103 | KEY_FORWARD, | ||
104 | KEY_NEXTSONG, | ||
105 | KEY_RESERVED, | ||
106 | KEY_RESERVED, | ||
107 | KEY_RESERVED, | ||
108 | KEY_PAUSE, | ||
109 | KEY_VOLUMEUP, | ||
110 | KEY_RESERVED, | ||
111 | KEY_RESERVED, | ||
112 | KEY_RESERVED, | ||
113 | KEY_VOLUMEDOWN, | ||
114 | KEY_RESERVED, | ||
115 | KEY_UP, | ||
116 | KEY_RESERVED, | ||
117 | KEY_MUTE, | ||
118 | KEY_LEFT, | ||
119 | KEY_ENTER, | ||
120 | KEY_RIGHT, | ||
121 | KEY_RESERVED, | ||
122 | KEY_RESERVED, | ||
123 | KEY_DOWN, | ||
124 | KEY_RESERVED, | ||
125 | KEY_KPASTERISK, | ||
126 | KEY_RESERVED, | ||
127 | KEY_MENU | ||
128 | }; | ||
129 | |||
130 | static struct usb_driver keyspan_driver; | ||
131 | |||
132 | /* | ||
133 | * Debug routine that prints out what we've received from the remote. | ||
134 | */ | ||
135 | static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/ | ||
136 | { | ||
137 | char codes[4 * RECV_SIZE]; | ||
138 | int i; | ||
139 | |||
140 | for (i = 0; i < RECV_SIZE; i++) | ||
141 | snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]); | ||
142 | |||
143 | dev_info(&dev->udev->dev, "%s\n", codes); | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Routine that manages the bit_tester structure. It makes sure that there are | ||
148 | * at least bits_needed bits loaded into the tester. | ||
149 | */ | ||
150 | static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed) | ||
151 | { | ||
152 | if (dev->data.bits_left >= bits_needed) | ||
153 | return 0; | ||
154 | |||
155 | /* | ||
156 | * Somehow we've missed the last message. The message will be repeated | ||
157 | * though so it's not too big a deal | ||
158 | */ | ||
159 | if (dev->data.pos >= dev->data.len) { | ||
160 | dev_dbg(&dev->udev->dev, | ||
161 | "%s - Error ran out of data. pos: %d, len: %d\n", | ||
162 | __FUNCTION__, dev->data.pos, dev->data.len); | ||
163 | return -1; | ||
164 | } | ||
165 | |||
166 | /* Load as much as we can into the tester. */ | ||
167 | while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) && | ||
168 | (dev->data.pos < dev->data.len)) { | ||
169 | dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left); | ||
170 | dev->data.bits_left += 8; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Routine that handles all the logic needed to parse out the message from the remote. | ||
178 | */ | ||
179 | static void keyspan_check_data(struct usb_keyspan *remote) | ||
180 | { | ||
181 | int i; | ||
182 | int found = 0; | ||
183 | struct keyspan_message message; | ||
184 | |||
185 | switch(remote->stage) { | ||
186 | case 0: | ||
187 | /* | ||
188 | * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler. | ||
189 | * So the first byte that isn't a FF should be the start of a new message. | ||
190 | */ | ||
191 | for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i); | ||
192 | |||
193 | if (i < RECV_SIZE) { | ||
194 | memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE); | ||
195 | remote->data.len = RECV_SIZE; | ||
196 | remote->data.pos = 0; | ||
197 | remote->data.tester = 0; | ||
198 | remote->data.bits_left = 0; | ||
199 | remote->stage = 1; | ||
200 | } | ||
201 | break; | ||
202 | |||
203 | case 1: | ||
204 | /* | ||
205 | * Stage 1 we should have 16 bytes and should be able to detect a | ||
206 | * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's. | ||
207 | */ | ||
208 | memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); | ||
209 | remote->data.len += RECV_SIZE; | ||
210 | |||
211 | found = 0; | ||
212 | while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) { | ||
213 | for (i = 0; i < 8; ++i) { | ||
214 | if (keyspan_load_tester(remote, 14) != 0) { | ||
215 | remote->stage = 0; | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | if ((remote->data.tester & SYNC_MASK) == SYNC) { | ||
220 | remote->data.tester = remote->data.tester >> 14; | ||
221 | remote->data.bits_left -= 14; | ||
222 | found = 1; | ||
223 | break; | ||
224 | } else { | ||
225 | remote->data.tester = remote->data.tester >> 1; | ||
226 | --remote->data.bits_left; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | if (!found) { | ||
232 | remote->stage = 0; | ||
233 | remote->data.len = 0; | ||
234 | } else { | ||
235 | remote->stage = 2; | ||
236 | } | ||
237 | break; | ||
238 | |||
239 | case 2: | ||
240 | /* | ||
241 | * Stage 2 we should have 24 bytes which will be enough for a full | ||
242 | * message. We need to parse out the system code, button code, | ||
243 | * toggle code, and stop. | ||
244 | */ | ||
245 | memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE); | ||
246 | remote->data.len += RECV_SIZE; | ||
247 | |||
248 | message.system = 0; | ||
249 | for (i = 0; i < 9; i++) { | ||
250 | keyspan_load_tester(remote, 6); | ||
251 | |||
252 | if ((remote->data.tester & ZERO_MASK) == ZERO) { | ||
253 | message.system = message.system << 1; | ||
254 | remote->data.tester = remote->data.tester >> 5; | ||
255 | remote->data.bits_left -= 5; | ||
256 | } else if ((remote->data.tester & ONE_MASK) == ONE) { | ||
257 | message.system = (message.system << 1) + 1; | ||
258 | remote->data.tester = remote->data.tester >> 6; | ||
259 | remote->data.bits_left -= 6; | ||
260 | } else { | ||
261 | err("%s - Unknown sequence found in system data.\n", __FUNCTION__); | ||
262 | remote->stage = 0; | ||
263 | return; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | message.button = 0; | ||
268 | for (i = 0; i < 5; i++) { | ||
269 | keyspan_load_tester(remote, 6); | ||
270 | |||
271 | if ((remote->data.tester & ZERO_MASK) == ZERO) { | ||
272 | message.button = message.button << 1; | ||
273 | remote->data.tester = remote->data.tester >> 5; | ||
274 | remote->data.bits_left -= 5; | ||
275 | } else if ((remote->data.tester & ONE_MASK) == ONE) { | ||
276 | message.button = (message.button << 1) + 1; | ||
277 | remote->data.tester = remote->data.tester >> 6; | ||
278 | remote->data.bits_left -= 6; | ||
279 | } else { | ||
280 | err("%s - Unknown sequence found in button data.\n", __FUNCTION__); | ||
281 | remote->stage = 0; | ||
282 | return; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | keyspan_load_tester(remote, 6); | ||
287 | if ((remote->data.tester & ZERO_MASK) == ZERO) { | ||
288 | message.toggle = 0; | ||
289 | remote->data.tester = remote->data.tester >> 5; | ||
290 | remote->data.bits_left -= 5; | ||
291 | } else if ((remote->data.tester & ONE_MASK) == ONE) { | ||
292 | message.toggle = 1; | ||
293 | remote->data.tester = remote->data.tester >> 6; | ||
294 | remote->data.bits_left -= 6; | ||
295 | } else { | ||
296 | err("%s - Error in message, invalid toggle.\n", __FUNCTION__); | ||
297 | remote->stage = 0; | ||
298 | return; | ||
299 | } | ||
300 | |||
301 | keyspan_load_tester(remote, 5); | ||
302 | if ((remote->data.tester & STOP_MASK) == STOP) { | ||
303 | remote->data.tester = remote->data.tester >> 5; | ||
304 | remote->data.bits_left -= 5; | ||
305 | } else { | ||
306 | err("Bad message recieved, no stop bit found.\n"); | ||
307 | } | ||
308 | |||
309 | dev_dbg(&remote->udev->dev, | ||
310 | "%s found valid message: system: %d, button: %d, toggle: %d\n", | ||
311 | __FUNCTION__, message.system, message.button, message.toggle); | ||
312 | |||
313 | if (message.toggle != remote->toggle) { | ||
314 | input_report_key(remote->input, keyspan_key_table[message.button], 1); | ||
315 | input_report_key(remote->input, keyspan_key_table[message.button], 0); | ||
316 | input_sync(remote->input); | ||
317 | remote->toggle = message.toggle; | ||
318 | } | ||
319 | |||
320 | remote->stage = 0; | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Routine for sending all the initialization messages to the remote. | ||
327 | */ | ||
328 | static int keyspan_setup(struct usb_device* dev) | ||
329 | { | ||
330 | int retval = 0; | ||
331 | |||
332 | retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
333 | 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); | ||
334 | if (retval) { | ||
335 | dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", | ||
336 | __FUNCTION__, retval); | ||
337 | return(retval); | ||
338 | } | ||
339 | |||
340 | retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
341 | 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); | ||
342 | if (retval) { | ||
343 | dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", | ||
344 | __FUNCTION__, retval); | ||
345 | return(retval); | ||
346 | } | ||
347 | |||
348 | retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
349 | 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); | ||
350 | if (retval) { | ||
351 | dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", | ||
352 | __FUNCTION__, retval); | ||
353 | return(retval); | ||
354 | } | ||
355 | |||
356 | dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__); | ||
357 | return(retval); | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Routine used to handle a new message that has come in. | ||
362 | */ | ||
363 | static void keyspan_irq_recv(struct urb *urb) | ||
364 | { | ||
365 | struct usb_keyspan *dev = urb->context; | ||
366 | int retval; | ||
367 | |||
368 | /* Check our status in case we need to bail out early. */ | ||
369 | switch (urb->status) { | ||
370 | case 0: | ||
371 | break; | ||
372 | |||
373 | /* Device went away so don't keep trying to read from it. */ | ||
374 | case -ECONNRESET: | ||
375 | case -ENOENT: | ||
376 | case -ESHUTDOWN: | ||
377 | return; | ||
378 | |||
379 | default: | ||
380 | goto resubmit; | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | if (debug) | ||
385 | keyspan_print(dev); | ||
386 | |||
387 | keyspan_check_data(dev); | ||
388 | |||
389 | resubmit: | ||
390 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
391 | if (retval) | ||
392 | err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval); | ||
393 | } | ||
394 | |||
395 | static int keyspan_open(struct input_dev *dev) | ||
396 | { | ||
397 | struct usb_keyspan *remote = input_get_drvdata(dev); | ||
398 | |||
399 | remote->irq_urb->dev = remote->udev; | ||
400 | if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) | ||
401 | return -EIO; | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static void keyspan_close(struct input_dev *dev) | ||
407 | { | ||
408 | struct usb_keyspan *remote = input_get_drvdata(dev); | ||
409 | |||
410 | usb_kill_urb(remote->irq_urb); | ||
411 | } | ||
412 | |||
413 | static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface) | ||
414 | { | ||
415 | |||
416 | struct usb_endpoint_descriptor *endpoint; | ||
417 | int i; | ||
418 | |||
419 | for (i = 0; i < iface->desc.bNumEndpoints; ++i) { | ||
420 | endpoint = &iface->endpoint[i].desc; | ||
421 | |||
422 | if (usb_endpoint_is_int_in(endpoint)) { | ||
423 | /* we found our interrupt in endpoint */ | ||
424 | return endpoint; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Routine that sets up the driver to handle a specific USB device detected on the bus. | ||
433 | */ | ||
434 | static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id) | ||
435 | { | ||
436 | struct usb_device *udev = interface_to_usbdev(interface); | ||
437 | struct usb_endpoint_descriptor *endpoint; | ||
438 | struct usb_keyspan *remote; | ||
439 | struct input_dev *input_dev; | ||
440 | int i, error; | ||
441 | |||
442 | endpoint = keyspan_get_in_endpoint(interface->cur_altsetting); | ||
443 | if (!endpoint) | ||
444 | return -ENODEV; | ||
445 | |||
446 | remote = kzalloc(sizeof(*remote), GFP_KERNEL); | ||
447 | input_dev = input_allocate_device(); | ||
448 | if (!remote || !input_dev) { | ||
449 | error = -ENOMEM; | ||
450 | goto fail1; | ||
451 | } | ||
452 | |||
453 | remote->udev = udev; | ||
454 | remote->input = input_dev; | ||
455 | remote->interface = interface; | ||
456 | remote->in_endpoint = endpoint; | ||
457 | remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ | ||
458 | |||
459 | remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); | ||
460 | if (!remote->in_buffer) { | ||
461 | error = -ENOMEM; | ||
462 | goto fail1; | ||
463 | } | ||
464 | |||
465 | remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
466 | if (!remote->irq_urb) { | ||
467 | error = -ENOMEM; | ||
468 | goto fail2; | ||
469 | } | ||
470 | |||
471 | error = keyspan_setup(udev); | ||
472 | if (error) { | ||
473 | error = -ENODEV; | ||
474 | goto fail3; | ||
475 | } | ||
476 | |||
477 | if (udev->manufacturer) | ||
478 | strlcpy(remote->name, udev->manufacturer, sizeof(remote->name)); | ||
479 | |||
480 | if (udev->product) { | ||
481 | if (udev->manufacturer) | ||
482 | strlcat(remote->name, " ", sizeof(remote->name)); | ||
483 | strlcat(remote->name, udev->product, sizeof(remote->name)); | ||
484 | } | ||
485 | |||
486 | if (!strlen(remote->name)) | ||
487 | snprintf(remote->name, sizeof(remote->name), | ||
488 | "USB Keyspan Remote %04x:%04x", | ||
489 | le16_to_cpu(udev->descriptor.idVendor), | ||
490 | le16_to_cpu(udev->descriptor.idProduct)); | ||
491 | |||
492 | usb_make_path(udev, remote->phys, sizeof(remote->phys)); | ||
493 | strlcat(remote->phys, "/input0", sizeof(remote->phys)); | ||
494 | |||
495 | input_dev->name = remote->name; | ||
496 | input_dev->phys = remote->phys; | ||
497 | usb_to_input_id(udev, &input_dev->id); | ||
498 | input_dev->dev.parent = &interface->dev; | ||
499 | |||
500 | input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */ | ||
501 | for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++) | ||
502 | if (keyspan_key_table[i] != KEY_RESERVED) | ||
503 | set_bit(keyspan_key_table[i], input_dev->keybit); | ||
504 | |||
505 | input_set_drvdata(input_dev, remote); | ||
506 | |||
507 | input_dev->open = keyspan_open; | ||
508 | input_dev->close = keyspan_close; | ||
509 | |||
510 | /* | ||
511 | * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open() | ||
512 | */ | ||
513 | usb_fill_int_urb(remote->irq_urb, | ||
514 | remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress), | ||
515 | remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote, | ||
516 | remote->in_endpoint->bInterval); | ||
517 | remote->irq_urb->transfer_dma = remote->in_dma; | ||
518 | remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
519 | |||
520 | /* we can register the device now, as it is ready */ | ||
521 | error = input_register_device(remote->input); | ||
522 | if (error) | ||
523 | goto fail3; | ||
524 | |||
525 | /* save our data pointer in this interface device */ | ||
526 | usb_set_intfdata(interface, remote); | ||
527 | |||
528 | return 0; | ||
529 | |||
530 | fail3: usb_free_urb(remote->irq_urb); | ||
531 | fail2: usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma); | ||
532 | fail1: kfree(remote); | ||
533 | input_free_device(input_dev); | ||
534 | |||
535 | return error; | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Routine called when a device is disconnected from the USB. | ||
540 | */ | ||
541 | static void keyspan_disconnect(struct usb_interface *interface) | ||
542 | { | ||
543 | struct usb_keyspan *remote; | ||
544 | |||
545 | remote = usb_get_intfdata(interface); | ||
546 | usb_set_intfdata(interface, NULL); | ||
547 | |||
548 | if (remote) { /* We have a valid driver structure so clean up everything we allocated. */ | ||
549 | input_unregister_device(remote->input); | ||
550 | usb_kill_urb(remote->irq_urb); | ||
551 | usb_free_urb(remote->irq_urb); | ||
552 | usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); | ||
553 | kfree(remote); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * Standard driver set up sections | ||
559 | */ | ||
560 | static struct usb_driver keyspan_driver = | ||
561 | { | ||
562 | .name = "keyspan_remote", | ||
563 | .probe = keyspan_probe, | ||
564 | .disconnect = keyspan_disconnect, | ||
565 | .id_table = keyspan_table | ||
566 | }; | ||
567 | |||
568 | static int __init usb_keyspan_init(void) | ||
569 | { | ||
570 | int result; | ||
571 | |||
572 | /* register this driver with the USB subsystem */ | ||
573 | result = usb_register(&keyspan_driver); | ||
574 | if (result) | ||
575 | err("usb_register failed. Error number %d\n", result); | ||
576 | |||
577 | return result; | ||
578 | } | ||
579 | |||
580 | static void __exit usb_keyspan_exit(void) | ||
581 | { | ||
582 | /* deregister this driver with the USB subsystem */ | ||
583 | usb_deregister(&keyspan_driver); | ||
584 | } | ||
585 | |||
586 | module_init(usb_keyspan_init); | ||
587 | module_exit(usb_keyspan_exit); | ||
588 | |||
589 | MODULE_DEVICE_TABLE(usb, keyspan_table); | ||
590 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
591 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
592 | MODULE_LICENSE(DRIVER_LICENSE); | ||
diff --git a/drivers/input/misc/map_to_7segment.h b/drivers/input/misc/map_to_7segment.h new file mode 100644 index 000000000000..a424094d9fe2 --- /dev/null +++ b/drivers/input/misc/map_to_7segment.h | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * drivers/usb/input/map_to_7segment.h | ||
3 | * | ||
4 | * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of | ||
9 | * the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef MAP_TO_7SEGMENT_H | ||
22 | #define MAP_TO_7SEGMENT_H | ||
23 | |||
24 | /* This file provides translation primitives and tables for the conversion | ||
25 | * of (ASCII) characters to a 7-segments notation. | ||
26 | * | ||
27 | * The 7 segment's wikipedia notation below is used as standard. | ||
28 | * See: http://en.wikipedia.org/wiki/Seven_segment_display | ||
29 | * | ||
30 | * Notation: +-a-+ | ||
31 | * f b | ||
32 | * +-g-+ | ||
33 | * e c | ||
34 | * +-d-+ | ||
35 | * | ||
36 | * Usage: | ||
37 | * | ||
38 | * Register a map variable, and fill it with a character set: | ||
39 | * static SEG7_DEFAULT_MAP(map_seg7); | ||
40 | * | ||
41 | * | ||
42 | * Then use for conversion: | ||
43 | * seg7 = map_to_seg7(&map_seg7, some_char); | ||
44 | * ... | ||
45 | * | ||
46 | * In device drivers it is recommended, if required, to make the char map | ||
47 | * accessible via the sysfs interface using the following scheme: | ||
48 | * | ||
49 | * static ssize_t show_map(struct device *dev, char *buf) { | ||
50 | * memcpy(buf, &map_seg7, sizeof(map_seg7)); | ||
51 | * return sizeof(map_seg7); | ||
52 | * } | ||
53 | * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) { | ||
54 | * if(cnt != sizeof(map_seg7)) | ||
55 | * return -EINVAL; | ||
56 | * memcpy(&map_seg7, buf, cnt); | ||
57 | * return cnt; | ||
58 | * } | ||
59 | * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map); | ||
60 | * | ||
61 | * History: | ||
62 | * 2005-05-31 RFC linux-kernel@vger.kernel.org | ||
63 | */ | ||
64 | #include <linux/errno.h> | ||
65 | |||
66 | |||
67 | #define BIT_SEG7_A 0 | ||
68 | #define BIT_SEG7_B 1 | ||
69 | #define BIT_SEG7_C 2 | ||
70 | #define BIT_SEG7_D 3 | ||
71 | #define BIT_SEG7_E 4 | ||
72 | #define BIT_SEG7_F 5 | ||
73 | #define BIT_SEG7_G 6 | ||
74 | #define BIT_SEG7_RESERVED 7 | ||
75 | |||
76 | struct seg7_conversion_map { | ||
77 | unsigned char table[128]; | ||
78 | }; | ||
79 | |||
80 | static inline int map_to_seg7(struct seg7_conversion_map *map, int c) | ||
81 | { | ||
82 | return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL; | ||
83 | } | ||
84 | |||
85 | #define SEG7_CONVERSION_MAP(_name, _map) \ | ||
86 | struct seg7_conversion_map _name = { .table = { _map } } | ||
87 | |||
88 | /* | ||
89 | * It is recommended to use a facility that allows user space to redefine | ||
90 | * custom character sets for LCD devices. Please use a sysfs interface | ||
91 | * as described above. | ||
92 | */ | ||
93 | #define MAP_TO_SEG7_SYSFS_FILE "map_seg7" | ||
94 | |||
95 | /******************************************************************************* | ||
96 | * ASCII conversion table | ||
97 | ******************************************************************************/ | ||
98 | |||
99 | #define _SEG7(l,a,b,c,d,e,f,g) \ | ||
100 | ( a<<BIT_SEG7_A | b<<BIT_SEG7_B | c<<BIT_SEG7_C | d<<BIT_SEG7_D | \ | ||
101 | e<<BIT_SEG7_E | f<<BIT_SEG7_F | g<<BIT_SEG7_G ) | ||
102 | |||
103 | #define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE \ | ||
104 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||
105 | |||
106 | #define _MAP_33_47_ASCII_SEG7_SYMBOL \ | ||
107 | _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\ | ||
108 | _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\ | ||
109 | _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\ | ||
110 | _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\ | ||
111 | _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1), | ||
112 | |||
113 | #define _MAP_48_57_ASCII_SEG7_NUMERIC \ | ||
114 | _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\ | ||
115 | _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\ | ||
116 | _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\ | ||
117 | _SEG7('9',1,1,1,1,0,1,1), | ||
118 | |||
119 | #define _MAP_58_64_ASCII_SEG7_SYMBOL \ | ||
120 | _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\ | ||
121 | _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\ | ||
122 | _SEG7('@',1,1,0,1,1,1,1), | ||
123 | |||
124 | #define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR \ | ||
125 | _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\ | ||
126 | _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\ | ||
127 | _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\ | ||
128 | _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\ | ||
129 | _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\ | ||
130 | _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\ | ||
131 | _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\ | ||
132 | _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\ | ||
133 | _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1), | ||
134 | |||
135 | #define _MAP_91_96_ASCII_SEG7_SYMBOL \ | ||
136 | _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\ | ||
137 | _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0), | ||
138 | |||
139 | #define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER \ | ||
140 | _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\ | ||
141 | _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\ | ||
142 | _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\ | ||
143 | _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\ | ||
144 | _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\ | ||
145 | _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\ | ||
146 | _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\ | ||
147 | _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\ | ||
148 | _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1), | ||
149 | |||
150 | #define _MAP_123_126_ASCII_SEG7_SYMBOL \ | ||
151 | _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\ | ||
152 | _SEG7('~',1,0,0,0,0,0,0), | ||
153 | |||
154 | /* Maps */ | ||
155 | |||
156 | /* This set tries to map as close as possible to the visible characteristics | ||
157 | * of the ASCII symbol, lowercase and uppercase letters may differ in | ||
158 | * presentation on the display. | ||
159 | */ | ||
160 | #define MAP_ASCII7SEG_ALPHANUM \ | ||
161 | _MAP_0_32_ASCII_SEG7_NON_PRINTABLE \ | ||
162 | _MAP_33_47_ASCII_SEG7_SYMBOL \ | ||
163 | _MAP_48_57_ASCII_SEG7_NUMERIC \ | ||
164 | _MAP_58_64_ASCII_SEG7_SYMBOL \ | ||
165 | _MAP_65_90_ASCII_SEG7_ALPHA_UPPR \ | ||
166 | _MAP_91_96_ASCII_SEG7_SYMBOL \ | ||
167 | _MAP_97_122_ASCII_SEG7_ALPHA_LOWER \ | ||
168 | _MAP_123_126_ASCII_SEG7_SYMBOL | ||
169 | |||
170 | /* This set tries to map as close as possible to the symbolic characteristics | ||
171 | * of the ASCII character for maximum discrimination. | ||
172 | * For now this means all alpha chars are in lower case representations. | ||
173 | * (This for example facilitates the use of hex numbers with uppercase input.) | ||
174 | */ | ||
175 | #define MAP_ASCII7SEG_ALPHANUM_LC \ | ||
176 | _MAP_0_32_ASCII_SEG7_NON_PRINTABLE \ | ||
177 | _MAP_33_47_ASCII_SEG7_SYMBOL \ | ||
178 | _MAP_48_57_ASCII_SEG7_NUMERIC \ | ||
179 | _MAP_58_64_ASCII_SEG7_SYMBOL \ | ||
180 | _MAP_97_122_ASCII_SEG7_ALPHA_LOWER \ | ||
181 | _MAP_91_96_ASCII_SEG7_SYMBOL \ | ||
182 | _MAP_97_122_ASCII_SEG7_ALPHA_LOWER \ | ||
183 | _MAP_123_126_ASCII_SEG7_SYMBOL | ||
184 | |||
185 | #define SEG7_DEFAULT_MAP(_name) \ | ||
186 | SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM) | ||
187 | |||
188 | #endif /* MAP_TO_7SEGMENT_H */ | ||
189 | |||
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c new file mode 100644 index 000000000000..448a470d28f2 --- /dev/null +++ b/drivers/input/misc/powermate.c | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial. | ||
3 | * | ||
4 | * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com> | ||
5 | * | ||
6 | * This device is a anodised aluminium knob which connects over USB. It can measure | ||
7 | * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with | ||
8 | * a spring for automatic release. The base contains a pair of LEDs which illuminate | ||
9 | * the translucent base. It rotates without limit and reports its relative rotation | ||
10 | * back to the host when polled by the USB controller. | ||
11 | * | ||
12 | * Testing with the knob I have has shown that it measures approximately 94 "clicks" | ||
13 | * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was | ||
14 | * a variable speed cordless electric drill) has shown that the device can measure | ||
15 | * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from | ||
16 | * the host. If it counts more than 7 clicks before it is polled, it will wrap back | ||
17 | * to zero and start counting again. This was at quite high speed, however, almost | ||
18 | * certainly faster than the human hand could turn it. Griffin say that it loses a | ||
19 | * pulse or two on a direction change; the granularity is so fine that I never | ||
20 | * noticed this in practice. | ||
21 | * | ||
22 | * The device's microcontroller can be programmed to set the LED to either a constant | ||
23 | * intensity, or to a rhythmic pulsing. Several patterns and speeds are available. | ||
24 | * | ||
25 | * Griffin were very happy to provide documentation and free hardware for development. | ||
26 | * | ||
27 | * Some userspace tools are available on the web: http://sowerbutts.com/powermate/ | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/usb/input.h> | ||
37 | |||
38 | #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ | ||
39 | #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ | ||
40 | #define POWERMATE_PRODUCT_OLD 0x04AA /* Griffin soundKnob */ | ||
41 | |||
42 | #define CONTOUR_VENDOR 0x05f3 /* Contour Design, Inc. */ | ||
43 | #define CONTOUR_JOG 0x0240 /* Jog and Shuttle */ | ||
44 | |||
45 | /* these are the command codes we send to the device */ | ||
46 | #define SET_STATIC_BRIGHTNESS 0x01 | ||
47 | #define SET_PULSE_ASLEEP 0x02 | ||
48 | #define SET_PULSE_AWAKE 0x03 | ||
49 | #define SET_PULSE_MODE 0x04 | ||
50 | |||
51 | /* these refer to bits in the powermate_device's requires_update field. */ | ||
52 | #define UPDATE_STATIC_BRIGHTNESS (1<<0) | ||
53 | #define UPDATE_PULSE_ASLEEP (1<<1) | ||
54 | #define UPDATE_PULSE_AWAKE (1<<2) | ||
55 | #define UPDATE_PULSE_MODE (1<<3) | ||
56 | |||
57 | /* at least two versions of the hardware exist, with differing payload | ||
58 | sizes. the first three bytes always contain the "interesting" data in | ||
59 | the relevant format. */ | ||
60 | #define POWERMATE_PAYLOAD_SIZE_MAX 6 | ||
61 | #define POWERMATE_PAYLOAD_SIZE_MIN 3 | ||
62 | struct powermate_device { | ||
63 | signed char *data; | ||
64 | dma_addr_t data_dma; | ||
65 | struct urb *irq, *config; | ||
66 | struct usb_ctrlrequest *configcr; | ||
67 | dma_addr_t configcr_dma; | ||
68 | struct usb_device *udev; | ||
69 | struct input_dev *input; | ||
70 | spinlock_t lock; | ||
71 | int static_brightness; | ||
72 | int pulse_speed; | ||
73 | int pulse_table; | ||
74 | int pulse_asleep; | ||
75 | int pulse_awake; | ||
76 | int requires_update; // physical settings which are out of sync | ||
77 | char phys[64]; | ||
78 | }; | ||
79 | |||
80 | static char pm_name_powermate[] = "Griffin PowerMate"; | ||
81 | static char pm_name_soundknob[] = "Griffin SoundKnob"; | ||
82 | |||
83 | static void powermate_config_complete(struct urb *urb); | ||
84 | |||
85 | /* Callback for data arriving from the PowerMate over the USB interrupt pipe */ | ||
86 | static void powermate_irq(struct urb *urb) | ||
87 | { | ||
88 | struct powermate_device *pm = urb->context; | ||
89 | int retval; | ||
90 | |||
91 | switch (urb->status) { | ||
92 | case 0: | ||
93 | /* success */ | ||
94 | break; | ||
95 | case -ECONNRESET: | ||
96 | case -ENOENT: | ||
97 | case -ESHUTDOWN: | ||
98 | /* this urb is terminated, clean up */ | ||
99 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | ||
100 | return; | ||
101 | default: | ||
102 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | ||
103 | goto exit; | ||
104 | } | ||
105 | |||
106 | /* handle updates to device state */ | ||
107 | input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); | ||
108 | input_report_rel(pm->input, REL_DIAL, pm->data[1]); | ||
109 | input_sync(pm->input); | ||
110 | |||
111 | exit: | ||
112 | retval = usb_submit_urb (urb, GFP_ATOMIC); | ||
113 | if (retval) | ||
114 | err ("%s - usb_submit_urb failed with result %d", | ||
115 | __FUNCTION__, retval); | ||
116 | } | ||
117 | |||
118 | /* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */ | ||
119 | static void powermate_sync_state(struct powermate_device *pm) | ||
120 | { | ||
121 | if (pm->requires_update == 0) | ||
122 | return; /* no updates are required */ | ||
123 | if (pm->config->status == -EINPROGRESS) | ||
124 | return; /* an update is already in progress; it'll issue this update when it completes */ | ||
125 | |||
126 | if (pm->requires_update & UPDATE_PULSE_ASLEEP){ | ||
127 | pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP ); | ||
128 | pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); | ||
129 | pm->requires_update &= ~UPDATE_PULSE_ASLEEP; | ||
130 | }else if (pm->requires_update & UPDATE_PULSE_AWAKE){ | ||
131 | pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE ); | ||
132 | pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); | ||
133 | pm->requires_update &= ~UPDATE_PULSE_AWAKE; | ||
134 | }else if (pm->requires_update & UPDATE_PULSE_MODE){ | ||
135 | int op, arg; | ||
136 | /* the powermate takes an operation and an argument for its pulse algorithm. | ||
137 | the operation can be: | ||
138 | 0: divide the speed | ||
139 | 1: pulse at normal speed | ||
140 | 2: multiply the speed | ||
141 | the argument only has an effect for operations 0 and 2, and ranges between | ||
142 | 1 (least effect) to 255 (maximum effect). | ||
143 | |||
144 | thus, several states are equivalent and are coalesced into one state. | ||
145 | |||
146 | we map this onto a range from 0 to 510, with: | ||
147 | 0 -- 254 -- use divide (0 = slowest) | ||
148 | 255 -- use normal speed | ||
149 | 256 -- 510 -- use multiple (510 = fastest). | ||
150 | |||
151 | Only values of 'arg' quite close to 255 are particularly useful/spectacular. | ||
152 | */ | ||
153 | if (pm->pulse_speed < 255) { | ||
154 | op = 0; // divide | ||
155 | arg = 255 - pm->pulse_speed; | ||
156 | } else if (pm->pulse_speed > 255) { | ||
157 | op = 2; // multiply | ||
158 | arg = pm->pulse_speed - 255; | ||
159 | } else { | ||
160 | op = 1; // normal speed | ||
161 | arg = 0; // can be any value | ||
162 | } | ||
163 | pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); | ||
164 | pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); | ||
165 | pm->requires_update &= ~UPDATE_PULSE_MODE; | ||
166 | } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) { | ||
167 | pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); | ||
168 | pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); | ||
169 | pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; | ||
170 | } else { | ||
171 | printk(KERN_ERR "powermate: unknown update required"); | ||
172 | pm->requires_update = 0; /* fudge the bug */ | ||
173 | return; | ||
174 | } | ||
175 | |||
176 | /* printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */ | ||
177 | |||
178 | pm->configcr->bRequestType = 0x41; /* vendor request */ | ||
179 | pm->configcr->bRequest = 0x01; | ||
180 | pm->configcr->wLength = 0; | ||
181 | |||
182 | usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), | ||
183 | (void *) pm->configcr, NULL, 0, | ||
184 | powermate_config_complete, pm); | ||
185 | pm->config->setup_dma = pm->configcr_dma; | ||
186 | pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP; | ||
187 | |||
188 | if (usb_submit_urb(pm->config, GFP_ATOMIC)) | ||
189 | printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); | ||
190 | } | ||
191 | |||
192 | /* Called when our asynchronous control message completes. We may need to issue another immediately */ | ||
193 | static void powermate_config_complete(struct urb *urb) | ||
194 | { | ||
195 | struct powermate_device *pm = urb->context; | ||
196 | unsigned long flags; | ||
197 | |||
198 | if (urb->status) | ||
199 | printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); | ||
200 | |||
201 | spin_lock_irqsave(&pm->lock, flags); | ||
202 | powermate_sync_state(pm); | ||
203 | spin_unlock_irqrestore(&pm->lock, flags); | ||
204 | } | ||
205 | |||
206 | /* Set the LED up as described and begin the sync with the hardware if required */ | ||
207 | static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, | ||
208 | int pulse_table, int pulse_asleep, int pulse_awake) | ||
209 | { | ||
210 | unsigned long flags; | ||
211 | |||
212 | if (pulse_speed < 0) | ||
213 | pulse_speed = 0; | ||
214 | if (pulse_table < 0) | ||
215 | pulse_table = 0; | ||
216 | if (pulse_speed > 510) | ||
217 | pulse_speed = 510; | ||
218 | if (pulse_table > 2) | ||
219 | pulse_table = 2; | ||
220 | |||
221 | pulse_asleep = !!pulse_asleep; | ||
222 | pulse_awake = !!pulse_awake; | ||
223 | |||
224 | |||
225 | spin_lock_irqsave(&pm->lock, flags); | ||
226 | |||
227 | /* mark state updates which are required */ | ||
228 | if (static_brightness != pm->static_brightness) { | ||
229 | pm->static_brightness = static_brightness; | ||
230 | pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; | ||
231 | } | ||
232 | if (pulse_asleep != pm->pulse_asleep) { | ||
233 | pm->pulse_asleep = pulse_asleep; | ||
234 | pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); | ||
235 | } | ||
236 | if (pulse_awake != pm->pulse_awake) { | ||
237 | pm->pulse_awake = pulse_awake; | ||
238 | pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); | ||
239 | } | ||
240 | if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) { | ||
241 | pm->pulse_speed = pulse_speed; | ||
242 | pm->pulse_table = pulse_table; | ||
243 | pm->requires_update |= UPDATE_PULSE_MODE; | ||
244 | } | ||
245 | |||
246 | powermate_sync_state(pm); | ||
247 | |||
248 | spin_unlock_irqrestore(&pm->lock, flags); | ||
249 | } | ||
250 | |||
251 | /* Callback from the Input layer when an event arrives from userspace to configure the LED */ | ||
252 | static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value) | ||
253 | { | ||
254 | unsigned int command = (unsigned int)_value; | ||
255 | struct powermate_device *pm = input_get_drvdata(dev); | ||
256 | |||
257 | if (type == EV_MSC && code == MSC_PULSELED){ | ||
258 | /* | ||
259 | bits 0- 7: 8 bits: LED brightness | ||
260 | bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster. | ||
261 | bits 17-18: 2 bits: pulse table (0, 1, 2 valid) | ||
262 | bit 19: 1 bit : pulse whilst asleep? | ||
263 | bit 20: 1 bit : pulse constantly? | ||
264 | */ | ||
265 | int static_brightness = command & 0xFF; // bits 0-7 | ||
266 | int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16 | ||
267 | int pulse_table = (command >> 17) & 0x3; // bits 17-18 | ||
268 | int pulse_asleep = (command >> 19) & 0x1; // bit 19 | ||
269 | int pulse_awake = (command >> 20) & 0x1; // bit 20 | ||
270 | |||
271 | powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake); | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) | ||
278 | { | ||
279 | pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX, | ||
280 | GFP_ATOMIC, &pm->data_dma); | ||
281 | if (!pm->data) | ||
282 | return -1; | ||
283 | |||
284 | pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), | ||
285 | GFP_ATOMIC, &pm->configcr_dma); | ||
286 | if (!pm->configcr) | ||
287 | return -1; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm) | ||
293 | { | ||
294 | usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX, | ||
295 | pm->data, pm->data_dma); | ||
296 | usb_buffer_free(udev, sizeof(*(pm->configcr)), | ||
297 | pm->configcr, pm->configcr_dma); | ||
298 | } | ||
299 | |||
300 | /* Called whenever a USB device matching one in our supported devices table is connected */ | ||
301 | static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
302 | { | ||
303 | struct usb_device *udev = interface_to_usbdev (intf); | ||
304 | struct usb_host_interface *interface; | ||
305 | struct usb_endpoint_descriptor *endpoint; | ||
306 | struct powermate_device *pm; | ||
307 | struct input_dev *input_dev; | ||
308 | int pipe, maxp; | ||
309 | int error = -ENOMEM; | ||
310 | |||
311 | interface = intf->cur_altsetting; | ||
312 | endpoint = &interface->endpoint[0].desc; | ||
313 | if (!usb_endpoint_is_int_in(endpoint)) | ||
314 | return -EIO; | ||
315 | |||
316 | usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
317 | 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
318 | 0, interface->desc.bInterfaceNumber, NULL, 0, | ||
319 | USB_CTRL_SET_TIMEOUT); | ||
320 | |||
321 | pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL); | ||
322 | input_dev = input_allocate_device(); | ||
323 | if (!pm || !input_dev) | ||
324 | goto fail1; | ||
325 | |||
326 | if (powermate_alloc_buffers(udev, pm)) | ||
327 | goto fail2; | ||
328 | |||
329 | pm->irq = usb_alloc_urb(0, GFP_KERNEL); | ||
330 | if (!pm->irq) | ||
331 | goto fail2; | ||
332 | |||
333 | pm->config = usb_alloc_urb(0, GFP_KERNEL); | ||
334 | if (!pm->config) | ||
335 | goto fail3; | ||
336 | |||
337 | pm->udev = udev; | ||
338 | pm->input = input_dev; | ||
339 | |||
340 | usb_make_path(udev, pm->phys, sizeof(pm->phys)); | ||
341 | strlcpy(pm->phys, "/input0", sizeof(pm->phys)); | ||
342 | |||
343 | spin_lock_init(&pm->lock); | ||
344 | |||
345 | switch (le16_to_cpu(udev->descriptor.idProduct)) { | ||
346 | case POWERMATE_PRODUCT_NEW: | ||
347 | input_dev->name = pm_name_powermate; | ||
348 | break; | ||
349 | case POWERMATE_PRODUCT_OLD: | ||
350 | input_dev->name = pm_name_soundknob; | ||
351 | break; | ||
352 | default: | ||
353 | input_dev->name = pm_name_soundknob; | ||
354 | printk(KERN_WARNING "powermate: unknown product id %04x\n", | ||
355 | le16_to_cpu(udev->descriptor.idProduct)); | ||
356 | } | ||
357 | |||
358 | input_dev->phys = pm->phys; | ||
359 | usb_to_input_id(udev, &input_dev->id); | ||
360 | input_dev->dev.parent = &intf->dev; | ||
361 | |||
362 | input_set_drvdata(input_dev, pm); | ||
363 | |||
364 | input_dev->event = powermate_input_event; | ||
365 | |||
366 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); | ||
367 | input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
368 | input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); | ||
369 | input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); | ||
370 | |||
371 | /* get a handle to the interrupt data pipe */ | ||
372 | pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); | ||
373 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
374 | |||
375 | if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { | ||
376 | printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", | ||
377 | POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); | ||
378 | maxp = POWERMATE_PAYLOAD_SIZE_MAX; | ||
379 | } | ||
380 | |||
381 | usb_fill_int_urb(pm->irq, udev, pipe, pm->data, | ||
382 | maxp, powermate_irq, | ||
383 | pm, endpoint->bInterval); | ||
384 | pm->irq->transfer_dma = pm->data_dma; | ||
385 | pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
386 | |||
387 | /* register our interrupt URB with the USB system */ | ||
388 | if (usb_submit_urb(pm->irq, GFP_KERNEL)) { | ||
389 | error = -EIO; | ||
390 | goto fail4; | ||
391 | } | ||
392 | |||
393 | error = input_register_device(pm->input); | ||
394 | if (error) | ||
395 | goto fail5; | ||
396 | |||
397 | |||
398 | /* force an update of everything */ | ||
399 | pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; | ||
400 | powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters | ||
401 | |||
402 | usb_set_intfdata(intf, pm); | ||
403 | return 0; | ||
404 | |||
405 | fail5: usb_kill_urb(pm->irq); | ||
406 | fail4: usb_free_urb(pm->config); | ||
407 | fail3: usb_free_urb(pm->irq); | ||
408 | fail2: powermate_free_buffers(udev, pm); | ||
409 | fail1: input_free_device(input_dev); | ||
410 | kfree(pm); | ||
411 | return error; | ||
412 | } | ||
413 | |||
414 | /* Called when a USB device we've accepted ownership of is removed */ | ||
415 | static void powermate_disconnect(struct usb_interface *intf) | ||
416 | { | ||
417 | struct powermate_device *pm = usb_get_intfdata (intf); | ||
418 | |||
419 | usb_set_intfdata(intf, NULL); | ||
420 | if (pm) { | ||
421 | pm->requires_update = 0; | ||
422 | usb_kill_urb(pm->irq); | ||
423 | input_unregister_device(pm->input); | ||
424 | usb_free_urb(pm->irq); | ||
425 | usb_free_urb(pm->config); | ||
426 | powermate_free_buffers(interface_to_usbdev(intf), pm); | ||
427 | |||
428 | kfree(pm); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static struct usb_device_id powermate_devices [] = { | ||
433 | { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) }, | ||
434 | { USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) }, | ||
435 | { USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) }, | ||
436 | { } /* Terminating entry */ | ||
437 | }; | ||
438 | |||
439 | MODULE_DEVICE_TABLE (usb, powermate_devices); | ||
440 | |||
441 | static struct usb_driver powermate_driver = { | ||
442 | .name = "powermate", | ||
443 | .probe = powermate_probe, | ||
444 | .disconnect = powermate_disconnect, | ||
445 | .id_table = powermate_devices, | ||
446 | }; | ||
447 | |||
448 | static int __init powermate_init(void) | ||
449 | { | ||
450 | return usb_register(&powermate_driver); | ||
451 | } | ||
452 | |||
453 | static void __exit powermate_cleanup(void) | ||
454 | { | ||
455 | usb_deregister(&powermate_driver); | ||
456 | } | ||
457 | |||
458 | module_init(powermate_init); | ||
459 | module_exit(powermate_cleanup); | ||
460 | |||
461 | MODULE_AUTHOR( "William R Sowerbutts" ); | ||
462 | MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" ); | ||
463 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c new file mode 100644 index 000000000000..ab15880fd566 --- /dev/null +++ b/drivers/input/misc/yealink.c | |||
@@ -0,0 +1,1004 @@ | |||
1 | /* | ||
2 | * drivers/usb/input/yealink.c | ||
3 | * | ||
4 | * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of | ||
9 | * the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | /* | ||
21 | * Description: | ||
22 | * Driver for the USB-P1K voip usb phone. | ||
23 | * This device is produced by Yealink Network Technology Co Ltd | ||
24 | * but may be branded under several names: | ||
25 | * - Yealink usb-p1k | ||
26 | * - Tiptel 115 | ||
27 | * - ... | ||
28 | * | ||
29 | * This driver is based on: | ||
30 | * - the usbb2k-api http://savannah.nongnu.org/projects/usbb2k-api/ | ||
31 | * - information from http://memeteau.free.fr/usbb2k | ||
32 | * - the xpad-driver drivers/input/joystick/xpad.c | ||
33 | * | ||
34 | * Thanks to: | ||
35 | * - Olivier Vandorpe, for providing the usbb2k-api. | ||
36 | * - Martin Diehl, for spotting my memory allocation bug. | ||
37 | * | ||
38 | * History: | ||
39 | * 20050527 henk First version, functional keyboard. Keyboard events | ||
40 | * will pop-up on the ../input/eventX bus. | ||
41 | * 20050531 henk Added led, LCD, dialtone and sysfs interface. | ||
42 | * 20050610 henk Cleanups, make it ready for public consumption. | ||
43 | * 20050630 henk Cleanups, fixes in response to comments. | ||
44 | * 20050701 henk sysfs write serialisation, fix potential unload races | ||
45 | * 20050801 henk Added ringtone, restructure USB | ||
46 | * 20050816 henk Merge 2.6.13-rc6 | ||
47 | */ | ||
48 | |||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/init.h> | ||
51 | #include <linux/slab.h> | ||
52 | #include <linux/module.h> | ||
53 | #include <linux/rwsem.h> | ||
54 | #include <linux/usb/input.h> | ||
55 | |||
56 | #include "map_to_7segment.h" | ||
57 | #include "yealink.h" | ||
58 | |||
59 | #define DRIVER_VERSION "yld-20051230" | ||
60 | #define DRIVER_AUTHOR "Henk Vergonet" | ||
61 | #define DRIVER_DESC "Yealink phone driver" | ||
62 | |||
63 | #define YEALINK_POLLING_FREQUENCY 10 /* in [Hz] */ | ||
64 | |||
65 | struct yld_status { | ||
66 | u8 lcd[24]; | ||
67 | u8 led; | ||
68 | u8 dialtone; | ||
69 | u8 ringtone; | ||
70 | u8 keynum; | ||
71 | } __attribute__ ((packed)); | ||
72 | |||
73 | /* | ||
74 | * Register the LCD segment and icon map | ||
75 | */ | ||
76 | #define _LOC(k,l) { .a = (k), .m = (l) } | ||
77 | #define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm) \ | ||
78 | { .type = (t), \ | ||
79 | .u = { .s = { _LOC(a, am), _LOC(b, bm), _LOC(c, cm), \ | ||
80 | _LOC(d, dm), _LOC(e, em), _LOC(g, gm), \ | ||
81 | _LOC(f, fm) } } } | ||
82 | #define _PIC(t, h, hm, n) \ | ||
83 | { .type = (t), \ | ||
84 | .u = { .p = { .name = (n), .a = (h), .m = (hm) } } } | ||
85 | |||
86 | static const struct lcd_segment_map { | ||
87 | char type; | ||
88 | union { | ||
89 | struct pictogram_map { | ||
90 | u8 a,m; | ||
91 | char name[10]; | ||
92 | } p; | ||
93 | struct segment_map { | ||
94 | u8 a,m; | ||
95 | } s[7]; | ||
96 | } u; | ||
97 | } lcdMap[] = { | ||
98 | #include "yealink.h" | ||
99 | }; | ||
100 | |||
101 | struct yealink_dev { | ||
102 | struct input_dev *idev; /* input device */ | ||
103 | struct usb_device *udev; /* usb device */ | ||
104 | |||
105 | /* irq input channel */ | ||
106 | struct yld_ctl_packet *irq_data; | ||
107 | dma_addr_t irq_dma; | ||
108 | struct urb *urb_irq; | ||
109 | |||
110 | /* control output channel */ | ||
111 | struct yld_ctl_packet *ctl_data; | ||
112 | dma_addr_t ctl_dma; | ||
113 | struct usb_ctrlrequest *ctl_req; | ||
114 | dma_addr_t ctl_req_dma; | ||
115 | struct urb *urb_ctl; | ||
116 | |||
117 | char phys[64]; /* physical device path */ | ||
118 | |||
119 | u8 lcdMap[ARRAY_SIZE(lcdMap)]; /* state of LCD, LED ... */ | ||
120 | int key_code; /* last reported key */ | ||
121 | |||
122 | int stat_ix; | ||
123 | union { | ||
124 | struct yld_status s; | ||
125 | u8 b[sizeof(struct yld_status)]; | ||
126 | } master, copy; | ||
127 | }; | ||
128 | |||
129 | |||
130 | /******************************************************************************* | ||
131 | * Yealink lcd interface | ||
132 | ******************************************************************************/ | ||
133 | |||
134 | /* | ||
135 | * Register a default 7 segment character set | ||
136 | */ | ||
137 | static SEG7_DEFAULT_MAP(map_seg7); | ||
138 | |||
139 | /* Display a char, | ||
140 | * char '\9' and '\n' are placeholders and do not overwrite the original text. | ||
141 | * A space will always hide an icon. | ||
142 | */ | ||
143 | static int setChar(struct yealink_dev *yld, int el, int chr) | ||
144 | { | ||
145 | int i, a, m, val; | ||
146 | |||
147 | if (el >= ARRAY_SIZE(lcdMap)) | ||
148 | return -EINVAL; | ||
149 | |||
150 | if (chr == '\t' || chr == '\n') | ||
151 | return 0; | ||
152 | |||
153 | yld->lcdMap[el] = chr; | ||
154 | |||
155 | if (lcdMap[el].type == '.') { | ||
156 | a = lcdMap[el].u.p.a; | ||
157 | m = lcdMap[el].u.p.m; | ||
158 | if (chr != ' ') | ||
159 | yld->master.b[a] |= m; | ||
160 | else | ||
161 | yld->master.b[a] &= ~m; | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | val = map_to_seg7(&map_seg7, chr); | ||
166 | for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) { | ||
167 | m = lcdMap[el].u.s[i].m; | ||
168 | |||
169 | if (m == 0) | ||
170 | continue; | ||
171 | |||
172 | a = lcdMap[el].u.s[i].a; | ||
173 | if (val & 1) | ||
174 | yld->master.b[a] |= m; | ||
175 | else | ||
176 | yld->master.b[a] &= ~m; | ||
177 | val = val >> 1; | ||
178 | } | ||
179 | return 0; | ||
180 | }; | ||
181 | |||
182 | /******************************************************************************* | ||
183 | * Yealink key interface | ||
184 | ******************************************************************************/ | ||
185 | |||
186 | /* Map device buttons to internal key events. | ||
187 | * | ||
188 | * USB-P1K button layout: | ||
189 | * | ||
190 | * up | ||
191 | * IN OUT | ||
192 | * down | ||
193 | * | ||
194 | * pickup C hangup | ||
195 | * 1 2 3 | ||
196 | * 4 5 6 | ||
197 | * 7 8 9 | ||
198 | * * 0 # | ||
199 | * | ||
200 | * The "up" and "down" keys, are symbolised by arrows on the button. | ||
201 | * The "pickup" and "hangup" keys are symbolised by a green and red phone | ||
202 | * on the button. | ||
203 | */ | ||
204 | static int map_p1k_to_key(int scancode) | ||
205 | { | ||
206 | switch(scancode) { /* phone key: */ | ||
207 | case 0x23: return KEY_LEFT; /* IN */ | ||
208 | case 0x33: return KEY_UP; /* up */ | ||
209 | case 0x04: return KEY_RIGHT; /* OUT */ | ||
210 | case 0x24: return KEY_DOWN; /* down */ | ||
211 | case 0x03: return KEY_ENTER; /* pickup */ | ||
212 | case 0x14: return KEY_BACKSPACE; /* C */ | ||
213 | case 0x13: return KEY_ESC; /* hangup */ | ||
214 | case 0x00: return KEY_1; /* 1 */ | ||
215 | case 0x01: return KEY_2; /* 2 */ | ||
216 | case 0x02: return KEY_3; /* 3 */ | ||
217 | case 0x10: return KEY_4; /* 4 */ | ||
218 | case 0x11: return KEY_5; /* 5 */ | ||
219 | case 0x12: return KEY_6; /* 6 */ | ||
220 | case 0x20: return KEY_7; /* 7 */ | ||
221 | case 0x21: return KEY_8; /* 8 */ | ||
222 | case 0x22: return KEY_9; /* 9 */ | ||
223 | case 0x30: return KEY_KPASTERISK; /* * */ | ||
224 | case 0x31: return KEY_0; /* 0 */ | ||
225 | case 0x32: return KEY_LEFTSHIFT | | ||
226 | KEY_3 << 8; /* # */ | ||
227 | } | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | /* Completes a request by converting the data into events for the | ||
232 | * input subsystem. | ||
233 | * | ||
234 | * The key parameter can be cascaded: key2 << 8 | key1 | ||
235 | */ | ||
236 | static void report_key(struct yealink_dev *yld, int key) | ||
237 | { | ||
238 | struct input_dev *idev = yld->idev; | ||
239 | |||
240 | if (yld->key_code >= 0) { | ||
241 | /* old key up */ | ||
242 | input_report_key(idev, yld->key_code & 0xff, 0); | ||
243 | if (yld->key_code >> 8) | ||
244 | input_report_key(idev, yld->key_code >> 8, 0); | ||
245 | } | ||
246 | |||
247 | yld->key_code = key; | ||
248 | if (key >= 0) { | ||
249 | /* new valid key */ | ||
250 | input_report_key(idev, key & 0xff, 1); | ||
251 | if (key >> 8) | ||
252 | input_report_key(idev, key >> 8, 1); | ||
253 | } | ||
254 | input_sync(idev); | ||
255 | } | ||
256 | |||
257 | /******************************************************************************* | ||
258 | * Yealink usb communication interface | ||
259 | ******************************************************************************/ | ||
260 | |||
261 | static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p) | ||
262 | { | ||
263 | u8 *buf = (u8 *)p; | ||
264 | int i; | ||
265 | u8 sum = 0; | ||
266 | |||
267 | for(i=0; i<USB_PKT_LEN-1; i++) | ||
268 | sum -= buf[i]; | ||
269 | p->sum = sum; | ||
270 | return usb_control_msg(yld->udev, | ||
271 | usb_sndctrlpipe(yld->udev, 0), | ||
272 | USB_REQ_SET_CONFIGURATION, | ||
273 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
274 | 0x200, 3, | ||
275 | p, sizeof(*p), | ||
276 | USB_CTRL_SET_TIMEOUT); | ||
277 | } | ||
278 | |||
279 | static u8 default_ringtone[] = { | ||
280 | 0xEF, /* volume [0-255] */ | ||
281 | 0xFB, 0x1E, 0x00, 0x0C, /* 1250 [hz], 12/100 [s] */ | ||
282 | 0xFC, 0x18, 0x00, 0x0C, /* 1000 [hz], 12/100 [s] */ | ||
283 | 0xFB, 0x1E, 0x00, 0x0C, | ||
284 | 0xFC, 0x18, 0x00, 0x0C, | ||
285 | 0xFB, 0x1E, 0x00, 0x0C, | ||
286 | 0xFC, 0x18, 0x00, 0x0C, | ||
287 | 0xFB, 0x1E, 0x00, 0x0C, | ||
288 | 0xFC, 0x18, 0x00, 0x0C, | ||
289 | 0xFF, 0xFF, 0x01, 0x90, /* silent, 400/100 [s] */ | ||
290 | 0x00, 0x00 /* end of sequence */ | ||
291 | }; | ||
292 | |||
293 | static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size) | ||
294 | { | ||
295 | struct yld_ctl_packet *p = yld->ctl_data; | ||
296 | int ix, len; | ||
297 | |||
298 | if (size <= 0) | ||
299 | return -EINVAL; | ||
300 | |||
301 | /* Set the ringtone volume */ | ||
302 | memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data))); | ||
303 | yld->ctl_data->cmd = CMD_RING_VOLUME; | ||
304 | yld->ctl_data->size = 1; | ||
305 | yld->ctl_data->data[0] = buf[0]; | ||
306 | yealink_cmd(yld, p); | ||
307 | |||
308 | buf++; | ||
309 | size--; | ||
310 | |||
311 | p->cmd = CMD_RING_NOTE; | ||
312 | ix = 0; | ||
313 | while (size != ix) { | ||
314 | len = size - ix; | ||
315 | if (len > sizeof(p->data)) | ||
316 | len = sizeof(p->data); | ||
317 | p->size = len; | ||
318 | p->offset = cpu_to_be16(ix); | ||
319 | memcpy(p->data, &buf[ix], len); | ||
320 | yealink_cmd(yld, p); | ||
321 | ix += len; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /* keep stat_master & stat_copy in sync. | ||
327 | */ | ||
328 | static int yealink_do_idle_tasks(struct yealink_dev *yld) | ||
329 | { | ||
330 | u8 val; | ||
331 | int i, ix, len; | ||
332 | |||
333 | ix = yld->stat_ix; | ||
334 | |||
335 | memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data))); | ||
336 | yld->ctl_data->cmd = CMD_KEYPRESS; | ||
337 | yld->ctl_data->size = 1; | ||
338 | yld->ctl_data->sum = 0xff - CMD_KEYPRESS; | ||
339 | |||
340 | /* If state update pointer wraps do a KEYPRESS first. */ | ||
341 | if (ix >= sizeof(yld->master)) { | ||
342 | yld->stat_ix = 0; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | /* find update candidates: copy != master */ | ||
347 | do { | ||
348 | val = yld->master.b[ix]; | ||
349 | if (val != yld->copy.b[ix]) | ||
350 | goto send_update; | ||
351 | } while (++ix < sizeof(yld->master)); | ||
352 | |||
353 | /* nothing todo, wait a bit and poll for a KEYPRESS */ | ||
354 | yld->stat_ix = 0; | ||
355 | /* TODO how can we wait abit. ?? | ||
356 | * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY); | ||
357 | */ | ||
358 | return 0; | ||
359 | |||
360 | send_update: | ||
361 | |||
362 | /* Setup an appropriate update request */ | ||
363 | yld->copy.b[ix] = val; | ||
364 | yld->ctl_data->data[0] = val; | ||
365 | |||
366 | switch(ix) { | ||
367 | case offsetof(struct yld_status, led): | ||
368 | yld->ctl_data->cmd = CMD_LED; | ||
369 | yld->ctl_data->sum = -1 - CMD_LED - val; | ||
370 | break; | ||
371 | case offsetof(struct yld_status, dialtone): | ||
372 | yld->ctl_data->cmd = CMD_DIALTONE; | ||
373 | yld->ctl_data->sum = -1 - CMD_DIALTONE - val; | ||
374 | break; | ||
375 | case offsetof(struct yld_status, ringtone): | ||
376 | yld->ctl_data->cmd = CMD_RINGTONE; | ||
377 | yld->ctl_data->sum = -1 - CMD_RINGTONE - val; | ||
378 | break; | ||
379 | case offsetof(struct yld_status, keynum): | ||
380 | val--; | ||
381 | val &= 0x1f; | ||
382 | yld->ctl_data->cmd = CMD_SCANCODE; | ||
383 | yld->ctl_data->offset = cpu_to_be16(val); | ||
384 | yld->ctl_data->data[0] = 0; | ||
385 | yld->ctl_data->sum = -1 - CMD_SCANCODE - val; | ||
386 | break; | ||
387 | default: | ||
388 | len = sizeof(yld->master.s.lcd) - ix; | ||
389 | if (len > sizeof(yld->ctl_data->data)) | ||
390 | len = sizeof(yld->ctl_data->data); | ||
391 | |||
392 | /* Combine up to <len> consecutive LCD bytes in a singe request | ||
393 | */ | ||
394 | yld->ctl_data->cmd = CMD_LCD; | ||
395 | yld->ctl_data->offset = cpu_to_be16(ix); | ||
396 | yld->ctl_data->size = len; | ||
397 | yld->ctl_data->sum = -CMD_LCD - ix - val - len; | ||
398 | for(i=1; i<len; i++) { | ||
399 | ix++; | ||
400 | val = yld->master.b[ix]; | ||
401 | yld->copy.b[ix] = val; | ||
402 | yld->ctl_data->data[i] = val; | ||
403 | yld->ctl_data->sum -= val; | ||
404 | } | ||
405 | } | ||
406 | yld->stat_ix = ix + 1; | ||
407 | return 1; | ||
408 | } | ||
409 | |||
410 | /* Decide on how to handle responses | ||
411 | * | ||
412 | * The state transition diagram is somethhing like: | ||
413 | * | ||
414 | * syncState<--+ | ||
415 | * | | | ||
416 | * | idle | ||
417 | * \|/ | | ||
418 | * init --ok--> waitForKey --ok--> getKey | ||
419 | * ^ ^ | | ||
420 | * | +-------ok-------+ | ||
421 | * error,start | ||
422 | * | ||
423 | */ | ||
424 | static void urb_irq_callback(struct urb *urb) | ||
425 | { | ||
426 | struct yealink_dev *yld = urb->context; | ||
427 | int ret; | ||
428 | |||
429 | if (urb->status) | ||
430 | err("%s - urb status %d", __FUNCTION__, urb->status); | ||
431 | |||
432 | switch (yld->irq_data->cmd) { | ||
433 | case CMD_KEYPRESS: | ||
434 | |||
435 | yld->master.s.keynum = yld->irq_data->data[0]; | ||
436 | break; | ||
437 | |||
438 | case CMD_SCANCODE: | ||
439 | dbg("get scancode %x", yld->irq_data->data[0]); | ||
440 | |||
441 | report_key(yld, map_p1k_to_key(yld->irq_data->data[0])); | ||
442 | break; | ||
443 | |||
444 | default: | ||
445 | err("unexpected response %x", yld->irq_data->cmd); | ||
446 | } | ||
447 | |||
448 | yealink_do_idle_tasks(yld); | ||
449 | |||
450 | ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); | ||
451 | if (ret) | ||
452 | err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); | ||
453 | } | ||
454 | |||
455 | static void urb_ctl_callback(struct urb *urb) | ||
456 | { | ||
457 | struct yealink_dev *yld = urb->context; | ||
458 | int ret; | ||
459 | |||
460 | if (urb->status) | ||
461 | err("%s - urb status %d", __FUNCTION__, urb->status); | ||
462 | |||
463 | switch (yld->ctl_data->cmd) { | ||
464 | case CMD_KEYPRESS: | ||
465 | case CMD_SCANCODE: | ||
466 | /* ask for a response */ | ||
467 | ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC); | ||
468 | break; | ||
469 | default: | ||
470 | /* send new command */ | ||
471 | yealink_do_idle_tasks(yld); | ||
472 | ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); | ||
473 | } | ||
474 | |||
475 | if (ret) | ||
476 | err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); | ||
477 | } | ||
478 | |||
479 | /******************************************************************************* | ||
480 | * input event interface | ||
481 | ******************************************************************************/ | ||
482 | |||
483 | /* TODO should we issue a ringtone on a SND_BELL event? | ||
484 | static int input_ev(struct input_dev *dev, unsigned int type, | ||
485 | unsigned int code, int value) | ||
486 | { | ||
487 | |||
488 | if (type != EV_SND) | ||
489 | return -EINVAL; | ||
490 | |||
491 | switch (code) { | ||
492 | case SND_BELL: | ||
493 | case SND_TONE: | ||
494 | break; | ||
495 | default: | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | */ | ||
502 | |||
503 | static int input_open(struct input_dev *dev) | ||
504 | { | ||
505 | struct yealink_dev *yld = input_get_drvdata(dev); | ||
506 | int i, ret; | ||
507 | |||
508 | dbg("%s", __FUNCTION__); | ||
509 | |||
510 | /* force updates to device */ | ||
511 | for (i = 0; i<sizeof(yld->master); i++) | ||
512 | yld->copy.b[i] = ~yld->master.b[i]; | ||
513 | yld->key_code = -1; /* no keys pressed */ | ||
514 | |||
515 | yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone)); | ||
516 | |||
517 | /* issue INIT */ | ||
518 | memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data))); | ||
519 | yld->ctl_data->cmd = CMD_INIT; | ||
520 | yld->ctl_data->size = 10; | ||
521 | yld->ctl_data->sum = 0x100-CMD_INIT-10; | ||
522 | if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) { | ||
523 | dbg("%s - usb_submit_urb failed with result %d", | ||
524 | __FUNCTION__, ret); | ||
525 | return ret; | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static void input_close(struct input_dev *dev) | ||
531 | { | ||
532 | struct yealink_dev *yld = input_get_drvdata(dev); | ||
533 | |||
534 | usb_kill_urb(yld->urb_ctl); | ||
535 | usb_kill_urb(yld->urb_irq); | ||
536 | } | ||
537 | |||
538 | /******************************************************************************* | ||
539 | * sysfs interface | ||
540 | ******************************************************************************/ | ||
541 | |||
542 | static DECLARE_RWSEM(sysfs_rwsema); | ||
543 | |||
544 | /* Interface to the 7-segments translation table aka. char set. | ||
545 | */ | ||
546 | static ssize_t show_map(struct device *dev, struct device_attribute *attr, | ||
547 | char *buf) | ||
548 | { | ||
549 | memcpy(buf, &map_seg7, sizeof(map_seg7)); | ||
550 | return sizeof(map_seg7); | ||
551 | } | ||
552 | |||
553 | static ssize_t store_map(struct device *dev, struct device_attribute *attr, | ||
554 | const char *buf, size_t cnt) | ||
555 | { | ||
556 | if (cnt != sizeof(map_seg7)) | ||
557 | return -EINVAL; | ||
558 | memcpy(&map_seg7, buf, sizeof(map_seg7)); | ||
559 | return sizeof(map_seg7); | ||
560 | } | ||
561 | |||
562 | /* Interface to the LCD. | ||
563 | */ | ||
564 | |||
565 | /* Reading /sys/../lineX will return the format string with its settings: | ||
566 | * | ||
567 | * Example: | ||
568 | * cat ./line3 | ||
569 | * 888888888888 | ||
570 | * Linux Rocks! | ||
571 | */ | ||
572 | static ssize_t show_line(struct device *dev, char *buf, int a, int b) | ||
573 | { | ||
574 | struct yealink_dev *yld; | ||
575 | int i; | ||
576 | |||
577 | down_read(&sysfs_rwsema); | ||
578 | yld = dev_get_drvdata(dev); | ||
579 | if (yld == NULL) { | ||
580 | up_read(&sysfs_rwsema); | ||
581 | return -ENODEV; | ||
582 | } | ||
583 | |||
584 | for (i = a; i < b; i++) | ||
585 | *buf++ = lcdMap[i].type; | ||
586 | *buf++ = '\n'; | ||
587 | for (i = a; i < b; i++) | ||
588 | *buf++ = yld->lcdMap[i]; | ||
589 | *buf++ = '\n'; | ||
590 | *buf = 0; | ||
591 | |||
592 | up_read(&sysfs_rwsema); | ||
593 | return 3 + ((b - a) << 1); | ||
594 | } | ||
595 | |||
596 | static ssize_t show_line1(struct device *dev, struct device_attribute *attr, | ||
597 | char *buf) | ||
598 | { | ||
599 | return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET); | ||
600 | } | ||
601 | |||
602 | static ssize_t show_line2(struct device *dev, struct device_attribute *attr, | ||
603 | char *buf) | ||
604 | { | ||
605 | return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET); | ||
606 | } | ||
607 | |||
608 | static ssize_t show_line3(struct device *dev, struct device_attribute *attr, | ||
609 | char *buf) | ||
610 | { | ||
611 | return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET); | ||
612 | } | ||
613 | |||
614 | /* Writing to /sys/../lineX will set the coresponding LCD line. | ||
615 | * - Excess characters are ignored. | ||
616 | * - If less characters are written than allowed, the remaining digits are | ||
617 | * unchanged. | ||
618 | * - The '\n' or '\t' char is a placeholder, it does not overwrite the | ||
619 | * original content. | ||
620 | */ | ||
621 | static ssize_t store_line(struct device *dev, const char *buf, size_t count, | ||
622 | int el, size_t len) | ||
623 | { | ||
624 | struct yealink_dev *yld; | ||
625 | int i; | ||
626 | |||
627 | down_write(&sysfs_rwsema); | ||
628 | yld = dev_get_drvdata(dev); | ||
629 | if (yld == NULL) { | ||
630 | up_write(&sysfs_rwsema); | ||
631 | return -ENODEV; | ||
632 | } | ||
633 | |||
634 | if (len > count) | ||
635 | len = count; | ||
636 | for (i = 0; i < len; i++) | ||
637 | setChar(yld, el++, buf[i]); | ||
638 | |||
639 | up_write(&sysfs_rwsema); | ||
640 | return count; | ||
641 | } | ||
642 | |||
643 | static ssize_t store_line1(struct device *dev, struct device_attribute *attr, | ||
644 | const char *buf, size_t count) | ||
645 | { | ||
646 | return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE); | ||
647 | } | ||
648 | |||
649 | static ssize_t store_line2(struct device *dev, struct device_attribute *attr, | ||
650 | const char *buf, size_t count) | ||
651 | { | ||
652 | return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE); | ||
653 | } | ||
654 | |||
655 | static ssize_t store_line3(struct device *dev, struct device_attribute *attr, | ||
656 | const char *buf, size_t count) | ||
657 | { | ||
658 | return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE); | ||
659 | } | ||
660 | |||
661 | /* Interface to visible and audible "icons", these include: | ||
662 | * pictures on the LCD, the LED, and the dialtone signal. | ||
663 | */ | ||
664 | |||
665 | /* Get a list of "switchable elements" with their current state. */ | ||
666 | static ssize_t get_icons(struct device *dev, struct device_attribute *attr, | ||
667 | char *buf) | ||
668 | { | ||
669 | struct yealink_dev *yld; | ||
670 | int i, ret = 1; | ||
671 | |||
672 | down_read(&sysfs_rwsema); | ||
673 | yld = dev_get_drvdata(dev); | ||
674 | if (yld == NULL) { | ||
675 | up_read(&sysfs_rwsema); | ||
676 | return -ENODEV; | ||
677 | } | ||
678 | |||
679 | for (i = 0; i < ARRAY_SIZE(lcdMap); i++) { | ||
680 | if (lcdMap[i].type != '.') | ||
681 | continue; | ||
682 | ret += sprintf(&buf[ret], "%s %s\n", | ||
683 | yld->lcdMap[i] == ' ' ? " " : "on", | ||
684 | lcdMap[i].u.p.name); | ||
685 | } | ||
686 | up_read(&sysfs_rwsema); | ||
687 | return ret; | ||
688 | } | ||
689 | |||
690 | /* Change the visibility of a particular element. */ | ||
691 | static ssize_t set_icon(struct device *dev, const char *buf, size_t count, | ||
692 | int chr) | ||
693 | { | ||
694 | struct yealink_dev *yld; | ||
695 | int i; | ||
696 | |||
697 | down_write(&sysfs_rwsema); | ||
698 | yld = dev_get_drvdata(dev); | ||
699 | if (yld == NULL) { | ||
700 | up_write(&sysfs_rwsema); | ||
701 | return -ENODEV; | ||
702 | } | ||
703 | |||
704 | for (i = 0; i < ARRAY_SIZE(lcdMap); i++) { | ||
705 | if (lcdMap[i].type != '.') | ||
706 | continue; | ||
707 | if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) { | ||
708 | setChar(yld, i, chr); | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | up_write(&sysfs_rwsema); | ||
714 | return count; | ||
715 | } | ||
716 | |||
717 | static ssize_t show_icon(struct device *dev, struct device_attribute *attr, | ||
718 | const char *buf, size_t count) | ||
719 | { | ||
720 | return set_icon(dev, buf, count, buf[0]); | ||
721 | } | ||
722 | |||
723 | static ssize_t hide_icon(struct device *dev, struct device_attribute *attr, | ||
724 | const char *buf, size_t count) | ||
725 | { | ||
726 | return set_icon(dev, buf, count, ' '); | ||
727 | } | ||
728 | |||
729 | /* Upload a ringtone to the device. | ||
730 | */ | ||
731 | |||
732 | /* Stores raw ringtone data in the phone */ | ||
733 | static ssize_t store_ringtone(struct device *dev, | ||
734 | struct device_attribute *attr, | ||
735 | const char *buf, size_t count) | ||
736 | { | ||
737 | struct yealink_dev *yld; | ||
738 | |||
739 | down_write(&sysfs_rwsema); | ||
740 | yld = dev_get_drvdata(dev); | ||
741 | if (yld == NULL) { | ||
742 | up_write(&sysfs_rwsema); | ||
743 | return -ENODEV; | ||
744 | } | ||
745 | |||
746 | /* TODO locking with async usb control interface??? */ | ||
747 | yealink_set_ringtone(yld, (char *)buf, count); | ||
748 | up_write(&sysfs_rwsema); | ||
749 | return count; | ||
750 | } | ||
751 | |||
752 | #define _M444 S_IRUGO | ||
753 | #define _M664 S_IRUGO|S_IWUSR|S_IWGRP | ||
754 | #define _M220 S_IWUSR|S_IWGRP | ||
755 | |||
756 | static DEVICE_ATTR(map_seg7 , _M664, show_map , store_map ); | ||
757 | static DEVICE_ATTR(line1 , _M664, show_line1 , store_line1 ); | ||
758 | static DEVICE_ATTR(line2 , _M664, show_line2 , store_line2 ); | ||
759 | static DEVICE_ATTR(line3 , _M664, show_line3 , store_line3 ); | ||
760 | static DEVICE_ATTR(get_icons , _M444, get_icons , NULL ); | ||
761 | static DEVICE_ATTR(show_icon , _M220, NULL , show_icon ); | ||
762 | static DEVICE_ATTR(hide_icon , _M220, NULL , hide_icon ); | ||
763 | static DEVICE_ATTR(ringtone , _M220, NULL , store_ringtone); | ||
764 | |||
765 | static struct attribute *yld_attributes[] = { | ||
766 | &dev_attr_line1.attr, | ||
767 | &dev_attr_line2.attr, | ||
768 | &dev_attr_line3.attr, | ||
769 | &dev_attr_get_icons.attr, | ||
770 | &dev_attr_show_icon.attr, | ||
771 | &dev_attr_hide_icon.attr, | ||
772 | &dev_attr_map_seg7.attr, | ||
773 | &dev_attr_ringtone.attr, | ||
774 | NULL | ||
775 | }; | ||
776 | |||
777 | static struct attribute_group yld_attr_group = { | ||
778 | .attrs = yld_attributes | ||
779 | }; | ||
780 | |||
781 | /******************************************************************************* | ||
782 | * Linux interface and usb initialisation | ||
783 | ******************************************************************************/ | ||
784 | |||
785 | struct driver_info { | ||
786 | char *name; | ||
787 | }; | ||
788 | |||
789 | static const struct driver_info info_P1K = { | ||
790 | .name = "Yealink usb-p1k", | ||
791 | }; | ||
792 | |||
793 | static const struct usb_device_id usb_table [] = { | ||
794 | { | ||
795 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
796 | USB_DEVICE_ID_MATCH_INT_INFO, | ||
797 | .idVendor = 0x6993, | ||
798 | .idProduct = 0xb001, | ||
799 | .bInterfaceClass = USB_CLASS_HID, | ||
800 | .bInterfaceSubClass = 0, | ||
801 | .bInterfaceProtocol = 0, | ||
802 | .driver_info = (kernel_ulong_t)&info_P1K | ||
803 | }, | ||
804 | { } | ||
805 | }; | ||
806 | |||
807 | static int usb_cleanup(struct yealink_dev *yld, int err) | ||
808 | { | ||
809 | if (yld == NULL) | ||
810 | return err; | ||
811 | |||
812 | usb_kill_urb(yld->urb_irq); /* parameter validation in core/urb */ | ||
813 | usb_kill_urb(yld->urb_ctl); /* parameter validation in core/urb */ | ||
814 | |||
815 | if (yld->idev) { | ||
816 | if (err) | ||
817 | input_free_device(yld->idev); | ||
818 | else | ||
819 | input_unregister_device(yld->idev); | ||
820 | } | ||
821 | |||
822 | usb_free_urb(yld->urb_irq); | ||
823 | usb_free_urb(yld->urb_ctl); | ||
824 | |||
825 | usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), | ||
826 | yld->ctl_req, yld->ctl_req_dma); | ||
827 | usb_buffer_free(yld->udev, USB_PKT_LEN, | ||
828 | yld->ctl_data, yld->ctl_dma); | ||
829 | usb_buffer_free(yld->udev, USB_PKT_LEN, | ||
830 | yld->irq_data, yld->irq_dma); | ||
831 | |||
832 | kfree(yld); | ||
833 | return err; | ||
834 | } | ||
835 | |||
836 | static void usb_disconnect(struct usb_interface *intf) | ||
837 | { | ||
838 | struct yealink_dev *yld; | ||
839 | |||
840 | down_write(&sysfs_rwsema); | ||
841 | yld = usb_get_intfdata(intf); | ||
842 | sysfs_remove_group(&intf->dev.kobj, &yld_attr_group); | ||
843 | usb_set_intfdata(intf, NULL); | ||
844 | up_write(&sysfs_rwsema); | ||
845 | |||
846 | usb_cleanup(yld, 0); | ||
847 | } | ||
848 | |||
849 | static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
850 | { | ||
851 | struct usb_device *udev = interface_to_usbdev (intf); | ||
852 | struct driver_info *nfo = (struct driver_info *)id->driver_info; | ||
853 | struct usb_host_interface *interface; | ||
854 | struct usb_endpoint_descriptor *endpoint; | ||
855 | struct yealink_dev *yld; | ||
856 | struct input_dev *input_dev; | ||
857 | int ret, pipe, i; | ||
858 | |||
859 | interface = intf->cur_altsetting; | ||
860 | endpoint = &interface->endpoint[0].desc; | ||
861 | if (!usb_endpoint_is_int_in(endpoint)) | ||
862 | return -ENODEV; | ||
863 | |||
864 | yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL); | ||
865 | if (!yld) | ||
866 | return -ENOMEM; | ||
867 | |||
868 | yld->udev = udev; | ||
869 | |||
870 | yld->idev = input_dev = input_allocate_device(); | ||
871 | if (!input_dev) | ||
872 | return usb_cleanup(yld, -ENOMEM); | ||
873 | |||
874 | /* allocate usb buffers */ | ||
875 | yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, | ||
876 | GFP_ATOMIC, &yld->irq_dma); | ||
877 | if (yld->irq_data == NULL) | ||
878 | return usb_cleanup(yld, -ENOMEM); | ||
879 | |||
880 | yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN, | ||
881 | GFP_ATOMIC, &yld->ctl_dma); | ||
882 | if (!yld->ctl_data) | ||
883 | return usb_cleanup(yld, -ENOMEM); | ||
884 | |||
885 | yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)), | ||
886 | GFP_ATOMIC, &yld->ctl_req_dma); | ||
887 | if (yld->ctl_req == NULL) | ||
888 | return usb_cleanup(yld, -ENOMEM); | ||
889 | |||
890 | /* allocate urb structures */ | ||
891 | yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL); | ||
892 | if (yld->urb_irq == NULL) | ||
893 | return usb_cleanup(yld, -ENOMEM); | ||
894 | |||
895 | yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL); | ||
896 | if (yld->urb_ctl == NULL) | ||
897 | return usb_cleanup(yld, -ENOMEM); | ||
898 | |||
899 | /* get a handle to the interrupt data pipe */ | ||
900 | pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); | ||
901 | ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
902 | if (ret != USB_PKT_LEN) | ||
903 | err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN); | ||
904 | |||
905 | /* initialise irq urb */ | ||
906 | usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data, | ||
907 | USB_PKT_LEN, | ||
908 | urb_irq_callback, | ||
909 | yld, endpoint->bInterval); | ||
910 | yld->urb_irq->transfer_dma = yld->irq_dma; | ||
911 | yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
912 | yld->urb_irq->dev = udev; | ||
913 | |||
914 | /* initialise ctl urb */ | ||
915 | yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | | ||
916 | USB_DIR_OUT; | ||
917 | yld->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION; | ||
918 | yld->ctl_req->wValue = cpu_to_le16(0x200); | ||
919 | yld->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber); | ||
920 | yld->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN); | ||
921 | |||
922 | usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0), | ||
923 | (void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN, | ||
924 | urb_ctl_callback, yld); | ||
925 | yld->urb_ctl->setup_dma = yld->ctl_req_dma; | ||
926 | yld->urb_ctl->transfer_dma = yld->ctl_dma; | ||
927 | yld->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP | | ||
928 | URB_NO_TRANSFER_DMA_MAP; | ||
929 | yld->urb_ctl->dev = udev; | ||
930 | |||
931 | /* find out the physical bus location */ | ||
932 | usb_make_path(udev, yld->phys, sizeof(yld->phys)); | ||
933 | strlcat(yld->phys, "/input0", sizeof(yld->phys)); | ||
934 | |||
935 | /* register settings for the input device */ | ||
936 | input_dev->name = nfo->name; | ||
937 | input_dev->phys = yld->phys; | ||
938 | usb_to_input_id(udev, &input_dev->id); | ||
939 | input_dev->dev.parent = &intf->dev; | ||
940 | |||
941 | input_set_drvdata(input_dev, yld); | ||
942 | |||
943 | input_dev->open = input_open; | ||
944 | input_dev->close = input_close; | ||
945 | /* input_dev->event = input_ev; TODO */ | ||
946 | |||
947 | /* register available key events */ | ||
948 | input_dev->evbit[0] = BIT(EV_KEY); | ||
949 | for (i = 0; i < 256; i++) { | ||
950 | int k = map_p1k_to_key(i); | ||
951 | if (k >= 0) { | ||
952 | set_bit(k & 0xff, input_dev->keybit); | ||
953 | if (k >> 8) | ||
954 | set_bit(k >> 8, input_dev->keybit); | ||
955 | } | ||
956 | } | ||
957 | |||
958 | ret = input_register_device(yld->idev); | ||
959 | if (ret) | ||
960 | return usb_cleanup(yld, ret); | ||
961 | |||
962 | usb_set_intfdata(intf, yld); | ||
963 | |||
964 | /* clear visible elements */ | ||
965 | for (i = 0; i < ARRAY_SIZE(lcdMap); i++) | ||
966 | setChar(yld, i, ' '); | ||
967 | |||
968 | /* display driver version on LCD line 3 */ | ||
969 | store_line3(&intf->dev, NULL, | ||
970 | DRIVER_VERSION, sizeof(DRIVER_VERSION)); | ||
971 | |||
972 | /* Register sysfs hooks (don't care about failure) */ | ||
973 | ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static struct usb_driver yealink_driver = { | ||
978 | .name = "yealink", | ||
979 | .probe = usb_probe, | ||
980 | .disconnect = usb_disconnect, | ||
981 | .id_table = usb_table, | ||
982 | }; | ||
983 | |||
984 | static int __init yealink_dev_init(void) | ||
985 | { | ||
986 | int ret = usb_register(&yealink_driver); | ||
987 | if (ret == 0) | ||
988 | info(DRIVER_DESC ":" DRIVER_VERSION); | ||
989 | return ret; | ||
990 | } | ||
991 | |||
992 | static void __exit yealink_dev_exit(void) | ||
993 | { | ||
994 | usb_deregister(&yealink_driver); | ||
995 | } | ||
996 | |||
997 | module_init(yealink_dev_init); | ||
998 | module_exit(yealink_dev_exit); | ||
999 | |||
1000 | MODULE_DEVICE_TABLE (usb, usb_table); | ||
1001 | |||
1002 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1003 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1004 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h new file mode 100644 index 000000000000..48af0be9cbdf --- /dev/null +++ b/drivers/input/misc/yealink.h | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * drivers/usb/input/yealink.h | ||
3 | * | ||
4 | * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> | ||
5 | * | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation; either version 2 of | ||
10 | * the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #ifndef INPUT_YEALINK_H | ||
22 | #define INPUT_YEALINK_H | ||
23 | |||
24 | /* Using the control channel on interface 3 various aspects of the phone | ||
25 | * can be controlled like LCD, LED, dialtone and the ringtone. | ||
26 | */ | ||
27 | |||
28 | struct yld_ctl_packet { | ||
29 | u8 cmd; /* command code, see below */ | ||
30 | u8 size; /* 1-11, size of used data bytes. */ | ||
31 | u16 offset; /* internal packet offset */ | ||
32 | u8 data[11]; | ||
33 | s8 sum; /* negative sum of 15 preceding bytes */ | ||
34 | } __attribute__ ((packed)); | ||
35 | |||
36 | #define USB_PKT_LEN sizeof(struct yld_ctl_packet) | ||
37 | |||
38 | /* The following yld_ctl_packet's are available: */ | ||
39 | |||
40 | /* Init registers | ||
41 | * | ||
42 | * cmd 0x8e | ||
43 | * size 10 | ||
44 | * offset 0 | ||
45 | * data 0,0,0,0.... | ||
46 | */ | ||
47 | #define CMD_INIT 0x8e | ||
48 | |||
49 | /* Request key scan | ||
50 | * | ||
51 | * cmd 0x80 | ||
52 | * size 1 | ||
53 | * offset 0 | ||
54 | * data[0] on return returns the key number, if it changes there's a new | ||
55 | * key pressed. | ||
56 | */ | ||
57 | #define CMD_KEYPRESS 0x80 | ||
58 | |||
59 | /* Request scancode | ||
60 | * | ||
61 | * cmd 0x81 | ||
62 | * size 1 | ||
63 | * offset key number [0-1f] | ||
64 | * data[0] on return returns the scancode | ||
65 | */ | ||
66 | #define CMD_SCANCODE 0x81 | ||
67 | |||
68 | /* Set LCD | ||
69 | * | ||
70 | * cmd 0x04 | ||
71 | * size 1-11 | ||
72 | * offset 0-23 | ||
73 | * data segment bits | ||
74 | */ | ||
75 | #define CMD_LCD 0x04 | ||
76 | |||
77 | /* Set led | ||
78 | * | ||
79 | * cmd 0x05 | ||
80 | * size 1 | ||
81 | * offset 0 | ||
82 | * data[0] 0 OFF / 1 ON | ||
83 | */ | ||
84 | #define CMD_LED 0x05 | ||
85 | |||
86 | /* Set ringtone volume | ||
87 | * | ||
88 | * cmd 0x11 | ||
89 | * size 1 | ||
90 | * offset 0 | ||
91 | * data[0] 0-0xff volume | ||
92 | */ | ||
93 | #define CMD_RING_VOLUME 0x11 | ||
94 | |||
95 | /* Set ringtone notes | ||
96 | * | ||
97 | * cmd 0x02 | ||
98 | * size 1-11 | ||
99 | * offset 0-> | ||
100 | * data binary representation LE16(-freq), LE16(duration) .... | ||
101 | */ | ||
102 | #define CMD_RING_NOTE 0x02 | ||
103 | |||
104 | /* Sound ringtone via the speaker on the back | ||
105 | * | ||
106 | * cmd 0x03 | ||
107 | * size 1 | ||
108 | * offset 0 | ||
109 | * data[0] 0 OFF / 0x24 ON | ||
110 | */ | ||
111 | #define CMD_RINGTONE 0x03 | ||
112 | |||
113 | /* Sound dial tone via the ear speaker | ||
114 | * | ||
115 | * cmd 0x09 | ||
116 | * size 1 | ||
117 | * offset 0 | ||
118 | * data[0] 0 OFF / 1 ON | ||
119 | */ | ||
120 | #define CMD_DIALTONE 0x09 | ||
121 | |||
122 | #endif /* INPUT_YEALINK_H */ | ||
123 | |||
124 | |||
125 | #if defined(_SEG) && defined(_PIC) | ||
126 | /* This table maps the LCD segments onto individual bit positions in the | ||
127 | * yld_status struct. | ||
128 | */ | ||
129 | |||
130 | /* LCD, each segment must be driven seperately. | ||
131 | * | ||
132 | * Layout: | ||
133 | * | ||
134 | * |[] [][] [][] [][] in |[][] | ||
135 | * |[] M [][] D [][] : [][] out |[][] | ||
136 | * store | ||
137 | * | ||
138 | * NEW REP SU MO TU WE TH FR SA | ||
139 | * | ||
140 | * [] [] [] [] [] [] [] [] [] [] [] [] | ||
141 | * [] [] [] [] [] [] [] [] [] [] [] [] | ||
142 | */ | ||
143 | |||
144 | /* Line 1 | ||
145 | * Format : 18.e8.M8.88...188 | ||
146 | * Icon names : M D : IN OUT STORE | ||
147 | */ | ||
148 | #define LCD_LINE1_OFFSET 0 | ||
149 | #define LCD_LINE1_SIZE 17 | ||
150 | |||
151 | /* Note: first g then f => ! ! */ | ||
152 | /* _SEG( type a b c d e g f ) */ | ||
153 | _SEG('1', 0,0 , 22,2 , 22,2 , 0,0 , 0,0 , 0,0 , 0,0 ), | ||
154 | _SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1 ), | ||
155 | _PIC('.', 22,1 , "M" ), | ||
156 | _SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1 ), | ||
157 | _SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1 ), | ||
158 | _PIC('.', 15,8 , "D" ), | ||
159 | _SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1 ), | ||
160 | _SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1 ), | ||
161 | _PIC('.', 11,8 , ":" ), | ||
162 | _SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1 ), | ||
163 | _SEG('8', 8,1 , 8,2 , 8,4 , 8,8 , 9,4 , 9,2 , 9,1 ), | ||
164 | _PIC('.', 7,1 , "IN" ), | ||
165 | _PIC('.', 7,2 , "OUT" ), | ||
166 | _PIC('.', 7,4 , "STORE" ), | ||
167 | _SEG('1', 0,0 , 5,1 , 5,1 , 0,0 , 0,0 , 0,0 , 0,0 ), | ||
168 | _SEG('8', 4,1 , 4,2 , 4,4 , 4,8 , 5,8 , 5,4 , 5,2 ), | ||
169 | _SEG('8', 2,1 , 2,2 , 2,4 , 2,8 , 3,4 , 3,2 , 3,1 ), | ||
170 | |||
171 | /* Line 2 | ||
172 | * Format : ......... | ||
173 | * Pict. name : NEW REP SU MO TU WE TH FR SA | ||
174 | */ | ||
175 | #define LCD_LINE2_OFFSET LCD_LINE1_OFFSET + LCD_LINE1_SIZE | ||
176 | #define LCD_LINE2_SIZE 9 | ||
177 | |||
178 | _PIC('.', 23,2 , "NEW" ), | ||
179 | _PIC('.', 23,4 , "REP" ), | ||
180 | _PIC('.', 1,8 , "SU" ), | ||
181 | _PIC('.', 1,4 , "MO" ), | ||
182 | _PIC('.', 1,2 , "TU" ), | ||
183 | _PIC('.', 1,1 , "WE" ), | ||
184 | _PIC('.', 0,1 , "TH" ), | ||
185 | _PIC('.', 0,2 , "FR" ), | ||
186 | _PIC('.', 0,4 , "SA" ), | ||
187 | |||
188 | /* Line 3 | ||
189 | * Format : 888888888888 | ||
190 | */ | ||
191 | #define LCD_LINE3_OFFSET LCD_LINE2_OFFSET + LCD_LINE2_SIZE | ||
192 | #define LCD_LINE3_SIZE 12 | ||
193 | |||
194 | _SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32 ), | ||
195 | _SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32 ), | ||
196 | _SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32 ), | ||
197 | _SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32 ), | ||
198 | _SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32 ), | ||
199 | _SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32 ), | ||
200 | _SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32 ), | ||
201 | _SEG('8', 8,16, 8,32, 8,64, 8,128, 9,128, 9,64, 9,32 ), | ||
202 | _SEG('8', 6,16, 6,32, 6,64, 6,128, 7,128, 7,64, 7,32 ), | ||
203 | _SEG('8', 4,16, 4,32, 4,64, 4,128, 5,128, 5,64, 5,32 ), | ||
204 | _SEG('8', 2,16, 2,32, 2,64, 2,128, 3,128, 3,64, 3,32 ), | ||
205 | _SEG('8', 0,16, 0,32, 0,64, 0,128, 1,128, 1,64, 1,32 ), | ||
206 | |||
207 | /* Line 4 | ||
208 | * | ||
209 | * The LED, DIALTONE and RINGTONE are implemented as icons and use the same | ||
210 | * sysfs interface. | ||
211 | */ | ||
212 | #define LCD_LINE4_OFFSET LCD_LINE3_OFFSET + LCD_LINE3_SIZE | ||
213 | |||
214 | _PIC('.', offsetof(struct yld_status, led) , 0x01, "LED" ), | ||
215 | _PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ), | ||
216 | _PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ), | ||
217 | |||
218 | #undef _SEG | ||
219 | #undef _PIC | ||
220 | #endif /* _SEG && _PIC */ | ||