blob: 74e2aa23b04501792fb2236b195924bbc1bd5ab1 [file] [log] [blame]
Matthew Dharm34008db2005-07-28 14:49:01 -07001/*
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:
Dmitry Torokhov88789672005-09-15 02:01:43 -05008 * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
Matthew Dharm34008db2005-07-28 14:49:01 -07009 *
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
Matthew Dharm34008db2005-07-28 14:49:01 -070031#include <linux/kernel.h>
32#include <linux/input.h>
Matthew Dharm34008db2005-07-28 14:49:01 -070033#include <linux/slab.h>
34#include <linux/module.h>
David Brownellae0dadc2006-06-13 10:04:34 -070035#include <linux/usb/input.h>
Matthew Dharm34008db2005-07-28 14:49:01 -070036#include "usb.h"
Matthew Dharm34008db2005-07-28 14:49:01 -070037#include "debug.h"
38
Maciej Grela4246b062009-02-28 12:39:20 -080039MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
40MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
41MODULE_LICENSE("GPL");
42
Alan Stern9cfb95e2009-02-12 14:48:33 -050043#define ONETOUCH_PKT_LEN 0x02
44#define ONETOUCH_BUTTON KEY_PROG1
45
46static int onetouch_connect_input(struct us_data *ss);
Adrian Bunk43c1e982008-04-28 18:39:37 +030047static void onetouch_release_input(void *onetouch_);
Matthew Dharm34008db2005-07-28 14:49:01 -070048
49struct usb_onetouch {
50 char name[128];
51 char phys[64];
Dmitry Torokhov88789672005-09-15 02:01:43 -050052 struct input_dev *dev; /* input device interface */
Matthew Dharm34008db2005-07-28 14:49:01 -070053 struct usb_device *udev; /* usb device */
54
55 struct urb *irq; /* urb for interrupt in report */
56 unsigned char *data; /* input data */
57 dma_addr_t data_dma;
Matthew Dharm7931e1c2005-12-04 21:56:51 -080058 unsigned int is_open:1;
Matthew Dharm34008db2005-07-28 14:49:01 -070059};
60
Alan Stern9cfb95e2009-02-12 14:48:33 -050061
62/*
63 * The table of devices
64 */
65#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
66 vendorName, productName, useProtocol, useTransport, \
67 initFunction, flags) \
68{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
Sebastian Andrzej Siewiorf61870e2012-08-28 22:37:13 +020069 .driver_info = (flags) }
Alan Stern9cfb95e2009-02-12 14:48:33 -050070
Felipe Balbie2c83f02011-11-15 09:53:36 +020071static struct usb_device_id onetouch_usb_ids[] = {
Alan Stern9cfb95e2009-02-12 14:48:33 -050072# include "unusual_onetouch.h"
73 { } /* Terminating entry */
74};
75MODULE_DEVICE_TABLE(usb, onetouch_usb_ids);
76
77#undef UNUSUAL_DEV
78
79/*
80 * The flags table
81 */
82#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
83 vendor_name, product_name, use_protocol, use_transport, \
84 init_function, Flags) \
85{ \
86 .vendorName = vendor_name, \
87 .productName = product_name, \
88 .useProtocol = use_protocol, \
89 .useTransport = use_transport, \
90 .initFunction = init_function, \
91}
92
93static struct us_unusual_dev onetouch_unusual_dev_list[] = {
94# include "unusual_onetouch.h"
95 { } /* Terminating entry */
96};
97
98#undef UNUSUAL_DEV
99
100
David Howells7d12e782006-10-05 14:55:46 +0100101static void usb_onetouch_irq(struct urb *urb)
Matthew Dharm34008db2005-07-28 14:49:01 -0700102{
103 struct usb_onetouch *onetouch = urb->context;
104 signed char *data = onetouch->data;
Dmitry Torokhov88789672005-09-15 02:01:43 -0500105 struct input_dev *dev = onetouch->dev;
Greg Kroah-Hartman62e5a332007-07-18 10:58:02 -0700106 int status = urb->status;
107 int retval;
Matthew Dharm34008db2005-07-28 14:49:01 -0700108
Greg Kroah-Hartman62e5a332007-07-18 10:58:02 -0700109 switch (status) {
Matthew Dharm34008db2005-07-28 14:49:01 -0700110 case 0: /* success */
111 break;
112 case -ECONNRESET: /* unlink */
113 case -ENOENT:
114 case -ESHUTDOWN:
115 return;
116 /* -EPIPE: should clear the halt */
117 default: /* error */
118 goto resubmit;
119 }
120
Dmitry Torokhov88789672005-09-15 02:01:43 -0500121 input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
Matthew Dharm34008db2005-07-28 14:49:01 -0700122 input_sync(dev);
Dmitry Torokhov88789672005-09-15 02:01:43 -0500123
Matthew Dharm34008db2005-07-28 14:49:01 -0700124resubmit:
Greg Kroah-Hartman62e5a332007-07-18 10:58:02 -0700125 retval = usb_submit_urb (urb, GFP_ATOMIC);
126 if (retval)
Greg Kroah-Hartman802f3892008-08-14 09:37:34 -0700127 dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
128 "retval %d\n", onetouch->udev->bus->bus_name,
Greg Kroah-Hartman62e5a332007-07-18 10:58:02 -0700129 onetouch->udev->devpath, retval);
Matthew Dharm34008db2005-07-28 14:49:01 -0700130}
131
132static int usb_onetouch_open(struct input_dev *dev)
133{
Dmitry Torokhov09b70022007-05-08 00:31:30 -0400134 struct usb_onetouch *onetouch = input_get_drvdata(dev);
Matthew Dharm34008db2005-07-28 14:49:01 -0700135
Matthew Dharm7931e1c2005-12-04 21:56:51 -0800136 onetouch->is_open = 1;
Matthew Dharm34008db2005-07-28 14:49:01 -0700137 onetouch->irq->dev = onetouch->udev;
138 if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
Greg Kroah-Hartman802f3892008-08-14 09:37:34 -0700139 dev_err(&dev->dev, "usb_submit_urb failed\n");
Matthew Dharm34008db2005-07-28 14:49:01 -0700140 return -EIO;
141 }
142
143 return 0;
144}
145
146static void usb_onetouch_close(struct input_dev *dev)
147{
Dmitry Torokhov09b70022007-05-08 00:31:30 -0400148 struct usb_onetouch *onetouch = input_get_drvdata(dev);
Matthew Dharm34008db2005-07-28 14:49:01 -0700149
150 usb_kill_urb(onetouch->irq);
Matthew Dharm7931e1c2005-12-04 21:56:51 -0800151 onetouch->is_open = 0;
Matthew Dharm34008db2005-07-28 14:49:01 -0700152}
153
Matthew Dharm7931e1c2005-12-04 21:56:51 -0800154#ifdef CONFIG_PM
155static void usb_onetouch_pm_hook(struct us_data *us, int action)
156{
157 struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
158
159 if (onetouch->is_open) {
160 switch (action) {
161 case US_SUSPEND:
162 usb_kill_urb(onetouch->irq);
163 break;
164 case US_RESUME:
Oliver Neukume5dc8ae2009-08-26 19:56:12 +0200165 if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
Greg Kroah-Hartman802f3892008-08-14 09:37:34 -0700166 dev_err(&onetouch->irq->dev->dev,
167 "usb_submit_urb failed\n");
Matthew Dharm7931e1c2005-12-04 21:56:51 -0800168 break;
169 default:
170 break;
171 }
172 }
173}
174#endif /* CONFIG_PM */
175
Alan Stern9cfb95e2009-02-12 14:48:33 -0500176static int onetouch_connect_input(struct us_data *ss)
Matthew Dharm34008db2005-07-28 14:49:01 -0700177{
178 struct usb_device *udev = ss->pusb_dev;
179 struct usb_host_interface *interface;
180 struct usb_endpoint_descriptor *endpoint;
181 struct usb_onetouch *onetouch;
Dmitry Torokhov88789672005-09-15 02:01:43 -0500182 struct input_dev *input_dev;
Matthew Dharm34008db2005-07-28 14:49:01 -0700183 int pipe, maxp;
Dmitry Torokhov17efe152006-08-01 22:45:28 -0400184 int error = -ENOMEM;
Matthew Dharm34008db2005-07-28 14:49:01 -0700185
186 interface = ss->pusb_intf->cur_altsetting;
187
Nick Sillikd6450e12005-08-17 13:37:34 -0400188 if (interface->desc.bNumEndpoints != 3)
Matthew Dharm34008db2005-07-28 14:49:01 -0700189 return -ENODEV;
Nick Sillikd6450e12005-08-17 13:37:34 -0400190
191 endpoint = &interface->endpoint[2].desc;
Luiz Fernando N. Capitulino66722a12006-10-26 13:02:55 -0300192 if (!usb_endpoint_is_int_in(endpoint))
Matthew Dharm34008db2005-07-28 14:49:01 -0700193 return -ENODEV;
194
195 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
196 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
Dan Carpenterbba90ae2013-03-01 08:14:19 +0300197 maxp = min(maxp, ONETOUCH_PKT_LEN);
Matthew Dharm34008db2005-07-28 14:49:01 -0700198
Dmitry Torokhov88789672005-09-15 02:01:43 -0500199 onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
200 input_dev = input_allocate_device();
201 if (!onetouch || !input_dev)
202 goto fail1;
Matthew Dharm34008db2005-07-28 14:49:01 -0700203
Daniel Mack997ea582010-04-12 13:17:25 +0200204 onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
205 GFP_KERNEL, &onetouch->data_dma);
Dmitry Torokhov88789672005-09-15 02:01:43 -0500206 if (!onetouch->data)
207 goto fail1;
Matthew Dharm34008db2005-07-28 14:49:01 -0700208
209 onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
Dmitry Torokhov88789672005-09-15 02:01:43 -0500210 if (!onetouch->irq)
211 goto fail2;
Matthew Dharm34008db2005-07-28 14:49:01 -0700212
213 onetouch->udev = udev;
Dmitry Torokhov88789672005-09-15 02:01:43 -0500214 onetouch->dev = input_dev;
Matthew Dharm34008db2005-07-28 14:49:01 -0700215
216 if (udev->manufacturer)
Dmitry Torokhov88789672005-09-15 02:01:43 -0500217 strlcpy(onetouch->name, udev->manufacturer,
218 sizeof(onetouch->name));
219 if (udev->product) {
220 if (udev->manufacturer)
221 strlcat(onetouch->name, " ", sizeof(onetouch->name));
222 strlcat(onetouch->name, udev->product, sizeof(onetouch->name));
223 }
224
Matthew Dharm34008db2005-07-28 14:49:01 -0700225 if (!strlen(onetouch->name))
Dmitry Torokhov88789672005-09-15 02:01:43 -0500226 snprintf(onetouch->name, sizeof(onetouch->name),
227 "Maxtor Onetouch %04x:%04x",
228 le16_to_cpu(udev->descriptor.idVendor),
229 le16_to_cpu(udev->descriptor.idProduct));
230
231 usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys));
232 strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys));
233
234 input_dev->name = onetouch->name;
235 input_dev->phys = onetouch->phys;
236 usb_to_input_id(udev, &input_dev->id);
Dmitry Torokhov09b70022007-05-08 00:31:30 -0400237 input_dev->dev.parent = &udev->dev;
Dmitry Torokhov88789672005-09-15 02:01:43 -0500238
239 set_bit(EV_KEY, input_dev->evbit);
240 set_bit(ONETOUCH_BUTTON, input_dev->keybit);
241 clear_bit(0, input_dev->keybit);
242
Dmitry Torokhov09b70022007-05-08 00:31:30 -0400243 input_set_drvdata(input_dev, onetouch);
244
Dmitry Torokhov88789672005-09-15 02:01:43 -0500245 input_dev->open = usb_onetouch_open;
246 input_dev->close = usb_onetouch_close;
Matthew Dharm34008db2005-07-28 14:49:01 -0700247
Dan Carpenterbba90ae2013-03-01 08:14:19 +0300248 usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
Matthew Dharm34008db2005-07-28 14:49:01 -0700249 usb_onetouch_irq, onetouch, endpoint->bInterval);
250 onetouch->irq->transfer_dma = onetouch->data_dma;
251 onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
252
253 ss->extra_destructor = onetouch_release_input;
254 ss->extra = onetouch;
Matthew Dharm7931e1c2005-12-04 21:56:51 -0800255#ifdef CONFIG_PM
256 ss->suspend_resume_hook = usb_onetouch_pm_hook;
257#endif
Matthew Dharm34008db2005-07-28 14:49:01 -0700258
Dmitry Torokhov17efe152006-08-01 22:45:28 -0400259 error = input_register_device(onetouch->dev);
260 if (error)
261 goto fail3;
Matthew Dharm34008db2005-07-28 14:49:01 -0700262
263 return 0;
Dmitry Torokhov88789672005-09-15 02:01:43 -0500264
Dmitry Torokhov17efe152006-08-01 22:45:28 -0400265 fail3: usb_free_urb(onetouch->irq);
Daniel Mack997ea582010-04-12 13:17:25 +0200266 fail2: usb_free_coherent(udev, ONETOUCH_PKT_LEN,
267 onetouch->data, onetouch->data_dma);
Dmitry Torokhov88789672005-09-15 02:01:43 -0500268 fail1: kfree(onetouch);
269 input_free_device(input_dev);
Dmitry Torokhov17efe152006-08-01 22:45:28 -0400270 return error;
Matthew Dharm34008db2005-07-28 14:49:01 -0700271}
272
Adrian Bunk43c1e982008-04-28 18:39:37 +0300273static void onetouch_release_input(void *onetouch_)
Matthew Dharm34008db2005-07-28 14:49:01 -0700274{
275 struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
276
277 if (onetouch) {
278 usb_kill_urb(onetouch->irq);
Dmitry Torokhov88789672005-09-15 02:01:43 -0500279 input_unregister_device(onetouch->dev);
Matthew Dharm34008db2005-07-28 14:49:01 -0700280 usb_free_urb(onetouch->irq);
Daniel Mack997ea582010-04-12 13:17:25 +0200281 usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
282 onetouch->data, onetouch->data_dma);
Matthew Dharm34008db2005-07-28 14:49:01 -0700283 }
284}
Alan Stern9cfb95e2009-02-12 14:48:33 -0500285
286static int onetouch_probe(struct usb_interface *intf,
287 const struct usb_device_id *id)
288{
289 struct us_data *us;
290 int result;
291
292 result = usb_stor_probe1(&us, intf, id,
293 (id - onetouch_usb_ids) + onetouch_unusual_dev_list);
294 if (result)
295 return result;
296
297 /* Use default transport and protocol */
298
299 result = usb_stor_probe2(us);
300 return result;
301}
302
303static struct usb_driver onetouch_driver = {
304 .name = "ums-onetouch",
305 .probe = onetouch_probe,
306 .disconnect = usb_stor_disconnect,
307 .suspend = usb_stor_suspend,
308 .resume = usb_stor_resume,
309 .reset_resume = usb_stor_reset_resume,
310 .pre_reset = usb_stor_pre_reset,
311 .post_reset = usb_stor_post_reset,
312 .id_table = onetouch_usb_ids,
313 .soft_unbind = 1,
Huajun Lie73b2db2012-01-14 10:15:21 +0800314 .no_dynamic_id = 1,
Alan Stern9cfb95e2009-02-12 14:48:33 -0500315};
316
Greg Kroah-Hartman65db4302011-11-18 09:34:02 -0800317module_usb_driver(onetouch_driver);