// SPDX-License-Identifier: GPL-2.0+ 
 | 
/* 
 | 
 * Driver for Datafab USB Compact Flash reader 
 | 
 * 
 | 
 * datafab driver v0.1: 
 | 
 * 
 | 
 * First release 
 | 
 * 
 | 
 * Current development and maintenance by: 
 | 
 *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) 
 | 
 * 
 | 
 *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver 
 | 
 *   which I used as a template for this driver. 
 | 
 * 
 | 
 *   Some bugfixes and scatter-gather code by Gregory P. Smith  
 | 
 *   (greg-usb@electricrain.com) 
 | 
 * 
 | 
 *   Fix for media change by Joerg Schneider (js@joergschneider.com) 
 | 
 * 
 | 
 * Other contributors: 
 | 
 *   (c) 2002 Alan Stern <stern@rowland.org> 
 | 
 */ 
 | 
  
 | 
/* 
 | 
 * This driver attempts to support USB CompactFlash reader/writer devices 
 | 
 * based on Datafab USB-to-ATA chips.  It was specifically developed for the  
 | 
 * Datafab MDCFE-B USB CompactFlash reader but has since been found to work  
 | 
 * with a variety of Datafab-based devices from a number of manufacturers. 
 | 
 * I've received a report of this driver working with a Datafab-based 
 | 
 * SmartMedia device though please be aware that I'm personally unable to 
 | 
 * test SmartMedia support. 
 | 
 * 
 | 
 * This driver supports reading and writing.  If you're truly paranoid, 
 | 
 * however, you can force the driver into a write-protected state by setting 
 | 
 * the WP enable bits in datafab_handle_mode_sense().  See the comments 
 | 
 * in that routine. 
 | 
 */ 
 | 
  
 | 
#include <linux/errno.h> 
 | 
#include <linux/module.h> 
 | 
#include <linux/slab.h> 
 | 
  
 | 
#include <scsi/scsi.h> 
 | 
#include <scsi/scsi_cmnd.h> 
 | 
  
 | 
#include "usb.h" 
 | 
#include "transport.h" 
 | 
#include "protocol.h" 
 | 
#include "debug.h" 
 | 
#include "scsiglue.h" 
 | 
  
 | 
#define DRV_NAME "ums-datafab" 
 | 
  
 | 
MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader"); 
 | 
MODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>"); 
 | 
MODULE_LICENSE("GPL"); 
 | 
MODULE_IMPORT_NS(USB_STORAGE); 
 | 
  
 | 
struct datafab_info { 
 | 
    unsigned long   sectors;    /* total sector count */ 
 | 
    unsigned long   ssize;        /* sector size in bytes */ 
 | 
    signed char    lun;        /* used for dual-slot readers */ 
 | 
  
 | 
    /* the following aren't used yet */ 
 | 
    unsigned char   sense_key; 
 | 
    unsigned long   sense_asc;    /* additional sense code */ 
 | 
    unsigned long   sense_ascq;    /* additional sense code qualifier */ 
 | 
}; 
 | 
  
 | 
static int datafab_determine_lun(struct us_data *us, 
 | 
                 struct datafab_info *info); 
 | 
  
 | 
  
 | 
/* 
 | 
 * The table of devices 
 | 
 */ 
 | 
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 
 | 
            vendorName, productName, useProtocol, useTransport, \ 
 | 
            initFunction, flags) \ 
 | 
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 
 | 
  .driver_info = (flags) } 
 | 
  
 | 
static struct usb_device_id datafab_usb_ids[] = { 
 | 
#    include "unusual_datafab.h" 
 | 
    { }        /* Terminating entry */ 
 | 
}; 
 | 
MODULE_DEVICE_TABLE(usb, datafab_usb_ids); 
 | 
  
 | 
#undef UNUSUAL_DEV 
 | 
  
 | 
/* 
 | 
 * The flags table 
 | 
 */ 
 | 
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 
 | 
            vendor_name, product_name, use_protocol, use_transport, \ 
 | 
            init_function, Flags) \ 
 | 
{ \ 
 | 
    .vendorName = vendor_name,    \ 
 | 
    .productName = product_name,    \ 
 | 
    .useProtocol = use_protocol,    \ 
 | 
    .useTransport = use_transport,    \ 
 | 
    .initFunction = init_function,    \ 
 | 
} 
 | 
  
 | 
