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