18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Lexar "Jumpshot" Compact Flash reader 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * jumpshot driver v0.1: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * First release 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Current development and maintenance by: 108c2ecf20Sopenharmony_ci * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver 138c2ecf20Sopenharmony_ci * which I used as a template for this driver. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Some bugfixes and scatter-gather code by Gregory P. Smith 168c2ecf20Sopenharmony_ci * (greg-usb@electricrain.com) 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Fix for media change by Joerg Schneider (js@joergschneider.com) 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Developed with the assistance of: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * (C) 2002 Alan Stern <stern@rowland.org> 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* 268c2ecf20Sopenharmony_ci * This driver attempts to support the Lexar Jumpshot USB CompactFlash 278c2ecf20Sopenharmony_ci * reader. Like many other USB CompactFlash readers, the Jumpshot contains 288c2ecf20Sopenharmony_ci * a USB-to-ATA chip. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * This driver supports reading and writing. If you're truly paranoid, 318c2ecf20Sopenharmony_ci * however, you can force the driver into a write-protected state by setting 328c2ecf20Sopenharmony_ci * the WP enable bits in jumpshot_handle_mode_sense. See the comments 338c2ecf20Sopenharmony_ci * in that routine. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/errno.h> 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 418c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "usb.h" 448c2ecf20Sopenharmony_ci#include "transport.h" 458c2ecf20Sopenharmony_ci#include "protocol.h" 468c2ecf20Sopenharmony_ci#include "debug.h" 478c2ecf20Sopenharmony_ci#include "scsiglue.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define DRV_NAME "ums-jumpshot" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader"); 528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jimmie Mayfield <mayfield+usb@sackheads.org>"); 538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 548c2ecf20Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * The table of devices 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 608c2ecf20Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 618c2ecf20Sopenharmony_ci initFunction, flags) \ 628c2ecf20Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 638c2ecf20Sopenharmony_ci .driver_info = (flags) } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic struct usb_device_id jumpshot_usb_ids[] = { 668c2ecf20Sopenharmony_ci# include "unusual_jumpshot.h" 678c2ecf20Sopenharmony_ci { } /* Terminating entry */ 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, jumpshot_usb_ids); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * The flags table 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 778c2ecf20Sopenharmony_ci vendor_name, product_name, use_protocol, use_transport, \ 788c2ecf20Sopenharmony_ci init_function, Flags) \ 798c2ecf20Sopenharmony_ci{ \ 808c2ecf20Sopenharmony_ci .vendorName = vendor_name, \ 818c2ecf20Sopenharmony_ci .productName = product_name, \ 828c2ecf20Sopenharmony_ci .useProtocol = use_protocol, \ 838c2ecf20Sopenharmony_ci .useTransport = use_transport, \ 848c2ecf20Sopenharmony_ci .initFunction = init_function, \ 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct us_unusual_dev jumpshot_unusual_dev_list[] = { 888c2ecf20Sopenharmony_ci# include "unusual_jumpshot.h" 898c2ecf20Sopenharmony_ci { } /* Terminating entry */ 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#undef UNUSUAL_DEV 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct jumpshot_info { 968c2ecf20Sopenharmony_ci unsigned long sectors; /* total sector count */ 978c2ecf20Sopenharmony_ci unsigned long ssize; /* sector size in bytes */ 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* the following aren't used yet */ 1008c2ecf20Sopenharmony_ci unsigned char sense_key; 1018c2ecf20Sopenharmony_ci unsigned long sense_asc; /* additional sense code */ 1028c2ecf20Sopenharmony_ci unsigned long sense_ascq; /* additional sense code qualifier */ 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic inline int jumpshot_bulk_read(struct us_data *us, 1068c2ecf20Sopenharmony_ci unsigned char *data, 1078c2ecf20Sopenharmony_ci unsigned int len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (len == 0) 1108c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 1138c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 1148c2ecf20Sopenharmony_ci data, len, NULL); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic inline int jumpshot_bulk_write(struct us_data *us, 1198c2ecf20Sopenharmony_ci unsigned char *data, 1208c2ecf20Sopenharmony_ci unsigned int len) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (len == 0) 1238c2ecf20Sopenharmony_ci return USB_STOR_XFER_GOOD; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci usb_stor_dbg(us, "len = %d\n", len); 1268c2ecf20Sopenharmony_ci return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 1278c2ecf20Sopenharmony_ci data, len, NULL); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int jumpshot_get_status(struct us_data *us) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int rc; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!us) 1368c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci // send the setup 1398c2ecf20Sopenharmony_ci rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, 1408c2ecf20Sopenharmony_ci 0, 0xA0, 0, 7, us->iobuf, 1); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) 1438c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (us->iobuf[0] != 0x50) { 1468c2ecf20Sopenharmony_ci usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]); 1478c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int jumpshot_read_data(struct us_data *us, 1548c2ecf20Sopenharmony_ci struct jumpshot_info *info, 1558c2ecf20Sopenharmony_ci u32 sector, 1568c2ecf20Sopenharmony_ci u32 sectors) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 1598c2ecf20Sopenharmony_ci unsigned char *buffer; 1608c2ecf20Sopenharmony_ci unsigned char thistime; 1618c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 1628c2ecf20Sopenharmony_ci int len, result; 1638c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 1648c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 1678c2ecf20Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Jumpshot 1688c2ecf20Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 1698c2ecf20Sopenharmony_ci // since it requires > 8GB CF card. 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (sector > 0x0FFFFFFF) 1728c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci // Since we don't read more than 64 KB at a time, we have to create 1778c2ecf20Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 1788c2ecf20Sopenharmony_ci // bounce buffer and the actual transfer buffer. 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 1818c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 1828c2ecf20Sopenharmony_ci if (buffer == NULL) 1838c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci do { 1868c2ecf20Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 1878c2ecf20Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 1888c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 1898c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci command[0] = 0; 1928c2ecf20Sopenharmony_ci command[1] = thistime; 1938c2ecf20Sopenharmony_ci command[2] = sector & 0xFF; 1948c2ecf20Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 1958c2ecf20Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci command[5] = 0xE0 | ((sector >> 24) & 0x0F); 1988c2ecf20Sopenharmony_ci command[6] = 0x20; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci // send the setup + command 2018c2ecf20Sopenharmony_ci result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 2028c2ecf20Sopenharmony_ci 0, 0x20, 0, 1, command, 7); 2038c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2048c2ecf20Sopenharmony_ci goto leave; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci // read the result 2078c2ecf20Sopenharmony_ci result = jumpshot_bulk_read(us, buffer, len); 2088c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2098c2ecf20Sopenharmony_ci goto leave; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci usb_stor_dbg(us, "%d bytes\n", len); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci // Store the data in the transfer buffer 2148c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 2158c2ecf20Sopenharmony_ci &sg, &sg_offset, TO_XFER_BUF); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci sector += thistime; 2188c2ecf20Sopenharmony_ci totallen -= len; 2198c2ecf20Sopenharmony_ci } while (totallen > 0); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci kfree(buffer); 2228c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci leave: 2258c2ecf20Sopenharmony_ci kfree(buffer); 2268c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int jumpshot_write_data(struct us_data *us, 2318c2ecf20Sopenharmony_ci struct jumpshot_info *info, 2328c2ecf20Sopenharmony_ci u32 sector, 2338c2ecf20Sopenharmony_ci u32 sectors) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 2368c2ecf20Sopenharmony_ci unsigned char *buffer; 2378c2ecf20Sopenharmony_ci unsigned char thistime; 2388c2ecf20Sopenharmony_ci unsigned int totallen, alloclen; 2398c2ecf20Sopenharmony_ci int len, result, waitcount; 2408c2ecf20Sopenharmony_ci unsigned int sg_offset = 0; 2418c2ecf20Sopenharmony_ci struct scatterlist *sg = NULL; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci // we're working in LBA mode. according to the ATA spec, 2448c2ecf20Sopenharmony_ci // we can support up to 28-bit addressing. I don't know if Jumpshot 2458c2ecf20Sopenharmony_ci // supports beyond 24-bit addressing. It's kind of hard to test 2468c2ecf20Sopenharmony_ci // since it requires > 8GB CF card. 2478c2ecf20Sopenharmony_ci // 2488c2ecf20Sopenharmony_ci if (sector > 0x0FFFFFFF) 2498c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci totallen = sectors * info->ssize; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci // Since we don't write more than 64 KB at a time, we have to create 2548c2ecf20Sopenharmony_ci // a bounce buffer and move the data a piece at a time between the 2558c2ecf20Sopenharmony_ci // bounce buffer and the actual transfer buffer. 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci alloclen = min(totallen, 65536u); 2588c2ecf20Sopenharmony_ci buffer = kmalloc(alloclen, GFP_NOIO); 2598c2ecf20Sopenharmony_ci if (buffer == NULL) 2608c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci do { 2638c2ecf20Sopenharmony_ci // loop, never allocate or transfer more than 64k at once 2648c2ecf20Sopenharmony_ci // (min(128k, 255*info->ssize) is the real limit) 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci len = min(totallen, alloclen); 2678c2ecf20Sopenharmony_ci thistime = (len / info->ssize) & 0xff; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci // Get the data from the transfer buffer 2708c2ecf20Sopenharmony_ci usb_stor_access_xfer_buf(buffer, len, us->srb, 2718c2ecf20Sopenharmony_ci &sg, &sg_offset, FROM_XFER_BUF); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci command[0] = 0; 2748c2ecf20Sopenharmony_ci command[1] = thistime; 2758c2ecf20Sopenharmony_ci command[2] = sector & 0xFF; 2768c2ecf20Sopenharmony_ci command[3] = (sector >> 8) & 0xFF; 2778c2ecf20Sopenharmony_ci command[4] = (sector >> 16) & 0xFF; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci command[5] = 0xE0 | ((sector >> 24) & 0x0F); 2808c2ecf20Sopenharmony_ci command[6] = 0x30; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci // send the setup + command 2838c2ecf20Sopenharmony_ci result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 2848c2ecf20Sopenharmony_ci 0, 0x20, 0, 1, command, 7); 2858c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2868c2ecf20Sopenharmony_ci goto leave; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci // send the data 2898c2ecf20Sopenharmony_ci result = jumpshot_bulk_write(us, buffer, len); 2908c2ecf20Sopenharmony_ci if (result != USB_STOR_XFER_GOOD) 2918c2ecf20Sopenharmony_ci goto leave; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci // read the result. apparently the bulk write can complete 2948c2ecf20Sopenharmony_ci // before the jumpshot drive is finished writing. so we loop 2958c2ecf20Sopenharmony_ci // here until we get a good return code 2968c2ecf20Sopenharmony_ci waitcount = 0; 2978c2ecf20Sopenharmony_ci do { 2988c2ecf20Sopenharmony_ci result = jumpshot_get_status(us); 2998c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) { 3008c2ecf20Sopenharmony_ci // I have not experimented to find the smallest value. 3018c2ecf20Sopenharmony_ci // 3028c2ecf20Sopenharmony_ci msleep(50); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci } while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (result != USB_STOR_TRANSPORT_GOOD) 3078c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! Waitcount = 10. Bad write!?\n"); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci sector += thistime; 3108c2ecf20Sopenharmony_ci totallen -= len; 3118c2ecf20Sopenharmony_ci } while (totallen > 0); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci kfree(buffer); 3148c2ecf20Sopenharmony_ci return result; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci leave: 3178c2ecf20Sopenharmony_ci kfree(buffer); 3188c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int jumpshot_id_device(struct us_data *us, 3228c2ecf20Sopenharmony_ci struct jumpshot_info *info) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci unsigned char *command = us->iobuf; 3258c2ecf20Sopenharmony_ci unsigned char *reply; 3268c2ecf20Sopenharmony_ci int rc; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (!info) 3298c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci command[0] = 0xE0; 3328c2ecf20Sopenharmony_ci command[1] = 0xEC; 3338c2ecf20Sopenharmony_ci reply = kmalloc(512, GFP_NOIO); 3348c2ecf20Sopenharmony_ci if (!reply) 3358c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci // send the setup 3388c2ecf20Sopenharmony_ci rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 3398c2ecf20Sopenharmony_ci 0, 0x20, 0, 6, command, 2); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 3428c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n"); 3438c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 3448c2ecf20Sopenharmony_ci goto leave; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci // read the reply 3488c2ecf20Sopenharmony_ci rc = jumpshot_bulk_read(us, reply, 512); 3498c2ecf20Sopenharmony_ci if (rc != USB_STOR_XFER_GOOD) { 3508c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_ERROR; 3518c2ecf20Sopenharmony_ci goto leave; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci info->sectors = ((u32)(reply[117]) << 24) | 3558c2ecf20Sopenharmony_ci ((u32)(reply[116]) << 16) | 3568c2ecf20Sopenharmony_ci ((u32)(reply[115]) << 8) | 3578c2ecf20Sopenharmony_ci ((u32)(reply[114]) ); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci rc = USB_STOR_TRANSPORT_GOOD; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci leave: 3628c2ecf20Sopenharmony_ci kfree(reply); 3638c2ecf20Sopenharmony_ci return rc; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int jumpshot_handle_mode_sense(struct us_data *us, 3678c2ecf20Sopenharmony_ci struct scsi_cmnd * srb, 3688c2ecf20Sopenharmony_ci int sense_6) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci static unsigned char rw_err_page[12] = { 3718c2ecf20Sopenharmony_ci 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 3728c2ecf20Sopenharmony_ci }; 3738c2ecf20Sopenharmony_ci static unsigned char cache_page[12] = { 3748c2ecf20Sopenharmony_ci 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 3758c2ecf20Sopenharmony_ci }; 3768c2ecf20Sopenharmony_ci static unsigned char rbac_page[12] = { 3778c2ecf20Sopenharmony_ci 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 3788c2ecf20Sopenharmony_ci }; 3798c2ecf20Sopenharmony_ci static unsigned char timer_page[8] = { 3808c2ecf20Sopenharmony_ci 0x1C, 0x6, 0, 0, 0, 0 3818c2ecf20Sopenharmony_ci }; 3828c2ecf20Sopenharmony_ci unsigned char pc, page_code; 3838c2ecf20Sopenharmony_ci unsigned int i = 0; 3848c2ecf20Sopenharmony_ci struct jumpshot_info *info = (struct jumpshot_info *) (us->extra); 3858c2ecf20Sopenharmony_ci unsigned char *ptr = us->iobuf; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci pc = srb->cmnd[2] >> 6; 3888c2ecf20Sopenharmony_ci page_code = srb->cmnd[2] & 0x3F; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci switch (pc) { 3918c2ecf20Sopenharmony_ci case 0x0: 3928c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Current values\n"); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case 0x1: 3958c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Changeable values\n"); 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci case 0x2: 3988c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Default values\n"); 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case 0x3: 4018c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Saves values\n"); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci memset(ptr, 0, 8); 4068c2ecf20Sopenharmony_ci if (sense_6) { 4078c2ecf20Sopenharmony_ci ptr[2] = 0x00; // WP enable: 0x80 4088c2ecf20Sopenharmony_ci i = 4; 4098c2ecf20Sopenharmony_ci } else { 4108c2ecf20Sopenharmony_ci ptr[3] = 0x00; // WP enable: 0x80 4118c2ecf20Sopenharmony_ci i = 8; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci switch (page_code) { 4158c2ecf20Sopenharmony_ci case 0x0: 4168c2ecf20Sopenharmony_ci // vendor-specific mode 4178c2ecf20Sopenharmony_ci info->sense_key = 0x05; 4188c2ecf20Sopenharmony_ci info->sense_asc = 0x24; 4198c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 4208c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci case 0x1: 4238c2ecf20Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 4248c2ecf20Sopenharmony_ci i += sizeof(rw_err_page); 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci case 0x8: 4288c2ecf20Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 4298c2ecf20Sopenharmony_ci i += sizeof(cache_page); 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci case 0x1B: 4338c2ecf20Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 4348c2ecf20Sopenharmony_ci i += sizeof(rbac_page); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci case 0x1C: 4388c2ecf20Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 4398c2ecf20Sopenharmony_ci i += sizeof(timer_page); 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci case 0x3F: 4438c2ecf20Sopenharmony_ci memcpy(ptr + i, timer_page, sizeof(timer_page)); 4448c2ecf20Sopenharmony_ci i += sizeof(timer_page); 4458c2ecf20Sopenharmony_ci memcpy(ptr + i, rbac_page, sizeof(rbac_page)); 4468c2ecf20Sopenharmony_ci i += sizeof(rbac_page); 4478c2ecf20Sopenharmony_ci memcpy(ptr + i, cache_page, sizeof(cache_page)); 4488c2ecf20Sopenharmony_ci i += sizeof(cache_page); 4498c2ecf20Sopenharmony_ci memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); 4508c2ecf20Sopenharmony_ci i += sizeof(rw_err_page); 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (sense_6) 4558c2ecf20Sopenharmony_ci ptr[0] = i - 1; 4568c2ecf20Sopenharmony_ci else 4578c2ecf20Sopenharmony_ci ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); 4588c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, i, srb); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic void jumpshot_info_destructor(void *extra) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci // this routine is a placeholder... 4678c2ecf20Sopenharmony_ci // currently, we don't allocate any extra blocks so we're okay 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci// Transport for the Lexar 'Jumpshot' 4738c2ecf20Sopenharmony_ci// 4748c2ecf20Sopenharmony_cistatic int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct jumpshot_info *info; 4778c2ecf20Sopenharmony_ci int rc; 4788c2ecf20Sopenharmony_ci unsigned long block, blocks; 4798c2ecf20Sopenharmony_ci unsigned char *ptr = us->iobuf; 4808c2ecf20Sopenharmony_ci static unsigned char inquiry_response[8] = { 4818c2ecf20Sopenharmony_ci 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 4828c2ecf20Sopenharmony_ci }; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (!us->extra) { 4858c2ecf20Sopenharmony_ci us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO); 4868c2ecf20Sopenharmony_ci if (!us->extra) 4878c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci us->extra_destructor = jumpshot_info_destructor; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci info = (struct jumpshot_info *) (us->extra); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (srb->cmnd[0] == INQUIRY) { 4958c2ecf20Sopenharmony_ci usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); 4968c2ecf20Sopenharmony_ci memcpy(ptr, inquiry_response, sizeof(inquiry_response)); 4978c2ecf20Sopenharmony_ci fill_inquiry_response(us, ptr, 36); 4988c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_CAPACITY) { 5028c2ecf20Sopenharmony_ci info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci rc = jumpshot_get_status(us); 5058c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 5068c2ecf20Sopenharmony_ci return rc; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci rc = jumpshot_id_device(us, info); 5098c2ecf20Sopenharmony_ci if (rc != USB_STOR_TRANSPORT_GOOD) 5108c2ecf20Sopenharmony_ci return rc; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", 5138c2ecf20Sopenharmony_ci info->sectors, info->ssize); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci // build the reply 5168c2ecf20Sopenharmony_ci // 5178c2ecf20Sopenharmony_ci ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); 5188c2ecf20Sopenharmony_ci ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); 5198c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 8, srb); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SELECT_10) { 5258c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); 5268c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_ERROR; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_10) { 5308c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 5318c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", 5368c2ecf20Sopenharmony_ci block, blocks); 5378c2ecf20Sopenharmony_ci return jumpshot_read_data(us, info, block, blocks); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (srb->cmnd[0] == READ_12) { 5418c2ecf20Sopenharmony_ci // I don't think we'll ever see a READ_12 but support it anyway... 5428c2ecf20Sopenharmony_ci // 5438c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 5448c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 5478c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", 5508c2ecf20Sopenharmony_ci block, blocks); 5518c2ecf20Sopenharmony_ci return jumpshot_read_data(us, info, block, blocks); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_10) { 5558c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 5568c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", 5618c2ecf20Sopenharmony_ci block, blocks); 5628c2ecf20Sopenharmony_ci return jumpshot_write_data(us, info, block, blocks); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (srb->cmnd[0] == WRITE_12) { 5668c2ecf20Sopenharmony_ci // I don't think we'll ever see a WRITE_12 but support it anyway... 5678c2ecf20Sopenharmony_ci // 5688c2ecf20Sopenharmony_ci block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | 5698c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | 5728c2ecf20Sopenharmony_ci ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", 5758c2ecf20Sopenharmony_ci block, blocks); 5768c2ecf20Sopenharmony_ci return jumpshot_write_data(us, info, block, blocks); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (srb->cmnd[0] == TEST_UNIT_READY) { 5818c2ecf20Sopenharmony_ci usb_stor_dbg(us, "TEST_UNIT_READY\n"); 5828c2ecf20Sopenharmony_ci return jumpshot_get_status(us); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (srb->cmnd[0] == REQUEST_SENSE) { 5868c2ecf20Sopenharmony_ci usb_stor_dbg(us, "REQUEST_SENSE\n"); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci memset(ptr, 0, 18); 5898c2ecf20Sopenharmony_ci ptr[0] = 0xF0; 5908c2ecf20Sopenharmony_ci ptr[2] = info->sense_key; 5918c2ecf20Sopenharmony_ci ptr[7] = 11; 5928c2ecf20Sopenharmony_ci ptr[12] = info->sense_asc; 5938c2ecf20Sopenharmony_ci ptr[13] = info->sense_ascq; 5948c2ecf20Sopenharmony_ci usb_stor_set_xfer_buf(ptr, 18, srb); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE) { 6008c2ecf20Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); 6018c2ecf20Sopenharmony_ci return jumpshot_handle_mode_sense(us, srb, 1); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (srb->cmnd[0] == MODE_SENSE_10) { 6058c2ecf20Sopenharmony_ci usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); 6068c2ecf20Sopenharmony_ci return jumpshot_handle_mode_sense(us, srb, 0); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * sure. whatever. not like we can stop the user from popping 6128c2ecf20Sopenharmony_ci * the media out of the device (no locking doors, etc) 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_GOOD; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (srb->cmnd[0] == START_STOP) { 6188c2ecf20Sopenharmony_ci /* 6198c2ecf20Sopenharmony_ci * this is used by sd.c'check_scsidisk_media_change to detect 6208c2ecf20Sopenharmony_ci * media change 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci usb_stor_dbg(us, "START_STOP\n"); 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * the first jumpshot_id_device after a media change returns 6258c2ecf20Sopenharmony_ci * an error (determined experimentally) 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci rc = jumpshot_id_device(us, info); 6288c2ecf20Sopenharmony_ci if (rc == USB_STOR_TRANSPORT_GOOD) { 6298c2ecf20Sopenharmony_ci info->sense_key = NO_SENSE; 6308c2ecf20Sopenharmony_ci srb->result = SUCCESS; 6318c2ecf20Sopenharmony_ci } else { 6328c2ecf20Sopenharmony_ci info->sense_key = UNIT_ATTENTION; 6338c2ecf20Sopenharmony_ci srb->result = SAM_STAT_CHECK_CONDITION; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci return rc; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", 6398c2ecf20Sopenharmony_ci srb->cmnd[0], srb->cmnd[0]); 6408c2ecf20Sopenharmony_ci info->sense_key = 0x05; 6418c2ecf20Sopenharmony_ci info->sense_asc = 0x20; 6428c2ecf20Sopenharmony_ci info->sense_ascq = 0x00; 6438c2ecf20Sopenharmony_ci return USB_STOR_TRANSPORT_FAILED; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic struct scsi_host_template jumpshot_host_template; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int jumpshot_probe(struct usb_interface *intf, 6498c2ecf20Sopenharmony_ci const struct usb_device_id *id) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct us_data *us; 6528c2ecf20Sopenharmony_ci int result; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci result = usb_stor_probe1(&us, intf, id, 6558c2ecf20Sopenharmony_ci (id - jumpshot_usb_ids) + jumpshot_unusual_dev_list, 6568c2ecf20Sopenharmony_ci &jumpshot_host_template); 6578c2ecf20Sopenharmony_ci if (result) 6588c2ecf20Sopenharmony_ci return result; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci us->transport_name = "Lexar Jumpshot Control/Bulk"; 6618c2ecf20Sopenharmony_ci us->transport = jumpshot_transport; 6628c2ecf20Sopenharmony_ci us->transport_reset = usb_stor_Bulk_reset; 6638c2ecf20Sopenharmony_ci us->max_lun = 1; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci result = usb_stor_probe2(us); 6668c2ecf20Sopenharmony_ci return result; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic struct usb_driver jumpshot_driver = { 6708c2ecf20Sopenharmony_ci .name = DRV_NAME, 6718c2ecf20Sopenharmony_ci .probe = jumpshot_probe, 6728c2ecf20Sopenharmony_ci .disconnect = usb_stor_disconnect, 6738c2ecf20Sopenharmony_ci .suspend = usb_stor_suspend, 6748c2ecf20Sopenharmony_ci .resume = usb_stor_resume, 6758c2ecf20Sopenharmony_ci .reset_resume = usb_stor_reset_resume, 6768c2ecf20Sopenharmony_ci .pre_reset = usb_stor_pre_reset, 6778c2ecf20Sopenharmony_ci .post_reset = usb_stor_post_reset, 6788c2ecf20Sopenharmony_ci .id_table = jumpshot_usb_ids, 6798c2ecf20Sopenharmony_ci .soft_unbind = 1, 6808c2ecf20Sopenharmony_ci .no_dynamic_id = 1, 6818c2ecf20Sopenharmony_ci}; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cimodule_usb_stor_driver(jumpshot_driver, jumpshot_host_template, DRV_NAME); 684