import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / char / joystick / cobra.c
1 /*
2  * $Id: cobra.c,v 1.1.1.1 2005/04/11 02:50:21 jack Exp $
3  *
4  *  Copyright (c) 1999-2000 Vojtech Pavlik
5  *
6  *  Sponsored by SuSE
7  */
8
9 /*
10  * Creative Labd Blaster GamePad Cobra driver for Linux
11  */
12
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27  *
28  * Should you need to contact me, the author, you can do so either by
29  * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
30  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
31  */
32
33 #include <linux/kernel.h>
34 #include <linux/module.h>
35 #include <linux/slab.h>
36 #include <linux/init.h>
37 #include <linux/gameport.h>
38 #include <linux/input.h>
39
40 #define COBRA_MAX_STROBE        45      /* 45 us max wait for first strobe */
41 #define COBRA_REFRESH_TIME      HZ/50   /* 20 ms between reads */
42 #define COBRA_LENGTH            36
43
44 static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
45
46 static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
47
48 struct cobra {
49         struct gameport *gameport;
50         struct timer_list timer;
51         struct input_dev dev[2];
52         int used;
53         int reads;
54         int bads;
55         unsigned char exists;
56 };
57
58 static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
59 {
60         unsigned long flags;
61         unsigned char u, v, w;
62         __u64 buf[2];
63         int r[2], t[2];
64         int i, j, ret;
65
66         int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
67
68         for (i = 0; i < 2; i++) {
69                 r[i] = buf[i] = 0;
70                 t[i] = COBRA_MAX_STROBE;
71         }
72         
73         __save_flags(flags);
74         __cli();
75
76         u = gameport_read(gameport);
77
78         do {
79                 t[0]--; t[1]--;
80                 v = gameport_read(gameport);
81                 for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
82                         if (w & 0x30) {
83                                 if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
84                                         buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
85                                         t[i] = strobe;
86                                         u = v;
87                                 } else t[i] = 0;
88                         }
89         } while (t[0] > 0 || t[1] > 0);
90
91         __restore_flags(flags);
92
93         ret = 0;
94
95         for (i = 0; i < 2; i++) {
96
97                 if (r[i] != COBRA_LENGTH) continue;
98
99                 for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
100                         buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
101
102                 if (j < COBRA_LENGTH) ret |= (1 << i);
103
104                 data[i] = ((buf[i] >>  7) & 0x000001f) | ((buf[i] >>  8) & 0x00003e0)
105                         | ((buf[i] >>  9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
106                         | ((buf[i] >> 11) & 0x1f00000);
107
108         }
109
110         return ret;
111 }
112
113 static void cobra_timer(unsigned long private)
114 {
115         struct cobra *cobra = (void *) private;
116         struct input_dev *dev;
117         unsigned int data[2];
118         int i, j, r;
119
120         cobra->reads++;
121
122         if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
123                 cobra->bads++;
124
125         for (i = 0; i < 2; i++)
126                 if (cobra->exists & r & (1 << i)) {
127
128                         dev = cobra->dev + i;
129
130                         input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
131                         input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
132
133                         for (j = 0; cobra_btn[j]; j++)
134                                 input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
135
136                 }
137
138         mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); 
139 }
140
141 static int cobra_open(struct input_dev *dev)
142 {
143         struct cobra *cobra = dev->private;
144         if (!cobra->used++)
145                 mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME); 
146         return 0;
147 }
148
149 static void cobra_close(struct input_dev *dev)
150 {
151         struct cobra *cobra = dev->private;
152         if (!--cobra->used)
153                 del_timer(&cobra->timer);
154 }
155
156 static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
157 {
158         struct cobra *cobra;
159         unsigned int data[2];
160         int i, j;
161
162         if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
163                 return;
164         memset(cobra, 0, sizeof(struct cobra));
165
166         gameport->private = cobra;
167
168         cobra->gameport = gameport;
169         init_timer(&cobra->timer);
170         cobra->timer.data = (long) cobra;
171         cobra->timer.function = cobra_timer;
172
173         if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
174                 goto fail1;
175
176         cobra->exists = cobra_read_packet(gameport, data);
177
178         for (i = 0; i < 2; i++) 
179                 if ((cobra->exists >> i) & data[i] & 1) {
180                         printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
181                                 " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
182                         cobra->exists &= ~(1 << i);
183                 }
184
185         if (!cobra->exists)
186                 goto fail2;
187
188         for (i = 0; i < 2; i++)
189                 if ((cobra->exists >> i) & 1) {
190
191                         cobra->dev[i].private = cobra;
192                         cobra->dev[i].open = cobra_open;
193                         cobra->dev[i].close = cobra_close;
194
195                         cobra->dev[i].name = cobra_name;
196                         cobra->dev[i].idbus = BUS_GAMEPORT;
197                         cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
198                         cobra->dev[i].idproduct = 0x0008;
199                         cobra->dev[i].idversion = 0x0100;
200                 
201                         cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
202                         cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
203
204                         for (j = 0; cobra_btn[j]; j++)
205                                 set_bit(cobra_btn[j], cobra->dev[i].keybit);
206
207                         cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
208                         cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
209
210                         input_register_device(cobra->dev + i);
211                         printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
212                                 cobra->dev[i].number, cobra_name, gameport->number, i);
213                 }
214
215
216         return;
217 fail2:  gameport_close(gameport);
218 fail1:  kfree(cobra);
219 }
220
221 static void cobra_disconnect(struct gameport *gameport)
222 {
223         int i;
224
225         struct cobra *cobra = gameport->private;
226         for (i = 0; i < 2; i++)
227                 if ((cobra->exists >> i) & 1)
228                         input_unregister_device(cobra->dev + i);
229         gameport_close(gameport);
230         kfree(cobra);
231 }
232
233 static struct gameport_dev cobra_dev = {
234         connect:        cobra_connect,
235         disconnect:     cobra_disconnect,
236 };
237
238 int __init cobra_init(void)
239 {
240         gameport_register_device(&cobra_dev);
241         return 0;
242 }
243
244 void __exit cobra_exit(void)
245 {
246         gameport_unregister_device(&cobra_dev);
247 }
248
249 module_init(cobra_init);
250 module_exit(cobra_exit);
251
252 MODULE_LICENSE("GPL");