static struct us_unusual_dev datafab_unusual_dev_list[] = { 
 | 
#    include "unusual_datafab.h" 
 | 
    { }        /* Terminating entry */ 
 | 
}; 
 | 
  
 | 
#undef UNUSUAL_DEV 
 | 
  
 | 
  
 | 
static inline int 
 | 
datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { 
 | 
    if (len == 0) 
 | 
        return USB_STOR_XFER_GOOD; 
 | 
  
 | 
    usb_stor_dbg(us, "len = %d\n", len); 
 | 
    return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 
 | 
            data, len, NULL); 
 | 
} 
 | 
  
 | 
  
 | 
static inline int 
 | 
datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { 
 | 
    if (len == 0) 
 | 
        return USB_STOR_XFER_GOOD; 
 | 
  
 | 
    usb_stor_dbg(us, "len = %d\n", len); 
 | 
    return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 
 | 
            data, len, NULL); 
 | 
} 
 | 
  
 | 
  
 | 
static int datafab_read_data(struct us_data *us, 
 | 
                 struct datafab_info *info, 
 | 
                 u32 sector, 
 | 
                 u32 sectors) 
 | 
{ 
 | 
    unsigned char *command = us->iobuf; 
 | 
    unsigned char *buffer; 
 | 
    unsigned char  thistime; 
 | 
    unsigned int totallen, alloclen; 
 | 
    int len, result; 
 | 
    unsigned int sg_offset = 0; 
 | 
    struct scatterlist *sg = NULL; 
 | 
  
 | 
    // we're working in LBA mode.  according to the ATA spec,  
 | 
    // we can support up to 28-bit addressing.  I don't know if Datafab 
 | 
    // supports beyond 24-bit addressing.  It's kind of hard to test  
 | 
    // since it requires > 8GB CF card. 
 | 
    // 
 | 
    if (sectors > 0x0FFFFFFF) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    if (info->lun == -1) { 
 | 
        result = datafab_determine_lun(us, info); 
 | 
        if (result != USB_STOR_TRANSPORT_GOOD) 
 | 
            return result; 
 | 
    } 
 | 
  
 | 
    totallen = sectors * info->ssize; 
 | 
  
 | 
    // Since we don't read more than 64 KB at a time, we have to create 
 | 
    // a bounce buffer and move the data a piece at a time between the 
 | 
    // bounce buffer and the actual transfer buffer. 
 | 
  
 | 
    alloclen = min(totallen, 65536u); 
 | 
    buffer = kmalloc(alloclen, GFP_NOIO); 
 | 
    if (buffer == NULL) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    do { 
 | 
        // loop, never allocate or transfer more than 64k at once 
 | 
        // (min(128k, 255*info->ssize) is the real limit) 
 | 
  
 | 
        len = min(totallen, alloclen); 
 | 
        thistime = (len / info->ssize) & 0xff; 
 | 
  
 | 
        command[0] = 0; 
 | 
        command[1] = thistime; 
 | 
        command[2] = sector & 0xFF; 
 | 
        command[3] = (sector >> 8) & 0xFF; 
 | 
        command[4] = (sector >> 16) & 0xFF; 
 | 
  
 | 
        command[5] = 0xE0 + (info->lun << 4); 
 | 
        command[5] |= (sector >> 24) & 0x0F; 
 | 
        command[6] = 0x20; 
 | 
        command[7] = 0x01; 
 | 
  
 | 
        // send the read command 
 | 
        result = datafab_bulk_write(us, command, 8); 
 | 
        if (result != USB_STOR_XFER_GOOD) 
 | 
            goto leave; 
 | 
  
 | 
        // read the result 
 | 
        result = datafab_bulk_read(us, buffer, len); 
 | 
        if (result != USB_STOR_XFER_GOOD) 
 | 
            goto leave; 
 | 
  
 | 
        // Store the data in the transfer buffer 
 | 
        usb_stor_access_xfer_buf(buffer, len, us->srb, 
 | 
                 &sg, &sg_offset, TO_XFER_BUF); 
 | 
  
 | 
        sector += thistime; 
 | 
        totallen -= len; 
 | 
    } while (totallen > 0); 
 | 
  
 | 
    kfree(buffer); 
 | 
    return USB_STOR_TRANSPORT_GOOD; 
 | 
  
 | 
 leave: 
 | 
    kfree(buffer); 
 | 
    return USB_STOR_TRANSPORT_ERROR; 
 | 
} 
 | 
  
 | 
  
 | 
