linux/drivers/usb/storage/freecom.c
<<
>>
Prefs
   1/*
   2 * Driver for Freecom USB/IDE adaptor
   3 *
   4 * Freecom v0.1:
   5 *
   6 * First release
   7 *
   8 * Current development and maintenance by:
   9 *   (C) 2000 David Brown <usb-storage@davidb.org>
  10 *
  11 * This program is free software; you can redistribute it and/or modify it
  12 * under the terms of the GNU General Public License as published by the
  13 * Free Software Foundation; either version 2, or (at your option) any
  14 * later version.
  15 *
  16 * This program is distributed in the hope that it will be useful, but
  17 * WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19 * General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License along
  22 * with this program; if not, write to the Free Software Foundation, Inc.,
  23 * 675 Mass Ave, Cambridge, MA 02139, USA.
  24 *
  25 * This driver was developed with information provided in FREECOM's USB
  26 * Programmers Reference Guide.  For further information contact Freecom
  27 * (http://www.freecom.de/)
  28 */
  29
  30#include <linux/module.h>
  31#include <scsi/scsi.h>
  32#include <scsi/scsi_cmnd.h>
  33
  34#include "usb.h"
  35#include "transport.h"
  36#include "protocol.h"
  37#include "debug.h"
  38#include "scsiglue.h"
  39
  40#define DRV_NAME "ums-freecom"
  41
  42MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
  43MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
  44MODULE_LICENSE("GPL");
  45
  46#ifdef CONFIG_USB_STORAGE_DEBUG
  47static void pdump(struct us_data *us, void *ibuffer, int length);
  48#endif
  49
  50/* Bits of HD_STATUS */
  51#define ERR_STAT                0x01
  52#define DRQ_STAT                0x08
  53
  54/* All of the outgoing packets are 64 bytes long. */
  55struct freecom_cb_wrap {
  56        u8    Type;             /* Command type. */
  57        u8    Timeout;          /* Timeout in seconds. */
  58        u8    Atapi[12];        /* An ATAPI packet. */
  59        u8    Filler[50];       /* Padding Data. */
  60};
  61
  62struct freecom_xfer_wrap {
  63        u8    Type;             /* Command type. */
  64        u8    Timeout;          /* Timeout in seconds. */
  65        __le32   Count;         /* Number of bytes to transfer. */
  66        u8    Pad[58];
  67} __attribute__ ((packed));
  68
  69struct freecom_ide_out {
  70        u8    Type;             /* Type + IDE register. */
  71        u8    Pad;
  72        __le16   Value;         /* Value to write. */
  73        u8    Pad2[60];
  74};
  75
  76struct freecom_ide_in {
  77        u8    Type;             /* Type | IDE register. */
  78        u8    Pad[63];
  79};
  80
  81struct freecom_status {
  82        u8    Status;
  83        u8    Reason;
  84        __le16   Count;
  85        u8    Pad[60];
  86};
  87
  88/*
  89 * Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
  90 * register.
  91 */
  92#define FCM_INT_STATUS          0x02 /* INDEX_STAT */
  93#define FCM_STATUS_BUSY         0x80
  94
  95/*
  96 * These are the packet types.  The low bit indicates that this command
  97 * should wait for an interrupt.
  98 */
  99#define FCM_PACKET_ATAPI        0x21
 100#define FCM_PACKET_STATUS       0x20
 101
 102/*
 103 * Receive data from the IDE interface.  The ATAPI packet has already
 104 * waited, so the data should be immediately available.
 105 */
 106#define FCM_PACKET_INPUT        0x81
 107
 108/* Send data to the IDE interface. */
 109#define FCM_PACKET_OUTPUT       0x01
 110
 111/*
 112 * Write a value to an ide register.  Or the ide register to write after
 113 * munging the address a bit.
 114 */
 115#define FCM_PACKET_IDE_WRITE    0x40
 116#define FCM_PACKET_IDE_READ     0xC0
 117
 118/* All packets (except for status) are 64 bytes long. */
 119#define FCM_PACKET_LENGTH               64
 120#define FCM_STATUS_PACKET_LENGTH        4
 121
 122static int init_freecom(struct us_data *us);
 123
 124
 125/*
 126 * The table of devices
 127 */
 128#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
 129                    vendorName, productName, useProtocol, useTransport, \
 130                    initFunction, flags) \
 131{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
 132  .driver_info = (flags) }
 133
 134static struct usb_device_id freecom_usb_ids[] = {
 135#       include "unusual_freecom.h"
 136        { }             /* Terminating entry */
 137};
 138MODULE_DEVICE_TABLE(usb, freecom_usb_ids);
 139
 140#undef UNUSUAL_DEV
 141
 142/*
 143 * The flags table
 144 */
 145#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
 146                    vendor_name, product_name, use_protocol, use_transport, \
 147                    init_function, Flags) \
 148{ \
 149        .vendorName = vendor_name,      \
 150        .productName = product_name,    \
 151        .useProtocol = use_protocol,    \
 152        .useTransport = use_transport,  \
 153        .initFunction = init_function,  \
 154}
 155
 156static struct us_unusual_dev freecom_unusual_dev_list[] = {
 157#       include "unusual_freecom.h"
 158        { }             /* Terminating entry */
 159};
 160
 161#undef UNUSUAL_DEV
 162
 163static int
 164freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
 165                unsigned int ipipe, unsigned int opipe, int count)
 166{
 167        struct freecom_xfer_wrap *fxfr =
 168                (struct freecom_xfer_wrap *) us->iobuf;
 169        int result;
 170
 171        fxfr->Type = FCM_PACKET_INPUT | 0x00;
 172        fxfr->Timeout = 0;    /* Short timeout for debugging. */
 173        fxfr->Count = cpu_to_le32 (count);
 174        memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
 175
 176        usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
 177
 178        /* Issue the transfer command. */
 179        result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
 180                        FCM_PACKET_LENGTH, NULL);
 181        if (result != USB_STOR_XFER_GOOD) {
 182                usb_stor_dbg(us, "Freecom readdata transport error\n");
 183                return USB_STOR_TRANSPORT_ERROR;
 184        }
 185
 186        /* Now transfer all of our blocks. */
 187        usb_stor_dbg(us, "Start of read\n");
 188        result = usb_stor_bulk_srb(us, ipipe, srb);
 189        usb_stor_dbg(us, "freecom_readdata done!\n");
 190
 191        if (result > USB_STOR_XFER_SHORT)
 192                return USB_STOR_TRANSPORT_ERROR;
 193        return USB_STOR_TRANSPORT_GOOD;
 194}
 195
 196static int
 197freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
 198                int unsigned ipipe, unsigned int opipe, int count)
 199{
 200        struct freecom_xfer_wrap *fxfr =
 201                (struct freecom_xfer_wrap *) us->iobuf;
 202        int result;
 203
 204        fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
 205        fxfr->Timeout = 0;    /* Short timeout for debugging. */
 206        fxfr->Count = cpu_to_le32 (count);
 207        memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
 208
 209        usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
 210
 211        /* Issue the transfer command. */
 212        result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
 213                        FCM_PACKET_LENGTH, NULL);
 214        if (result != USB_STOR_XFER_GOOD) {
 215                usb_stor_dbg(us, "Freecom writedata transport error\n");
 216                return USB_STOR_TRANSPORT_ERROR;
 217        }
 218
 219        /* Now transfer all of our blocks. */
 220        usb_stor_dbg(us, "Start of write\n");
 221        result = usb_stor_bulk_srb(us, opipe, srb);
 222
 223        usb_stor_dbg(us, "freecom_writedata done!\n");
 224        if (result > USB_STOR_XFER_SHORT)
 225                return USB_STOR_TRANSPORT_ERROR;
 226        return USB_STOR_TRANSPORT_GOOD;
 227}
 228
 229/*
 230 * Transport for the Freecom USB/IDE adaptor.
 231 *
 232 */
 233static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
 234{
 235        struct freecom_cb_wrap *fcb;
 236        struct freecom_status  *fst;
 237        unsigned int ipipe, opipe;              /* We need both pipes. */
 238        int result;
 239        unsigned int partial;
 240        int length;
 241
 242        fcb = (struct freecom_cb_wrap *) us->iobuf;
 243        fst = (struct freecom_status *) us->iobuf;
 244
 245        usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
 246
 247        /* Get handles for both transports. */
 248        opipe = us->send_bulk_pipe;
 249        ipipe = us->recv_bulk_pipe;
 250
 251        /* The ATAPI Command always goes out first. */
 252        fcb->Type = FCM_PACKET_ATAPI | 0x00;
 253        fcb->Timeout = 0;
 254        memcpy (fcb->Atapi, srb->cmnd, 12);
 255        memset (fcb->Filler, 0, sizeof (fcb->Filler));
 256
 257        US_DEBUG(pdump(us, srb->cmnd, 12));
 258
 259        /* Send it out. */
 260        result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
 261                        FCM_PACKET_LENGTH, NULL);
 262
 263        /*
 264         * The Freecom device will only fail if there is something wrong in
 265         * USB land.  It returns the status in its own registers, which
 266         * come back in the bulk pipe.
 267         */
 268        if (result != USB_STOR_XFER_GOOD) {
 269                usb_stor_dbg(us, "freecom transport error\n");
 270                return USB_STOR_TRANSPORT_ERROR;
 271        }
 272
 273        /*
 274         * There are times we can optimize out this status read, but it
 275         * doesn't hurt us to always do it now.
 276         */
 277        result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
 278                        FCM_STATUS_PACKET_LENGTH, &partial);
 279        usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
 280        if (result != USB_STOR_XFER_GOOD)
 281                return USB_STOR_TRANSPORT_ERROR;
 282
 283        US_DEBUG(pdump(us, (void *)fst, partial));
 284
 285        /*
 286         * The firmware will time-out commands after 20 seconds. Some commands
 287         * can legitimately take longer than this, so we use a different
 288         * command that only waits for the interrupt and then sends status,
 289         * without having to send a new ATAPI command to the device.
 290         *
 291         * NOTE: There is some indication that a data transfer after a timeout
 292         * may not work, but that is a condition that should never happen.
 293         */
 294        while (fst->Status & FCM_STATUS_BUSY) {
 295                usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
 296                usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
 297
 298                /* Get the status again */
 299                fcb->Type = FCM_PACKET_STATUS;
 300                fcb->Timeout = 0;
 301                memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
 302                memset (fcb->Filler, 0, sizeof (fcb->Filler));
 303
 304                /* Send it out. */
 305                result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
 306                                FCM_PACKET_LENGTH, NULL);
 307
 308                /*
 309                 * The Freecom device will only fail if there is something
 310                 * wrong in USB land.  It returns the status in its own
 311                 * registers, which come back in the bulk pipe.
 312                 */
 313                if (result != USB_STOR_XFER_GOOD) {
 314                        usb_stor_dbg(us, "freecom transport error\n");
 315                        return USB_STOR_TRANSPORT_ERROR;
 316                }
 317
 318                /* get the data */
 319                result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
 320                                FCM_STATUS_PACKET_LENGTH, &partial);
 321
 322                usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
 323                if (result != USB_STOR_XFER_GOOD)
 324                        return USB_STOR_TRANSPORT_ERROR;
 325
 326                US_DEBUG(pdump(us, (void *)fst, partial));
 327        }
 328
 329        if (partial != 4)
 330                return USB_STOR_TRANSPORT_ERROR;
 331        if ((fst->Status & 1) != 0) {
 332                usb_stor_dbg(us, "operation failed\n");
 333                return USB_STOR_TRANSPORT_FAILED;
 334        }
 335
 336        /*
 337         * The device might not have as much data available as we
 338         * requested.  If you ask for more than the device has, this reads
 339         * and such will hang.
 340         */
 341        usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
 342                     le16_to_cpu(fst->Count));
 343        usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
 344
 345        /* Find the length we desire to read. */
 346        switch (srb->cmnd[0]) {
 347        case INQUIRY:
 348        case REQUEST_SENSE:     /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
 349        case MODE_SENSE:
 350        case MODE_SENSE_10:
 351                length = le16_to_cpu(fst->Count);
 352                break;
 353        default:
 354                length = scsi_bufflen(srb);
 355        }
 356
 357        /* verify that this amount is legal */
 358        if (length > scsi_bufflen(srb)) {
 359                length = scsi_bufflen(srb);
 360                usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
 361                             length);
 362        }
 363
 364        /*
 365         * What we do now depends on what direction the data is supposed to
 366         * move in.
 367         */
 368
 369        switch (us->srb->sc_data_direction) {
 370        case DMA_FROM_DEVICE:
 371                /* catch bogus "read 0 length" case */
 372                if (!length)
 373                        break;
 374                /*
 375                 * Make sure that the status indicates that the device
 376                 * wants data as well.
 377                 */
 378                if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
 379                        usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
 380                        return USB_STOR_TRANSPORT_FAILED;
 381                }
 382                result = freecom_readdata (srb, us, ipipe, opipe, length);
 383                if (result != USB_STOR_TRANSPORT_GOOD)
 384                        return result;
 385
 386                usb_stor_dbg(us, "Waiting for status\n");
 387                result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
 388                                FCM_PACKET_LENGTH, &partial);
 389                US_DEBUG(pdump(us, (void *)fst, partial));
 390
 391                if (partial != 4 || result > USB_STOR_XFER_SHORT)
 392                        return USB_STOR_TRANSPORT_ERROR;
 393                if ((fst->Status & ERR_STAT) != 0) {
 394                        usb_stor_dbg(us, "operation failed\n");
 395                        return USB_STOR_TRANSPORT_FAILED;
 396                }
 397                if ((fst->Reason & 3) != 3) {
 398                        usb_stor_dbg(us, "Drive seems still hungry\n");
 399                        return USB_STOR_TRANSPORT_FAILED;
 400                }
 401                usb_stor_dbg(us, "Transfer happy\n");
 402                break;
 403
 404        case DMA_TO_DEVICE:
 405                /* catch bogus "write 0 length" case */
 406                if (!length)
 407                        break;
 408                /*
 409                 * Make sure the status indicates that the device wants to
 410                 * send us data.
 411                 */
 412                /* !!IMPLEMENT!! */
 413                result = freecom_writedata (srb, us, ipipe, opipe, length);
 414                if (result != USB_STOR_TRANSPORT_GOOD)
 415                        return result;
 416
 417                usb_stor_dbg(us, "Waiting for status\n");
 418                result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
 419                                FCM_PACKET_LENGTH, &partial);
 420
 421                if (partial != 4 || result > USB_STOR_XFER_SHORT)
 422                        return USB_STOR_TRANSPORT_ERROR;
 423                if ((fst->Status & ERR_STAT) != 0) {
 424                        usb_stor_dbg(us, "operation failed\n");
 425                        return USB_STOR_TRANSPORT_FAILED;
 426                }
 427                if ((fst->Reason & 3) != 3) {
 428                        usb_stor_dbg(us, "Drive seems still hungry\n");
 429                        return USB_STOR_TRANSPORT_FAILED;
 430                }
 431
 432                usb_stor_dbg(us, "Transfer happy\n");
 433                break;
 434
 435
 436        case DMA_NONE:
 437                /* Easy, do nothing. */
 438                break;
 439
 440        default:
 441                /* should never hit here -- filtered in usb.c */
 442                usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
 443                             us->srb->sc_data_direction);
 444                /* Return fail, SCSI seems to handle this better. */
 445                return USB_STOR_TRANSPORT_FAILED;
 446                break;
 447        }
 448
 449        return USB_STOR_TRANSPORT_GOOD;
 450}
 451
 452static int init_freecom(struct us_data *us)
 453{
 454        int result;
 455        char *buffer = us->iobuf;
 456
 457        /*
 458         * The DMA-mapped I/O buffer is 64 bytes long, just right for
 459         * all our packets.  No need to allocate any extra buffer space.
 460         */
 461
 462        result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
 463                        0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
 464        buffer[32] = '\0';
 465        usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
 466
 467        /*
 468         * Special thanks to the people at Freecom for providing me with
 469         * this "magic sequence", which they use in their Windows and MacOS
 470         * drivers to make sure that all the attached perhiperals are
 471         * properly reset.
 472         */
 473
 474        /* send reset */
 475        result = usb_stor_control_msg(us, us->send_ctrl_pipe,
 476                        0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
 477        usb_stor_dbg(us, "result from activate reset is %d\n", result);
 478
 479        /* wait 250ms */
 480        mdelay(250);
 481
 482        /* clear reset */
 483        result = usb_stor_control_msg(us, us->send_ctrl_pipe,
 484                        0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
 485        usb_stor_dbg(us, "result from clear reset is %d\n", result);
 486
 487        /* wait 3 seconds */
 488        mdelay(3 * 1000);
 489
 490        return USB_STOR_TRANSPORT_GOOD;
 491}
 492
 493static int usb_stor_freecom_reset(struct us_data *us)
 494{
 495        printk (KERN_CRIT "freecom reset called\n");
 496
 497        /* We don't really have this feature. */
 498        return FAILED;
 499}
 500
 501#ifdef CONFIG_USB_STORAGE_DEBUG
 502static void pdump(struct us_data *us, void *ibuffer, int length)
 503{
 504        static char line[80];
 505        int offset = 0;
 506        unsigned char *buffer = (unsigned char *) ibuffer;
 507        int i, j;
 508        int from, base;
 509
 510        offset = 0;
 511        for (i = 0; i < length; i++) {
 512                if ((i & 15) == 0) {
 513                        if (i > 0) {
 514                                offset += sprintf (line+offset, " - ");
 515                                for (j = i - 16; j < i; j++) {
 516                                        if (buffer[j] >= 32 && buffer[j] <= 126)
 517                                                line[offset++] = buffer[j];
 518                                        else
 519                                                line[offset++] = '.';
 520                                }
 521                                line[offset] = 0;
 522                                usb_stor_dbg(us, "%s\n", line);
 523                                offset = 0;
 524                        }
 525                        offset += sprintf (line+offset, "%08x:", i);
 526                } else if ((i & 7) == 0) {
 527                        offset += sprintf (line+offset, " -");
 528                }
 529                offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
 530        }
 531
 532        /* Add the last "chunk" of data. */
 533        from = (length - 1) % 16;
 534        base = ((length - 1) / 16) * 16;
 535
 536        for (i = from + 1; i < 16; i++)
 537                offset += sprintf (line+offset, "   ");
 538        if (from < 8)
 539                offset += sprintf (line+offset, "  ");
 540        offset += sprintf (line+offset, " - ");
 541
 542        for (i = 0; i <= from; i++) {
 543                if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
 544                        line[offset++] = buffer[base+i];
 545                else
 546                        line[offset++] = '.';
 547        }
 548        line[offset] = 0;
 549        usb_stor_dbg(us, "%s\n", line);
 550        offset = 0;
 551}
 552#endif
 553
 554static struct scsi_host_template freecom_host_template;
 555
 556static int freecom_probe(struct usb_interface *intf,
 557                         const struct usb_device_id *id)
 558{
 559        struct us_data *us;
 560        int result;
 561
 562        result = usb_stor_probe1(&us, intf, id,
 563                        (id - freecom_usb_ids) + freecom_unusual_dev_list,
 564                        &freecom_host_template);
 565        if (result)
 566                return result;
 567
 568        us->transport_name = "Freecom";
 569        us->transport = freecom_transport;
 570        us->transport_reset = usb_stor_freecom_reset;
 571        us->max_lun = 0;
 572
 573        result = usb_stor_probe2(us);
 574        return result;
 575}
 576
 577static struct usb_driver freecom_driver = {
 578        .name =         DRV_NAME,
 579        .probe =        freecom_probe,
 580        .disconnect =   usb_stor_disconnect,
 581        .suspend =      usb_stor_suspend,
 582        .resume =       usb_stor_resume,
 583        .reset_resume = usb_stor_reset_resume,
 584        .pre_reset =    usb_stor_pre_reset,
 585        .post_reset =   usb_stor_post_reset,
 586        .id_table =     freecom_usb_ids,
 587        .soft_unbind =  1,
 588        .no_dynamic_id = 1,
 589};
 590
 591module_usb_stor_driver(freecom_driver, freecom_host_template, DRV_NAME);
 592