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