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/config.h> 3234008dbfSMatthew Dharm #include <linux/kernel.h> 3334008dbfSMatthew Dharm #include <linux/input.h> 3434008dbfSMatthew Dharm #include <linux/init.h> 3534008dbfSMatthew Dharm #include <linux/slab.h> 3634008dbfSMatthew Dharm #include <linux/module.h> 37d6450e19SNick Sillik #include <linux/usb_ch9.h> 38ae0dadcfSDavid Brownell #include <linux/usb/input.h> 3934008dbfSMatthew Dharm #include "usb.h" 4034008dbfSMatthew Dharm #include "onetouch.h" 4134008dbfSMatthew Dharm #include "debug.h" 4234008dbfSMatthew Dharm 4334008dbfSMatthew Dharm void onetouch_release_input(void *onetouch_); 4434008dbfSMatthew Dharm 4534008dbfSMatthew Dharm struct usb_onetouch { 4634008dbfSMatthew Dharm char name[128]; 4734008dbfSMatthew Dharm char phys[64]; 4888789672SDmitry Torokhov struct input_dev *dev; /* input device interface */ 4934008dbfSMatthew Dharm struct usb_device *udev; /* usb device */ 5034008dbfSMatthew Dharm 5134008dbfSMatthew Dharm struct urb *irq; /* urb for interrupt in report */ 5234008dbfSMatthew Dharm unsigned char *data; /* input data */ 5334008dbfSMatthew Dharm dma_addr_t data_dma; 547931e1c6SMatthew Dharm unsigned int is_open:1; 5534008dbfSMatthew Dharm }; 5634008dbfSMatthew Dharm 5734008dbfSMatthew Dharm static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs) 5834008dbfSMatthew Dharm { 5934008dbfSMatthew Dharm struct usb_onetouch *onetouch = urb->context; 6034008dbfSMatthew Dharm signed char *data = onetouch->data; 6188789672SDmitry Torokhov struct input_dev *dev = onetouch->dev; 6234008dbfSMatthew Dharm int status; 6334008dbfSMatthew Dharm 6434008dbfSMatthew Dharm switch (urb->status) { 6534008dbfSMatthew Dharm case 0: /* success */ 6634008dbfSMatthew Dharm break; 6734008dbfSMatthew Dharm case -ECONNRESET: /* unlink */ 6834008dbfSMatthew Dharm case -ENOENT: 6934008dbfSMatthew Dharm case -ESHUTDOWN: 7034008dbfSMatthew Dharm return; 7134008dbfSMatthew Dharm /* -EPIPE: should clear the halt */ 7234008dbfSMatthew Dharm default: /* error */ 7334008dbfSMatthew Dharm goto resubmit; 7434008dbfSMatthew Dharm } 7534008dbfSMatthew Dharm 7634008dbfSMatthew Dharm input_regs(dev, regs); 7788789672SDmitry Torokhov input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); 7834008dbfSMatthew Dharm input_sync(dev); 7988789672SDmitry Torokhov 8034008dbfSMatthew Dharm resubmit: 8134008dbfSMatthew Dharm status = usb_submit_urb (urb, SLAB_ATOMIC); 8234008dbfSMatthew Dharm if (status) 8334008dbfSMatthew Dharm err ("can't resubmit intr, %s-%s/input0, status %d", 8434008dbfSMatthew Dharm onetouch->udev->bus->bus_name, 8534008dbfSMatthew Dharm onetouch->udev->devpath, status); 8634008dbfSMatthew Dharm } 8734008dbfSMatthew Dharm 8834008dbfSMatthew Dharm static int usb_onetouch_open(struct input_dev *dev) 8934008dbfSMatthew Dharm { 9034008dbfSMatthew Dharm struct usb_onetouch *onetouch = dev->private; 9134008dbfSMatthew Dharm 927931e1c6SMatthew Dharm onetouch->is_open = 1; 9334008dbfSMatthew Dharm onetouch->irq->dev = onetouch->udev; 9434008dbfSMatthew Dharm if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { 9534008dbfSMatthew Dharm err("usb_submit_urb failed"); 9634008dbfSMatthew Dharm return -EIO; 9734008dbfSMatthew Dharm } 9834008dbfSMatthew Dharm 9934008dbfSMatthew Dharm return 0; 10034008dbfSMatthew Dharm } 10134008dbfSMatthew Dharm 10234008dbfSMatthew Dharm static void usb_onetouch_close(struct input_dev *dev) 10334008dbfSMatthew Dharm { 10434008dbfSMatthew Dharm struct usb_onetouch *onetouch = dev->private; 10534008dbfSMatthew Dharm 10634008dbfSMatthew Dharm usb_kill_urb(onetouch->irq); 1077931e1c6SMatthew Dharm onetouch->is_open = 0; 10834008dbfSMatthew Dharm } 10934008dbfSMatthew Dharm 1107931e1c6SMatthew Dharm #ifdef CONFIG_PM 1117931e1c6SMatthew Dharm static void usb_onetouch_pm_hook(struct us_data *us, int action) 1127931e1c6SMatthew Dharm { 1137931e1c6SMatthew Dharm struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra; 1147931e1c6SMatthew Dharm 1157931e1c6SMatthew Dharm if (onetouch->is_open) { 1167931e1c6SMatthew Dharm switch (action) { 1177931e1c6SMatthew Dharm case US_SUSPEND: 1187931e1c6SMatthew Dharm usb_kill_urb(onetouch->irq); 1197931e1c6SMatthew Dharm break; 1207931e1c6SMatthew Dharm case US_RESUME: 1217931e1c6SMatthew Dharm if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0) 1227931e1c6SMatthew Dharm err("usb_submit_urb failed"); 1237931e1c6SMatthew Dharm break; 1247931e1c6SMatthew Dharm default: 1257931e1c6SMatthew Dharm break; 1267931e1c6SMatthew Dharm } 1277931e1c6SMatthew Dharm } 1287931e1c6SMatthew Dharm } 1297931e1c6SMatthew Dharm #endif /* CONFIG_PM */ 1307931e1c6SMatthew Dharm 13134008dbfSMatthew Dharm int onetouch_connect_input(struct us_data *ss) 13234008dbfSMatthew Dharm { 13334008dbfSMatthew Dharm struct usb_device *udev = ss->pusb_dev; 13434008dbfSMatthew Dharm struct usb_host_interface *interface; 13534008dbfSMatthew Dharm struct usb_endpoint_descriptor *endpoint; 13634008dbfSMatthew Dharm struct usb_onetouch *onetouch; 13788789672SDmitry Torokhov struct input_dev *input_dev; 13834008dbfSMatthew Dharm int pipe, maxp; 13934008dbfSMatthew Dharm 14034008dbfSMatthew Dharm interface = ss->pusb_intf->cur_altsetting; 14134008dbfSMatthew Dharm 142d6450e19SNick Sillik if (interface->desc.bNumEndpoints != 3) 14334008dbfSMatthew Dharm return -ENODEV; 144d6450e19SNick Sillik 145d6450e19SNick Sillik endpoint = &interface->endpoint[2].desc; 146d6450e19SNick Sillik if (!(endpoint->bEndpointAddress & USB_DIR_IN)) 147d6450e19SNick Sillik return -ENODEV; 148d6450e19SNick Sillik if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) 149d6450e19SNick Sillik != USB_ENDPOINT_XFER_INT) 15034008dbfSMatthew Dharm return -ENODEV; 15134008dbfSMatthew Dharm 15234008dbfSMatthew Dharm pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); 15334008dbfSMatthew Dharm maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); 15434008dbfSMatthew Dharm 15588789672SDmitry Torokhov onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); 15688789672SDmitry Torokhov input_dev = input_allocate_device(); 15788789672SDmitry Torokhov if (!onetouch || !input_dev) 15888789672SDmitry Torokhov goto fail1; 15934008dbfSMatthew Dharm 160d6450e19SNick Sillik onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, 161d6450e19SNick Sillik SLAB_ATOMIC, &onetouch->data_dma); 16288789672SDmitry Torokhov if (!onetouch->data) 16388789672SDmitry Torokhov goto fail1; 16434008dbfSMatthew Dharm 16534008dbfSMatthew Dharm onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); 16688789672SDmitry Torokhov if (!onetouch->irq) 16788789672SDmitry Torokhov goto fail2; 16834008dbfSMatthew Dharm 16934008dbfSMatthew Dharm onetouch->udev = udev; 17088789672SDmitry Torokhov onetouch->dev = input_dev; 17134008dbfSMatthew Dharm 17234008dbfSMatthew Dharm if (udev->manufacturer) 17388789672SDmitry Torokhov strlcpy(onetouch->name, udev->manufacturer, 17488789672SDmitry Torokhov sizeof(onetouch->name)); 17588789672SDmitry Torokhov if (udev->product) { 17688789672SDmitry Torokhov if (udev->manufacturer) 17788789672SDmitry Torokhov strlcat(onetouch->name, " ", sizeof(onetouch->name)); 17888789672SDmitry Torokhov strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); 17988789672SDmitry Torokhov } 18088789672SDmitry Torokhov 18134008dbfSMatthew Dharm if (!strlen(onetouch->name)) 18288789672SDmitry Torokhov snprintf(onetouch->name, sizeof(onetouch->name), 18388789672SDmitry Torokhov "Maxtor Onetouch %04x:%04x", 18488789672SDmitry Torokhov le16_to_cpu(udev->descriptor.idVendor), 18588789672SDmitry Torokhov le16_to_cpu(udev->descriptor.idProduct)); 18688789672SDmitry Torokhov 18788789672SDmitry Torokhov usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); 18888789672SDmitry Torokhov strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); 18988789672SDmitry Torokhov 19088789672SDmitry Torokhov input_dev->name = onetouch->name; 19188789672SDmitry Torokhov input_dev->phys = onetouch->phys; 19288789672SDmitry Torokhov usb_to_input_id(udev, &input_dev->id); 19388789672SDmitry Torokhov input_dev->cdev.dev = &udev->dev; 19488789672SDmitry Torokhov 19588789672SDmitry Torokhov set_bit(EV_KEY, input_dev->evbit); 19688789672SDmitry Torokhov set_bit(ONETOUCH_BUTTON, input_dev->keybit); 19788789672SDmitry Torokhov clear_bit(0, input_dev->keybit); 19888789672SDmitry Torokhov 19988789672SDmitry Torokhov input_dev->private = onetouch; 20088789672SDmitry Torokhov input_dev->open = usb_onetouch_open; 20188789672SDmitry Torokhov input_dev->close = usb_onetouch_close; 20234008dbfSMatthew Dharm 20334008dbfSMatthew Dharm usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, 20434008dbfSMatthew Dharm (maxp > 8 ? 8 : maxp), 20534008dbfSMatthew Dharm usb_onetouch_irq, onetouch, endpoint->bInterval); 20634008dbfSMatthew Dharm onetouch->irq->transfer_dma = onetouch->data_dma; 20734008dbfSMatthew Dharm onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 20834008dbfSMatthew Dharm 20934008dbfSMatthew Dharm ss->extra_destructor = onetouch_release_input; 21034008dbfSMatthew Dharm ss->extra = onetouch; 2117931e1c6SMatthew Dharm #ifdef CONFIG_PM 2127931e1c6SMatthew Dharm ss->suspend_resume_hook = usb_onetouch_pm_hook; 2137931e1c6SMatthew Dharm #endif 21434008dbfSMatthew Dharm 21588789672SDmitry Torokhov input_register_device(onetouch->dev); 21634008dbfSMatthew Dharm 21734008dbfSMatthew Dharm return 0; 21888789672SDmitry Torokhov 21988789672SDmitry Torokhov fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN, 22088789672SDmitry Torokhov onetouch->data, onetouch->data_dma); 22188789672SDmitry Torokhov fail1: kfree(onetouch); 22288789672SDmitry Torokhov input_free_device(input_dev); 22388789672SDmitry Torokhov return -ENOMEM; 22434008dbfSMatthew Dharm } 22534008dbfSMatthew Dharm 22634008dbfSMatthew Dharm void onetouch_release_input(void *onetouch_) 22734008dbfSMatthew Dharm { 22834008dbfSMatthew Dharm struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; 22934008dbfSMatthew Dharm 23034008dbfSMatthew Dharm if (onetouch) { 23134008dbfSMatthew Dharm usb_kill_urb(onetouch->irq); 23288789672SDmitry Torokhov input_unregister_device(onetouch->dev); 23334008dbfSMatthew Dharm usb_free_urb(onetouch->irq); 23434008dbfSMatthew Dharm usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN, 23534008dbfSMatthew Dharm onetouch->data, onetouch->data_dma); 23634008dbfSMatthew Dharm } 23734008dbfSMatthew Dharm } 238