Input: iforce - use DMA-safe buffer when getting IDs from USB
[linux-block.git] / drivers / input / joystick / iforce / iforce-usb.c
CommitLineData
1da177e4 1 /*
1da177e4 2 * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
598972d4 3 * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
1da177e4
LT
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
1da177e4
LT
22 */
23
4f99de6d 24#include <linux/usb.h>
1da177e4
LT
25#include "iforce.h"
26
81fd4313
DT
27struct iforce_usb {
28 struct iforce iforce;
29
30 struct usb_device *usbdev;
31 struct usb_interface *intf;
48735862 32 struct urb *irq, *out;
81fd4313
DT
33};
34
38d10769 35static void __iforce_usb_xmit(struct iforce *iforce)
1da177e4 36{
81fd4313
DT
37 struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
38 iforce);
1da177e4
LT
39 int n, c;
40 unsigned long flags;
41
42 spin_lock_irqsave(&iforce->xmit_lock, flags);
43
44 if (iforce->xmit.head == iforce->xmit.tail) {
45 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
46 spin_unlock_irqrestore(&iforce->xmit_lock, flags);
47 return;
48 }
49
81fd4313 50 ((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
1da177e4
LT
51 XMIT_INC(iforce->xmit.tail, 1);
52 n = iforce->xmit.buf[iforce->xmit.tail];
53 XMIT_INC(iforce->xmit.tail, 1);
54
81fd4313
DT
55 iforce_usb->out->transfer_buffer_length = n + 1;
56 iforce_usb->out->dev = iforce_usb->usbdev;
1da177e4
LT
57
58 /* Copy rest of data then */
59 c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
60 if (n < c) c=n;
61
81fd4313 62 memcpy(iforce_usb->out->transfer_buffer + 1,
1da177e4
LT
63 &iforce->xmit.buf[iforce->xmit.tail],
64 c);
65 if (n != c) {
81fd4313 66 memcpy(iforce_usb->out->transfer_buffer + 1 + c,
1da177e4
LT
67 &iforce->xmit.buf[0],
68 n-c);
69 }
70 XMIT_INC(iforce->xmit.tail, n);
71
81fd4313 72 if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
b8691fd2 73 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
81fd4313
DT
74 dev_warn(&iforce_usb->intf->dev,
75 "usb_submit_urb failed %d\n", n);
1da177e4
LT
76 }
77
78 /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
79 * As long as the urb completion handler is not called, the transmiting
80 * is considered to be running */
81 spin_unlock_irqrestore(&iforce->xmit_lock, flags);
82}
83
38d10769
DT
84static void iforce_usb_xmit(struct iforce *iforce)
85{
86 if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags))
87 __iforce_usb_xmit(iforce);
88}
89
2a1433ff
DT
90static int iforce_usb_get_id(struct iforce *iforce, u8 *packet)
91{
81fd4313
DT
92 struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
93 iforce);
48735862 94 u8 *buf;
2a1433ff
DT
95 int status;
96
48735862
DT
97 buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL);
98 if (!buf)
99 return -ENOMEM;
100
101 status = usb_control_msg(iforce_usb->usbdev,
102 usb_rcvctrlpipe(iforce_usb->usbdev, 0),
103 packet[0],
104 USB_TYPE_VENDOR | USB_DIR_IN |
105 USB_RECIP_INTERFACE,
106 0, 0, buf, IFORCE_MAX_LENGTH, HZ);
107 if (status < 0) {
81fd4313 108 dev_err(&iforce_usb->intf->dev,
48735862
DT
109 "usb_submit_urb failed: %d\n", status);
110 } else if (buf[0] != packet[0]) {
111 status = -EIO;
112 } else {
113 iforce->ecmd = 0xff00 | status;
114 memcpy(iforce->edata, buf, status);
115 status = 0;
2a1433ff
DT
116 }
117
48735862
DT
118 kfree(buf);
119 return status;
2a1433ff
DT
120}
121
05ca3828
DT
122static int iforce_usb_start_io(struct iforce *iforce)
123{
81fd4313
DT
124 struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
125 iforce);
126
127 if (usb_submit_urb(iforce_usb->irq, GFP_KERNEL))
05ca3828
DT
128 return -EIO;
129
130 return 0;
131}
132
133static void iforce_usb_stop_io(struct iforce *iforce)
134{
81fd4313
DT
135 struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
136 iforce);
137
138 usb_kill_urb(iforce_usb->irq);
139 usb_kill_urb(iforce_usb->out);
05ca3828
DT
140}
141
38d10769
DT
142static const struct iforce_xport_ops iforce_usb_xport_ops = {
143 .xmit = iforce_usb_xmit,
2a1433ff 144 .get_id = iforce_usb_get_id,
05ca3828
DT
145 .start_io = iforce_usb_start_io,
146 .stop_io = iforce_usb_stop_io,
38d10769
DT
147};
148
7d12e780 149static void iforce_usb_irq(struct urb *urb)
1da177e4 150{
81fd4313
DT
151 struct iforce_usb *iforce_usb = urb->context;
152 struct iforce *iforce = &iforce_usb->iforce;
153 struct device *dev = &iforce_usb->intf->dev;
1da177e4
LT
154 int status;
155
156 switch (urb->status) {
157 case 0:
158 /* success */
159 break;
160 case -ECONNRESET:
161 case -ENOENT:
162 case -ESHUTDOWN:
163 /* this urb is terminated, clean up */
f576125d
GKH
164 dev_dbg(dev, "%s - urb shutting down with status: %d\n",
165 __func__, urb->status);
1da177e4
LT
166 return;
167 default:
f576125d
GKH
168 dev_dbg(dev, "%s - urb has status of: %d\n",
169 __func__, urb->status);
1da177e4
LT
170 goto exit;
171 }
172
173 iforce_process_packet(iforce,
7d12e780 174 (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
1da177e4
LT
175
176exit:
81fd4313 177 status = usb_submit_urb(urb, GFP_ATOMIC);
1da177e4 178 if (status)
f576125d 179 dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
7b22a885 180 __func__, status);
1da177e4
LT
181}
182
7d12e780 183static void iforce_usb_out(struct urb *urb)
1da177e4 184{
81fd4313
DT
185 struct iforce_usb *iforce_usb = urb->context;
186 struct iforce *iforce = &iforce_usb->iforce;
1da177e4
LT
187
188 if (urb->status) {
c2b27ef6 189 clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
81fd4313 190 dev_dbg(&iforce_usb->intf->dev, "urb->status %d, exiting\n",
f576125d 191 urb->status);
1da177e4
LT
192 return;
193 }
194
38d10769 195 __iforce_usb_xmit(iforce);
1da177e4
LT
196
197 wake_up(&iforce->wait);
198}
199
1da177e4
LT
200static int iforce_usb_probe(struct usb_interface *intf,
201 const struct usb_device_id *id)
202{
203 struct usb_device *dev = interface_to_usbdev(intf);
204 struct usb_host_interface *interface;
205 struct usb_endpoint_descriptor *epirq, *epout;
81fd4313 206 struct iforce_usb *iforce_usb;
1da177e4 207 struct iforce *iforce;
17dd3f0f 208 int err = -ENOMEM;
1da177e4
LT
209
210 interface = intf->cur_altsetting;
211
59cf8bed
JH
212 if (interface->desc.bNumEndpoints < 2)
213 return -ENODEV;
214
1da177e4
LT
215 epirq = &interface->endpoint[0].desc;
216 epout = &interface->endpoint[1].desc;
217
81fd4313 218 if (!(iforce_usb = kzalloc(sizeof(*iforce_usb) + 32, GFP_KERNEL)))
1da177e4
LT
219 goto fail;
220
81fd4313 221 if (!(iforce_usb->irq = usb_alloc_urb(0, GFP_KERNEL)))
1da177e4 222 goto fail;
1da177e4 223
81fd4313 224 if (!(iforce_usb->out = usb_alloc_urb(0, GFP_KERNEL)))
1da177e4 225 goto fail;
1da177e4 226
81fd4313
DT
227 iforce = &iforce_usb->iforce;
228
38d10769 229 iforce->xport_ops = &iforce_usb_xport_ops;
1da177e4 230 iforce->bus = IFORCE_USB;
1da177e4 231
81fd4313
DT
232 iforce_usb->usbdev = dev;
233 iforce_usb->intf = intf;
234
81fd4313
DT
235 usb_fill_int_urb(iforce_usb->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
236 iforce->data, 16, iforce_usb_irq, iforce_usb, epirq->bInterval);
1da177e4 237
81fd4313
DT
238 usb_fill_int_urb(iforce_usb->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress),
239 iforce_usb + 1, 32, iforce_usb_out, iforce_usb, epout->bInterval);
1da177e4 240
501025df 241 err = iforce_init_device(&intf->dev, BUS_USB, iforce);
17dd3f0f
DT
242 if (err)
243 goto fail;
1da177e4 244
81fd4313 245 usb_set_intfdata(intf, iforce_usb);
1da177e4
LT
246 return 0;
247
248fail:
81fd4313
DT
249 if (iforce_usb) {
250 usb_free_urb(iforce_usb->irq);
251 usb_free_urb(iforce_usb->out);
81fd4313 252 kfree(iforce_usb);
1da177e4
LT
253 }
254
17dd3f0f 255 return err;
1da177e4
LT
256}
257
1da177e4
LT
258static void iforce_usb_disconnect(struct usb_interface *intf)
259{
81fd4313 260 struct iforce_usb *iforce_usb = usb_get_intfdata(intf);
1da177e4
LT
261
262 usb_set_intfdata(intf, NULL);
1da177e4 263
81fd4313 264 input_unregister_device(iforce_usb->iforce.dev);
98b7fb04 265
81fd4313
DT
266 usb_free_urb(iforce_usb->irq);
267 usb_free_urb(iforce_usb->out);
98b7fb04 268
81fd4313 269 kfree(iforce_usb);
1da177e4
LT
270}
271
c1295851 272static const struct usb_device_id iforce_usb_ids[] = {
1da177e4
LT
273 { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */
274 { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */
275 { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */
276 { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */
277 { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */
278 { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */
279 { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
68947b8f 280 { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */
1da177e4 281 { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
d861f7bf 282 { USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */
1da177e4 283 { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
18098a6c 284 { USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
1da177e4
LT
285 { } /* Terminating entry */
286};
287
288MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
289
290struct usb_driver iforce_usb_driver = {
1da177e4
LT
291 .name = "iforce",
292 .probe = iforce_usb_probe,
293 .disconnect = iforce_usb_disconnect,
294 .id_table = iforce_usb_ids,
295};
4f99de6d
DT
296
297module_usb_driver(iforce_usb_driver);
298
299MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
300MODULE_DESCRIPTION("USB I-Force joysticks and wheels driver");
301MODULE_LICENSE("GPL");