134008dbfSMatthew Dharm /* 234008dbfSMatthew Dharm * Support for the Maxtor OneTouch USB hard drive's button 334008dbfSMatthew Dharm * 434008dbfSMatthew Dharm * Current development and maintenance by: 534008dbfSMatthew Dharm * Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu> 634008dbfSMatthew Dharm * 734008dbfSMatthew Dharm * Initial work by: 8d6450e19SNick Sillik * Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se> 934008dbfSMatthew Dharm * 1034008dbfSMatthew Dharm * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann) 1134008dbfSMatthew Dharm * 1234008dbfSMatthew Dharm */ 1334008dbfSMatthew Dharm 1434008dbfSMatthew Dharm /* 1534008dbfSMatthew Dharm * This program is free software; you can redistribute it and/or modify 1634008dbfSMatthew Dharm * it under the terms of the GNU General Public License as published by 1734008dbfSMatthew Dharm * the Free Software Foundation; either version 2 of the License, or 1834008dbfSMatthew Dharm * (at your option) any later version. 1934008dbfSMatthew Dharm * 2034008dbfSMatthew Dharm * This program is distributed in the hope that it will be useful, 2134008dbfSMatthew Dharm * but WITHOUT ANY WARRANTY; without even the implied warranty of 2234008dbfSMatthew Dharm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2334008dbfSMatthew Dharm * GNU General Public License for more details. 2434008dbfSMatthew Dharm * 2534008dbfSMatthew Dharm * You should have received a copy of the GNU General Public License 2634008dbfSMatthew Dharm * along with this program; if not, write to the Free Software 2734008dbfSMatthew Dharm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2834008dbfSMatthew Dharm * 2934008dbfSMatthew Dharm */ 3034008dbfSMatthew Dharm 3134008dbfSMatthew Dharm #include <linux/kernel.h> 3234008dbfSMatthew Dharm #include <linux/input.h> 3334008dbfSMatthew Dharm #include <linux/init.h> 3434008dbfSMatthew Dharm #include <linux/slab.h> 3534008dbfSMatthew Dharm #include <linux/module.h> 36ae0dadcfSDavid Brownell #include <linux/usb/input.h> 3734008dbfSMatthew Dharm #include "usb.h" 3834008dbfSMatthew Dharm #include "debug.h" 3934008dbfSMatthew Dharm 409cfb95efSAlan Stern #define ONETOUCH_PKT_LEN 0x02 419cfb95efSAlan Stern #define ONETOUCH_BUTTON KEY_PROG1 429cfb95efSAlan Stern 439cfb95efSAlan Stern static int onetouch_connect_input(struct us_data *ss); 4443c1e98cSAdrian Bunk static void onetouch_release_input(void *onetouch_); 4534008dbfSMatthew Dharm 4634008dbfSMatthew Dharm struct usb_onetouch { 4734008dbfSMatthew Dharm char name[128]; 4834008dbfSMatthew Dharm char phys[64]; 4988789672SDmitry Torokhov struct input_dev *dev; /* input device interface */ 5034008dbfSMatthew Dharm struct usb_device *udev; /* usb device */ 5134008dbfSMatthew Dharm 5234008dbfSMatthew Dharm struct urb *irq; /* urb for interrupt in report */ 5334008dbfSMatthew Dharm unsigned char *data; /* input data */ 5434008dbfSMatthew Dharm dma_addr_t data_dma; 557931e1c6SMatthew Dharm unsigned int is_open:1; 5634008dbfSMatthew Dharm }; 5734008dbfSMatthew Dharm 589cfb95efSAlan Stern 599cfb95efSAlan Stern /* 609cfb95efSAlan Stern * The table of devices 619cfb95efSAlan Stern */ 629cfb95efSAlan Stern #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 639cfb95efSAlan Stern vendorName, productName, useProtocol, useTransport, \ 649cfb95efSAlan Stern initFunction, flags) \ 659cfb95efSAlan Stern { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 669cfb95efSAlan Stern .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } 679cfb95efSAlan Stern 689cfb95efSAlan Stern struct usb_device_id onetouch_usb_ids[] = { 699cfb95efSAlan Stern # include "unusual_onetouch.h" 709cfb95efSAlan Stern { } /* Terminating entry */ 719cfb95efSAlan Stern }; 729cfb95efSAlan Stern MODULE_DEVICE_TABLE(usb, onetouch_usb_ids); 739cfb95efSAlan Stern 749cfb95efSAlan Stern #undef UNUSUAL_DEV 759cfb95efSAlan Stern 769cfb95efSAlan Stern /* 779cfb95efSAlan Stern * The flags table 789cfb95efSAlan Stern */ 799cfb95efSAlan Stern #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 809cfb95efSAlan Stern vendor_name, product_name, use_protocol, use_transport, \ 819cfb95efSAlan Stern init_function, Flags) \ 829cfb95efSAlan Stern { \ 839cfb95efSAlan Stern .vendorName = vendor_name, \ 849cfb95efSAlan Stern .productName = product_name, \ 859cfb95efSAlan Stern .useProtocol = use_protocol, \ 869cfb95efSAlan Stern .useTransport = use_transport, \ 879cfb95efSAlan Stern .initFunction = init_function, \ 889cfb95efSAlan Stern } 899cfb95efSAlan Stern 909cfb95efSAlan Stern static struct us_unusual_dev onetouch_unusual_dev_list[] = { 919cfb95efSAlan Stern # include "unusual_onetouch.h" 929cfb95efSAlan Stern { } /* Terminating entry */ 939cfb95efSAlan Stern }; 949cfb95efSAlan Stern 959cfb95efSAlan Stern #undef UNUSUAL_DEV 969cfb95efSAlan Stern 979cfb95efSAlan Stern 987d12e780SDavid Howells static void usb_onetouch_irq(struct urb *urb) 9934008dbfSMatthew Dharm { 10034008dbfSMatthew Dharm struct usb_onetouch *onetouch = urb->context; 10134008dbfSMatthew Dharm signed char *data = onetouch->data; 10288789672SDmitry Torokhov struct input_dev *dev = onetouch->dev; 10362e5a330SGreg Kroah-Hartman int status = urb->status; 10462e5a330SGreg Kroah-Hartman int retval; 10534008dbfSMatthew Dharm 10662e5a330SGreg Kroah-Hartman switch (status) { 10734008dbfSMatthew Dharm case 0: /* success */ 10834008dbfSMatthew Dharm break; 10934008dbfSMatthew Dharm case -ECONNRESET: /* unlink */ 11034008dbfSMatthew Dharm case -ENOENT: 11134008dbfSMatthew Dharm case -ESHUTDOWN: 11234008dbfSMatthew Dharm return; 11334008dbfSMatthew Dharm /* -EPIPE: should clear the halt */ 11434008dbfSMatthew Dharm default: /* error */ 11534008dbfSMatthew Dharm goto resubmit; 11634008dbfSMatthew Dharm } 11734008dbfSMatthew Dharm 11888789672SDmitry Torokhov input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); 11934008dbfSMatthew Dharm input_sync(dev); 12088789672SDmitry Torokhov 12134008dbfSMatthew Dharm resubmit: 12262e5a330SGreg Kroah-Hartman retval = usb_submit_urb (urb, GFP_ATOMIC); 12362e5a330SGreg Kroah-Hartman if (retval) 124802f389aSGreg Kroah-Hartman dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, " 125802f389aSGreg Kroah-Hartman "retval %d\n", onetouch->udev->bus->bus_name, 12662e5a330SGreg Kroah-Hartman onetouch->udev->devpath, retval); 12734008dbfSMatthew Dharm } 12834008dbfSMatthew Dharm 12934008dbfSMatthew Dharm static int usb_onetouch_open(struct input_dev *dev) 13034008dbfSMatthew Dharm { 13109b7002dSDmitry Torokhov struct usb_onetouch *onetouch = input_get_drvdata(dev); 13234008dbfSMatthew Dharm 1337931e1c6SMatthew Dharm onetouch->is_open = 1; 13434008dbfSMatthew Dharm onetouch->irq->dev = onetouch->udev; 13534008dbfSMatthew Dharm if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { 136802f389aSGreg Kroah-Hartman dev_err(&dev->dev, "usb_submit_urb failed\n"); 13734008dbfSMatthew Dharm return -EIO; 13834008dbfSMatthew Dharm } 13934008dbfSMatthew Dharm 14034008dbfSMatthew Dharm return 0; 14134008dbfSMatthew Dharm } 14234008dbfSMatthew Dharm 14334008dbfSMatthew Dharm static void usb_onetouch_close(struct input_dev *dev) 14434008dbfSMatthew Dharm { 14509b7002dSDmitry Torokhov struct usb_onetouch *onetouch = input_get_drvdata(dev); 14634008dbfSMatthew Dharm 14734008dbfSMatthew Dharm usb_kill_urb(onetouch->irq); 1487931e1c6SMatthew Dharm onetouch->is_open = 0; 14934008dbfSMatthew Dharm } 15034008dbfSMatthew Dharm 1517931e1c6SMatthew Dharm #ifdef CONFIG_PM 1527931e1c6SMatthew Dharm static void usb_onetouch_pm_hook(struct us_data *us, int action) 1537931e1c6SMatthew Dharm { 1547931e1c6SMatthew Dharm struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra; 1557931e1c6SMatthew Dharm 1567931e1c6SMatthew Dharm if (onetouch->is_open) { 1577931e1c6SMatthew Dharm switch (action) { 1587931e1c6SMatthew Dharm case US_SUSPEND: 1597931e1c6SMatthew Dharm usb_kill_urb(onetouch->irq); 1607931e1c6SMatthew Dharm break; 1617931e1c6SMatthew Dharm case US_RESUME: 1627931e1c6SMatthew Dharm if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0) 163802f389aSGreg Kroah-Hartman dev_err(&onetouch->irq->dev->dev, 164802f389aSGreg Kroah-Hartman "usb_submit_urb failed\n"); 1657931e1c6SMatthew Dharm break; 1667931e1c6SMatthew Dharm default: 1677931e1c6SMatthew Dharm break; 1687931e1c6SMatthew Dharm } 1697931e1c6SMatthew Dharm } 1707931e1c6SMatthew Dharm } 1717931e1c6SMatthew Dharm #endif /* CONFIG_PM */ 1727931e1c6SMatthew Dharm 1739cfb95efSAlan Stern static int onetouch_connect_input(struct us_data *ss) 17434008dbfSMatthew Dharm { 17534008dbfSMatthew Dharm struct usb_device *udev = ss->pusb_dev; 17634008dbfSMatthew Dharm struct usb_host_interface *interface; 17734008dbfSMatthew Dharm struct usb_endpoint_descriptor *endpoint; 17834008dbfSMatthew Dharm struct usb_onetouch *onetouch; 17988789672SDmitry Torokhov struct input_dev *input_dev; 18034008dbfSMatthew Dharm int pipe, maxp; 18117efe155SDmitry Torokhov int error = -ENOMEM; 18234008dbfSMatthew Dharm 18334008dbfSMatthew Dharm interface = ss->pusb_intf->cur_altsetting; 18434008dbfSMatthew Dharm 185d6450e19SNick Sillik if (interface->desc.bNumEndpoints != 3) 18634008dbfSMatthew Dharm return -ENODEV; 187d6450e19SNick Sillik 188d6450e19SNick Sillik endpoint = &interface->endpoint[2].desc; 18966722a19SLuiz Fernando N. Capitulino if (!usb_endpoint_is_int_in(endpoint)) 19034008dbfSMatthew Dharm return -ENODEV; 19134008dbfSMatthew Dharm 19234008dbfSMatthew Dharm pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); 19334008dbfSMatthew Dharm maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); 19434008dbfSMatthew Dharm 19588789672SDmitry Torokhov onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); 19688789672SDmitry Torokhov input_dev = input_allocate_device(); 19788789672SDmitry Torokhov if (!onetouch || !input_dev) 19888789672SDmitry Torokhov goto fail1; 19934008dbfSMatthew Dharm 200d6450e19SNick Sillik onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, 20154e6ecb2SChristoph Lameter GFP_ATOMIC, &onetouch->data_dma); 20288789672SDmitry Torokhov if (!onetouch->data) 20388789672SDmitry Torokhov goto fail1; 20434008dbfSMatthew Dharm 20534008dbfSMatthew Dharm onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); 20688789672SDmitry Torokhov if (!onetouch->irq) 20788789672SDmitry Torokhov goto fail2; 20834008dbfSMatthew Dharm 20934008dbfSMatthew Dharm onetouch->udev = udev; 21088789672SDmitry Torokhov onetouch->dev = input_dev; 21134008dbfSMatthew Dharm 21234008dbfSMatthew Dharm if (udev->manufacturer) 21388789672SDmitry Torokhov strlcpy(onetouch->name, udev->manufacturer, 21488789672SDmitry Torokhov sizeof(onetouch->name)); 21588789672SDmitry Torokhov if (udev->product) { 21688789672SDmitry Torokhov if (udev->manufacturer) 21788789672SDmitry Torokhov strlcat(onetouch->name, " ", sizeof(onetouch->name)); 21888789672SDmitry Torokhov strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); 21988789672SDmitry Torokhov } 22088789672SDmitry Torokhov 22134008dbfSMatthew Dharm if (!strlen(onetouch->name)) 22288789672SDmitry Torokhov snprintf(onetouch->name, sizeof(onetouch->name), 22388789672SDmitry Torokhov "Maxtor Onetouch %04x:%04x", 22488789672SDmitry Torokhov le16_to_cpu(udev->descriptor.idVendor), 22588789672SDmitry Torokhov le16_to_cpu(udev->descriptor.idProduct)); 22688789672SDmitry Torokhov 22788789672SDmitry Torokhov usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); 22888789672SDmitry Torokhov strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); 22988789672SDmitry Torokhov 23088789672SDmitry Torokhov input_dev->name = onetouch->name; 23188789672SDmitry Torokhov input_dev->phys = onetouch->phys; 23288789672SDmitry Torokhov usb_to_input_id(udev, &input_dev->id); 23309b7002dSDmitry Torokhov input_dev->dev.parent = &udev->dev; 23488789672SDmitry Torokhov 23588789672SDmitry Torokhov set_bit(EV_KEY, input_dev->evbit); 23688789672SDmitry Torokhov set_bit(ONETOUCH_BUTTON, input_dev->keybit); 23788789672SDmitry Torokhov clear_bit(0, input_dev->keybit); 23888789672SDmitry Torokhov 23909b7002dSDmitry Torokhov input_set_drvdata(input_dev, onetouch); 24009b7002dSDmitry Torokhov 24188789672SDmitry Torokhov input_dev->open = usb_onetouch_open; 24288789672SDmitry Torokhov input_dev->close = usb_onetouch_close; 24334008dbfSMatthew Dharm 24434008dbfSMatthew Dharm usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, 24534008dbfSMatthew Dharm (maxp > 8 ? 8 : maxp), 24634008dbfSMatthew Dharm usb_onetouch_irq, onetouch, endpoint->bInterval); 24734008dbfSMatthew Dharm onetouch->irq->transfer_dma = onetouch->data_dma; 24834008dbfSMatthew Dharm onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 24934008dbfSMatthew Dharm 25034008dbfSMatthew Dharm ss->extra_destructor = onetouch_release_input; 25134008dbfSMatthew Dharm ss->extra = onetouch; 2527931e1c6SMatthew Dharm #ifdef CONFIG_PM 2537931e1c6SMatthew Dharm ss->suspend_resume_hook = usb_onetouch_pm_hook; 2547931e1c6SMatthew Dharm #endif 25534008dbfSMatthew Dharm 25617efe155SDmitry Torokhov error = input_register_device(onetouch->dev); 25717efe155SDmitry Torokhov if (error) 25817efe155SDmitry Torokhov goto fail3; 25934008dbfSMatthew Dharm 26034008dbfSMatthew Dharm return 0; 26188789672SDmitry Torokhov 26217efe155SDmitry Torokhov fail3: usb_free_urb(onetouch->irq); 26388789672SDmitry Torokhov fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN, 26488789672SDmitry Torokhov onetouch->data, onetouch->data_dma); 26588789672SDmitry Torokhov fail1: kfree(onetouch); 26688789672SDmitry Torokhov input_free_device(input_dev); 26717efe155SDmitry Torokhov return error; 26834008dbfSMatthew Dharm } 26934008dbfSMatthew Dharm 27043c1e98cSAdrian Bunk static void onetouch_release_input(void *onetouch_) 27134008dbfSMatthew Dharm { 27234008dbfSMatthew Dharm struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; 27334008dbfSMatthew Dharm 27434008dbfSMatthew Dharm if (onetouch) { 27534008dbfSMatthew Dharm usb_kill_urb(onetouch->irq); 27688789672SDmitry Torokhov input_unregister_device(onetouch->dev); 27734008dbfSMatthew Dharm usb_free_urb(onetouch->irq); 27834008dbfSMatthew Dharm usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, 27934008dbfSMatthew Dharm onetouch->data, onetouch->data_dma); 28034008dbfSMatthew Dharm } 28134008dbfSMatthew Dharm } 2829cfb95efSAlan Stern 2839cfb95efSAlan Stern static int onetouch_probe(struct usb_interface *intf, 2849cfb95efSAlan Stern const struct usb_device_id *id) 2859cfb95efSAlan Stern { 2869cfb95efSAlan Stern struct us_data *us; 2879cfb95efSAlan Stern int result; 2889cfb95efSAlan Stern 2899cfb95efSAlan Stern result = usb_stor_probe1(&us, intf, id, 2909cfb95efSAlan Stern (id - onetouch_usb_ids) + onetouch_unusual_dev_list); 2919cfb95efSAlan Stern if (result) 2929cfb95efSAlan Stern return result; 2939cfb95efSAlan Stern 2949cfb95efSAlan Stern /* Use default transport and protocol */ 2959cfb95efSAlan Stern 2969cfb95efSAlan Stern result = usb_stor_probe2(us); 2979cfb95efSAlan Stern return result; 2989cfb95efSAlan Stern } 2999cfb95efSAlan Stern 3009cfb95efSAlan Stern static struct usb_driver onetouch_driver = { 3019cfb95efSAlan Stern .name = "ums-onetouch", 3029cfb95efSAlan Stern .probe = onetouch_probe, 3039cfb95efSAlan Stern .disconnect = usb_stor_disconnect, 3049cfb95efSAlan Stern .suspend = usb_stor_suspend, 3059cfb95efSAlan Stern .resume = usb_stor_resume, 3069cfb95efSAlan Stern .reset_resume = usb_stor_reset_resume, 3079cfb95efSAlan Stern .pre_reset = usb_stor_pre_reset, 3089cfb95efSAlan Stern .post_reset = usb_stor_post_reset, 3099cfb95efSAlan Stern .id_table = onetouch_usb_ids, 3109cfb95efSAlan Stern .soft_unbind = 1, 3119cfb95efSAlan Stern }; 3129cfb95efSAlan Stern 3139cfb95efSAlan Stern static int __init onetouch_init(void) 3149cfb95efSAlan Stern { 3159cfb95efSAlan Stern return usb_register(&onetouch_driver); 3169cfb95efSAlan Stern } 3179cfb95efSAlan Stern 3189cfb95efSAlan Stern static void __exit onetouch_exit(void) 3199cfb95efSAlan Stern { 3209cfb95efSAlan Stern usb_deregister(&onetouch_driver); 3219cfb95efSAlan Stern } 3229cfb95efSAlan Stern 3239cfb95efSAlan Stern module_init(onetouch_init); 3249cfb95efSAlan Stern module_exit(onetouch_exit); 325