static int datafab_write_data(struct us_data *us, 
 | 
                  struct datafab_info *info, 
 | 
                  u32 sector, 
 | 
                  u32 sectors) 
 | 
{ 
 | 
    unsigned char *command = us->iobuf; 
 | 
    unsigned char *reply = us->iobuf; 
 | 
    unsigned char *buffer; 
 | 
    unsigned char thistime; 
 | 
    unsigned int totallen, alloclen; 
 | 
    int len, result; 
 | 
    unsigned int sg_offset = 0; 
 | 
    struct scatterlist *sg = NULL; 
 | 
  
 | 
    // we're working in LBA mode.  according to the ATA spec,  
 | 
    // we can support up to 28-bit addressing.  I don't know if Datafab 
 | 
    // supports beyond 24-bit addressing.  It's kind of hard to test  
 | 
    // since it requires > 8GB CF card. 
 | 
    // 
 | 
    if (sectors > 0x0FFFFFFF) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    if (info->lun == -1) { 
 | 
        result = datafab_determine_lun(us, info); 
 | 
        if (result != USB_STOR_TRANSPORT_GOOD) 
 | 
            return result; 
 | 
    } 
 | 
  
 | 
    totallen = sectors * info->ssize; 
 | 
  
 | 
    // Since we don't write more than 64 KB at a time, we have to create 
 | 
    // a bounce buffer and move the data a piece at a time between the 
 | 
    // bounce buffer and the actual transfer buffer. 
 | 
  
 | 
    alloclen = min(totallen, 65536u); 
 | 
    buffer = kmalloc(alloclen, GFP_NOIO); 
 | 
    if (buffer == NULL) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    do { 
 | 
        // loop, never allocate or transfer more than 64k at once 
 | 
        // (min(128k, 255*info->ssize) is the real limit) 
 | 
  
 | 
        len = min(totallen, alloclen); 
 | 
        thistime = (len / info->ssize) & 0xff; 
 | 
  
 | 
        // Get the data from the transfer buffer 
 | 
        usb_stor_access_xfer_buf(buffer, len, us->srb, 
 | 
                &sg, &sg_offset, FROM_XFER_BUF); 
 | 
  
 | 
        command[0] = 0; 
 | 
        command[1] = thistime; 
 | 
        command[2] = sector & 0xFF; 
 | 
        command[3] = (sector >> 8) & 0xFF; 
 | 
        command[4] = (sector >> 16) & 0xFF; 
 | 
  
 | 
        command[5] = 0xE0 + (info->lun << 4); 
 | 
        command[5] |= (sector >> 24) & 0x0F; 
 | 
        command[6] = 0x30; 
 | 
        command[7] = 0x02; 
 | 
  
 | 
        // send the command 
 | 
        result = datafab_bulk_write(us, command, 8); 
 | 
        if (result != USB_STOR_XFER_GOOD) 
 | 
            goto leave; 
 | 
  
 | 
        // send the data 
 | 
        result = datafab_bulk_write(us, buffer, len); 
 | 
        if (result != USB_STOR_XFER_GOOD) 
 | 
            goto leave; 
 | 
  
 | 
        // read the result 
 | 
        result = datafab_bulk_read(us, reply, 2); 
 | 
        if (result != USB_STOR_XFER_GOOD) 
 | 
            goto leave; 
 | 
  
 | 
        if (reply[0] != 0x50 && reply[1] != 0) { 
 | 
            usb_stor_dbg(us, "Gah! write return code: %02x %02x\n", 
 | 
                     reply[0], reply[1]); 
 | 
            result = USB_STOR_TRANSPORT_ERROR; 
 | 
            goto leave; 
 | 
        } 
 | 
  
 | 
        sector += thistime; 
 | 
        totallen -= len; 
 | 
    } while (totallen > 0); 
 | 
  
 | 
    kfree(buffer); 
 | 
    return USB_STOR_TRANSPORT_GOOD; 
 | 
  
 | 
 leave: 
 | 
    kfree(buffer); 
 | 
    return USB_STOR_TRANSPORT_ERROR; 
 | 
} 
 | 
  
 | 
  
 | 
