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