diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-09-09 21:14:47 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-09-09 21:14:47 -0400 |
commit | d344c5e0856ad03278d8700b503762dbc8b86e12 (patch) | |
tree | a6d893a643470a3c2580a58f3228a55fa1fd1d82 /drivers/usb/storage/onetouch.c | |
parent | 010988e888a0abbe7118635c1b33d049caae6b29 (diff) | |
parent | 87fc767b832ef5a681a0ff9d203c3289bc3be2bf (diff) |
Manual merge with Linus
Diffstat (limited to 'drivers/usb/storage/onetouch.c')
-rw-r--r-- | drivers/usb/storage/onetouch.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c new file mode 100644 index 000000000000..2c9402dc702b --- /dev/null +++ b/drivers/usb/storage/onetouch.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Support for the Maxtor OneTouch USB hard drive's button | ||
3 | * | ||
4 | * Current development and maintenance by: | ||
5 | * Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu> | ||
6 | * | ||
7 | * Initial work by: | ||
8 | * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se> | ||
9 | * | ||
10 | * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann) | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/config.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/usb.h> | ||
38 | #include <linux/usb_ch9.h> | ||
39 | #include <linux/usb_input.h> | ||
40 | #include "usb.h" | ||
41 | #include "onetouch.h" | ||
42 | #include "debug.h" | ||
43 | |||
44 | void onetouch_release_input(void *onetouch_); | ||
45 | |||
46 | struct usb_onetouch { | ||
47 | char name[128]; | ||
48 | char phys[64]; | ||
49 | struct input_dev dev; /* input device interface */ | ||
50 | struct usb_device *udev; /* usb device */ | ||
51 | |||
52 | struct urb *irq; /* urb for interrupt in report */ | ||
53 | unsigned char *data; /* input data */ | ||
54 | dma_addr_t data_dma; | ||
55 | }; | ||
56 | |||
57 | static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) | ||
58 | { | ||
59 | struct usb_onetouch *onetouch = urb->context; | ||
60 | signed char *data = onetouch->data; | ||
61 | struct input_dev *dev = &onetouch->dev; | ||
62 | int status; | ||
63 | |||
64 | switch (urb->status) { | ||
65 | case 0: /* success */ | ||
66 | break; | ||
67 | case -ECONNRESET: /* unlink */ | ||
68 | case -ENOENT: | ||
69 | case -ESHUTDOWN: | ||
70 | return; | ||
71 | /* -EPIPE: should clear the halt */ | ||
72 | default: /* error */ | ||
73 | goto resubmit; | ||
74 | } | ||
75 | |||
76 | input_regs(dev, regs); | ||
77 | |||
78 | input_report_key(&onetouch->dev, ONETOUCH_BUTTON, | ||
79 | data[0] & 0x02); | ||
80 | |||
81 | input_sync(dev); | ||
82 | resubmit: | ||
83 | status = usb_submit_urb (urb, SLAB_ATOMIC); | ||
84 | if (status) | ||
85 | err ("can't resubmit intr, %s-%s/input0, status %d", | ||
86 | onetouch->udev->bus->bus_name, | ||
87 | onetouch->udev->devpath, status); | ||
88 | } | ||
89 | |||
90 | static int usb_onetouch_open(struct input_dev *dev) | ||
91 | { | ||
92 | struct usb_onetouch *onetouch = dev->private; | ||
93 | |||
94 | onetouch->irq->dev = onetouch->udev; | ||
95 | if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { | ||
96 | err("usb_submit_urb failed"); | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void usb_onetouch_close(struct input_dev *dev) | ||
104 | { | ||
105 | struct usb_onetouch *onetouch = dev->private; | ||
106 | |||
107 | usb_kill_urb(onetouch->irq); | ||
108 | } | ||
109 | |||
110 | int onetouch_connect_input(struct us_data *ss) | ||
111 | { | ||
112 | struct usb_device *udev = ss->pusb_dev; | ||
113 | struct usb_host_interface *interface; | ||
114 | struct usb_endpoint_descriptor *endpoint; | ||
115 | struct usb_onetouch *onetouch; | ||
116 | int pipe, maxp; | ||
117 | char path[64]; | ||
118 | |||
119 | interface = ss->pusb_intf->cur_altsetting; | ||
120 | |||
121 | if (interface->desc.bNumEndpoints != 3) | ||
122 | return -ENODEV; | ||
123 | |||
124 | endpoint = &interface->endpoint[2].desc; | ||
125 | if(!(endpoint->bEndpointAddress & USB_DIR_IN)) | ||
126 | return -ENODEV; | ||
127 | if((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
128 | != USB_ENDPOINT_XFER_INT) | ||
129 | return -ENODEV; | ||
130 | |||
131 | pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); | ||
132 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | ||
133 | |||
134 | if (!(onetouch = kcalloc(1, sizeof(struct usb_onetouch), GFP_KERNEL))) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, | ||
138 | SLAB_ATOMIC, &onetouch->data_dma); | ||
139 | if (!onetouch->data){ | ||
140 | kfree(onetouch); | ||
141 | return -ENOMEM; | ||
142 | } | ||
143 | |||
144 | onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); | ||
145 | if (!onetouch->irq){ | ||
146 | kfree(onetouch); | ||
147 | usb_buffer_free(udev, ONETOUCH_PKT_LEN, | ||
148 | onetouch->data, onetouch->data_dma); | ||
149 | return -ENODEV; | ||
150 | } | ||
151 | |||
152 | |||
153 | onetouch->udev = udev; | ||
154 | |||
155 | set_bit(EV_KEY, onetouch->dev.evbit); | ||
156 | set_bit(ONETOUCH_BUTTON, onetouch->dev.keybit); | ||
157 | clear_bit(0, onetouch->dev.keybit); | ||
158 | |||
159 | onetouch->dev.private = onetouch; | ||
160 | onetouch->dev.open = usb_onetouch_open; | ||
161 | onetouch->dev.close = usb_onetouch_close; | ||
162 | |||
163 | usb_make_path(udev, path, sizeof(path)); | ||
164 | sprintf(onetouch->phys, "%s/input0", path); | ||
165 | |||
166 | onetouch->dev.name = onetouch->name; | ||
167 | onetouch->dev.phys = onetouch->phys; | ||
168 | |||
169 | usb_to_input_id(udev, &onetouch->dev.id); | ||
170 | |||
171 | onetouch->dev.dev = &udev->dev; | ||
172 | |||
173 | if (udev->manufacturer) | ||
174 | strcat(onetouch->name, udev->manufacturer); | ||
175 | if (udev->product) | ||
176 | sprintf(onetouch->name, "%s %s", onetouch->name, | ||
177 | udev->product); | ||
178 | if (!strlen(onetouch->name)) | ||
179 | sprintf(onetouch->name, "Maxtor Onetouch %04x:%04x", | ||
180 | onetouch->dev.id.vendor, onetouch->dev.id.product); | ||
181 | |||
182 | usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, | ||
183 | (maxp > 8 ? 8 : maxp), | ||
184 | usb_onetouch_irq, onetouch, endpoint->bInterval); | ||
185 | onetouch->irq->transfer_dma = onetouch->data_dma; | ||
186 | onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
187 | |||
188 | ss->extra_destructor = onetouch_release_input; | ||
189 | ss->extra = onetouch; | ||
190 | |||
191 | input_register_device(&onetouch->dev); | ||
192 | printk(KERN_INFO "usb-input: %s on %s\n", onetouch->dev.name, path); | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | void onetouch_release_input(void *onetouch_) | ||
198 | { | ||
199 | struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; | ||
200 | |||
201 | if (onetouch) { | ||
202 | usb_kill_urb(onetouch->irq); | ||
203 | input_unregister_device(&onetouch->dev); | ||
204 | usb_free_urb(onetouch->irq); | ||
205 | usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, | ||
206 | onetouch->data, onetouch->data_dma); | ||
207 | printk(KERN_INFO "usb-input: deregistering %s\n", | ||
208 | onetouch->dev.name); | ||
209 | } | ||
210 | } | ||