]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/usb/storage/onetouch.c
USB: add SPDX identifiers to all remaining files in drivers/usb/
[mirror_ubuntu-jammy-kernel.git] / drivers / usb / storage / onetouch.c
CommitLineData
5fd54ace 1// SPDX-License-Identifier: GPL-2.0+
34008dbf
MD
2/*
3 * Support for the Maxtor OneTouch USB hard drive's button
4 *
5 * Current development and maintenance by:
6 * Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
7 *
8 * Initial work by:
88789672 9 * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
34008dbf
MD
10 *
11 * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
12 *
13 */
14
15/*
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
34008dbf
MD
32#include <linux/kernel.h>
33#include <linux/input.h>
34008dbf
MD
34#include <linux/slab.h>
35#include <linux/module.h>
ae0dadcf 36#include <linux/usb/input.h>
34008dbf 37#include "usb.h"
34008dbf 38#include "debug.h"
aa519be3
AM
39#include "scsiglue.h"
40
41#define DRV_NAME "ums-onetouch"
34008dbf 42
4246b06a
MG
43MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver");
44MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>");
45MODULE_LICENSE("GPL");
46
9cfb95ef
AS
47#define ONETOUCH_PKT_LEN 0x02
48#define ONETOUCH_BUTTON KEY_PROG1
49
50static int onetouch_connect_input(struct us_data *ss);
43c1e98c 51static void onetouch_release_input(void *onetouch_);
34008dbf
MD
52
53struct usb_onetouch {
54 char name[128];
55 char phys[64];
88789672 56 struct input_dev *dev; /* input device interface */
34008dbf
MD
57 struct usb_device *udev; /* usb device */
58
59 struct urb *irq; /* urb for interrupt in report */
60 unsigned char *data; /* input data */
61 dma_addr_t data_dma;
7931e1c6 62 unsigned int is_open:1;
34008dbf
MD
63};
64
9cfb95ef
AS
65
66/*
67 * The table of devices
68 */
69#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
70 vendorName, productName, useProtocol, useTransport, \
71 initFunction, flags) \
72{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
f61870ee 73 .driver_info = (flags) }
9cfb95ef 74
e2c83f01 75static struct usb_device_id onetouch_usb_ids[] = {
9cfb95ef
AS
76# include "unusual_onetouch.h"
77 { } /* Terminating entry */
78};
79MODULE_DEVICE_TABLE(usb, onetouch_usb_ids);
80
81#undef UNUSUAL_DEV
82
83/*
84 * The flags table
85 */
86#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
87 vendor_name, product_name, use_protocol, use_transport, \
88 init_function, Flags) \
89{ \
90 .vendorName = vendor_name, \
91 .productName = product_name, \
92 .useProtocol = use_protocol, \
93 .useTransport = use_transport, \
94 .initFunction = init_function, \
95}
96
97static struct us_unusual_dev onetouch_unusual_dev_list[] = {
98# include "unusual_onetouch.h"
99 { } /* Terminating entry */
100};
101
102#undef UNUSUAL_DEV
103
104
7d12e780 105static void usb_onetouch_irq(struct urb *urb)
34008dbf
MD
106{
107 struct usb_onetouch *onetouch = urb->context;
108 signed char *data = onetouch->data;
88789672 109 struct input_dev *dev = onetouch->dev;
62e5a330
GKH
110 int status = urb->status;
111 int retval;
34008dbf 112
62e5a330 113 switch (status) {
34008dbf
MD
114 case 0: /* success */
115 break;
116 case -ECONNRESET: /* unlink */
117 case -ENOENT:
118 case -ESHUTDOWN:
119 return;
120 /* -EPIPE: should clear the halt */
121 default: /* error */
122 goto resubmit;
123 }
124
88789672 125 input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
34008dbf 126 input_sync(dev);
88789672 127
34008dbf 128resubmit:
62e5a330
GKH
129 retval = usb_submit_urb (urb, GFP_ATOMIC);
130 if (retval)
802f389a
GKH
131 dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, "
132 "retval %d\n", onetouch->udev->bus->bus_name,
62e5a330 133 onetouch->udev->devpath, retval);
34008dbf
MD
134}
135
136static int usb_onetouch_open(struct input_dev *dev)
137{
09b7002d 138 struct usb_onetouch *onetouch = input_get_drvdata(dev);
34008dbf 139
7931e1c6 140 onetouch->is_open = 1;
34008dbf
MD
141 onetouch->irq->dev = onetouch->udev;
142 if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
802f389a 143 dev_err(&dev->dev, "usb_submit_urb failed\n");
34008dbf
MD
144 return -EIO;
145 }
146
147 return 0;
148}
149
150static void usb_onetouch_close(struct input_dev *dev)
151{
09b7002d 152 struct usb_onetouch *onetouch = input_get_drvdata(dev);
34008dbf
MD
153
154 usb_kill_urb(onetouch->irq);
7931e1c6 155 onetouch->is_open = 0;
34008dbf
MD
156}
157
7931e1c6
MD
158#ifdef CONFIG_PM
159static void usb_onetouch_pm_hook(struct us_data *us, int action)
160{
161 struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra;
162
163 if (onetouch->is_open) {
164 switch (action) {
165 case US_SUSPEND:
166 usb_kill_urb(onetouch->irq);
167 break;
168 case US_RESUME:
e5dc8ae1 169 if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
802f389a
GKH
170 dev_err(&onetouch->irq->dev->dev,
171 "usb_submit_urb failed\n");
7931e1c6
MD
172 break;
173 default:
174 break;
175 }
176 }
177}
178#endif /* CONFIG_PM */
179
9cfb95ef 180static int onetouch_connect_input(struct us_data *ss)
34008dbf
MD
181{
182 struct usb_device *udev = ss->pusb_dev;
183 struct usb_host_interface *interface;
184 struct usb_endpoint_descriptor *endpoint;
185 struct usb_onetouch *onetouch;
88789672 186 struct input_dev *input_dev;
34008dbf 187 int pipe, maxp;
17efe155 188 int error = -ENOMEM;
34008dbf
MD
189
190 interface = ss->pusb_intf->cur_altsetting;
191
d6450e19
NS
192 if (interface->desc.bNumEndpoints != 3)
193 return -ENODEV;
194
34008dbf 195 endpoint = &interface->endpoint[2].desc;
66722a19 196 if (!usb_endpoint_is_int_in(endpoint))
34008dbf
MD
197 return -ENODEV;
198
199 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
200 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
bba90aed 201 maxp = min(maxp, ONETOUCH_PKT_LEN);
34008dbf 202
88789672
DT
203 onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
204 input_dev = input_allocate_device();
205 if (!onetouch || !input_dev)
206 goto fail1;
34008dbf 207
997ea58e
DM
208 onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN,
209 GFP_KERNEL, &onetouch->data_dma);
88789672
DT
210 if (!onetouch->data)
211 goto fail1;
34008dbf
MD
212
213 onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
88789672
DT
214 if (!onetouch->irq)
215 goto fail2;
34008dbf
MD
216
217 onetouch->udev = udev;
88789672 218 onetouch->dev = input_dev;
34008dbf 219
88789672
DT
220 if (udev->manufacturer)
221 strlcpy(onetouch->name, udev->manufacturer,
222 sizeof(onetouch->name));
223 if (udev->product) {
224 if (udev->manufacturer)
225 strlcat(onetouch->name, " ", sizeof(onetouch->name));
226 strlcat(onetouch->name, udev->product, sizeof(onetouch->name));
227 }
34008dbf 228
88789672
DT
229 if (!strlen(onetouch->name))
230 snprintf(onetouch->name, sizeof(onetouch->name),
231 "Maxtor Onetouch %04x:%04x",
232 le16_to_cpu(udev->descriptor.idVendor),
233 le16_to_cpu(udev->descriptor.idProduct));
34008dbf 234
88789672
DT
235 usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys));
236 strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys));
34008dbf 237
88789672
DT
238 input_dev->name = onetouch->name;
239 input_dev->phys = onetouch->phys;
240 usb_to_input_id(udev, &input_dev->id);
09b7002d 241 input_dev->dev.parent = &udev->dev;
34008dbf 242
88789672
DT
243 set_bit(EV_KEY, input_dev->evbit);
244 set_bit(ONETOUCH_BUTTON, input_dev->keybit);
245 clear_bit(0, input_dev->keybit);
34008dbf 246
09b7002d
DT
247 input_set_drvdata(input_dev, onetouch);
248
88789672
DT
249 input_dev->open = usb_onetouch_open;
250 input_dev->close = usb_onetouch_close;
34008dbf 251
bba90aed 252 usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
34008dbf
MD
253 usb_onetouch_irq, onetouch, endpoint->bInterval);
254 onetouch->irq->transfer_dma = onetouch->data_dma;
255 onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
256
257 ss->extra_destructor = onetouch_release_input;
258 ss->extra = onetouch;
7931e1c6
MD
259#ifdef CONFIG_PM
260 ss->suspend_resume_hook = usb_onetouch_pm_hook;
261#endif
34008dbf 262
17efe155
DT
263 error = input_register_device(onetouch->dev);
264 if (error)
265 goto fail3;
34008dbf
MD
266
267 return 0;
88789672 268
17efe155 269 fail3: usb_free_urb(onetouch->irq);
997ea58e
DM
270 fail2: usb_free_coherent(udev, ONETOUCH_PKT_LEN,
271 onetouch->data, onetouch->data_dma);
88789672
DT
272 fail1: kfree(onetouch);
273 input_free_device(input_dev);
17efe155 274 return error;
34008dbf
MD
275}
276
43c1e98c 277static void onetouch_release_input(void *onetouch_)
34008dbf
MD
278{
279 struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
280
281 if (onetouch) {
282 usb_kill_urb(onetouch->irq);
88789672 283 input_unregister_device(onetouch->dev);
34008dbf 284 usb_free_urb(onetouch->irq);
997ea58e
DM
285 usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN,
286 onetouch->data, onetouch->data_dma);
34008dbf
MD
287 }
288}
9cfb95ef 289
aa519be3
AM
290static struct scsi_host_template onetouch_host_template;
291
9cfb95ef
AS
292static int onetouch_probe(struct usb_interface *intf,
293 const struct usb_device_id *id)
294{
295 struct us_data *us;
296 int result;
297
298 result = usb_stor_probe1(&us, intf, id,
aa519be3
AM
299 (id - onetouch_usb_ids) + onetouch_unusual_dev_list,
300 &onetouch_host_template);
9cfb95ef
AS
301 if (result)
302 return result;
303
304 /* Use default transport and protocol */
305
306 result = usb_stor_probe2(us);
307 return result;
308}
309
310static struct usb_driver onetouch_driver = {
aa519be3 311 .name = DRV_NAME,
9cfb95ef
AS
312 .probe = onetouch_probe,
313 .disconnect = usb_stor_disconnect,
314 .suspend = usb_stor_suspend,
315 .resume = usb_stor_resume,
316 .reset_resume = usb_stor_reset_resume,
317 .pre_reset = usb_stor_pre_reset,
318 .post_reset = usb_stor_post_reset,
319 .id_table = onetouch_usb_ids,
320 .soft_unbind = 1,
e73b2db6 321 .no_dynamic_id = 1,
9cfb95ef
AS
322};
323
aa519be3 324module_usb_stor_driver(onetouch_driver, onetouch_host_template, DRV_NAME);