static int datafab_determine_lun(struct us_data *us, 
 | 
                 struct datafab_info *info) 
 | 
{ 
 | 
    // Dual-slot readers can be thought of as dual-LUN devices. 
 | 
    // We need to determine which card slot is being used. 
 | 
    // We'll send an IDENTIFY DEVICE command and see which LUN responds... 
 | 
    // 
 | 
    // There might be a better way of doing this? 
 | 
  
 | 
    static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 
 | 
    unsigned char *command = us->iobuf; 
 | 
    unsigned char *buf; 
 | 
    int count = 0, rc; 
 | 
  
 | 
    if (!info) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    memcpy(command, scommand, 8); 
 | 
    buf = kmalloc(512, GFP_NOIO); 
 | 
    if (!buf) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    usb_stor_dbg(us, "locating...\n"); 
 | 
  
 | 
    // we'll try 3 times before giving up... 
 | 
    // 
 | 
    while (count++ < 3) { 
 | 
        command[5] = 0xa0; 
 | 
  
 | 
        rc = datafab_bulk_write(us, command, 8); 
 | 
        if (rc != USB_STOR_XFER_GOOD) { 
 | 
            rc = USB_STOR_TRANSPORT_ERROR; 
 | 
            goto leave; 
 | 
        } 
 | 
  
 | 
        rc = datafab_bulk_read(us, buf, 512); 
 | 
        if (rc == USB_STOR_XFER_GOOD) { 
 | 
            info->lun = 0; 
 | 
            rc = USB_STOR_TRANSPORT_GOOD; 
 | 
            goto leave; 
 | 
        } 
 | 
  
 | 
        command[5] = 0xb0; 
 | 
  
 | 
        rc = datafab_bulk_write(us, command, 8); 
 | 
        if (rc != USB_STOR_XFER_GOOD) { 
 | 
            rc = USB_STOR_TRANSPORT_ERROR; 
 | 
            goto leave; 
 | 
        } 
 | 
  
 | 
        rc = datafab_bulk_read(us, buf, 512); 
 | 
        if (rc == USB_STOR_XFER_GOOD) { 
 | 
            info->lun = 1; 
 | 
            rc = USB_STOR_TRANSPORT_GOOD; 
 | 
            goto leave; 
 | 
        } 
 | 
  
 | 
        msleep(20); 
 | 
    } 
 | 
  
 | 
    rc = USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
 leave: 
 | 
    kfree(buf); 
 | 
    return rc; 
 | 
} 
 | 
  
 | 
static int datafab_id_device(struct us_data *us, 
 | 
                 struct datafab_info *info) 
 | 
{ 
 | 
    // this is a variation of the ATA "IDENTIFY DEVICE" command...according 
 | 
    // to the ATA spec, 'Sector Count' isn't used but the Windows driver 
 | 
    // sets this bit so we do too... 
 | 
    // 
 | 
    static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 
 | 
    unsigned char *command = us->iobuf; 
 | 
    unsigned char *reply; 
 | 
    int rc; 
 | 
  
 | 
    if (!info) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    if (info->lun == -1) { 
 | 
        rc = datafab_determine_lun(us, info); 
 | 
        if (rc != USB_STOR_TRANSPORT_GOOD) 
 | 
            return rc; 
 | 
    } 
 | 
  
 | 
    memcpy(command, scommand, 8); 
 | 
    reply = kmalloc(512, GFP_NOIO); 
 | 
    if (!reply) 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
    command[5] += (info->lun << 4); 
 | 
  
 | 
    rc = datafab_bulk_write(us, command, 8); 
 | 
    if (rc != USB_STOR_XFER_GOOD) { 
 | 
        rc = USB_STOR_TRANSPORT_ERROR; 
 | 
        goto leave; 
 | 
    } 
 | 
  
 | 
    // we'll go ahead and extract the media capacity while we're here... 
 | 
    // 
 | 
    rc = datafab_bulk_read(us, reply, 512); 
 | 
    if (rc == USB_STOR_XFER_GOOD) { 
 | 
        // capacity is at word offset 57-58 
 | 
        // 
 | 
        info->sectors = ((u32)(reply[117]) << 24) |  
 | 
                ((u32)(reply[116]) << 16) | 
 | 
                ((u32)(reply[115]) <<  8) |  
 | 
                ((u32)(reply[114])      ); 
 | 
        rc = USB_STOR_TRANSPORT_GOOD; 
 | 
        goto leave; 
 | 
    } 
 | 
  
 | 
    rc = USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
 leave: 
 | 
    kfree(reply); 
 | 
    return rc; 
 | 
} 
 | 
  
 | 
  
 | 
