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