162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for Datafab USB Compact Flash reader 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * datafab driver v0.1: 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * First release 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Current development and maintenance by: 1062306a36Sopenharmony_ci * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver 1362306a36Sopenharmony_ci * which I used as a template for this driver. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Some bugfixes and scatter-gather code by Gregory P. Smith 1662306a36Sopenharmony_ci * (greg-usb@electricrain.com) 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Fix for media change by Joerg Schneider (js@joergschneider.com) 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Other contributors: 2162306a36Sopenharmony_ci * (c) 2002 Alan Stern <stern@rowland.org> 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * This driver attempts to support USB CompactFlash reader/writer devices 2662306a36Sopenharmony_ci * based on Datafab USB-to-ATA chips. It was specifically developed for the 2762306a36Sopenharmony_ci * Datafab MDCFE-B USB CompactFlash reader but has since been found to work 2862306a36Sopenharmony_ci * with a variety of Datafab-based devices from a number of manufacturers. 2962306a36Sopenharmony_ci * I've received a report of this driver working with a Datafab-based 3062306a36Sopenharmony_ci * SmartMedia device though please be aware that I'm personally unable to 3162306a36Sopenharmony_ci * test SmartMedia support. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * This driver supports reading and writing. If you're truly paranoid, 3462306a36Sopenharmony_ci * however, you can force the driver into a write-protected state by setting 3562306a36Sopenharmony_ci * the WP enable bits in datafab_handle_mode_sense(). See the comments 3662306a36Sopenharmony_ci * in that routine. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/errno.h> 4062306a36Sopenharmony_ci#include <linux/module.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <scsi/scsi.h> 4462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include "usb.h" 4762306a36Sopenharmony_ci#include "transport.h" 4862306a36Sopenharmony_ci#include "protocol.h" 4962306a36Sopenharmony_ci#include "debug.h" 5062306a36Sopenharmony_ci#include "scsiglue.h" 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define DRV_NAME "ums-datafab" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader"); 5562306a36Sopenharmony_ciMODULE_AUTHOR("Jimmie Mayfield <mayfield+datafab@sackheads.org>"); 5662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5762306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct datafab_info { 6062306a36Sopenharmony_ci unsigned long sectors; /* total sector count */ 6162306a36Sopenharmony_ci unsigned long ssize; /* sector size in bytes */ 6262306a36Sopenharmony_ci signed char lun; /* used for dual-slot readers */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* the following aren't used yet */ 6562306a36Sopenharmony_ci unsigned char sense_key; 6662306a36Sopenharmony_ci unsigned long sense_asc; /* additional sense code */ 6762306a36Sopenharmony_ci unsigned long sense_ascq; /* additional sense code qualifier */ 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us, 7162306a36Sopenharmony_ci struct datafab_info *info); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * The table of devices 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 7862306a36Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 7962306a36Sopenharmony_ci initFunction, flags) \ 8062306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 8162306a36Sopenharmony_ci .driver_info = (flags) } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct usb_device_id datafab_usb_ids[] = { 8462306a36Sopenharmony_ci# include "unusual_datafab.h" 8562306a36Sopenharmony_ci { } /* Terminating entry */ 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, datafab_usb_ids); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#undef UNUSUAL_DEV 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * The flags table 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 9562306a36Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 9662306a36Sopenharmony_ci init_function, Flags) \ 9762306a36Sopenharmony_ci{ \ 9862306a36Sopenharmony_ci .vendorName = vendor_name, \ 9962306a36Sopenharmony_ci .productName = product_name, \ 10062306a36Sopenharmony_ci .useProtocol = use_protocol, \ 10162306a36Sopenharmony_ci .useTransport = use_transport, \ 10262306a36Sopenharmony_ci .initFunction = init_function, \ 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic struct us_unusual_dev datafab_unusual_dev_list[] = { 10662306a36Sopenharmony_ci# include "unusual_datafab.h" 10762306a36Sopenharmony_ci { } /* Terminating entry */ 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#undef UNUSUAL_DEV 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline int 11462306a36Sopenharmony_cidatafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { 11562306a36Sopenharmony_ci if (len == 0) 11662306a36Sopenharmony_ci return USB_STOR_XFER_GOOD; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 11962306a36Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 12062306a36Sopenharmony_ci data, len, NULL); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline int 12562306a36Sopenharmony_cidatafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { 12662306a36Sopenharmony_ci if (len == 0) 12762306a36Sopenharmony_ci return USB_STOR_XFER_GOOD; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 13062306a36Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 13162306a36Sopenharmony_ci data, len, NULL); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int datafab_read_data(struct us_data *us, 13662306a36Sopenharmony_ci struct datafab_info *info, 13762306a36Sopenharmony_ci u32 sector, 13862306a36Sopenharmony_ci u32 sectors) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci unsigned char *command = us->iobuf; 14162306a36Sopenharmony_ci unsigned char *buffer; 14262306a36Sopenharmony_ci unsigned char thistime; 14362306a36Sopenharmony_ci unsigned int totallen, alloclen; 14462306a36Sopenharmony_ci int len, result; 14562306a36Sopenharmony_ci unsigned int sg_offset = 0; 14662306a36Sopenharmony_ci struct scatterlist *sg = NULL; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 14962306a36Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Datafab 15062306a36Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 15162306a36Sopenharmony_ci // since it requires > 8GB CF card. 15262306a36Sopenharmony_ci // 15362306a36Sopenharmony_ci if (sectors > 0x0FFFFFFF) 15462306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (info->lun == -1) { 15762306a36Sopenharmony_ci result = datafab_determine_lun(us, info); 15862306a36Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 15962306a36Sopenharmony_ci return result; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci totallen = sectors * info->ssize; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci // Since we don't read more than 64 KB at a time, we have to create 16562306a36Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 16662306a36Sopenharmony_ci // bounce buffer and the actual transfer buffer. 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci alloclen = min(totallen, 65536u); 16962306a36Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 17062306a36Sopenharmony_ci if (buffer == NULL) 17162306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci do { 17462306a36Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 17562306a36Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci len = min(totallen, alloclen); 17862306a36Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci command[0] = 0; 18162306a36Sopenharmony_ci command[1] = thistime; 18262306a36Sopenharmony_ci command[2] = sector & 0xFF; 18362306a36Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 18462306a36Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci command[5] = 0xE0 + (info->lun << 4); 18762306a36Sopenharmony_ci command[5] |= (sector >> 24) & 0x0F; 18862306a36Sopenharmony_ci command[6] = 0x20; 18962306a36Sopenharmony_ci command[7] = 0x01; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci // send the read command 19262306a36Sopenharmony_ci result = datafab_bulk_write(us, command, 8); 19362306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 19462306a36Sopenharmony_ci goto leave; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci // read the result 19762306a36Sopenharmony_ci result = datafab_bulk_read(us, buffer, len); 19862306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 19962306a36Sopenharmony_ci goto leave; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci // Store the data in the transfer buffer 20262306a36Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 20362306a36Sopenharmony_ci &sg, &sg_offset, TO_XFER_BUF); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci sector += thistime; 20662306a36Sopenharmony_ci totallen -= len; 20762306a36Sopenharmony_ci } while (totallen > 0); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci kfree(buffer); 21062306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci leave: 21362306a36Sopenharmony_ci kfree(buffer); 21462306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int datafab_write_data(struct us_data *us, 21962306a36Sopenharmony_ci struct datafab_info *info, 22062306a36Sopenharmony_ci u32 sector, 22162306a36Sopenharmony_ci u32 sectors) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci unsigned char *command = us->iobuf; 22462306a36Sopenharmony_ci unsigned char *reply = us->iobuf; 22562306a36Sopenharmony_ci unsigned char *buffer; 22662306a36Sopenharmony_ci unsigned char thistime; 22762306a36Sopenharmony_ci unsigned int totallen, alloclen; 22862306a36Sopenharmony_ci int len, result; 22962306a36Sopenharmony_ci unsigned int sg_offset = 0; 23062306a36Sopenharmony_ci struct scatterlist *sg = NULL; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 23362306a36Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Datafab 23462306a36Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 23562306a36Sopenharmony_ci // since it requires > 8GB CF card. 23662306a36Sopenharmony_ci // 23762306a36Sopenharmony_ci if (sectors > 0x0FFFFFFF) 23862306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (info->lun == -1) { 24162306a36Sopenharmony_ci result = datafab_determine_lun(us, info); 24262306a36Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 24362306a36Sopenharmony_ci return result; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci totallen = sectors * info->ssize; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci // Since we don't write more than 64 KB at a time, we have to create 24962306a36Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 25062306a36Sopenharmony_ci // bounce buffer and the actual transfer buffer. 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci alloclen = min(totallen, 65536u); 25362306a36Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 25462306a36Sopenharmony_ci if (buffer == NULL) 25562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci do { 25862306a36Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 25962306a36Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci len = min(totallen, alloclen); 26262306a36Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci // Get the data from the transfer buffer 26562306a36Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 26662306a36Sopenharmony_ci &sg, &sg_offset, FROM_XFER_BUF); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci command[0] = 0; 26962306a36Sopenharmony_ci command[1] = thistime; 27062306a36Sopenharmony_ci command[2] = sector & 0xFF; 27162306a36Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 27262306a36Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci command[5] = 0xE0 + (info->lun << 4); 27562306a36Sopenharmony_ci command[5] |= (sector >> 24) & 0x0F; 27662306a36Sopenharmony_ci command[6] = 0x30; 27762306a36Sopenharmony_ci command[7] = 0x02; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci // send the command 28062306a36Sopenharmony_ci result = datafab_bulk_write(us, command, 8); 28162306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 28262306a36Sopenharmony_ci goto leave; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci // send the data 28562306a36Sopenharmony_ci result = datafab_bulk_write(us, buffer, len); 28662306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 28762306a36Sopenharmony_ci goto leave; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci // read the result 29062306a36Sopenharmony_ci result = datafab_bulk_read(us, reply, 2); 29162306a36Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 29262306a36Sopenharmony_ci goto leave; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (reply[0] != 0x50 && reply[1] != 0) { 29562306a36Sopenharmony_ci usb_stor_dbg(us, "Gah! write return code: %02x %02x\n", 29662306a36Sopenharmony_ci reply[0], reply[1]); 29762306a36Sopenharmony_ci goto leave; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci sector += thistime; 30162306a36Sopenharmony_ci totallen -= len; 30262306a36Sopenharmony_ci } while (totallen > 0); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci kfree(buffer); 30562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci leave: 30862306a36Sopenharmony_ci kfree(buffer); 30962306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int datafab_determine_lun(struct us_data *us, 31462306a36Sopenharmony_ci struct datafab_info *info) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci // Dual-slot readers can be thought of as dual-LUN devices. 31762306a36Sopenharmony_ci // We need to determine which card slot is being used. 31862306a36Sopenharmony_ci // We'll send an IDENTIFY DEVICE command and see which LUN responds... 31962306a36Sopenharmony_ci // 32062306a36Sopenharmony_ci // There might be a better way of doing this? 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 32362306a36Sopenharmony_ci unsigned char *command = us->iobuf; 32462306a36Sopenharmony_ci unsigned char *buf; 32562306a36Sopenharmony_ci int count = 0, rc; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (!info) 32862306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci memcpy(command, scommand, 8); 33162306a36Sopenharmony_ci buf = kmalloc(512, GFP_NOIO); 33262306a36Sopenharmony_ci if (!buf) 33362306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci usb_stor_dbg(us, "locating...\n"); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci // we'll try 3 times before giving up... 33862306a36Sopenharmony_ci // 33962306a36Sopenharmony_ci while (count++ < 3) { 34062306a36Sopenharmony_ci command[5] = 0xa0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 34362306a36Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 34462306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 34562306a36Sopenharmony_ci goto leave; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci rc = datafab_bulk_read(us, buf, 512); 34962306a36Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 35062306a36Sopenharmony_ci info->lun = 0; 35162306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 35262306a36Sopenharmony_ci goto leave; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci command[5] = 0xb0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 35862306a36Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 35962306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 36062306a36Sopenharmony_ci goto leave; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci rc = datafab_bulk_read(us, buf, 512); 36462306a36Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 36562306a36Sopenharmony_ci info->lun = 1; 36662306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 36762306a36Sopenharmony_ci goto leave; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci msleep(20); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci leave: 37662306a36Sopenharmony_ci kfree(buf); 37762306a36Sopenharmony_ci return rc; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int datafab_id_device(struct us_data *us, 38162306a36Sopenharmony_ci struct datafab_info *info) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci // this is a variation of the ATA "IDENTIFY DEVICE" command...according 38462306a36Sopenharmony_ci // to the ATA spec, 'Sector Count' isn't used but the Windows driver 38562306a36Sopenharmony_ci // sets this bit so we do too... 38662306a36Sopenharmony_ci // 38762306a36Sopenharmony_ci static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; 38862306a36Sopenharmony_ci unsigned char *command = us->iobuf; 38962306a36Sopenharmony_ci unsigned char *reply; 39062306a36Sopenharmony_ci int rc; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (!info) 39362306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (info->lun == -1) { 39662306a36Sopenharmony_ci rc = datafab_determine_lun(us, info); 39762306a36Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 39862306a36Sopenharmony_ci return rc; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci memcpy(command, scommand, 8); 40262306a36Sopenharmony_ci reply = kmalloc(512, GFP_NOIO); 40362306a36Sopenharmony_ci if (!reply) 40462306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci command[5] += (info->lun << 4); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci rc = datafab_bulk_write(us, command, 8); 40962306a36Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 41062306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 41162306a36Sopenharmony_ci goto leave; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci // we'll go ahead and extract the media capacity while we're here... 41562306a36Sopenharmony_ci // 41662306a36Sopenharmony_ci rc = datafab_bulk_read(us, reply, 512); 41762306a36Sopenharmony_ci if (rc == USB_STOR_XFER_GOOD) { 41862306a36Sopenharmony_ci // capacity is at word offset 57-58 41962306a36Sopenharmony_ci // 42062306a36Sopenharmony_ci info->sectors = ((u32)(reply[117]) << 24) | 42162306a36Sopenharmony_ci ((u32)(reply[116]) << 16) | 42262306a36Sopenharmony_ci ((u32)(reply[115]) << 8) | 42362306a36Sopenharmony_ci ((u32)(reply[114]) ); 42462306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 42562306a36Sopenharmony_ci goto leave; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci leave: 43162306a36Sopenharmony_ci kfree(reply); 43262306a36Sopenharmony_ci return rc; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int datafab_handle_mode_sense(struct us_data *us, 43762306a36Sopenharmony_ci struct scsi_cmnd * srb, 43862306a36Sopenharmony_ci int sense_6) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci static unsigned char rw_err_page[12] = { 44162306a36Sopenharmony_ci 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 44262306a36Sopenharmony_ci }; 44362306a36Sopenharmony_ci static unsigned char cache_page[12] = { 44462306a36Sopenharmony_ci 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 44562306a36Sopenharmony_ci }; 44662306a36Sopenharmony_ci static unsigned char rbac_page[12] = { 44762306a36Sopenharmony_ci 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 44862306a36Sopenharmony_ci }; 44962306a36Sopenharmony_ci static unsigned char timer_page[8] = { 45062306a36Sopenharmony_ci 0x1C, 0x6, 0, 0, 0, 0 45162306a36Sopenharmony_ci }; 45262306a36Sopenharmony_ci unsigned char pc, page_code; 45362306a36Sopenharmony_ci unsigned int i = 0; 45462306a36Sopenharmony_ci struct datafab_info *info = (struct datafab_info *) (us->extra); 45562306a36Sopenharmony_ci unsigned char *ptr = us->iobuf; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci // most of this stuff is just a hack to get things working. the 45862306a36Sopenharmony_ci // datafab reader doesn't present a SCSI interface so we 45962306a36Sopenharmony_ci // fudge the SCSI commands... 46062306a36Sopenharmony_ci // 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci pc = srb->cmnd[2] >> 6; 46362306a36Sopenharmony_ci page_code = srb->cmnd[2] & 0x3F; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci switch (pc) { 46662306a36Sopenharmony_ci case 0x0: 46762306a36Sopenharmony_ci usb_stor_dbg(us, "Current values\n"); 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case 0x1: 47062306a36Sopenharmony_ci usb_stor_dbg(us, "Changeable values\n"); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case 0x2: 47362306a36Sopenharmony_ci usb_stor_dbg(us, "Default values\n"); 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci case 0x3: 47662306a36Sopenharmony_ci usb_stor_dbg(us, "Saves values\n"); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci memset(ptr, 0, 8); 48162306a36Sopenharmony_ci if (sense_6) { 48262306a36Sopenharmony_ci ptr[2] = 0x00; // WP enable: 0x80 48362306a36Sopenharmony_ci i = 4; 48462306a36Sopenharmony_ci } else { 48562306a36Sopenharmony_ci ptr[3] = 0x00; // WP enable: 0x80 48662306a36Sopenharmony_ci i = 8; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci switch (page_code) { 49062306a36Sopenharmony_ci default: 49162306a36Sopenharmony_ci // vendor-specific mode 49262306a36Sopenharmony_ci info->sense_key = 0x05; 49362306a36Sopenharmony_ci info->sense_asc = 0x24; 49462306a36Sopenharmony_ci info->sense_ascq = 0x00; 49562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci case 0x1: 49862306a36Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 49962306a36Sopenharmony_ci i += sizeof(rw_err_page); 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci case 0x8: 50362306a36Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 50462306a36Sopenharmony_ci i += sizeof(cache_page); 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci case 0x1B: 50862306a36Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 50962306a36Sopenharmony_ci i += sizeof(rbac_page); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci case 0x1C: 51362306a36Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 51462306a36Sopenharmony_ci i += sizeof(timer_page); 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci case 0x3F: // retrieve all pages 51862306a36Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 51962306a36Sopenharmony_ci i += sizeof(timer_page); 52062306a36Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 52162306a36Sopenharmony_ci i += sizeof(rbac_page); 52262306a36Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 52362306a36Sopenharmony_ci i += sizeof(cache_page); 52462306a36Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 52562306a36Sopenharmony_ci i += sizeof(rw_err_page); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (sense_6) 53062306a36Sopenharmony_ci ptr[0] = i - 1; 53162306a36Sopenharmony_ci else 53262306a36Sopenharmony_ci ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); 53362306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, i, srb); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic void datafab_info_destructor(void *extra) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci // this routine is a placeholder... 54162306a36Sopenharmony_ci // currently, we don't allocate any extra memory so we're okay 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci// Transport for the Datafab MDCFE-B 54662306a36Sopenharmony_ci// 54762306a36Sopenharmony_cistatic int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct datafab_info *info; 55062306a36Sopenharmony_ci int rc; 55162306a36Sopenharmony_ci unsigned long block, blocks; 55262306a36Sopenharmony_ci unsigned char *ptr = us->iobuf; 55362306a36Sopenharmony_ci static unsigned char inquiry_reply[8] = { 55462306a36Sopenharmony_ci 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 55562306a36Sopenharmony_ci }; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (!us->extra) { 55862306a36Sopenharmony_ci us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); 55962306a36Sopenharmony_ci if (!us->extra) 56062306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci us->extra_destructor = datafab_info_destructor; 56362306a36Sopenharmony_ci ((struct datafab_info *)us->extra)->lun = -1; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci info = (struct datafab_info *) (us->extra); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (srb->cmnd[0] == INQUIRY) { 56962306a36Sopenharmony_ci usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); 57062306a36Sopenharmony_ci memcpy(ptr, inquiry_reply, sizeof(inquiry_reply)); 57162306a36Sopenharmony_ci fill_inquiry_response(us, ptr, 36); 57262306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (srb->cmnd[0] == READ_CAPACITY) { 57662306a36Sopenharmony_ci info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec 57762306a36Sopenharmony_ci rc = datafab_id_device(us, info); 57862306a36Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 57962306a36Sopenharmony_ci return rc; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", 58262306a36Sopenharmony_ci info->sectors, info->ssize); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci // build the reply 58562306a36Sopenharmony_ci // we need the last sector, not the number of sectors 58662306a36Sopenharmony_ci ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); 58762306a36Sopenharmony_ci ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); 58862306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 8, srb); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (srb->cmnd[0] == MODE_SELECT_10) { 59462306a36Sopenharmony_ci usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); 59562306a36Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci // don't bother implementing READ_6 or WRITE_6. 59962306a36Sopenharmony_ci // 60062306a36Sopenharmony_ci if (srb->cmnd[0] == READ_10) { 60162306a36Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 60262306a36Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", 60762306a36Sopenharmony_ci block, blocks); 60862306a36Sopenharmony_ci return datafab_read_data(us, info, block, blocks); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (srb->cmnd[0] == READ_12) { 61262306a36Sopenharmony_ci // we'll probably never see a READ_12 but we'll do it anyway... 61362306a36Sopenharmony_ci // 61462306a36Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 61562306a36Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 61862306a36Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", 62162306a36Sopenharmony_ci block, blocks); 62262306a36Sopenharmony_ci return datafab_read_data(us, info, block, blocks); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (srb->cmnd[0] == WRITE_10) { 62662306a36Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 62762306a36Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", 63262306a36Sopenharmony_ci block, blocks); 63362306a36Sopenharmony_ci return datafab_write_data(us, info, block, blocks); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (srb->cmnd[0] == WRITE_12) { 63762306a36Sopenharmony_ci // we'll probably never see a WRITE_12 but we'll do it anyway... 63862306a36Sopenharmony_ci // 63962306a36Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 64062306a36Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 64362306a36Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", 64662306a36Sopenharmony_ci block, blocks); 64762306a36Sopenharmony_ci return datafab_write_data(us, info, block, blocks); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (srb->cmnd[0] == TEST_UNIT_READY) { 65162306a36Sopenharmony_ci usb_stor_dbg(us, "TEST_UNIT_READY\n"); 65262306a36Sopenharmony_ci return datafab_id_device(us, info); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (srb->cmnd[0] == REQUEST_SENSE) { 65662306a36Sopenharmony_ci usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n"); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci // this response is pretty bogus right now. eventually if necessary 65962306a36Sopenharmony_ci // we can set the correct sense data. so far though it hasn't been 66062306a36Sopenharmony_ci // necessary 66162306a36Sopenharmony_ci // 66262306a36Sopenharmony_ci memset(ptr, 0, 18); 66362306a36Sopenharmony_ci ptr[0] = 0xF0; 66462306a36Sopenharmony_ci ptr[2] = info->sense_key; 66562306a36Sopenharmony_ci ptr[7] = 11; 66662306a36Sopenharmony_ci ptr[12] = info->sense_asc; 66762306a36Sopenharmony_ci ptr[13] = info->sense_ascq; 66862306a36Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 18, srb); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE) { 67462306a36Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); 67562306a36Sopenharmony_ci return datafab_handle_mode_sense(us, srb, 1); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE_10) { 67962306a36Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); 68062306a36Sopenharmony_ci return datafab_handle_mode_sense(us, srb, 0); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 68462306a36Sopenharmony_ci /* 68562306a36Sopenharmony_ci * sure. whatever. not like we can stop the user from 68662306a36Sopenharmony_ci * popping the media out of the device (no locking doors, etc) 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (srb->cmnd[0] == START_STOP) { 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * this is used by sd.c'check_scsidisk_media_change to detect 69462306a36Sopenharmony_ci * media change 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ci usb_stor_dbg(us, "START_STOP\n"); 69762306a36Sopenharmony_ci /* 69862306a36Sopenharmony_ci * the first datafab_id_device after a media change returns 69962306a36Sopenharmony_ci * an error (determined experimentally) 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci rc = datafab_id_device(us, info); 70262306a36Sopenharmony_ci if (rc == USB_STOR_TRANSPORT_GOOD) { 70362306a36Sopenharmony_ci info->sense_key = NO_SENSE; 70462306a36Sopenharmony_ci srb->result = SUCCESS; 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci info->sense_key = UNIT_ATTENTION; 70762306a36Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci return rc; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", 71362306a36Sopenharmony_ci srb->cmnd[0], srb->cmnd[0]); 71462306a36Sopenharmony_ci info->sense_key = 0x05; 71562306a36Sopenharmony_ci info->sense_asc = 0x20; 71662306a36Sopenharmony_ci info->sense_ascq = 0x00; 71762306a36Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic struct scsi_host_template datafab_host_template; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int datafab_probe(struct usb_interface *intf, 72362306a36Sopenharmony_ci const struct usb_device_id *id) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct us_data *us; 72662306a36Sopenharmony_ci int result; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 72962306a36Sopenharmony_ci (id - datafab_usb_ids) + datafab_unusual_dev_list, 73062306a36Sopenharmony_ci &datafab_host_template); 73162306a36Sopenharmony_ci if (result) 73262306a36Sopenharmony_ci return result; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci us->transport_name = "Datafab Bulk-Only"; 73562306a36Sopenharmony_ci us->transport = datafab_transport; 73662306a36Sopenharmony_ci us->transport_reset = usb_stor_Bulk_reset; 73762306a36Sopenharmony_ci us->max_lun = 1; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci result = usb_stor_probe2(us); 74062306a36Sopenharmony_ci return result; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic struct usb_driver datafab_driver = { 74462306a36Sopenharmony_ci .name = DRV_NAME, 74562306a36Sopenharmony_ci .probe = datafab_probe, 74662306a36Sopenharmony_ci .disconnect = usb_stor_disconnect, 74762306a36Sopenharmony_ci .suspend = usb_stor_suspend, 74862306a36Sopenharmony_ci .resume = usb_stor_resume, 74962306a36Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 75062306a36Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 75162306a36Sopenharmony_ci .post_reset = usb_stor_post_reset, 75262306a36Sopenharmony_ci .id_table = datafab_usb_ids, 75362306a36Sopenharmony_ci .soft_unbind = 1, 75462306a36Sopenharmony_ci .no_dynamic_id = 1, 75562306a36Sopenharmony_ci}; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cimodule_usb_stor_driver(datafab_driver, datafab_host_template, DRV_NAME); 758