static int datafab_handle_mode_sense(struct us_data *us, 
 | 
                     struct scsi_cmnd * srb,  
 | 
                     int sense_6) 
 | 
{ 
 | 
    static unsigned char rw_err_page[12] = { 
 | 
        0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 
 | 
    }; 
 | 
    static unsigned char cache_page[12] = { 
 | 
        0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 
 | 
    }; 
 | 
    static unsigned char rbac_page[12] = { 
 | 
        0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 
 | 
    }; 
 | 
    static unsigned char timer_page[8] = { 
 | 
        0x1C, 0x6, 0, 0, 0, 0 
 | 
    }; 
 | 
    unsigned char pc, page_code; 
 | 
    unsigned int i = 0; 
 | 
    struct datafab_info *info = (struct datafab_info *) (us->extra); 
 | 
    unsigned char *ptr = us->iobuf; 
 | 
  
 | 
    // most of this stuff is just a hack to get things working.  the 
 | 
    // datafab reader doesn't present a SCSI interface so we 
 | 
    // fudge the SCSI commands... 
 | 
    // 
 | 
  
 | 
    pc = srb->cmnd[2] >> 6; 
 | 
    page_code = srb->cmnd[2] & 0x3F; 
 | 
  
 | 
    switch (pc) { 
 | 
       case 0x0: 
 | 
           usb_stor_dbg(us, "Current values\n"); 
 | 
        break; 
 | 
       case 0x1: 
 | 
           usb_stor_dbg(us, "Changeable values\n"); 
 | 
        break; 
 | 
       case 0x2: 
 | 
           usb_stor_dbg(us, "Default values\n"); 
 | 
        break; 
 | 
       case 0x3: 
 | 
           usb_stor_dbg(us, "Saves values\n"); 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    memset(ptr, 0, 8); 
 | 
    if (sense_6) { 
 | 
        ptr[2] = 0x00;        // WP enable: 0x80 
 | 
        i = 4; 
 | 
    } else { 
 | 
        ptr[3] = 0x00;        // WP enable: 0x80 
 | 
        i = 8; 
 | 
    } 
 | 
  
 | 
    switch (page_code) { 
 | 
       default: 
 | 
        // vendor-specific mode 
 | 
        info->sense_key = 0x05; 
 | 
        info->sense_asc = 0x24; 
 | 
        info->sense_ascq = 0x00; 
 | 
        return USB_STOR_TRANSPORT_FAILED; 
 | 
  
 | 
       case 0x1: 
 | 
        memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 
 | 
        i += sizeof(rw_err_page); 
 | 
        break; 
 | 
  
 | 
       case 0x8: 
 | 
        memcpy(ptr + i, cache_page, sizeof(cache_page)); 
 | 
        i += sizeof(cache_page); 
 | 
        break; 
 | 
  
 | 
       case 0x1B: 
 | 
        memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 
 | 
        i += sizeof(rbac_page); 
 | 
        break; 
 | 
  
 | 
       case 0x1C: 
 | 
        memcpy(ptr + i, timer_page, sizeof(timer_page)); 
 | 
        i += sizeof(timer_page); 
 | 
        break; 
 | 
  
 | 
       case 0x3F:        // retrieve all pages 
 | 
        memcpy(ptr + i, timer_page, sizeof(timer_page)); 
 | 
        i += sizeof(timer_page); 
 | 
        memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 
 | 
        i += sizeof(rbac_page); 
 | 
        memcpy(ptr + i, cache_page, sizeof(cache_page)); 
 | 
        i += sizeof(cache_page); 
 | 
        memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 
 | 
        i += sizeof(rw_err_page); 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    if (sense_6) 
 | 
        ptr[0] = i - 1; 
 | 
    else 
 | 
        ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); 
 | 
    usb_stor_set_xfer_buf(ptr, i, srb); 
 | 
  
 | 
    return USB_STOR_TRANSPORT_GOOD; 
 | 
} 
 | 
  
 | 
static void datafab_info_destructor(void *extra) 
 | 
{ 
 | 
    // this routine is a placeholder... 
 | 
    // currently, we don't allocate any extra memory so we're okay 
 | 
} 
 | 
  
 | 
  
 | 
// Transport for the Datafab MDCFE-B 
 | 
// 
 | 
static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) 
 | 
{ 
 | 
    struct datafab_info *info; 
 | 
    int rc; 
 | 
    unsigned long block, blocks; 
 | 
    unsigned char *ptr = us->iobuf; 
 | 
    static unsigned char inquiry_reply[8] = { 
 | 
        0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 
 | 
    }; 
 | 
  
 | 
    if (!us->extra) { 
 | 
        us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); 
 | 
        if (!us->extra) 
 | 
            return USB_STOR_TRANSPORT_ERROR; 
 | 
  
 | 
        us->extra_destructor = datafab_info_destructor; 
 | 
          ((struct datafab_info *)us->extra)->lun = -1; 
 | 
    } 
 | 
  
 | 
    info = (struct datafab_info *) (us->extra); 
 | 
  
 | 
    if (srb->cmnd[0] == INQUIRY) { 
 | 
        usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); 
 | 
        memcpy(ptr, inquiry_reply, sizeof(inquiry_reply)); 
 | 
        fill_inquiry_response(us, ptr, 36); 
 | 
        return USB_STOR_TRANSPORT_GOOD; 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == READ_CAPACITY) { 
 | 
        info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec 
 | 
        rc = datafab_id_device(us, info); 
 | 
        if (rc != USB_STOR_TRANSPORT_GOOD) 
 | 
            return rc; 
 | 
  
 | 
        usb_stor_dbg(us, "READ_CAPACITY:  %ld sectors, %ld bytes per sector\n", 
 | 
                 info->sectors, info->ssize); 
 | 
  
 | 
        // build the reply 
 | 
        // we need the last sector, not the number of sectors 
 | 
        ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); 
 | 
        ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); 
 | 
        usb_stor_set_xfer_buf(ptr, 8, srb); 
 | 
  
 | 
        return USB_STOR_TRANSPORT_GOOD; 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == MODE_SELECT_10) { 
 | 
        usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); 
 | 
        return USB_STOR_TRANSPORT_ERROR; 
 | 
    } 
 | 
  
 | 
    // don't bother implementing READ_6 or WRITE_6. 
 | 
    // 
 | 
    if (srb->cmnd[0] == READ_10) { 
 | 
        block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 
 | 
            ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); 
 | 
  
 | 
        blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 
 | 
  
 | 
        usb_stor_dbg(us, "READ_10: read block 0x%04lx  count %ld\n", 
 | 
                 block, blocks); 
 | 
        return datafab_read_data(us, info, block, blocks); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == READ_12) { 
 | 
        // we'll probably never see a READ_12 but we'll do it anyway... 
 | 
        // 
 | 
        block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 
 | 
            ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); 
 | 
  
 | 
        blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 
 | 
             ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9])); 
 | 
  
 | 
        usb_stor_dbg(us, "READ_12: read block 0x%04lx  count %ld\n", 
 | 
                 block, blocks); 
 | 
        return datafab_read_data(us, info, block, blocks); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == WRITE_10) { 
 | 
        block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 
 | 
            ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); 
 | 
  
 | 
        blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 
 | 
  
 | 
        usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", 
 | 
                 block, blocks); 
 | 
        return datafab_write_data(us, info, block, blocks); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == WRITE_12) { 
 | 
        // we'll probably never see a WRITE_12 but we'll do it anyway... 
 | 
        // 
 | 
        block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 
 | 
            ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5])); 
 | 
  
 | 
        blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 
 | 
             ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9])); 
 | 
  
 | 
        usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", 
 | 
                 block, blocks); 
 | 
        return datafab_write_data(us, info, block, blocks); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == TEST_UNIT_READY) { 
 | 
        usb_stor_dbg(us, "TEST_UNIT_READY\n"); 
 | 
        return datafab_id_device(us, info); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == REQUEST_SENSE) { 
 | 
        usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n"); 
 | 
  
 | 
        // this response is pretty bogus right now.  eventually if necessary 
 | 
        // we can set the correct sense data.  so far though it hasn't been 
 | 
        // necessary 
 | 
        // 
 | 
        memset(ptr, 0, 18); 
 | 
        ptr[0] = 0xF0; 
 | 
        ptr[2] = info->sense_key; 
 | 
        ptr[7] = 11; 
 | 
        ptr[12] = info->sense_asc; 
 | 
        ptr[13] = info->sense_ascq; 
 | 
        usb_stor_set_xfer_buf(ptr, 18, srb); 
 | 
  
 | 
        return USB_STOR_TRANSPORT_GOOD; 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == MODE_SENSE) { 
 | 
        usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); 
 | 
        return datafab_handle_mode_sense(us, srb, 1); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == MODE_SENSE_10) { 
 | 
        usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); 
 | 
        return datafab_handle_mode_sense(us, srb, 0); 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 
 | 
        /* 
 | 
         * sure.  whatever.  not like we can stop the user from 
 | 
         * popping the media out of the device (no locking doors, etc) 
 | 
         */ 
 | 
        return USB_STOR_TRANSPORT_GOOD; 
 | 
    } 
 | 
  
 | 
    if (srb->cmnd[0] == START_STOP) { 
 | 
        /* 
 | 
         * this is used by sd.c'check_scsidisk_media_change to detect 
 | 
         * media change 
 | 
         */ 
 | 
        usb_stor_dbg(us, "START_STOP\n"); 
 | 
        /* 
 | 
         * the first datafab_id_device after a media change returns 
 | 
         * an error (determined experimentally) 
 | 
         */ 
 | 
        rc = datafab_id_device(us, info); 
 | 
        if (rc == USB_STOR_TRANSPORT_GOOD) { 
 | 
            info->sense_key = NO_SENSE; 
 | 
            srb->result = SUCCESS; 
 | 
        } else { 
 | 
            info->sense_key = UNIT_ATTENTION; 
 | 
            srb->result = SAM_STAT_CHECK_CONDITION; 
 | 
        } 
 | 
        return rc; 
 | 
    } 
 | 
  
 | 
    usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", 
 | 
             srb->cmnd[0], srb->cmnd[0]); 
 | 
    info->sense_key = 0x05; 
 | 
    info->sense_asc = 0x20; 
 | 
    info->sense_ascq = 0x00; 
 | 
    return USB_STOR_TRANSPORT_FAILED; 
 | 
} 
 | 
  
 | 
