2 * $Id: wmforce.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
4 * Copyright (c) 2000 Vojtech Pavlik
6 * USB Logitech WingMan Force joystick support
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
28 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
31 #include <linux/kernel.h>
32 #include <linux/malloc.h>
33 #include <linux/input.h>
34 #include <linux/module.h>
35 #include <linux/init.h>
36 #include <linux/usb.h>
38 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
40 #define USB_VENDOR_ID_LOGITECH 0x046d
41 #define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
53 } wmforce_hat_to_axis
[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
55 static char *wmforce_name
= "Logitech WingMan Force";
57 static void wmforce_irq(struct urb
*urb
)
59 struct wmforce
*wmforce
= urb
->context
;
60 unsigned char *data
= wmforce
->data
;
61 struct input_dev
*dev
= &wmforce
->dev
;
63 if (urb
->status
) return;
67 warn("received unknown report #%d", data
[0]);
71 input_report_abs(dev
, ABS_X
, (__s16
) (((__s16
)data
[2] << 8) | data
[1]));
72 input_report_abs(dev
, ABS_Y
, (__s16
) (((__s16
)data
[4] << 8) | data
[3]));
73 input_report_abs(dev
, ABS_THROTTLE
, data
[5]);
74 input_report_abs(dev
, ABS_HAT0X
, wmforce_hat_to_axis
[data
[7] >> 4].x
);
75 input_report_abs(dev
, ABS_HAT0Y
, wmforce_hat_to_axis
[data
[7] >> 4].y
);
77 input_report_key(dev
, BTN_TRIGGER
, data
[6] & 0x01);
78 input_report_key(dev
, BTN_TOP
, data
[6] & 0x02);
79 input_report_key(dev
, BTN_THUMB
, data
[6] & 0x04);
80 input_report_key(dev
, BTN_TOP2
, data
[6] & 0x08);
81 input_report_key(dev
, BTN_BASE
, data
[6] & 0x10);
82 input_report_key(dev
, BTN_BASE2
, data
[6] & 0x20);
83 input_report_key(dev
, BTN_BASE3
, data
[6] & 0x40);
84 input_report_key(dev
, BTN_BASE4
, data
[6] & 0x80);
85 input_report_key(dev
, BTN_BASE5
, data
[7] & 0x01);
88 static int wmforce_open(struct input_dev
*dev
)
90 struct wmforce
*wmforce
= dev
->private;
95 if (usb_submit_urb(&wmforce
->irq
))
101 static void wmforce_close(struct input_dev
*dev
)
103 struct wmforce
*wmforce
= dev
->private;
105 if (!--wmforce
->open
)
106 usb_unlink_urb(&wmforce
->irq
);
109 static void *wmforce_probe(struct usb_device
*dev
, unsigned int ifnum
)
111 struct usb_endpoint_descriptor
*endpoint
;
112 struct wmforce
*wmforce
;
115 if (dev
->descriptor
.idVendor
!= USB_VENDOR_ID_LOGITECH
||
116 dev
->descriptor
.idProduct
!= USB_DEVICE_ID_LOGITECH_WMFORCE
)
119 endpoint
= dev
->config
[0].interface
[ifnum
].altsetting
[0].endpoint
+ 0;
121 if (!(wmforce
= kmalloc(sizeof(struct wmforce
), GFP_KERNEL
))) return NULL
;
122 memset(wmforce
, 0, sizeof(struct wmforce
));
124 wmforce
->dev
.evbit
[0] = BIT(EV_KEY
) | BIT(EV_ABS
);
125 wmforce
->dev
.keybit
[LONG(BTN_JOYSTICK
)] = BIT(BTN_TRIGGER
) | BIT(BTN_TOP
) | BIT(BTN_THUMB
) | BIT(BTN_TOP2
) |
126 BIT(BTN_BASE
) | BIT(BTN_BASE2
) | BIT(BTN_BASE3
) | BIT(BTN_BASE4
) | BIT(BTN_BASE5
);
127 wmforce
->dev
.absbit
[0] = BIT(ABS_X
) | BIT(ABS_Y
) | BIT(ABS_THROTTLE
) | BIT(ABS_HAT0X
) | BIT(ABS_HAT0Y
);
129 for (i
= ABS_X
; i
<= ABS_Y
; i
++) {
130 wmforce
->dev
.absmax
[i
] = 1920;
131 wmforce
->dev
.absmin
[i
] = -1920;
132 wmforce
->dev
.absflat
[i
] = 128;
135 wmforce
->dev
.absmax
[ABS_THROTTLE
] = 255;
136 wmforce
->dev
.absmin
[ABS_THROTTLE
] = 0;
138 for (i
= ABS_HAT0X
; i
<= ABS_HAT0Y
; i
++) {
139 wmforce
->dev
.absmax
[i
] = 1;
140 wmforce
->dev
.absmin
[i
] = -1;
143 wmforce
->dev
.private = wmforce
;
144 wmforce
->dev
.open
= wmforce_open
;
145 wmforce
->dev
.close
= wmforce_close
;
147 wmforce
->dev
.name
= wmforce_name
;
148 wmforce
->dev
.idbus
= BUS_USB
;
149 wmforce
->dev
.idvendor
= dev
->descriptor
.idVendor
;
150 wmforce
->dev
.idproduct
= dev
->descriptor
.idProduct
;
151 wmforce
->dev
.idversion
= dev
->descriptor
.bcdDevice
;
153 FILL_INT_URB(&wmforce
->irq
, dev
, usb_rcvintpipe(dev
, endpoint
->bEndpointAddress
),
154 wmforce
->data
, 8, wmforce_irq
, wmforce
, endpoint
->bInterval
);
156 input_register_device(&wmforce
->dev
);
158 printk(KERN_INFO
"input%d: %s on usb%d:%d.%d\n",
159 wmforce
->dev
.number
, wmforce_name
, dev
->bus
->busnum
, dev
->devnum
, ifnum
);
164 static void wmforce_disconnect(struct usb_device
*dev
, void *ptr
)
166 struct wmforce
*wmforce
= ptr
;
167 usb_unlink_urb(&wmforce
->irq
);
168 input_unregister_device(&wmforce
->dev
);
172 static struct usb_driver wmforce_driver
= {
174 probe
: wmforce_probe
,
175 disconnect
: wmforce_disconnect
,
178 static int __init
wmforce_init(void)
180 usb_register(&wmforce_driver
);
184 static void __exit
wmforce_exit(void)
186 usb_deregister(&wmforce_driver
);
189 module_init(wmforce_init
);
190 module_exit(wmforce_exit
);