Rev 846 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
846 | giacomo | 1 | /* |
2 | * $Id: usbmouse.c,v 1.1 2004-09-13 15:04:47 giacomo Exp $ |
||
3 | * |
||
4 | * Copyright (c) 1999-2001 Vojtech Pavlik |
||
5 | * |
||
6 | * USB HIDBP Mouse support |
||
7 | */ |
||
8 | |||
9 | /* |
||
10 | * This program is free software; you can redistribute it and/or modify |
||
11 | * it under the terms of the GNU General Public License as published by |
||
12 | * the Free Software Foundation; either version 2 of the License, or |
||
13 | * (at your option) any later version. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU General Public License |
||
21 | * along with this program; if not, write to the Free Software |
||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
23 | * |
||
24 | * Should you need to contact me, the author, you can do so either by |
||
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
||
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
||
27 | */ |
||
28 | |||
29 | #include <linux/kernel.h> |
||
30 | #include <linux/slab.h> |
||
31 | #include <linux/input.h> |
||
32 | #include <linux/module.h> |
||
33 | #include <linux/init.h> |
||
34 | #include <linux/usb.h> |
||
35 | |||
36 | /* |
||
37 | * Version Information |
||
38 | */ |
||
39 | #define DRIVER_VERSION "v1.6" |
||
40 | #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" |
||
41 | #define DRIVER_DESC "USB HID Boot Protocol mouse driver" |
||
42 | #define DRIVER_LICENSE "GPL" |
||
43 | |||
44 | MODULE_AUTHOR(DRIVER_AUTHOR); |
||
45 | MODULE_DESCRIPTION(DRIVER_DESC); |
||
46 | MODULE_LICENSE(DRIVER_LICENSE); |
||
47 | |||
48 | struct usb_mouse { |
||
49 | char name[128]; |
||
50 | char phys[64]; |
||
51 | struct usb_device *usbdev; |
||
52 | struct input_dev dev; |
||
53 | struct urb *irq; |
||
54 | int open; |
||
55 | |||
56 | signed char *data; |
||
57 | dma_addr_t data_dma; |
||
58 | }; |
||
59 | |||
60 | static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs) |
||
61 | { |
||
62 | struct usb_mouse *mouse = urb->context; |
||
63 | signed char *data = mouse->data; |
||
64 | struct input_dev *dev = &mouse->dev; |
||
65 | int status; |
||
66 | |||
67 | switch (urb->status) { |
||
68 | case 0: /* success */ |
||
69 | break; |
||
70 | case -ECONNRESET: /* unlink */ |
||
71 | case -ENOENT: |
||
72 | case -ESHUTDOWN: |
||
73 | return; |
||
74 | /* -EPIPE: should clear the halt */ |
||
75 | default: /* error */ |
||
76 | goto resubmit; |
||
77 | } |
||
78 | |||
79 | input_regs(dev, regs); |
||
80 | |||
81 | input_report_key(dev, BTN_LEFT, data[0] & 0x01); |
||
82 | input_report_key(dev, BTN_RIGHT, data[0] & 0x02); |
||
83 | input_report_key(dev, BTN_MIDDLE, data[0] & 0x04); |
||
84 | input_report_key(dev, BTN_SIDE, data[0] & 0x08); |
||
85 | input_report_key(dev, BTN_EXTRA, data[0] & 0x10); |
||
86 | |||
87 | input_report_rel(dev, REL_X, data[1]); |
||
88 | input_report_rel(dev, REL_Y, data[2]); |
||
89 | input_report_rel(dev, REL_WHEEL, data[3]); |
||
90 | |||
91 | input_sync(dev); |
||
92 | resubmit: |
||
93 | status = usb_submit_urb (urb, SLAB_ATOMIC); |
||
94 | if (status) |
||
95 | err ("can't resubmit intr, %s-%s/input0, status %d", |
||
96 | mouse->usbdev->bus->bus_name, |
||
97 | mouse->usbdev->devpath, status); |
||
98 | } |
||
99 | |||
100 | static int usb_mouse_open(struct input_dev *dev) |
||
101 | { |
||
102 | struct usb_mouse *mouse = dev->private; |
||
103 | |||
104 | if (mouse->open++) |
||
105 | return 0; |
||
106 | |||
107 | mouse->irq->dev = mouse->usbdev; |
||
108 | if (usb_submit_urb(mouse->irq, GFP_KERNEL)) { |
||
109 | mouse->open--; |
||
110 | return -EIO; |
||
111 | } |
||
112 | |||
113 | return 0; |
||
114 | } |
||
115 | |||
116 | static void usb_mouse_close(struct input_dev *dev) |
||
117 | { |
||
118 | struct usb_mouse *mouse = dev->private; |
||
119 | |||
120 | if (!--mouse->open) |
||
121 | usb_unlink_urb(mouse->irq); |
||
122 | } |
||
123 | |||
124 | static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) |
||
125 | { |
||
126 | struct usb_device * dev = interface_to_usbdev(intf); |
||
127 | struct usb_host_interface *interface; |
||
128 | struct usb_endpoint_descriptor *endpoint; |
||
129 | struct usb_mouse *mouse; |
||
130 | int pipe, maxp; |
||
131 | char path[64]; |
||
132 | char *buf; |
||
133 | |||
134 | interface = &intf->altsetting[intf->act_altsetting]; |
||
135 | |||
136 | if (interface->desc.bNumEndpoints != 1) |
||
137 | return -ENODEV; |
||
138 | |||
139 | endpoint = &interface->endpoint[0].desc; |
||
140 | if (!(endpoint->bEndpointAddress & 0x80)) |
||
141 | return -ENODEV; |
||
142 | if ((endpoint->bmAttributes & 3) != 3) |
||
143 | return -ENODEV; |
||
144 | |||
145 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); |
||
146 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); |
||
147 | |||
148 | if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) |
||
149 | return -ENOMEM; |
||
150 | memset(mouse, 0, sizeof(struct usb_mouse)); |
||
151 | |||
152 | mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); |
||
153 | if (!mouse->data) { |
||
154 | kfree(mouse); |
||
155 | return -ENOMEM; |
||
156 | } |
||
157 | |||
158 | mouse->irq = usb_alloc_urb(0, GFP_KERNEL); |
||
159 | if (!mouse->irq) { |
||
160 | usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); |
||
161 | kfree(mouse); |
||
162 | return -ENODEV; |
||
163 | } |
||
164 | |||
165 | mouse->usbdev = dev; |
||
166 | |||
167 | mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); |
||
168 | mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); |
||
169 | mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); |
||
170 | mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); |
||
171 | mouse->dev.relbit[0] |= BIT(REL_WHEEL); |
||
172 | |||
173 | mouse->dev.private = mouse; |
||
174 | mouse->dev.open = usb_mouse_open; |
||
175 | mouse->dev.close = usb_mouse_close; |
||
176 | |||
177 | usb_make_path(dev, path, 64); |
||
178 | sprintf26(mouse->phys, "%s/input0", path); |
||
179 | |||
180 | mouse->dev.name = mouse->name; |
||
181 | mouse->dev.phys = mouse->phys; |
||
182 | mouse->dev.id.bustype = BUS_USB; |
||
183 | mouse->dev.id.vendor = dev->descriptor.idVendor; |
||
184 | mouse->dev.id.product = dev->descriptor.idProduct; |
||
185 | mouse->dev.id.version = dev->descriptor.bcdDevice; |
||
186 | |||
187 | if (!(buf = kmalloc(63, GFP_KERNEL))) { |
||
188 | usb_buffer_free(dev, 8, mouse->data, mouse->data_dma); |
||
189 | kfree(mouse); |
||
190 | return -ENOMEM; |
||
191 | } |
||
192 | |||
193 | if (dev->descriptor.iManufacturer && |
||
194 | usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) |
||
195 | strcat(mouse->name, buf); |
||
196 | if (dev->descriptor.iProduct && |
||
197 | usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) |
||
198 | sprintf26(mouse->name, "%s %s", mouse->name, buf); |
||
199 | |||
200 | if (!strlen(mouse->name)) |
||
201 | sprintf26(mouse->name, "USB HIDBP Mouse %04x:%04x", |
||
202 | mouse->dev.id.vendor, mouse->dev.id.product); |
||
203 | |||
204 | kfree(buf); |
||
205 | |||
206 | usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data, |
||
207 | (maxp > 8 ? 8 : maxp), |
||
208 | usb_mouse_irq, mouse, endpoint->bInterval); |
||
209 | mouse->irq->transfer_dma = mouse->data_dma; |
||
210 | mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
||
211 | |||
212 | input_register_device(&mouse->dev); |
||
213 | printk(KERN_INFO "input: %s on %s\n", mouse->name, path); |
||
214 | |||
215 | usb_set_intfdata(intf, mouse); |
||
216 | return 0; |
||
217 | } |
||
218 | |||
219 | static void usb_mouse_disconnect(struct usb_interface *intf) |
||
220 | { |
||
221 | struct usb_mouse *mouse = usb_get_intfdata (intf); |
||
222 | |||
223 | usb_set_intfdata(intf, NULL); |
||
224 | if (mouse) { |
||
225 | usb_unlink_urb(mouse->irq); |
||
226 | input_unregister_device(&mouse->dev); |
||
227 | usb_free_urb(mouse->irq); |
||
228 | usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); |
||
229 | kfree(mouse); |
||
230 | } |
||
231 | } |
||
232 | |||
233 | static struct usb_device_id usb_mouse_id_table [] = { |
||
234 | { USB_INTERFACE_INFO(3, 1, 2) }, |
||
235 | { } /* Terminating entry */ |
||
236 | }; |
||
237 | |||
238 | MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); |
||
239 | |||
240 | static struct usb_driver usb_mouse_driver = { |
||
241 | .owner = THIS_MODULE, |
||
242 | .name = "usbmouse", |
||
243 | .probe = usb_mouse_probe, |
||
244 | .disconnect = usb_mouse_disconnect, |
||
245 | .id_table = usb_mouse_id_table, |
||
246 | }; |
||
247 | |||
248 | /*static*/ int __init usb_mouse_init(void) |
||
249 | { |
||
250 | int retval = usb_register(&usb_mouse_driver); |
||
251 | if (retval == 0) |
||
252 | info(DRIVER_VERSION ":" DRIVER_DESC); |
||
253 | return retval; |
||
254 | } |
||
255 | |||
256 | /*static*/ void __exit usb_mouse_exit(void) |
||
257 | { |
||
258 | usb_deregister(&usb_mouse_driver); |
||
259 | } |
||
260 | |||
261 | module_init(usb_mouse_init); |
||
262 | module_exit(usb_mouse_exit); |