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/init.h> 34 #include <linux/slab.h> 35 #include <linux/module.h> 36 #include <linux/usb/input.h> 37 #include "usb.h" 38 #include "debug.h" 39 40 #define ONETOUCH_PKT_LEN 0x02 41 #define ONETOUCH_BUTTON KEY_PROG1 42 43 static int onetouch_connect_input(struct us_data *ss); 44 static 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 unsigned int is_open:1; 56 }; 57 58 59 /* 60 * The table of devices 61 */ 62 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 63 vendorName, productName, useProtocol, useTransport, \ 64 initFunction, flags) \ 65 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 66 .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } 67 68 struct usb_device_id onetouch_usb_ids[] = { 69 # include "unusual_onetouch.h" 70 { } /* Terminating entry */ 71 }; 72 MODULE_DEVICE_TABLE(usb, onetouch_usb_ids); 73 74 #undef UNUSUAL_DEV 75 76 /* 77 * The flags table 78 */ 79 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 80 vendor_name, product_name, use_protocol, use_transport, \ 81 init_function, Flags) \ 82 { \ 83 .vendorName = vendor_name, \ 84 .productName = product_name, \ 85 .useProtocol = use_protocol, \ 86 .useTransport = use_transport, \ 87 .initFunction = init_function, \ 88 } 89 90 static struct us_unusual_dev onetouch_unusual_dev_list[] = { 91 # include "unusual_onetouch.h" 92 { } /* Terminating entry */ 93 }; 94 95 #undef UNUSUAL_DEV 96 97 98 static void usb_onetouch_irq(struct urb *urb) 99 { 100 struct usb_onetouch *onetouch = urb->context; 101 signed char *data = onetouch->data; 102 struct input_dev *dev = onetouch->dev; 103 int status = urb->status; 104 int retval; 105 106 switch (status) { 107 case 0: /* success */ 108 break; 109 case -ECONNRESET: /* unlink */ 110 case -ENOENT: 111 case -ESHUTDOWN: 112 return; 113 /* -EPIPE: should clear the halt */ 114 default: /* error */ 115 goto resubmit; 116 } 117 118 input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); 119 input_sync(dev); 120 121 resubmit: 122 retval = usb_submit_urb (urb, GFP_ATOMIC); 123 if (retval) 124 dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, " 125 "retval %d\n", onetouch->udev->bus->bus_name, 126 onetouch->udev->devpath, retval); 127 } 128 129 static int usb_onetouch_open(struct input_dev *dev) 130 { 131 struct usb_onetouch *onetouch = input_get_drvdata(dev); 132 133 onetouch->is_open = 1; 134 onetouch->irq->dev = onetouch->udev; 135 if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { 136 dev_err(&dev->dev, "usb_submit_urb failed\n"); 137 return -EIO; 138 } 139 140 return 0; 141 } 142 143 static void usb_onetouch_close(struct input_dev *dev) 144 { 145 struct usb_onetouch *onetouch = input_get_drvdata(dev); 146 147 usb_kill_urb(onetouch->irq); 148 onetouch->is_open = 0; 149 } 150 151 #ifdef CONFIG_PM 152 static void usb_onetouch_pm_hook(struct us_data *us, int action) 153 { 154 struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra; 155 156 if (onetouch->is_open) { 157 switch (action) { 158 case US_SUSPEND: 159 usb_kill_urb(onetouch->irq); 160 break; 161 case US_RESUME: 162 if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0) 163 dev_err(&onetouch->irq->dev->dev, 164 "usb_submit_urb failed\n"); 165 break; 166 default: 167 break; 168 } 169 } 170 } 171 #endif /* CONFIG_PM */ 172 173 static int onetouch_connect_input(struct us_data *ss) 174 { 175 struct usb_device *udev = ss->pusb_dev; 176 struct usb_host_interface *interface; 177 struct usb_endpoint_descriptor *endpoint; 178 struct usb_onetouch *onetouch; 179 struct input_dev *input_dev; 180 int pipe, maxp; 181 int error = -ENOMEM; 182 183 interface = ss->pusb_intf->cur_altsetting; 184 185 if (interface->desc.bNumEndpoints != 3) 186 return -ENODEV; 187 188 endpoint = &interface->endpoint[2].desc; 189 if (!usb_endpoint_is_int_in(endpoint)) 190 return -ENODEV; 191 192 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); 193 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); 194 195 onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); 196 input_dev = input_allocate_device(); 197 if (!onetouch || !input_dev) 198 goto fail1; 199 200 onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, 201 GFP_ATOMIC, &onetouch->data_dma); 202 if (!onetouch->data) 203 goto fail1; 204 205 onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); 206 if (!onetouch->irq) 207 goto fail2; 208 209 onetouch->udev = udev; 210 onetouch->dev = input_dev; 211 212 if (udev->manufacturer) 213 strlcpy(onetouch->name, udev->manufacturer, 214 sizeof(onetouch->name)); 215 if (udev->product) { 216 if (udev->manufacturer) 217 strlcat(onetouch->name, " ", sizeof(onetouch->name)); 218 strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); 219 } 220 221 if (!strlen(onetouch->name)) 222 snprintf(onetouch->name, sizeof(onetouch->name), 223 "Maxtor Onetouch %04x:%04x", 224 le16_to_cpu(udev->descriptor.idVendor), 225 le16_to_cpu(udev->descriptor.idProduct)); 226 227 usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); 228 strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); 229 230 input_dev->name = onetouch->name; 231 input_dev->phys = onetouch->phys; 232 usb_to_input_id(udev, &input_dev->id); 233 input_dev->dev.parent = &udev->dev; 234 235 set_bit(EV_KEY, input_dev->evbit); 236 set_bit(ONETOUCH_BUTTON, input_dev->keybit); 237 clear_bit(0, input_dev->keybit); 238 239 input_set_drvdata(input_dev, onetouch); 240 241 input_dev->open = usb_onetouch_open; 242 input_dev->close = usb_onetouch_close; 243 244 usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, 245 (maxp > 8 ? 8 : maxp), 246 usb_onetouch_irq, onetouch, endpoint->bInterval); 247 onetouch->irq->transfer_dma = onetouch->data_dma; 248 onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 249 250 ss->extra_destructor = onetouch_release_input; 251 ss->extra = onetouch; 252 #ifdef CONFIG_PM 253 ss->suspend_resume_hook = usb_onetouch_pm_hook; 254 #endif 255 256 error = input_register_device(onetouch->dev); 257 if (error) 258 goto fail3; 259 260 return 0; 261 262 fail3: usb_free_urb(onetouch->irq); 263 fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN, 264 onetouch->data, onetouch->data_dma); 265 fail1: kfree(onetouch); 266 input_free_device(input_dev); 267 return error; 268 } 269 270 static void onetouch_release_input(void *onetouch_) 271 { 272 struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; 273 274 if (onetouch) { 275 usb_kill_urb(onetouch->irq); 276 input_unregister_device(onetouch->dev); 277 usb_free_urb(onetouch->irq); 278 usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, 279 onetouch->data, onetouch->data_dma); 280 } 281 } 282 283 static int onetouch_probe(struct usb_interface *intf, 284 const struct usb_device_id *id) 285 { 286 struct us_data *us; 287 int result; 288 289 result = usb_stor_probe1(&us, intf, id, 290 (id - onetouch_usb_ids) + onetouch_unusual_dev_list); 291 if (result) 292 return result; 293 294 /* Use default transport and protocol */ 295 296 result = usb_stor_probe2(us); 297 return result; 298 } 299 300 static struct usb_driver onetouch_driver = { 301 .name = "ums-onetouch", 302 .probe = onetouch_probe, 303 .disconnect = usb_stor_disconnect, 304 .suspend = usb_stor_suspend, 305 .resume = usb_stor_resume, 306 .reset_resume = usb_stor_reset_resume, 307 .pre_reset = usb_stor_pre_reset, 308 .post_reset = usb_stor_post_reset, 309 .id_table = onetouch_usb_ids, 310 .soft_unbind = 1, 311 }; 312 313 static int __init onetouch_init(void) 314 { 315 return usb_register(&onetouch_driver); 316 } 317 318 static void __exit onetouch_exit(void) 319 { 320 usb_deregister(&onetouch_driver); 321 } 322 323 module_init(onetouch_init); 324 module_exit(onetouch_exit); 325