linux/drivers/usb/storage/karma.c
<<
>>
Prefs
   1/* Driver for Rio Karma
   2 *
   3 *   (c) 2006 Bob Copeland <me@bobcopeland.com>
   4 *   (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the
   8 * Free Software Foundation; either version 2, or (at your option) any
   9 * later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License along
  17 * with this program; if not, write to the Free Software Foundation, Inc.,
  18 * 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20
  21#include <linux/module.h>
  22
  23#include <scsi/scsi.h>
  24#include <scsi/scsi_cmnd.h>
  25#include <scsi/scsi_device.h>
  26
  27#include "usb.h"
  28#include "transport.h"
  29#include "debug.h"
  30
  31MODULE_DESCRIPTION("Driver for Rio Karma");
  32MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>, Keith Bennett <keith@mcs.st-and.ac.uk>");
  33MODULE_LICENSE("GPL");
  34
  35#define RIO_PREFIX "RIOP\x00"
  36#define RIO_PREFIX_LEN 5
  37#define RIO_SEND_LEN 40
  38#define RIO_RECV_LEN 0x200
  39
  40#define RIO_ENTER_STORAGE 0x1
  41#define RIO_LEAVE_STORAGE 0x2
  42#define RIO_RESET 0xC
  43
  44struct karma_data {
  45        int in_storage;
  46        char *recv;
  47};
  48
  49static int rio_karma_init(struct us_data *us);
  50
  51
  52/*
  53 * The table of devices
  54 */
  55#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
  56                    vendorName, productName, useProtocol, useTransport, \
  57                    initFunction, flags) \
  58{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
  59  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
  60
  61struct usb_device_id karma_usb_ids[] = {
  62#       include "unusual_karma.h"
  63        { }             /* Terminating entry */
  64};
  65MODULE_DEVICE_TABLE(usb, karma_usb_ids);
  66
  67#undef UNUSUAL_DEV
  68
  69/*
  70 * The flags table
  71 */
  72#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
  73                    vendor_name, product_name, use_protocol, use_transport, \
  74                    init_function, Flags) \
  75{ \
  76        .vendorName = vendor_name,      \
  77        .productName = product_name,    \
  78        .useProtocol = use_protocol,    \
  79        .useTransport = use_transport,  \
  80        .initFunction = init_function,  \
  81}
  82
  83static struct us_unusual_dev karma_unusual_dev_list[] = {
  84#       include "unusual_karma.h"
  85        { }             /* Terminating entry */
  86};
  87
  88#undef UNUSUAL_DEV
  89
  90
  91/*
  92 * Send commands to Rio Karma.
  93 *
  94 * For each command we send 40 bytes starting 'RIOP\0' followed by
  95 * the command number and a sequence number, which the device will ack
  96 * with a 512-byte packet with the high four bits set and everything
  97 * else null.  Then we send 'RIOP\x80' followed by a zero and the
  98 * sequence number, until byte 5 in the response repeats the sequence
  99 * number.
 100 */
 101static int rio_karma_send_command(char cmd, struct us_data *us)
 102{
 103        int result, partial;
 104        unsigned long timeout;
 105        static unsigned char seq = 1;
 106        struct karma_data *data = (struct karma_data *) us->extra;
 107
 108        US_DEBUGP("karma: sending command %04x\n", cmd);
 109        memset(us->iobuf, 0, RIO_SEND_LEN);
 110        memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
 111        us->iobuf[5] = cmd;
 112        us->iobuf[6] = seq;
 113
 114        timeout = jiffies + msecs_to_jiffies(6000);
 115        for (;;) {
 116                result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
 117                        us->iobuf, RIO_SEND_LEN, &partial);
 118                if (result != USB_STOR_XFER_GOOD)
 119                        goto err;
 120
 121                result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
 122                        data->recv, RIO_RECV_LEN, &partial);
 123                if (result != USB_STOR_XFER_GOOD)
 124                        goto err;
 125
 126                if (data->recv[5] == seq)
 127                        break;
 128
 129                if (time_after(jiffies, timeout))
 130                        goto err;
 131
 132                us->iobuf[4] = 0x80;
 133                us->iobuf[5] = 0;
 134                msleep(50);
 135        }
 136
 137        seq++;
 138        if (seq == 0)
 139                seq = 1;
 140
 141        US_DEBUGP("karma: sent command %04x\n", cmd);
 142        return 0;
 143err:
 144        US_DEBUGP("karma: command %04x failed\n", cmd);
 145        return USB_STOR_TRANSPORT_FAILED;
 146}
 147
 148/*
 149 * Trap START_STOP and READ_10 to leave/re-enter storage mode.
 150 * Everything else is propagated to the normal bulk layer.
 151 */
 152static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
 153{
 154        int ret;
 155        struct karma_data *data = (struct karma_data *) us->extra;
 156
 157        if (srb->cmnd[0] == READ_10 && !data->in_storage) {
 158                ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
 159                if (ret)
 160                        return ret;
 161
 162                data->in_storage = 1;
 163                return usb_stor_Bulk_transport(srb, us);
 164        } else if (srb->cmnd[0] == START_STOP) {
 165                ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
 166                if (ret)
 167                        return ret;
 168
 169                data->in_storage = 0;
 170                return rio_karma_send_command(RIO_RESET, us);
 171        }
 172        return usb_stor_Bulk_transport(srb, us);
 173}
 174
 175static void rio_karma_destructor(void *extra)
 176{
 177        struct karma_data *data = (struct karma_data *) extra;
 178        kfree(data->recv);
 179}
 180
 181static int rio_karma_init(struct us_data *us)
 182{
 183        int ret = 0;
 184        struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
 185        if (!data)
 186                goto out;
 187
 188        data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
 189        if (!data->recv) {
 190                kfree(data);
 191                goto out;
 192        }
 193
 194        us->extra = data;
 195        us->extra_destructor = rio_karma_destructor;
 196        ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
 197        data->in_storage = (ret == 0);
 198out:
 199        return ret;
 200}
 201
 202static int karma_probe(struct usb_interface *intf,
 203                         const struct usb_device_id *id)
 204{
 205        struct us_data *us;
 206        int result;
 207
 208        result = usb_stor_probe1(&us, intf, id,
 209                        (id - karma_usb_ids) + karma_unusual_dev_list);
 210        if (result)
 211                return result;
 212
 213        us->transport_name = "Rio Karma/Bulk";
 214        us->transport = rio_karma_transport;
 215        us->transport_reset = usb_stor_Bulk_reset;
 216
 217        result = usb_stor_probe2(us);
 218        return result;
 219}
 220
 221static struct usb_driver karma_driver = {
 222        .name =         "ums-karma",
 223        .probe =        karma_probe,
 224        .disconnect =   usb_stor_disconnect,
 225        .suspend =      usb_stor_suspend,
 226        .resume =       usb_stor_resume,
 227        .reset_resume = usb_stor_reset_resume,
 228        .pre_reset =    usb_stor_pre_reset,
 229        .post_reset =   usb_stor_post_reset,
 230        .id_table =     karma_usb_ids,
 231        .soft_unbind =  1,
 232};
 233
 234static int __init karma_init(void)
 235{
 236        return usb_register(&karma_driver);
 237}
 238
 239static void __exit karma_exit(void)
 240{
 241        usb_deregister(&karma_driver);
 242}
 243
 244module_init(karma_init);
 245module_exit(karma_exit);
 246