📄 shuttle_usbat.c
字号:
/* Driver for SCM Microsystems USB-ATAPI cable * * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $ * * Current development and maintenance by: * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * * Developed with the assistance of: * (c) 2002 Alan Stern <stern@rowland.org> * * Many originally ATAPI devices were slightly modified to meet the USB * market by using some kind of translation from ATAPI to USB on the host, * and the peripheral would translate from USB back to ATAPI. * * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, * which does the USB-to-ATAPI conversion. By obtaining the data sheet on * their device under nondisclosure agreement, I have been able to write * this driver for Linux. * * The chip used in the device can also be used for EPP and ISA translation * as well. This driver is only guaranteed to work with the ATAPI * translation. * * The only peripheral that I know of (as of 27 Mar 2001) that uses this * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/sched.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/cdrom.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include "transport.h"#include "protocol.h"#include "usb.h"#include "debug.h"#include "shuttle_usbat.h"#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )#define LSB_of(s) ((s)&0xFF)#define MSB_of(s) ((s)>>8)int transferred = 0;static int usbat_read(struct us_data *us, unsigned char access, unsigned char reg, unsigned char *content){ int result; result = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, access, 0xC0, (u16)reg, 0, content, 1); return result;}static int usbat_write(struct us_data *us, unsigned char access, unsigned char reg, unsigned char content){ int result; result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, access|0x01, 0x40, short_pack(reg, content), 0, NULL, 0); return result;}static int usbat_set_shuttle_features(struct us_data *us, unsigned char external_trigger, unsigned char epp_control, unsigned char mask_byte, unsigned char test_pattern, unsigned char subcountH, unsigned char subcountL){ int result; unsigned char *command = us->iobuf; command[0] = 0x40; command[1] = 0x81; command[2] = epp_control; command[3] = external_trigger; command[4] = test_pattern; command[5] = mask_byte; command[6] = subcountL; command[7] = subcountH; result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0x80, 0x40, 0, 0, command, 8); return result;}static int usbat_read_block(struct us_data *us, unsigned char access, unsigned char reg, unsigned char *content, unsigned short len, int use_sg){ int result; unsigned char *command = us->iobuf; if (!len) return USB_STOR_TRANSPORT_GOOD; command[0] = 0xC0; command[1] = access | 0x02; command[2] = reg; command[3] = 0; command[4] = 0; command[5] = 0; command[6] = LSB_of(len); command[7] = MSB_of(len); result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0x80, 0x40, 0, 0, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, content, len, use_sg, NULL); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);}/* * Block, waiting for an ATA device to become not busy or to report * an error condition. */static int usbat_wait_not_busy(struct us_data *us, int minutes){ int i; int result; unsigned char *status = us->iobuf; /* Synchronizing cache on a CDR could take a heck of a long time, * but probably not more than 10 minutes or so. On the other hand, * doing a full blank on a CDRW at speed 1 will take about 75 * minutes! */ for (i=0; i<1200+minutes*60; i++) { result = usbat_read(us, USBAT_ATA, 0x17, status); if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (*status & 0x01) { // check condition result = usbat_read(us, USBAT_ATA, 0x10, status); return USB_STOR_TRANSPORT_FAILED; } if (*status & 0x20) // device fault return USB_STOR_TRANSPORT_FAILED; if ((*status & 0x80)==0x00) { // not busy US_DEBUGP("Waited not busy for %d steps\n", i); return USB_STOR_TRANSPORT_GOOD; } if (i<500) msleep(10); // 5 seconds else if (i<700) msleep(50); // 10 seconds else if (i<1200) msleep(100); // 50 seconds else msleep(1000); // X minutes } US_DEBUGP("Waited not busy for %d minutes, timing out.\n", minutes); return USB_STOR_TRANSPORT_FAILED;}static int usbat_write_block(struct us_data *us, unsigned char access, unsigned char reg, unsigned char *content, unsigned short len, int use_sg, int minutes){ int result; unsigned char *command = us->iobuf; if (!len) return USB_STOR_TRANSPORT_GOOD; command[0] = 0x40; command[1] = access | 0x03; command[2] = reg; command[3] = 0; command[4] = 0; command[5] = 0; command[6] = LSB_of(len); command[7] = MSB_of(len); result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0x80, 0x40, 0, 0, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, content, len, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; return usbat_wait_not_busy(us, minutes);}static int usbat_rw_block_test(struct us_data *us, unsigned char access, unsigned char *registers, unsigned char *data_out, unsigned short num_registers, unsigned char data_reg, unsigned char status_reg, unsigned char timeout, unsigned char qualifier, int direction, unsigned char *content, unsigned short len, int use_sg, int minutes){ int result; unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, // but that's what came out of the trace every single time. unsigned char *command = us->iobuf; int i, j; int cmdlen; unsigned char *data = us->iobuf; unsigned char *status = us->iobuf; BUG_ON(num_registers > US_IOBUF_SIZE/2); for (i=0; i<20; i++) { /* * The first time we send the full command, which consists * of downloading the SCSI command followed by downloading * the data via a write-and-test. Any other time we only * send the command to download the data -- the SCSI command * is still 'active' in some sense in the device. * * We're only going to try sending the data 10 times. After * that, we just return a failure. */ if (i==0) { cmdlen = 16; command[0] = 0x40; command[1] = access | 0x07; command[2] = 0x07; command[3] = 0x17; command[4] = 0xFC; command[5] = 0xE7; command[6] = LSB_of(num_registers*2); command[7] = MSB_of(num_registers*2); } else cmdlen = 8; command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | (direction==DMA_TO_DEVICE ? 0x05 : 0x04); command[cmdlen-6] = data_reg; command[cmdlen-5] = status_reg; command[cmdlen-4] = timeout; command[cmdlen-3] = qualifier; command[cmdlen-2] = LSB_of(len); command[cmdlen-1] = MSB_of(len); result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0x80, 0x40, 0, 0, command, cmdlen); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (i==0) { for (j=0; j<num_registers; j++) { data[j<<1] = registers[j]; data[1+(j<<1)] = data_out[j]; } result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, num_registers*2, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", // direction == DMA_TO_DEVICE ? "out" : "in", // len, use_sg); result = usb_stor_bulk_transfer_sg(us, pipe, content, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry * the bulk download -- but not the SCSI command because * in some sense the SCSI command is still 'active' and * waiting for the data. Don't ask me why this should be; * I'm only following what the Windoze driver did. * * Note that a stall for the test-and-read/write command means * that the test failed. In this case we're testing to make * sure that the device is error-free * (i.e. bit 0 -- CHK -- of status is 0). The most likely * hypothesis is that the USBAT chip somehow knows what * the device will accept, but doesn't give the device any * data until all data is received. Thus, the device would * still be waiting for the first byte of data if a stall * occurs, even if the stall implies that some data was * transferred. */ if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) { /* * If we're reading and we stalled, then clear * the bulk output pipe only the first time. */ if (direction==DMA_FROM_DEVICE && i==0) { if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; } /* * Read status: is the device angry, or just busy? */ result = usbat_read(us, USBAT_ATA, direction==DMA_TO_DEVICE ? 0x17 : 0x0E, status); if (result!=USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (*status & 0x01) // check condition return USB_STOR_TRANSPORT_FAILED; if (*status & 0x20) // device fault return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", direction==DMA_TO_DEVICE ? "write" : "read"); } else if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; else return usbat_wait_not_busy(us, minutes); } US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", direction==DMA_TO_DEVICE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED;}/* * Write data to multiple registers at once. Not meant for large * transfers of data! */static int usbat_multiple_write(struct us_data *us, unsigned char access, unsigned char *registers, unsigned char *data_out, unsigned short num_registers){ int result; unsigned char *data = us->iobuf; int i; unsigned char *command = us->iobuf; BUG_ON(num_registers > US_IOBUF_SIZE/2); command[0] = 0x40; command[1] = access | 0x07; command[2] = 0; command[3] = 0; command[4] = 0; command[5] = 0; command[6] = LSB_of(num_registers*2); command[7] = MSB_of(num_registers*2); result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0x80, 0x40, 0, 0, command, 8); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; for (i=0; i<num_registers; i++) { data[i<<1] = registers[i]; data[1+(i<<1)] = data_out[i]; } result = usb_stor_bulk_transfer_buf(us,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -