]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/input/joystick/iforce/iforce-serio.c
Input: iforce - drop bus type from iforce structure
[linux.git] / drivers / input / joystick / iforce / iforce-serio.c
1 /*
2  *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
3  *  Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
4  *
5  *  USB/RS232 I-Force joysticks and wheels.
6  */
7
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24 #include <linux/serio.h>
25 #include "iforce.h"
26
27 struct iforce_serio {
28         struct iforce iforce;
29
30         struct serio *serio;
31         int idx, pkt, len, id;
32         u8 csum;
33         u8 expect_packet;
34         u8 cmd_response[IFORCE_MAX_LENGTH];
35         u8 cmd_response_len;
36         u8 data_in[IFORCE_MAX_LENGTH];
37 };
38
39 static void iforce_serio_xmit(struct iforce *iforce)
40 {
41         struct iforce_serio *iforce_serio = container_of(iforce,
42                                                          struct iforce_serio,
43                                                          iforce);
44         unsigned char cs;
45         int i;
46         unsigned long flags;
47
48         if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
49                 set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
50                 return;
51         }
52
53         spin_lock_irqsave(&iforce->xmit_lock, flags);
54
55 again:
56         if (iforce->xmit.head == iforce->xmit.tail) {
57                 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
58                 spin_unlock_irqrestore(&iforce->xmit_lock, flags);
59                 return;
60         }
61
62         cs = 0x2b;
63
64         serio_write(iforce_serio->serio, 0x2b);
65
66         serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
67         cs ^= iforce->xmit.buf[iforce->xmit.tail];
68         XMIT_INC(iforce->xmit.tail, 1);
69
70         for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
71                 serio_write(iforce_serio->serio,
72                             iforce->xmit.buf[iforce->xmit.tail]);
73                 cs ^= iforce->xmit.buf[iforce->xmit.tail];
74                 XMIT_INC(iforce->xmit.tail, 1);
75         }
76
77         serio_write(iforce_serio->serio, cs);
78
79         if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
80                 goto again;
81
82         clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
83
84         spin_unlock_irqrestore(&iforce->xmit_lock, flags);
85 }
86
87 static int iforce_serio_get_id(struct iforce *iforce, u8 id,
88                                u8 *response_data, size_t *response_len)
89 {
90         struct iforce_serio *iforce_serio = container_of(iforce,
91                                                          struct iforce_serio,
92                                                          iforce);
93
94         iforce_serio->expect_packet = HI(FF_CMD_QUERY);
95         iforce_serio->cmd_response_len = 0;
96
97         iforce_send_packet(iforce, FF_CMD_QUERY, &id);
98
99         wait_event_interruptible_timeout(iforce->wait,
100                                          !iforce_serio->expect_packet, HZ);
101
102         if (iforce_serio->expect_packet) {
103                 iforce_serio->expect_packet = 0;
104                 return -ETIMEDOUT;
105         }
106
107         if (iforce_serio->cmd_response[0] != id)
108                 return -EIO;
109
110         memcpy(response_data, iforce_serio->cmd_response,
111                iforce_serio->cmd_response_len);
112         *response_len = iforce_serio->cmd_response_len;
113
114         return 0;
115 }
116
117 static int iforce_serio_start_io(struct iforce *iforce)
118 {
119         /* No special handling required */
120         return 0;
121 }
122
123 static void iforce_serio_stop_io(struct iforce *iforce)
124 {
125         //TODO: Wait for the last packets to be sent
126 }
127
128 static const struct iforce_xport_ops iforce_serio_xport_ops = {
129         .xmit           = iforce_serio_xmit,
130         .get_id         = iforce_serio_get_id,
131         .start_io       = iforce_serio_start_io,
132         .stop_io        = iforce_serio_stop_io,
133 };
134
135 static void iforce_serio_write_wakeup(struct serio *serio)
136 {
137         struct iforce *iforce = serio_get_drvdata(serio);
138
139         iforce_serio_xmit(iforce);
140 }
141
142 static irqreturn_t iforce_serio_irq(struct serio *serio,
143                                     unsigned char data, unsigned int flags)
144 {
145         struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
146         struct iforce *iforce = &iforce_serio->iforce;
147
148         if (!iforce_serio->pkt) {
149                 if (data == 0x2b)
150                         iforce_serio->pkt = 1;
151                 goto out;
152         }
153
154         if (!iforce_serio->id) {
155                 if (data > 3 && data != 0xff)
156                         iforce_serio->pkt = 0;
157                 else
158                         iforce_serio->id = data;
159                 goto out;
160         }
161
162         if (!iforce_serio->len) {
163                 if (data > IFORCE_MAX_LENGTH) {
164                         iforce_serio->pkt = 0;
165                         iforce_serio->id = 0;
166                 } else {
167                         iforce_serio->len = data;
168                 }
169                 goto out;
170         }
171
172         if (iforce_serio->idx < iforce_serio->len) {
173                 iforce_serio->data_in[iforce_serio->idx++] = data;
174                 iforce_serio->csum += data;
175                 goto out;
176         }
177
178         if (iforce_serio->idx == iforce_serio->len) {
179                 /* Handle command completion */
180                 if (iforce_serio->expect_packet == iforce_serio->id) {
181                         iforce_serio->expect_packet = 0;
182                         memcpy(iforce_serio->cmd_response,
183                                iforce_serio->data_in, IFORCE_MAX_LENGTH);
184                         iforce_serio->cmd_response_len = iforce_serio->len;
185
186                         /* Signal that command is done */
187                         wake_up(&iforce->wait);
188                 } else if (likely(iforce->type)) {
189                         iforce_process_packet(iforce, iforce_serio->id,
190                                               iforce_serio->data_in,
191                                               iforce_serio->len);
192                 }
193
194                 iforce_serio->pkt = 0;
195                 iforce_serio->id  = 0;
196                 iforce_serio->len = 0;
197                 iforce_serio->idx = 0;
198                 iforce_serio->csum = 0;
199         }
200 out:
201         return IRQ_HANDLED;
202 }
203
204 static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
205 {
206         struct iforce_serio *iforce_serio;
207         struct iforce *iforce;
208         int err;
209
210         iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
211         if (!iforce_serio)
212                 return -ENOMEM;
213
214         iforce = &iforce_serio->iforce;
215
216         iforce->xport_ops = &iforce_serio_xport_ops;
217
218         iforce_serio->serio = serio;
219         serio_set_drvdata(serio, iforce_serio);
220
221         err = serio_open(serio, drv);
222         if (err)
223                 goto fail1;
224
225         err = iforce_init_device(&serio->dev, BUS_RS232, iforce);
226         if (err)
227                 goto fail2;
228
229         return 0;
230
231  fail2: serio_close(serio);
232  fail1: serio_set_drvdata(serio, NULL);
233         kfree(iforce_serio);
234         return err;
235 }
236
237 static void iforce_serio_disconnect(struct serio *serio)
238 {
239         struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
240
241         input_unregister_device(iforce_serio->iforce.dev);
242         serio_close(serio);
243         serio_set_drvdata(serio, NULL);
244         kfree(iforce_serio);
245 }
246
247 static const struct serio_device_id iforce_serio_ids[] = {
248         {
249                 .type   = SERIO_RS232,
250                 .proto  = SERIO_IFORCE,
251                 .id     = SERIO_ANY,
252                 .extra  = SERIO_ANY,
253         },
254         { 0 }
255 };
256
257 MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
258
259 struct serio_driver iforce_serio_drv = {
260         .driver         = {
261                 .name   = "iforce",
262         },
263         .description    = "RS232 I-Force joysticks and wheels driver",
264         .id_table       = iforce_serio_ids,
265         .write_wakeup   = iforce_serio_write_wakeup,
266         .interrupt      = iforce_serio_irq,
267         .connect        = iforce_serio_connect,
268         .disconnect     = iforce_serio_disconnect,
269 };
270
271 module_serio_driver(iforce_serio_drv);
272
273 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
274 MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
275 MODULE_LICENSE("GPL");