static struct scsi_host_template datafab_host_template; 
 | 
  
 | 
static int datafab_probe(struct usb_interface *intf, 
 | 
             const struct usb_device_id *id) 
 | 
{ 
 | 
    struct us_data *us; 
 | 
    int result; 
 | 
  
 | 
    result = usb_stor_probe1(&us, intf, id, 
 | 
            (id - datafab_usb_ids) + datafab_unusual_dev_list, 
 | 
            &datafab_host_template); 
 | 
    if (result) 
 | 
        return result; 
 | 
  
 | 
    us->transport_name  = "Datafab Bulk-Only"; 
 | 
    us->transport = datafab_transport; 
 | 
    us->transport_reset = usb_stor_Bulk_reset; 
 | 
    us->max_lun = 1; 
 | 
  
 | 
    result = usb_stor_probe2(us); 
 | 
    return result; 
 | 
} 
 | 
  
 | 
static struct usb_driver datafab_driver = { 
 | 
    .name =        DRV_NAME, 
 | 
    .probe =    datafab_probe, 
 | 
    .disconnect =    usb_stor_disconnect, 
 | 
    .suspend =    usb_stor_suspend, 
 | 
    .resume =    usb_stor_resume, 
 | 
    .reset_resume =    usb_stor_reset_resume, 
 | 
    .pre_reset =    usb_stor_pre_reset, 
 | 
    .post_reset =    usb_stor_post_reset, 
 | 
    .id_table =    datafab_usb_ids, 
 | 
    .soft_unbind =    1, 
 | 
    .no_dynamic_id = 1, 
 | 
}; 
 | 
  
 | 
module_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME); 
 |