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/kernel.h> 32#include <linux/input.h> 33#include <linux/slab.h> 34#include <linux/module.h> 35#include <linux/usb/input.h> 36#include "usb.h" 37#include "debug.h" 38 39MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver"); 40MODULE_AUTHOR("Nick Sillik <n.sillik@temple.edu>"); 41MODULE_LICENSE("GPL"); 42 43#define ONETOUCH_PKT_LEN 0x02 44#define ONETOUCH_BUTTON KEY_PROG1 45 46static int onetouch_connect_input(struct us_data *ss); 47static void onetouch_release_input(void *onetouch_); 48 49struct usb_onetouch { 50 char name[128]; 51 char phys[64]; 52 struct input_dev *dev; /* input device interface */ 53 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; 58 unsigned int is_open:1; 59}; 60 61 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), \ 69 .driver_info = (flags) } 70 71static struct usb_device_id onetouch_usb_ids[] = { 72# 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 101static void usb_onetouch_irq(struct urb *urb) 102{ 103 struct usb_onetouch *onetouch = urb->context; 104 signed char *data = onetouch->data; 105 struct input_dev *dev = onetouch->dev; 106 int status = urb->status; 107 int retval; 108 109 switch (status) { 110 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 121 input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); 122 input_sync(dev); 123 124resubmit: 125 retval = usb_submit_urb (urb, GFP_ATOMIC); 126 if (retval) 127 dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, " 128 "retval %d\n", onetouch->udev->bus->bus_name, 129 onetouch->udev->devpath, retval); 130} 131 132static int usb_onetouch_open(struct input_dev *dev) 133{ 134 struct usb_onetouch *onetouch = input_get_drvdata(dev); 135 136 onetouch->is_open = 1; 137 onetouch->irq->dev = onetouch->udev; 138 if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { 139 dev_err(&dev->dev, "usb_submit_urb failed\n"); 140 return -EIO; 141 } 142 143 return 0; 144} 145 146static void usb_onetouch_close(struct input_dev *dev) 147{ 148 struct usb_onetouch *onetouch = input_get_drvdata(dev); 149 150 usb_kill_urb(onetouch->irq); 151 onetouch->is_open = 0; 152} 153 154#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: 165 if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0) 166 dev_err(&onetouch->irq->dev->dev, 167 "usb_submit_urb failed\n"); 168 break; 169 default: 170 break; 171 } 172 } 173} 174#endif /* CONFIG_PM */ 175 176static int onetouch_connect_input(struct us_data *ss) 177{ 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; 182 struct input_dev *input_dev; 183 int pipe, maxp; 184 int error = -ENOMEM; 185 186 interface = ss->pusb_intf->cur_altsetting; 187 188 if (interface->desc.bNumEndpoints != 3) 189 return -ENODEV; 190 191 endpoint = &interface->endpoint[2].desc; 192 if (!usb_endpoint_is_int_in(endpoint)) 193 return -ENODEV; 194 195 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); 196 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); 197 maxp = min(maxp, ONETOUCH_PKT_LEN); 198 199 onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); 200 input_dev = input_allocate_device(); 201 if (!onetouch || !input_dev) 202 goto fail1; 203 204 onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN, 205 GFP_KERNEL, &onetouch->data_dma); 206 if (!onetouch->data) 207 goto fail1; 208 209 onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); 210 if (!onetouch->irq) 211 goto fail2; 212 213 onetouch->udev = udev; 214 onetouch->dev = input_dev; 215 216 if (udev->manufacturer) 217 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 225 if (!strlen(onetouch->name)) 226 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); 237 input_dev->dev.parent = &udev->dev; 238 239 set_bit(EV_KEY, input_dev->evbit); 240 set_bit(ONETOUCH_BUTTON, input_dev->keybit); 241 clear_bit(0, input_dev->keybit); 242 243 input_set_drvdata(input_dev, onetouch); 244 245 input_dev->open = usb_onetouch_open; 246 input_dev->close = usb_onetouch_close; 247 248 usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp, 249 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; 255#ifdef CONFIG_PM 256 ss->suspend_resume_hook = usb_onetouch_pm_hook; 257#endif 258 259 error = input_register_device(onetouch->dev); 260 if (error) 261 goto fail3; 262 263 return 0; 264 265 fail3: usb_free_urb(onetouch->irq); 266 fail2: usb_free_coherent(udev, ONETOUCH_PKT_LEN, 267 onetouch->data, onetouch->data_dma); 268 fail1: kfree(onetouch); 269 input_free_device(input_dev); 270 return error; 271} 272 273static void onetouch_release_input(void *onetouch_) 274{ 275 struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; 276 277 if (onetouch) { 278 usb_kill_urb(onetouch->irq); 279 input_unregister_device(onetouch->dev); 280 usb_free_urb(onetouch->irq); 281 usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN, 282 onetouch->data, onetouch->data_dma); 283 } 284} 285 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, 314 .no_dynamic_id = 1, 315}; 316 317module_usb_driver(onetouch_driver); 318