Commit 16fae052 authored by Kristina Martšenko's avatar Kristina Martšenko Committed by Greg Kroah-Hartman

staging: keucr: remove driver

The driver hasn't been fully cleaned up and it doesn't look like anyone
is working on it anymore (including the original author). So remove the
driver and all references to it. If someone wants to finish cleaning
the driver up and moving it out of staging, this commit can be reverted.
Signed-off-by: default avatarKristina Martšenko <kristina.martsenko@gmail.com>
Cc: Cho, Yu-Chen <acho@novell.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0d317b91
......@@ -8619,11 +8619,6 @@ W: http://www.linux-speakup.org/
S: Odd Fixes
F: drivers/staging/speakup/
STAGING - USB ENE SM/MS CARD READER DRIVER
M: Al Cho <acho@novell.com>
S: Odd Fixes
F: drivers/staging/keucr/
STAGING - VIA VT665X DRIVERS
M: Forest Bond <forest@alittletooquiet.net>
S: Odd Fixes
......
......@@ -76,8 +76,6 @@ source "drivers/staging/quickstart/Kconfig"
source "drivers/staging/emxx_udc/Kconfig"
source "drivers/staging/keucr/Kconfig"
source "drivers/staging/bcm/Kconfig"
source "drivers/staging/ft1000/Kconfig"
......
......@@ -32,7 +32,6 @@ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_USB_ENESTORAGE) += keucr/
obj-$(CONFIG_BCM_WIMAX) += bcm/
obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
......
config USB_ENESTORAGE
tristate "USB ENE SM card reader support"
depends on USB && SCSI && m
---help---
Say Y here if you wish to control a ENE SM Card reader.
To use SD/MS card, please build driver/usb/storage/ums-eneub6250.ko
This option depends on 'SCSI' support being enabled, but you
probably also need 'SCSI device support: SCSI disk support'
(BLK_DEV_SD) for most USB storage devices.
To compile this driver as a module, choose M here: the
module will be called keucr.
ccflags-y := -Idrivers/scsi
obj-$(CONFIG_USB_ENESTORAGE) += keucr.o
keucr-y := \
usb.o \
scsiglue.o \
transport.o \
init.o \
smscsi.o \
smilmain.o \
smilsub.o \
smilecc.o
TODO:
- checkpatch.pl clean
- sparse clean
- determine if the driver should not be using a duplicate
version of the usb-storage scsi interface code, but should
be merged into the drivers/usb/storage/ directory and
infrastructure instead.
- review by the USB developer community
- smcommon.h & smilsub.c: use kernel hweight8(), hweight16()
Please send any patches for this driver to Al Cho <acho@novell.com> and
Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
#ifndef COMMON_INCD
#define COMMON_INCD
#define BYTE_MASK 0xff
#endif
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
#include "smil.h"
#include "init.h"
/*
* ENE_InitMedia():
*/
int ENE_InitMedia(struct us_data *us)
{
int result;
u8 MiscReg03 = 0;
dev_info(&us->pusb_dev->dev, "--- Init Media ---\n");
result = ene_read_byte(us, REG_CARD_STATUS, &MiscReg03);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev, "Failed to read register\n");
return USB_STOR_TRANSPORT_ERROR;
}
dev_info(&us->pusb_dev->dev, "MiscReg03 = %x\n", MiscReg03);
if (MiscReg03 & 0x02) {
if (!us->SM_Status.Ready && !us->MS_Status.Ready) {
result = ENE_SMInit(us);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
}
}
return result;
}
/*
* ene_read_byte() :
*/
int ene_read_byte(struct us_data *us, u16 index, void *buf)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x01;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xED;
bcb->CDB[2] = (u8)(index>>8);
bcb->CDB[3] = (u8)index;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
return result;
}
/*
*ENE_SMInit()
*/
int ENE_SMInit(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u8 buf[0x200];
dev_dbg(&us->pusb_dev->dev, "transport --- ENE_SMInit\n");
result = ENE_LoadBinCode(us, SM_INIT_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_info(&us->pusb_dev->dev,
"Failed to load SmartMedia init code\n: result= %x\n",
result);
return USB_STOR_TRANSPORT_ERROR;
}
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x01;
result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia init code: result = %x\n",
result);
return USB_STOR_TRANSPORT_ERROR;
}
us->SM_Status = *(struct keucr_sm_status *)&buf[0];
us->SM_DeviceID = buf[1];
us->SM_CardID = buf[2];
if (us->SM_Status.Insert && us->SM_Status.Ready) {
dev_info(&us->pusb_dev->dev, "Insert = %x\n",
us->SM_Status.Insert);
dev_info(&us->pusb_dev->dev, "Ready = %x\n",
us->SM_Status.Ready);
dev_info(&us->pusb_dev->dev, "WtP = %x\n",
us->SM_Status.WtP);
dev_info(&us->pusb_dev->dev, "DeviceID = %x\n",
us->SM_DeviceID);
dev_info(&us->pusb_dev->dev, "CardID = %x\n",
us->SM_CardID);
MediaChange = 1;
Check_D_MediaFmt(us);
} else {
dev_err(&us->pusb_dev->dev,
"SmartMedia Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
}
/*
* ENE_LoadBinCode()
*/
int ENE_LoadBinCode(struct us_data *us, u8 flag)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
/* void *buf; */
u8 *buf;
/* dev_info(&us->pusb_dev->dev, "transport --- ENE_LoadBinCode\n"); */
if (us->BIN_FLAG == flag)
return USB_STOR_TRANSPORT_GOOD;
buf = kmalloc(0x800, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
switch (flag) {
/* For SS */
case SM_INIT_PATTERN:
dev_dbg(&us->pusb_dev->dev, "SM_INIT_PATTERN\n");
memcpy(buf, SM_Init, 0x800);
break;
case SM_RW_PATTERN:
dev_dbg(&us->pusb_dev->dev, "SM_RW_PATTERN\n");
memcpy(buf, SM_Rdwr, 0x800);
break;
}
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x800;
bcb->Flags = 0x00;
bcb->CDB[0] = 0xEF;
result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
kfree(buf);
us->BIN_FLAG = flag;
return result;
}
/*
* ENE_SendScsiCmd():
*/
int ENE_SendScsiCmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
unsigned int transfer_length = bcb->DataTransferLength,
cswlen = 0, partial = 0;
unsigned int residue;
/* dev_dbg(&us->pusb_dev->dev, "transport --- ENE_SendScsiCmd\n"); */
/* send cmd to out endpoint */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"send cmd to out endpoint fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
if (buf) {
unsigned int pipe = fDir;
if (fDir == FDIR_READ)
pipe = us->recv_bulk_pipe;
else
pipe = us->send_bulk_pipe;
/* Bulk */
if (use_sg)
result = usb_stor_bulk_srb(us, pipe, us->srb);
else
result = usb_stor_bulk_transfer_sg(us, pipe, buf,
transfer_length, 0, &partial);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev, "data transfer fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
}
/* Get CSW for device status */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &cswlen);
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
dev_warn(&us->pusb_dev->dev,
"Received 0-length CSW; retrying...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
dev_warn(&us->pusb_dev->dev,
"Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, NULL);
}
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* check bulk status */
residue = le32_to_cpu(bcs->Residue);
/*
* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us
*/
if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
residue = min(residue, transfer_length);
if (us->srb)
scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
(int) residue));
}
if (bcs->Status != US_BULK_STAT_OK)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/*
* ENE_Read_Data()
*/
int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
/* dev_dbg(&us->pusb_dev->dev, "transport --- ENE_Read_Data\n"); */
/* set up the command wrapper */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = length;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xED;
bcb->CDB[2] = 0xFF;
bcb->CDB[3] = 0x81;
/* send cmd to out endpoint */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* R/W data */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
buf, length, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* Get CSW for device status */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (bcs->Status != US_BULK_STAT_OK)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/*
* ENE_Write_Data():
*/
int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
int result;
/* printk("transport --- ENE_Write_Data\n"); */
/* set up the command wrapper */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = length;
bcb->Flags = 0x00;
bcb->CDB[0] = 0xEE;
bcb->CDB[2] = 0xFF;
bcb->CDB[3] = 0x81;
/* send cmd to out endpoint */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* R/W data */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
buf, length, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* Get CSW for device status */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (bcs->Status != US_BULK_STAT_OK)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
#include "common.h"
static u8 SM_Init[] = {
0x7B, 0x09, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xCC,
0xE0, 0xB4, 0x07, 0x12, 0x90, 0xFF, 0x09, 0xE0,
0x30, 0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74, 0x80,
0xF0, 0x12, 0x2F, 0x5C, 0xD3, 0x22, 0x78, 0x00,
0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1, 0x92, 0x0A,
0x20, 0x0A, 0x03, 0x02, 0xE0, 0xD0, 0x7F, 0x00,
0x12, 0x2F, 0xCB, 0x20, 0x01, 0x05, 0xC2, 0x25,
0x02, 0xE0, 0xEB, 0xC3, 0xE8, 0x94, 0x02, 0x40,
0x03, 0x02, 0xE0, 0xD0, 0xC0, 0x00, 0x90, 0xFE,
0x66, 0x74, 0x90, 0xF0, 0x12, 0xE1, 0x40, 0x90,
0xFF, 0x95, 0xE0, 0xC2, 0xE4, 0xF0, 0x90, 0xFF,
0x97, 0x74, 0x01, 0xF0, 0x7E, 0x01, 0x7F, 0x90,
0x12, 0x2F, 0x74, 0x90, 0xFF, 0x97, 0x74, 0x03,
0xF0, 0x90, 0xFE, 0xC5, 0xE4, 0xF0, 0x74, 0x00,
0x90, 0xFE, 0x6A, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0,
0xA3, 0xF0, 0x7E, 0x23, 0x7F, 0xDC, 0x12, 0x2F,
0x74, 0x12, 0x2F, 0x5C, 0x90, 0xFE, 0x64, 0xE0,
0x54, 0x01, 0x60, 0x04, 0xD2, 0x02, 0x80, 0x02,
0xC2, 0x02, 0x90, 0xFF, 0x95, 0xE0, 0xD2, 0xE4,
0xF0, 0x78, 0x10, 0x79, 0x04, 0x12, 0xE1, 0x71,
0x50, 0x3A, 0x90, 0xE9, 0xC6, 0xE0, 0x90, 0xE9,
0xC3, 0xF0, 0x78, 0x9A, 0x79, 0x04, 0x12, 0xE1,
0x71, 0x50, 0x29, 0x90, 0xE9, 0xC7, 0xE0, 0xB4,
0xB5, 0x22, 0x90, 0xE9, 0xC4, 0xF0, 0xD0, 0x00,
0xD2, 0x00, 0xC2, 0x01, 0xC2, 0x25, 0x80, 0x1B,
0xC2, 0x00, 0xD2, 0x01, 0x74, 0xFF, 0x90, 0xE9,
0xC3, 0xF0, 0xA3, 0xF0, 0x51, 0x01, 0xC2, 0x0A,
0xC2, 0x02, 0x80, 0x07, 0xD0, 0x00, 0x05, 0x00,
0x02, 0xE0, 0x43, 0x90, 0xFF, 0x09, 0xE0, 0x30,
0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74, 0x80, 0xF0,
0x90, 0xFF, 0x09, 0xE0, 0x30, 0xE5, 0xFC, 0xE4,
0xA2, 0x0A, 0x92, 0xE0, 0xA2, 0x00, 0x92, 0xE1,
0xA2, 0x01, 0x92, 0xE2, 0xA2, 0x02, 0x92, 0xE6,
0xA2, 0x25, 0x92, 0xE7, 0x90, 0xF4, 0x00, 0xF0,
0x90, 0xE9, 0xC3, 0xE0, 0x90, 0xF4, 0x01, 0xF0,
0x90, 0xE9, 0xC4, 0xE0, 0x90, 0xF4, 0x02, 0xF0,
0x90, 0xFF, 0x2A, 0x74, 0x02, 0xF0, 0xA3, 0x74,
0x00, 0xF0, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
0x90, 0xFE, 0x71, 0xE4, 0xF0, 0x90, 0xFE, 0x72,
0x74, 0x01, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0x0C,
0xF0, 0x90, 0xFE, 0x64, 0x74, 0x00, 0x45, 0x4E,
0xF0, 0x90, 0xFE, 0x64, 0xE0, 0x54, 0x10, 0x60,
0x08, 0x90, 0xFE, 0x72, 0x74, 0x81, 0xF0, 0xD3,
0x22, 0x90, 0xFE, 0x64, 0x74, 0x08, 0xF0, 0xC3,
0x22, 0x90, 0xFE, 0x6F, 0xE9, 0x14, 0xF0, 0x90,
0xFE, 0x70, 0xE0, 0x54, 0xFC, 0xF0, 0x90, 0xFE,
0x68, 0x74, 0x00, 0xF0, 0xB8, 0x9A, 0x2A, 0x74,
0x15, 0x90, 0xFE, 0x64, 0xF0, 0x74, 0x9A, 0x90,
0xFE, 0x60, 0xF0, 0x74, 0x16, 0x90, 0xFE, 0x64,
0xF0, 0x74, 0x00, 0x90, 0xFE, 0x60, 0xF0, 0x30,
0x0A, 0x5D, 0x90, 0xFE, 0x64, 0xE0, 0x20, 0xE7,
0xF6, 0x74, 0x14, 0x90, 0xFE, 0x64, 0xF0, 0x80,
0x20, 0x90, 0xFE, 0x6E, 0xE8, 0x44, 0x01, 0xF0,
0xC2, 0x09, 0x12, 0xE3, 0x26, 0x20, 0x08, 0x0E,
0x12, 0xE3, 0x32, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x20, 0x09,
0x2E, 0x7A, 0xE9, 0x7B, 0xC5, 0x7C, 0xFE, 0x7D,
0x60, 0xB8, 0x10, 0x07, 0x90, 0xFE, 0x69, 0xE0,
0x20, 0xE6, 0xFC, 0x8C, 0x83, 0x8D, 0x82, 0xE0,
0x8A, 0x83, 0x8B, 0x82, 0xF0, 0xA3, 0xAA, 0x83,
0xAB, 0x82, 0xD9, 0xE5, 0xB8, 0x9A, 0x06, 0x74,
0x10, 0x90, 0xFE, 0x64, 0xF0, 0xD3, 0x22, 0xC3,
0x22, 0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1, 0x92,
0x25, 0x20, 0x25, 0x06, 0xC2, 0x1F, 0xD2, 0x19,
0xC3, 0x22, 0x7F, 0x02, 0x12, 0x2F, 0xCB, 0x20,
0x19, 0x05, 0x30, 0x1F, 0x02, 0xD3, 0x22, 0x90,
0xEA, 0x44, 0x74, 0x80, 0xF0, 0x7F, 0x10, 0x12,
0x2F, 0xC5, 0x90, 0xFE, 0x47, 0xE0, 0x44, 0x80,
0xF0, 0x78, 0x00, 0xE8, 0xC3, 0x94, 0x04, 0x50,
0x0A, 0x7F, 0x88, 0x7E, 0x13, 0x12, 0xE3, 0x4D,
0x08, 0x80, 0xF0, 0x90, 0xFE, 0x45, 0xE0, 0x54,
0xFB, 0xF0, 0x90, 0xFE, 0x47, 0xE0, 0x54, 0xBF,
0xF0, 0x90, 0xFE, 0x45, 0xE0, 0x54, 0xFE, 0xF0,
0x90, 0xFE, 0x45, 0xE0, 0x54, 0x7F, 0xF0, 0x90,
0xFE, 0x46, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0xFE,
0x45, 0xE0, 0x54, 0xC7, 0x44, 0x18, 0xF0, 0x90,
0xFE, 0x47, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0xFE,
0x45, 0xE0, 0x44, 0x40, 0xF0, 0x7F, 0x32, 0x7E,
0x00, 0x12, 0xE3, 0x4D, 0x90, 0xFE, 0x51, 0xE0,
0x54, 0x33, 0xF0, 0x90, 0xFE, 0x44, 0x74, 0x02,
0xF0, 0x30, 0x25, 0x04, 0xE0, 0x20, 0xE1, 0xF9,
0x90, 0xFE, 0x51, 0xE0, 0x54, 0x0F, 0xF0, 0x90,
0xFE, 0x44, 0x74, 0x02, 0xF0, 0x30, 0x25, 0x04,
0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xFE, 0x44, 0x74,
0x04, 0xF0, 0x30, 0x25, 0x04, 0xE0, 0x20, 0xE2,
0xF9, 0x90, 0xFE, 0x4C, 0xE0, 0xF0, 0x90, 0xFE,
0x4D, 0xE0, 0xF0, 0x90, 0xFE, 0x48, 0x74, 0x7F,
0xF0, 0x90, 0xFE, 0x49, 0x74, 0x9F, 0xF0, 0x90,
0xFE, 0x51, 0xE0, 0x54, 0x3C, 0x44, 0x02, 0xF0,
0x90, 0xFE, 0x44, 0x74, 0x02, 0xF0, 0x30, 0x25,
0x04, 0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xFE, 0x46,
0xE0, 0x44, 0x20, 0xF0, 0x79, 0x02, 0x7A, 0x06,
0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x06, 0x7E, 0xEB,
0x7F, 0xC9, 0x12, 0x2F, 0xA7, 0x40, 0x03, 0x02,
0xE3, 0x04, 0xD3, 0x22, 0xE4, 0x90, 0xFE, 0x48,
0xF0, 0x90, 0xFE, 0x49, 0xF0, 0x90, 0xFE, 0x4C,
0xE0, 0xF0, 0x90, 0xFE, 0x4D, 0xE0, 0xF0, 0x90,
0xFE, 0x47, 0xE0, 0x54, 0x7F, 0xF0, 0xC2, 0x25,
0xC2, 0x1F, 0xD2, 0x19, 0xC3, 0x22, 0xC2, 0x3E,
0x75, 0x7C, 0x00, 0x75, 0x7D, 0x00, 0x75, 0x7E,
0x00, 0x22, 0x05, 0x7C, 0xE5, 0x7C, 0x70, 0x14,
0x05, 0x7D, 0xE5, 0x7D, 0x70, 0x04, 0x05, 0x7E,
0x80, 0x0A, 0xB4, 0x17, 0x07, 0xE5, 0x7E, 0xB4,
0x06, 0x02, 0xD2, 0x3E, 0x22, 0x75, 0x8A, 0x00,
0x75, 0x8C, 0xCE, 0xC2, 0x8D, 0x90, 0xEA, 0x65,
0xE4, 0xF0, 0xA3, 0xF0, 0xD2, 0x8C, 0x90, 0xEA,
0x65, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xEC, 0xC3,
0x9E, 0x40, 0xF3, 0x70, 0x05, 0xED, 0xC3, 0x9F,
0x40, 0xEC, 0xC2, 0x8C, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x44, 0x2D, 0x49, 0x6E, 0x69, 0x74, 0x20,
0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x31 };
static u8 SM_Rdwr[] = {
0x7B, 0x0C, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xC3,
0xE0, 0xB4, 0x73, 0x04, 0x74, 0x40, 0x80, 0x09,
0xB4, 0x75, 0x04, 0x74, 0x40, 0x80, 0x02, 0x74,
0xC0, 0x90, 0xFE, 0x70, 0xF0, 0x90, 0xFF, 0x09,
0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74,
0x80, 0xF0, 0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1,
0x92, 0x0A, 0x40, 0x01, 0x22, 0x90, 0xFE, 0x6A,
0xE4, 0xF0, 0x90, 0xE9, 0xCC, 0xE0, 0xB4, 0x02,
0x05, 0xD2, 0x06, 0x02, 0xE0, 0x78, 0xB4, 0x03,
0x03, 0x02, 0xE3, 0xD0, 0xB4, 0x04, 0x03, 0x02,
0xE1, 0xC6, 0xB4, 0x05, 0x03, 0x02, 0xE5, 0x20,
0xB4, 0x06, 0x03, 0x02, 0xE5, 0xE0, 0xB4, 0x07,
0x05, 0x12, 0x2F, 0x5C, 0xD3, 0x22, 0xB4, 0x08,
0x05, 0xC2, 0x06, 0x02, 0xE6, 0x3B, 0xC3, 0x22,
0xE5, 0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA, 0xF0,
0xC0, 0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0, 0x12,
0xE0, 0xD8, 0xEF, 0x70, 0x21, 0x20, 0x37, 0x07,
0x20, 0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05, 0xD0,
0xF0, 0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90, 0xFF,
0x28, 0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF, 0x28,
0xE0, 0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0, 0xF0,
0x90, 0xE9, 0xCF, 0xE0, 0x24, 0x01, 0xF0, 0x90,
0xE9, 0xCE, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9,
0xCD, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0, 0x14,
0x70, 0xB6, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
0xC2, 0x08, 0xC2, 0x36, 0xC2, 0x37, 0xE4, 0x90,
0xEB, 0xC2, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0xF8,
0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90, 0xFE, 0x6B,
0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8, 0xF0, 0x90,
0xFE, 0x6F, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0x70,
0xE0, 0x54, 0xFC, 0x44, 0x02, 0xF0, 0x90, 0xFE,
0xC6, 0x74, 0x02, 0xF0, 0xA3, 0x74, 0x0F, 0xF0,
0x90, 0xFE, 0xC0, 0x74, 0xF4, 0xF0, 0x74, 0x00,
0xA3, 0xF0, 0x90, 0xFE, 0x68, 0x74, 0x21, 0xF0,
0x90, 0xFE, 0x64, 0x74, 0x70, 0x45, 0x4E, 0xF0,
0x90, 0xFE, 0x64, 0x74, 0x30, 0x45, 0x4E, 0xF0,
0x30, 0x06, 0x07, 0x90, 0xFF, 0x09, 0xE0, 0x30,
0xE5, 0xFC, 0x90, 0xFE, 0x6E, 0x74, 0x51, 0xF0,
0x90, 0xFE, 0xC4, 0x74, 0x21, 0xF0, 0xC2, 0x09,
0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E, 0x12, 0xE7,
0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE, 0xD8, 0x74,
0x01, 0xF0, 0xD2, 0x09, 0x30, 0x09, 0x03, 0x7F,
0x00, 0x22, 0x12, 0xE7, 0xB0, 0x20, 0x36, 0x11,
0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E,
0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2,
0x37, 0x30, 0x37, 0x03, 0x7F, 0x00, 0x22, 0x90,
0xFE, 0x64, 0x74, 0x10, 0x45, 0x4E, 0xF0, 0x90,
0xFE, 0x64, 0x74, 0x00, 0x45, 0x4E, 0xF0, 0x12,
0x2F, 0x65, 0x12, 0x2F, 0x68, 0xBF, 0x00, 0x09,
0x74, 0x02, 0x90, 0xEB, 0xC2, 0xF0, 0x7F, 0x00,
0x22, 0x12, 0x2F, 0x6B, 0xBF, 0x00, 0x0F, 0x12,
0x2F, 0x6E, 0xBF, 0x00, 0x09, 0x74, 0x01, 0x90,
0xEB, 0xC2, 0xF0, 0x7F, 0x00, 0x22, 0x30, 0x06,
0x0A, 0x90, 0xFF, 0x2A, 0x74, 0x02, 0xF0, 0xA3,
0x74, 0x00, 0xF0, 0x7F, 0x01, 0x22, 0x12, 0xE3,
0xAA, 0x74, 0x01, 0x90, 0xE9, 0xCB, 0xF0, 0xE5,
0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA, 0xF0, 0xC0,
0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0, 0x12, 0xE2,
0x2F, 0xEF, 0x70, 0x21, 0x20, 0x37, 0x07, 0x20,
0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05, 0xD0, 0xF0,
0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90, 0xFF, 0x28,
0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF, 0x28, 0xE0,
0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0, 0xF0, 0x90,
0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0, 0x90, 0xE9,
0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD0,
0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0, 0x14, 0x70,
0xB6, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00, 0x75,
0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22, 0xC2,
0x08, 0xC2, 0x36, 0xC2, 0x37, 0x90, 0xFE, 0x68,
0x74, 0x31, 0xF0, 0x90, 0xE9, 0xD0, 0xE0, 0xF8,
0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90, 0xFE, 0x6B,
0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8, 0xF0, 0x90,
0xFE, 0x6F, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0x70,
0xE0, 0x54, 0xFC, 0x44, 0x22, 0xF0, 0x90, 0xE9,
0xCB, 0xE0, 0x70, 0x0C, 0x90, 0xFE, 0xC0, 0x74,
0xF4, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x80, 0x0A,
0x90, 0xFE, 0xC0, 0x74, 0xF0, 0xF0, 0xA3, 0x74,
0x00, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0xF0, 0x45,
0x4E, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0xB0, 0x45,
0x4E, 0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x81, 0xF0,
0x90, 0xE9, 0xCB, 0xE0, 0x70, 0x0D, 0x90, 0xFE,
0xC6, 0x74, 0x02, 0xF0, 0xA3, 0x74, 0x0F, 0xF0,
0x02, 0xE3, 0x56, 0x20, 0x2D, 0x03, 0x02, 0xE2,
0xEF, 0x90, 0xFE, 0xC6, 0x74, 0x01, 0xF0, 0xA3,
0x74, 0xFF, 0xF0, 0x90, 0xFF, 0x09, 0x30, 0x0A,
0x04, 0xE0, 0x30, 0xE1, 0xF9, 0x90, 0xFE, 0xC4,
0x74, 0x23, 0xF0, 0x12, 0xE7, 0xB0, 0x20, 0x36,
0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30,
0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0,
0xD2, 0x37, 0x30, 0x37, 0x02, 0x61, 0xA7, 0x90,
0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF,
0x23, 0x74, 0x80, 0xF0, 0x02, 0xE3, 0x3F, 0x90,
0xFE, 0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x3F, 0xF0,
0x78, 0x08, 0xC0, 0x00, 0xC2, 0x36, 0xC2, 0x37,
0x90, 0xFF, 0x09, 0x30, 0x0A, 0x04, 0xE0, 0x30,
0xE1, 0xF9, 0x90, 0xFE, 0xC4, 0x74, 0x23, 0xF0,
0x12, 0xE7, 0xB0, 0x20, 0x36, 0x11, 0x20, 0x37,
0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF4, 0x90,
0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x37, 0x90,
0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF,
0x23, 0x74, 0x80, 0xF0, 0x30, 0x37, 0x04, 0xD0,
0x00, 0x80, 0x6C, 0xD0, 0x00, 0xD8, 0xBB, 0xC2,
0x36, 0xC2, 0x37, 0x90, 0xFE, 0xC6, 0xE4, 0xF0,
0xA3, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0xC0, 0x74,
0xF6, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE,
0xC4, 0x74, 0x23, 0xF0, 0x12, 0xE7, 0xB0, 0x20,
0x36, 0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC,
0x30, 0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01,
0xF0, 0xD2, 0x37, 0x30, 0x37, 0x02, 0x80, 0x2F,
0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E,
0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x30, 0x09,
0x02, 0x80, 0x14, 0x90, 0xFE, 0x64, 0x74, 0x90,
0x45, 0x4E, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0x80,
0x45, 0x4E, 0xF0, 0x12, 0x2F, 0x59, 0x22, 0x7F,
0x00, 0x22, 0x90, 0xF6, 0x00, 0x7F, 0x06, 0x74,
0xFF, 0xF0, 0xA3, 0xDF, 0xFC, 0x7B, 0x02, 0x7C,
0xE9, 0x7D, 0xD3, 0x7E, 0xF6, 0x7F, 0x06, 0x12,
0x2F, 0x71, 0x7B, 0x02, 0x7C, 0xE9, 0x7D, 0xD3,
0x7E, 0xF6, 0x7F, 0x0B, 0x12, 0x2F, 0x71, 0x22,
0x90, 0xFE, 0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x0F,
0xF0, 0x90, 0xFE, 0x6F, 0xF0, 0x90, 0xFE, 0x70,
0xE0, 0x54, 0xFC, 0xF0, 0x90, 0xFE, 0xC0, 0x74,
0xF6, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE,
0x68, 0x74, 0x21, 0xF0, 0x90, 0xFE, 0x66, 0xE0,
0x54, 0xEF, 0xF0, 0x90, 0xE9, 0xD3, 0xE0, 0xF5,
0x08, 0xA3, 0xE0, 0xF5, 0x09, 0x90, 0xFF, 0x09,
0xE0, 0x30, 0xE5, 0xFC, 0xE4, 0xF5, 0x10, 0x7E,
0xF4, 0x7F, 0x00, 0xC0, 0x06, 0xC0, 0x07, 0xC2,
0x36, 0xC2, 0x37, 0xC2, 0x09, 0x90, 0xE9, 0xCD,
0xE0, 0xF8, 0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90,
0xFE, 0x6B, 0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8,
0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x71, 0xF0, 0x90,
0xFE, 0xC4, 0x74, 0x21, 0xF0, 0x90, 0xFE, 0x65,
0x12, 0xE7, 0xB0, 0xE0, 0x20, 0xE4, 0x11, 0x12,
0xE7, 0xBC, 0x30, 0x3E, 0xF6, 0x90, 0xFE, 0xD8,
0x74, 0x01, 0xF0, 0xD2, 0x09, 0x02, 0xE4, 0x72,
0x74, 0x10, 0xF0, 0x12, 0xE7, 0xB0, 0x20, 0x36,
0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30,
0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0,
0xD2, 0x37, 0x20, 0x09, 0x05, 0x20, 0x37, 0x02,
0x80, 0x10, 0x90, 0xFE, 0x66, 0xE0, 0x44, 0x10,
0xF0, 0x12, 0x2F, 0x5C, 0xD0, 0x07, 0xD0, 0x06,
0xC3, 0x22, 0xD0, 0x07, 0xD0, 0x06, 0x7B, 0x10,
0x7C, 0xF6, 0x7D, 0x00, 0x12, 0x2F, 0x71, 0x05,
0x10, 0xC3, 0xE5, 0x09, 0x94, 0x01, 0xF5, 0x09,
0xE5, 0x08, 0x94, 0x00, 0xF5, 0x08, 0x45, 0x09,
0x70, 0x03, 0x02, 0xE4, 0xEF, 0x90, 0xE9, 0xCF,
0xE0, 0x24, 0x20, 0xF0, 0x90, 0xE9, 0xCE, 0xE0,
0x34, 0x00, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0x34,
0x00, 0xF0, 0xC3, 0xEF, 0x24, 0x10, 0xFF, 0xEE,
0x34, 0x00, 0xFE, 0xE5, 0x10, 0x64, 0x20, 0x60,
0x03, 0x02, 0xE4, 0x13, 0x90, 0xFF, 0x2A, 0x74,
0x02, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x75, 0x10,
0x00, 0x7E, 0xF4, 0x7F, 0x00, 0x90, 0xFF, 0x09,
0xE0, 0x30, 0xE5, 0xFC, 0x02, 0xE4, 0x13, 0xE5,
0x10, 0x60, 0x17, 0x7E, 0x00, 0x7F, 0x00, 0x78,
0x04, 0xC3, 0x33, 0xFF, 0xEE, 0x33, 0xFE, 0xEF,
0xD8, 0xF8, 0x90, 0xFF, 0x2A, 0xEE, 0xF0, 0xA3,
0xEF, 0xF0, 0x90, 0xFE, 0x66, 0xE0, 0x44, 0x10,
0xF0, 0x12, 0x2F, 0x5C, 0x78, 0x00, 0x88, 0x3C,
0x88, 0x3D, 0x88, 0x3E, 0x88, 0x3F, 0xD3, 0x22,
0x12, 0x2F, 0x5F, 0x12, 0x2F, 0x62, 0x90, 0xFE,
0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x0F, 0xF0, 0x90,
0xFE, 0x6F, 0xF0, 0x90, 0xFE, 0x70, 0xE0, 0x54,
0xFC, 0xF0, 0x90, 0xFE, 0xC0, 0x74, 0xF6, 0xF0,
0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE, 0x68, 0x74,
0x31, 0xF0, 0x90, 0xE9, 0xD3, 0xE0, 0xF8, 0xC0,
0x00, 0xC2, 0x08, 0xC2, 0x36, 0xC2, 0x37, 0x90,
0xE9, 0xD0, 0xE0, 0xF8, 0xA3, 0xE0, 0xF9, 0xA3,
0xE0, 0x90, 0xFE, 0x6B, 0xF0, 0xA3, 0xE9, 0xF0,
0xA3, 0xE8, 0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x81,
0xF0, 0x90, 0xFE, 0xC4, 0x74, 0x23, 0xF0, 0x12,
0xE7, 0xB0, 0x20, 0x36, 0x11, 0x20, 0x37, 0x0E,
0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF4, 0x90, 0xFE,
0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x37, 0x30, 0x37,
0x07, 0xD0, 0x00, 0x12, 0x2F, 0x5C, 0xC3, 0x22,
0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E,
0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x20, 0x09,
0xE0, 0x90, 0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0,
0x90, 0xE9, 0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90,
0xE9, 0xD0, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0x00,
0x18, 0xE8, 0x60, 0x03, 0x02, 0xE5, 0x4F, 0x12,
0x2F, 0x5C, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
0x90, 0xE9, 0xD0, 0xE0, 0xF8, 0xA3, 0xE0, 0xF9,
0xA3, 0xE0, 0x90, 0xFE, 0x6B, 0xF0, 0xA3, 0xE9,
0xF0, 0xA3, 0xE8, 0xF0, 0x90, 0xFE, 0x68, 0x74,
0x00, 0xF0, 0xC2, 0x08, 0x90, 0xFE, 0x6E, 0x74,
0xB1, 0xF0, 0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20,
0x08, 0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7,
0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09,
0x20, 0x09, 0x1E, 0x90, 0xFE, 0x70, 0xE0, 0x44,
0x10, 0xF0, 0x54, 0xEF, 0xF0, 0x12, 0x2F, 0x59,
0xEF, 0x60, 0x0E, 0x75, 0x3C, 0x00, 0x75, 0x3D,
0x00, 0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3,
0x22, 0xC3, 0x22, 0x7B, 0x03, 0x7C, 0xE9, 0x7D,
0xCD, 0x7E, 0xE9, 0x7F, 0xD7, 0x12, 0x2F, 0x71,
0x12, 0xE3, 0xAA, 0x90, 0xE9, 0xD5, 0xE0, 0x60,
0x12, 0xF9, 0x12, 0xE7, 0x17, 0x40, 0x01, 0x22,
0x90, 0xF6, 0x00, 0x78, 0x06, 0x74, 0xFF, 0xF0,
0xA3, 0xD8, 0xFC, 0x74, 0x01, 0x90, 0xE9, 0xCB,
0xF0, 0xE5, 0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA,
0xF0, 0xC0, 0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0,
0x12, 0xE2, 0x2F, 0xEF, 0x70, 0x21, 0x20, 0x37,
0x07, 0x20, 0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05,
0xD0, 0xF0, 0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90,
0xFF, 0x28, 0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF,
0x28, 0xE0, 0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0,
0xF0, 0x90, 0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0,
0x90, 0xE9, 0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90,
0xE9, 0xD0, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0,
0x14, 0x70, 0xB6, 0x90, 0xE9, 0xD5, 0xE0, 0xF8,
0x90, 0xE9, 0xCA, 0xE0, 0x28, 0xF5, 0xF0, 0xC3,
0x74, 0x20, 0x95, 0xF0, 0x60, 0x22, 0xF9, 0x90,
0xE9, 0xCA, 0xE0, 0xF5, 0xF0, 0x90, 0xE9, 0xCF,
0xE0, 0x25, 0xF0, 0xF0, 0x90, 0xE9, 0xCE, 0xE0,
0x34, 0x00, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0x34,
0x00, 0xF0, 0x12, 0xE7, 0x17, 0x40, 0x01, 0x22,
0x90, 0xE9, 0xD6, 0xE0, 0x70, 0x13, 0x7B, 0x03,
0x7C, 0xE9, 0x7D, 0xD7, 0x7E, 0xE9, 0x7F, 0xD0,
0x12, 0x2F, 0x71, 0x12, 0xE5, 0xE0, 0x40, 0x01,
0x22, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00, 0x75,
0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22, 0x90,
0xE9, 0xD6, 0xE0, 0x60, 0x18, 0x74, 0xFF, 0x90,
0xF4, 0x00, 0x78, 0xFF, 0xF0, 0xA3, 0x18, 0xB8,
0x00, 0xFA, 0x78, 0xFF, 0xF0, 0xA3, 0x18, 0xB8,
0x00, 0xFA, 0xF0, 0xA3, 0xF0, 0xC0, 0x01, 0x12,
0xE7, 0x70, 0x40, 0x04, 0xD0, 0x01, 0xC3, 0x22,
0x90, 0xE9, 0xCF, 0xE0, 0x24, 0x01, 0xF0, 0x90,
0xE9, 0xCE, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9,
0xCD, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD2,
0xE0, 0x24, 0x01, 0xF0, 0x90, 0xE9, 0xD1, 0xE0,
0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD0, 0xE0, 0x34,
0x00, 0xF0, 0xD0, 0x01, 0xD9, 0xC7, 0xD3, 0x22,
0xC2, 0x06, 0x90, 0xE9, 0xD6, 0xE0, 0x70, 0x28,
0x12, 0xE0, 0xD8, 0xEF, 0x60, 0x03, 0x02, 0xE7,
0xA0, 0x90, 0xEB, 0xC2, 0xE0, 0x60, 0x17, 0x64,
0x02, 0x60, 0x15, 0x90, 0xF6, 0x00, 0x78, 0x06,
0x74, 0xFF, 0xF0, 0xA3, 0xD8, 0xFC, 0x74, 0xF0,
0x90, 0xF6, 0x04, 0xF0, 0x80, 0x02, 0xC3, 0x22,
0xE4, 0x90, 0xE9, 0xCB, 0xF0, 0x12, 0xE2, 0x2F,
0xEF, 0x70, 0x03, 0x02, 0xE7, 0x81, 0xD3, 0x22,
0xC2, 0x3E, 0x75, 0x7C, 0x00, 0x75, 0x7D, 0x00,
0x75, 0x7E, 0x00, 0x22, 0x05, 0x7C, 0xE5, 0x7C,
0x70, 0x14, 0x05, 0x7D, 0xE5, 0x7D, 0x70, 0x04,
0x05, 0x7E, 0x80, 0x0A, 0xB4, 0x17, 0x07, 0xE5,
0x7E, 0xB4, 0x06, 0x02, 0xD2, 0x3E, 0x22, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x44, 0x2D, 0x52, 0x57, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30 };
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
/* Host functions */
/*
* host_info()
*/
static const char *host_info(struct Scsi_Host *host)
{
/* pr_info("scsiglue --- host_info\n"); */
return "SCSI emulation for USB Mass Storage devices";
}
/*
* slave_alloc()
*/
static int slave_alloc(struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
/* pr_info("scsiglue --- slave_alloc\n"); */
sdev->inquiry_len = 36;
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
if (us->subclass == USB_SC_UFI)
sdev->sdev_target->pdt_1f_for_no_lun = 1;
return 0;
}
/*
* slave_configure()
*/
static int slave_configure(struct scsi_device *sdev)
{
struct us_data *us = host_to_us(sdev->host);
/* pr_info("scsiglue --- slave_configure\n"); */
if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) {
unsigned int max_sectors = 64;
if (us->fflags & US_FL_MAX_SECTORS_MIN)
max_sectors = PAGE_CACHE_SIZE >> 9;
if (queue_max_sectors(sdev->request_queue) > max_sectors)
blk_queue_max_hw_sectors(sdev->request_queue,
max_sectors);
}
if (sdev->type == TYPE_DISK) {
if (us->subclass != USB_SC_SCSI &&
us->subclass != USB_SC_CYP_ATACB)
sdev->use_10_for_ms = 1;
sdev->use_192_bytes_for_3f = 1;
if (us->fflags & US_FL_NO_WP_DETECT)
sdev->skip_ms_page_3f = 1;
sdev->skip_ms_page_8 = 1;
if (us->fflags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
if (us->fflags & US_FL_CAPACITY_HEURISTICS)
sdev->guess_capacity = 1;
if (sdev->scsi_level > SCSI_2)
sdev->sdev_target->scsi_level = sdev->scsi_level
= SCSI_2;
sdev->retry_hwerror = 1;
sdev->allow_restart = 1;
sdev->last_sector_bug = 1;
} else {
sdev->use_10_for_ms = 1;
}
if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) &&
sdev->scsi_level == SCSI_UNKNOWN)
us->max_lun = 0;
if (us->fflags & US_FL_NOT_LOCKABLE)
sdev->lockable = 0;
return 0;
}
/* This is always called with scsi_lock(host) held */
/*
* queuecommand()
*/
static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
/* pr_info("scsiglue --- queuecommand\n"); */
/* check for state-transition errors */
if (us->srb != NULL) {
/* pr_info("Error in %s: us->srb = %p\n"
__func__, us->srb); */
return SCSI_MLQUEUE_HOST_BUSY;
}
/* fail the command if we are disconnecting */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
pr_info("Fail command during disconnect\n");
srb->result = DID_NO_CONNECT << 16;
done(srb);
return 0;
}
/* enqueue the command and wake up the control thread */
srb->scsi_done = done;
us->srb = srb;
complete(&us->cmnd_ready);
return 0;
}
static DEF_SCSI_QCMD(queuecommand)
/***********************************************************************
* Error handling functions
***********************************************************************/
/* Command timeout and abort */
/*
* command_abort()
*/
static int command_abort(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
/* pr_info("scsiglue --- command_abort\n"); */
scsi_lock(us_to_host(us));
if (us->srb != srb) {
scsi_unlock(us_to_host(us));
dev_info(&us->pusb_dev->dev, "-- nothing to abort\n");
return FAILED;
}
set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) {
set_bit(US_FLIDX_ABORTING, &us->dflags);
usb_stor_stop_transport(us);
}
scsi_unlock(us_to_host(us));
/* Wait for the aborted command to finish */
wait_for_completion(&us->notify);
return SUCCESS;
}
/* This invokes the transport reset mechanism to reset the state of the
* device.
*/
/*
* device_reset()
*/
static int device_reset(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
int result;
/* pr_info("scsiglue --- device_reset\n"); */
/* lock the device pointers and do the reset */
mutex_lock(&(us->dev_mutex));
result = us->transport_reset(us);
mutex_unlock(&us->dev_mutex);
return result < 0 ? FAILED : SUCCESS;
}
/*
* bus_reset()
*/
static int bus_reset(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
int result;
/* pr_info("scsiglue --- bus_reset\n"); */
result = usb_stor_port_reset(us);
return result < 0 ? FAILED : SUCCESS;
}
/*
* usb_stor_report_device_reset()
*/
void usb_stor_report_device_reset(struct us_data *us)
{
int i;
struct Scsi_Host *host = us_to_host(us);
/* pr_info("scsiglue --- usb_stor_report_device_reset\n"); */
scsi_report_device_reset(host, 0, 0);
if (us->fflags & US_FL_SCM_MULT_TARG) {
for (i = 1; i < host->max_id; ++i)
scsi_report_device_reset(host, 0, i);
}
}
/*
* usb_stor_report_bus_reset()
*/
void usb_stor_report_bus_reset(struct us_data *us)
{
struct Scsi_Host *host = us_to_host(us);
/* pr_info("scsiglue --- usb_stor_report_bus_reset\n"); */
scsi_lock(host);
scsi_report_bus_reset(host, 0);
scsi_unlock(host);
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
/* we use this macro to help us write into the buffer */
#undef SPRINTF
#define SPRINTF(args...) seq_printf(m, ##args)
static int write_info(struct Scsi_Host *host, char *buffer, int length)
{
return length;
}
static int show_info(struct seq_file *m, struct Scsi_Host *host)
{
struct us_data *us = host_to_us(host);
const char *string;
/* print the controller name */
SPRINTF(" Host scsi%d: usb-storage\n", host->host_no);
/* print product, vendor, and serial number strings */
if (us->pusb_dev->manufacturer)
string = us->pusb_dev->manufacturer;
else if (us->unusual_dev->vendorName)
string = us->unusual_dev->vendorName;
else
string = "Unknown";
SPRINTF(" Vendor: %s\n", string);
if (us->pusb_dev->product)
string = us->pusb_dev->product;
else if (us->unusual_dev->productName)
string = us->unusual_dev->productName;
else
string = "Unknown";
SPRINTF(" Product: %s\n", string);
if (us->pusb_dev->serial)
string = us->pusb_dev->serial;
else
string = "None";
SPRINTF("Serial Number: %s\n", string);
/* show the protocol and transport */
SPRINTF(" Protocol: %s\n", us->protocol_name);
SPRINTF(" Transport: %s\n", us->transport_name);
/* show the device flags */
SPRINTF(" Quirks:");
#define US_FLAG(name, value) \
do { \
if (us->fflags & value) \
SPRINTF(" " #name); \
} while (0);
US_DO_ALL_FLAGS
#undef US_FLAG
seq_putc(m, '\n');
return 0;
}
/***********************************************************************
* Sysfs interface
***********************************************************************/
/* Output routine for the sysfs max_sectors file */
static ssize_t max_sectors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
/* pr_info("scsiglue --- ssize_t show_max_sectors\n"); */
return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
}
/* Input routine for the sysfs max_sectors file */
static ssize_t max_sectors_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
unsigned short ms;
/* pr_info("scsiglue --- ssize_t store_max_sectors\n"); */
if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
blk_queue_max_hw_sectors(sdev->request_queue, ms);
return strlen(buf);
}
return -EINVAL;
}
static DEVICE_ATTR_RW(max_sectors);
static struct device_attribute *sysfs_device_attr_list[] = {
&dev_attr_max_sectors, NULL,
};
/* this defines our host template, with which we'll allocate hosts */
/*
* usb_stor_host_template()
*/
struct scsi_host_template usb_stor_host_template = {
/* basic userland interface stuff */
.name = "eucr-storage",
.proc_name = "eucr-storage",
.write_info = write_info,
.show_info = show_info,
.info = host_info,
/* command interface -- queued only */
.queuecommand = queuecommand,
/* error and abort handlers */
.eh_abort_handler = command_abort,
.eh_device_reset_handler = device_reset,
.eh_bus_reset_handler = bus_reset,
/* queue commands only, only one command per LUN */
.can_queue = 1,
.cmd_per_lun = 1,
/* unknown initiator id */
.this_id = -1,
.slave_alloc = slave_alloc,
.slave_configure = slave_configure,
/* lots of sg segments can be handled */
.sg_tablesize = SG_ALL,
/* limit the total size of a transfer to 120 KB */
.max_sectors = 240,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal.
*/
.use_clustering = 1,
/* emulated HBA */
.emulated = 1,
/* we do our own delay after a device or bus reset */
.skip_settle_delay = 1,
/* sysfs device attributes */
.sdev_attrs = sysfs_device_attr_list,
/* module management */
.module = THIS_MODULE
};
/* To Report "Illegal Request: Invalid Field in CDB */
unsigned char usb_stor_sense_invalidCDB[18] = {
[0] = 0x70, /* current error */
[2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */
[7] = 0x0a, /* additional length */
[12] = 0x24 /* Invalid Field in CDB */
};
/***********************************************************************
* Scatter-gather transfer buffer access routines
***********************************************************************/
/*
* usb_stor_access_xfer_buf()
*/
unsigned int usb_stor_access_xfer_buf(struct us_data *us,
unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb, struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
{
unsigned int cnt;
/* pr_info("transport --- usb_stor_access_xfer_buf\n"); */
struct scatterlist *sg = *sgptr;
if (!sg)
sg = scsi_sglist(srb);
cnt = 0;
while (cnt < buflen && sg) {
struct page *page = sg_page(sg) +
((sg->offset + *offset) >> PAGE_SHIFT);
unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
unsigned int sglen = sg->length - *offset;
if (sglen > buflen - cnt) {
/* Transfer ends within this s-g entry */
sglen = buflen - cnt;
*offset += sglen;
} else {
/* Transfer continues to next s-g entry */
*offset = 0;
sg = sg_next(sg);
}
while (sglen > 0) {
unsigned int plen = min(sglen,
(unsigned int)PAGE_SIZE - poff);
unsigned char *ptr = kmap(page);
if (dir == TO_XFER_BUF)
memcpy(ptr + poff, buffer + cnt, plen);
else
memcpy(buffer + cnt, ptr + poff, plen);
kunmap(page);
/* Start at the beginning of the next page */
poff = 0;
++page;
cnt += plen;
sglen -= plen;
}
}
*sgptr = sg;
/* Return the amount actually transferred */
return cnt;
}
/*
* Store the contents of buffer into srb's transfer
* buffer and set the SCSI residue.
*/
/*
* usb_stor_set_xfer_buf()
*/
void usb_stor_set_xfer_buf(struct us_data *us, unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, unsigned int dir)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
/* pr_info("transport --- usb_stor_set_xfer_buf\n"); */
/* TO_XFER_BUF = 0, FROM_XFER_BUF = 1 */
buflen = min(buflen, scsi_bufflen(srb));
buflen = usb_stor_access_xfer_buf(us, buffer, buflen, srb,
&sg, &offset, dir);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
#ifndef _SCSIGLUE_H_
#define _SCSIGLUE_H_
extern void usb_stor_report_device_reset(struct us_data *us);
extern void usb_stor_report_bus_reset(struct us_data *us);
extern unsigned char usb_stor_sense_invalidCDB[18];
extern struct scsi_host_template usb_stor_host_template;
#endif
/*----- < SMCommon.h> --------------------------------------------------*/
#ifndef SMCOMMON_INCD
#define SMCOMMON_INCD
/***************************************************************************
Define Definition
***************************************************************************/
#define SMSUCCESS 0x0000 /* SUCCESS */
#define ERROR 0xFFFF /* ERROR */
#define CORRECT 0x0001 /* CORRECTABLE */
/***************************************************************************/
#define NO_ERROR 0x0000 /* NO ERROR */
#define ERR_WriteFault 0x0003 /* Peripheral Device Write Fault */
#define ERR_HwError 0x0004 /* Hardware Error */
#define ERR_DataStatus 0x0010 /* DataStatus Error */
#define ERR_EccReadErr 0x0011 /* Unrecovered Read Error */
#define ERR_CorReadErr 0x0018 /* Recovered Read Data with ECC */
#define ERR_OutOfLBA 0x0021 /* Illegal Logical Block Address */
#define ERR_WrtProtect 0x0027 /* Write Protected */
#define ERR_ChangedMedia 0x0028 /* Medium Changed */
#define ERR_UnknownMedia 0x0030 /* Incompatible Medium Installed */
#define ERR_IllegalFmt 0x0031 /* Medium Format Corrupted */
#define ERR_NoSmartMedia 0x003A /* Medium Not Present */
/***************************************************************************/
#endif
/*----- < smil.h> ----------------------------------------------------*/
#ifndef SMIL_INCD
#define SMIL_INCD
/***************************************************************************
Define Definition
***************************************************************************/
#define K_BYTE 1024 /* Kilo Byte */
#define SECTSIZE 512 /* Sector buffer size */
#define REDTSIZE 16 /* Redundant buffer size */
/***************************************************************************/
#define DUMMY_DATA 0xFF /* No Assign Sector Read Data */
/***************************************************************************
Max Zone/Block/Sectors Data Definition
***************************************************************************/
#define MAX_ZONENUM 128 /* Max Zone Numbers in a SmartMedia */
#define MAX_BLOCKNUM 0x0400 /* Max Block Numbers in a Zone */
#define MAX_SECTNUM 0x20 /* Max Sector Numbers in a Block */
#define MAX_LOGBLOCK 1000 /* Max Logical Block Numbers in a Zone */
/***************************************************************************/
#define CIS_SEARCH_SECT 0x08 /* Max CIS Search Sector Number */
/***************************************************************************
Logical to Physical Block Table Data Definition
***************************************************************************/
#define NO_ASSIGN 0xFFFF /* No Assign Logical Block Address */
/***************************************************************************
'SectCopyMode' Data
***************************************************************************/
#define COMPLETED 0 /* Sector Copy Completed */
#define REQ_ERASE 1 /* Request Read Block Erase */
#define REQ_FAIL 2 /* Request Read Block Failed */
/***************************************************************************
Retry Counter Definition
***************************************************************************/
#define RDERR_REASSIGN 1 /* Reassign with Read Error */
#define L2P_ERR_ERASE 1 /* BlockErase for Contradicted L2P Table */
/***************************************************************************
Hardware ECC Definition
***************************************************************************/
#define HW_ECC_SUPPORTED 1 /* Hardware ECC Supported */
/* No definition for Software ECC */
/***************************************************************************
SmartMedia Command & Status Definition
***************************************************************************/
/* SmartMedia Command */
#define WRDATA 0x80
/* #define READ 0x00 */
#define READ_REDT 0x50
/* #define WRITE 0x10 */
#define RDSTATUS 0x70
#define READ1 0x00 /* NO */
#define READ2 0x01 /* NO */
#define READ3 0x50 /* NO */
#define RST_CHIP 0xFF
#define ERASE1 0x60
#define ERASE2 0xD0
#define READ_ID_1 0x90
#define READ_ID_2 0x91
#define READ_ID_3 0x9A
/* 712 SmartMedia Command */
#define SM_CMD_RESET 0x00 /* 0xFF */
#define SM_CMD_READ_ID_1 0x10 /* 0x90 */
#define SM_CMD_READ_ID_2 0x20 /* 0x91 */
#define SM_CMD_READ_STAT 0x30 /* 0x70 */
#define SM_CMD_RDMULTPL_STAT 0x40 /* 0x71 */
#define SM_CMD_READ_1 0x50 /* 0x00 */
#define SM_CMD_READ_2 0x60 /* 0x01 */
#define SM_CMD_READ_3 0x70 /* 0x50 */
#define SM_CMD_PAGPRGM_TRUE 0x80 /* {0x80, 0x10} */
#define SM_CMD_PAGPRGM_DUMY 0x90 /* {0x80, 0x11} */
#define SM_CMD_PAGPRGM_MBLK 0xA0 /* {0x80, 0x15} */
#define SM_CMD_BLKERASE 0xB0 /* {0x60, 0xD0} */
#define SM_CMD_BLKERASE_MULTPL 0xC0 /* {0x60-0x60, 0xD0} */
#define SM_CRADDTCT_DEBNCETIMER_EN 0x02
#define SM_CMD_START_BIT 0x01
#define SM_WaitCmdDone { while (!SM_CmdDone); }
#define SM_WaitDmaDone { while (!SM_DmaDone); }
/* SmartMedia Status */
#define WR_FAIL 0x01 /* 0:Pass, 1:Fail */
#define SUSPENDED 0x20 /* 0:Not Suspended, 1:Suspended */
#define READY 0x40 /* 0:Busy, 1:Ready */
#define WR_PRTCT 0x80 /* 0:Protect, 1:Not Protect */
/* SmartMedia Busy Time (1bit:0.1ms) */
#define BUSY_PROG 200 /* tPROG : 20ms ----- Program Time old : 200 */
#define BUSY_ERASE 4000 /* tBERASE : 400ms ----- Block Erase Time old : 4000 */
/*for 712 Test */
/* #define BUSY_READ 1 *//* tR : 100us ----- Data transfer Time old : 1 */
/* #define BUSY_READ 10 *//* tR : 100us ----- Data transfer Time old : 1 */
#define BUSY_READ 200 /* tR : 20ms ----- Data transfer Time old : 1 */
/* #define BUSY_RESET 60 *//* tRST : 6ms ----- Device Resetting Time old : 60 */
#define BUSY_RESET 600 /* tRST : 60ms ----- Device Resetting Time old : 60 */
/* Hardware Timer (1bit:0.1ms) */
#define TIME_PON 3000 /* 300ms ------ Power On Wait Time */
#define TIME_CDCHK 200 /* 20ms ------ Card Check Interval Timer */
#define TIME_WPCHK 50 /* 5ms ------ WP Check Interval Timer */
#define TIME_5VCHK 10 /* 1ms ------ 5V Check Interval Timer */
/***************************************************************************
Redundant Data
***************************************************************************/
#define REDT_DATA 0x04
#define REDT_BLOCK 0x05
#define REDT_ADDR1H 0x06
#define REDT_ADDR1L 0x07
#define REDT_ADDR2H 0x0B
#define REDT_ADDR2L 0x0C
#define REDT_ECC10 0x0D
#define REDT_ECC11 0x0E
#define REDT_ECC12 0x0F
#define REDT_ECC20 0x08
#define REDT_ECC21 0x09
#define REDT_ECC22 0x0A
/***************************************************************************
SmartMedia Model & Attribute
***************************************************************************/
/* SmartMedia Attribute */
#define NOWP 0x00 /* 0... .... No Write Protect */
#define WP 0x80 /* 1... .... Write Protected */
#define MASK 0x00 /* .00. .... NAND MASK ROM Model */
#define FLASH 0x20 /* .01. .... NAND Flash ROM Model */
#define AD3CYC 0x00 /* ...0 .... Address 3-cycle */
#define AD4CYC 0x10 /* ...1 .... Address 4-cycle */
#define BS16 0x00 /* .... 00.. 16page/block */
#define BS32 0x04 /* .... 01.. 32page/block */
#define PS256 0x00 /* .... ..00 256byte/page */
#define PS512 0x01 /* .... ..01 512byte/page */
#define MWP 0x80 /* WriteProtect mask */
#define MFLASH 0x60 /* Flash Rom mask */
#define MADC 0x10 /* Address Cycle */
#define MBS 0x0C /* BlockSize mask */
#define MPS 0x03 /* PageSize mask */
/* SmartMedia Model */
#define NOSSFDC 0x00 /* NO SmartMedia */
#define SSFDC1MB 0x01 /* 1MB SmartMedia */
#define SSFDC2MB 0x02 /* 2MB SmartMedia */
#define SSFDC4MB 0x03 /* 4MB SmartMedia */
#define SSFDC8MB 0x04 /* 8MB SmartMedia */
#define SSFDC16MB 0x05 /* 16MB SmartMedia */
#define SSFDC32MB 0x06 /* 32MB SmartMedia */
#define SSFDC64MB 0x07 /* 64MB SmartMedia */
#define SSFDC128MB 0x08 /*128MB SmartMedia */
#define SSFDC256MB 0x09
#define SSFDC512MB 0x0A
#define SSFDC1GB 0x0B
#define SSFDC2GB 0x0C
/***************************************************************************
Struct Definition
***************************************************************************/
struct keucr_media_info {
u8 Model;
u8 Attribute;
u8 MaxZones;
u8 MaxSectors;
u16 MaxBlocks;
u16 MaxLogBlocks;
};
struct keucr_media_address {
u8 Zone; /* Zone Number */
u8 Sector; /* Sector(512byte) Number on Block */
u16 PhyBlock; /* Physical Block Number on Zone */
u16 LogBlock; /* Logical Block Number of Zone */
};
struct keucr_media_area {
u8 Sector; /* Sector(512byte) Number on Block */
u16 PhyBlock; /* Physical Block Number on Zone 0 */
};
extern u16 ReadBlock;
extern u16 WriteBlock;
extern u32 MediaChange;
extern struct keucr_media_info Ssfdc;
extern struct keucr_media_address Media;
extern struct keucr_media_area CisArea;
/*
* SMILMain.c
*/
/******************************************/
int Init_D_SmartMedia(void);
int Pwoff_D_SmartMedia(void);
int Check_D_SmartMedia(void);
int Check_D_MediaFmt(struct us_data *);
int Check_D_Parameter(struct us_data *, u16 *, u8 *, u8 *);
int Media_D_ReadSector(struct us_data *, u32, u16, u8 *);
int Media_D_WriteSector(struct us_data *, u32, u16, u8 *);
int Media_D_CopySector(struct us_data *, u32, u16, u8 *);
int Media_D_EraseBlock(struct us_data *, u32, u16);
int Media_D_EraseAll(struct us_data *);
/******************************************/
int Media_D_OneSectWriteStart(struct us_data *, u32, u8 *);
int Media_D_OneSectWriteNext(struct us_data *, u8 *);
int Media_D_OneSectWriteFlush(struct us_data *);
/******************************************/
extern int SM_FreeMem(void); /* ENE SM function */
void SM_EnableLED(struct us_data *, bool);
void Led_D_TernOn(void);
void Led_D_TernOff(void);
int Media_D_EraseAllRedtData(u32 Index, bool CheckBlock);
/*DWORD Media_D_GetMediaInfo(struct us_data * fdoExt,
PIOCTL_MEDIA_INFO_IN pParamIn, PIOCTL_MEDIA_INFO_OUT pParamOut); */
/*
* SMILSub.c
*/
/******************************************/
int Check_D_DataBlank(u8 *);
int Check_D_FailBlock(u8 *);
int Check_D_DataStatus(u8 *);
int Load_D_LogBlockAddr(u8 *);
void Clr_D_RedundantData(u8 *);
void Set_D_LogBlockAddr(u8 *);
void Set_D_FailBlock(u8 *);
void Set_D_DataStaus(u8 *);
/******************************************/
void Ssfdc_D_Reset(struct us_data *);
int Ssfdc_D_ReadCisSect(struct us_data *, u8 *, u8 *);
void Ssfdc_D_WriteRedtMode(void);
void Ssfdc_D_ReadID(u8 *, u8);
int Ssfdc_D_ReadSect(struct us_data *, u8 *, u8 *);
int Ssfdc_D_ReadBlock(struct us_data *, u16, u8 *, u8 *);
int Ssfdc_D_WriteSect(struct us_data *, u8 *, u8 *);
int Ssfdc_D_WriteBlock(struct us_data *, u16, u8 *, u8 *);
int Ssfdc_D_CopyBlock(struct us_data *, u16, u8 *, u8 *);
int Ssfdc_D_WriteSectForCopy(struct us_data *, u8 *, u8 *);
int Ssfdc_D_EraseBlock(struct us_data *);
int Ssfdc_D_ReadRedtData(struct us_data *, u8 *);
int Ssfdc_D_WriteRedtData(struct us_data *, u8 *);
int Ssfdc_D_CheckStatus(void);
int Set_D_SsfdcModel(u8);
void Cnt_D_Reset(void);
int Cnt_D_PowerOn(void);
void Cnt_D_PowerOff(void);
void Cnt_D_LedOn(void);
void Cnt_D_LedOff(void);
int Check_D_CntPower(void);
int Check_D_CardExist(void);
int Check_D_CardStsChg(void);
int Check_D_SsfdcWP(void);
int SM_ReadBlock(struct us_data *, u8 *, u8 *);
int Ssfdc_D_ReadSect_DMA(struct us_data *, u8 *, u8 *);
int Ssfdc_D_ReadSect_PIO(struct us_data *, u8 *, u8 *);
int Ssfdc_D_WriteSect_DMA(struct us_data *, u8 *, u8 *);
int Ssfdc_D_WriteSect_PIO(struct us_data *, u8 *, u8 *);
/******************************************/
int Check_D_ReadError(u8 *);
int Check_D_Correct(u8 *, u8 *);
int Check_D_CISdata(u8 *, u8 *);
void Set_D_RightECC(u8 *);
/*
* SMILECC.c
*/
void calculate_ecc(u8 *, u8 *, u8 *, u8 *, u8 *);
u8 correct_data(u8 *, u8 *, u8, u8, u8);
int _Correct_D_SwECC(u8 *, u8 *, u8 *);
void _Calculate_D_SwECC(u8 *, u8 *);
#endif /* already included */
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
/* #include "stdlib.h" */
/* #include "EUCR6SK.h" */
#include "smcommon.h"
#include "smil.h"
/* #include <stdio.h> */
/* #include <stdlib.h> */
/* #include <string.h> */
/* #include <dos.h> */
/* #include "EMCRIOS.h" */
/* CP0-CP5 code table */
static u8 ecctable[256] = {
0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F, 0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03,
0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, 0x3F, 0x6A,
0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69,
0x3C, 0x3C, 0x69, 0x6A, 0x3F, 0x65, 0x30, 0x33, 0x66, 0x03, 0x56, 0x55, 0x00,
0x5A, 0x0F, 0x0C, 0x59, 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03, 0x69,
0x3C, 0x3F, 0x6A, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F,
0x3C, 0x69, 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00,
0x55, 0x0F, 0x5A, 0x59, 0x0C, 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55,
0x55, 0x00, 0x03, 0x56, 0x0C, 0x59, 0x5A, 0x0F, 0x6A, 0x3F, 0x3C, 0x69, 0x33,
0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F, 0x6A, 0x6A, 0x3F,
0x3C, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F,
0x6A, 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56,
0x0C, 0x59, 0x5A, 0x0F, 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, 0x56,
0x03, 0x00, 0x55, 0x0F, 0x5A, 0x59, 0x0C, 0x69, 0x3C, 0x3F, 0x6A, 0x30, 0x65,
0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F, 0x3C, 0x69, 0x03, 0x56, 0x55,
0x00, 0x5A, 0x0F, 0x0C, 0x59, 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03,
0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69, 0x3C, 0x3C, 0x69, 0x6A, 0x3F, 0x65,
0x30, 0x33, 0x66, 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, 0x3F, 0x6A,
0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, 0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F,
0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03, 0x56, 0x55, 0x00
};
static void trans_result(u8, u8, u8 *, u8 *);
#define BIT7 0x80
#define BIT6 0x40
#define BIT5 0x20
#define BIT4 0x10
#define BIT3 0x08
#define BIT2 0x04
#define BIT1 0x02
#define BIT0 0x01
#define BIT1BIT0 0x03
#define BIT23 0x00800000L
#define MASK_CPS 0x3f
#define CORRECTABLE 0x00555554L
/*
* reg2; * LP14,LP12,LP10,...
* reg3; * LP15,LP13,LP11,...
* *ecc1; * LP15,LP14,LP13,...
* *ecc2; * LP07,LP06,LP05,...
*/
static void trans_result(u8 reg2, u8 reg3, u8 *ecc1, u8 *ecc2)
{
u8 a; /* Working for reg2,reg3 */
u8 b; /* Working for ecc1,ecc2 */
u8 i; /* For counting */
a = BIT7; b = BIT7; /* 80h=10000000b */
*ecc1 = *ecc2 = 0; /* Clear ecc1,ecc2 */
for (i = 0; i < 4; ++i) {
if ((reg3&a) != 0)
*ecc1 |= b; /* LP15,13,11,9 -> ecc1 */
b = b>>1; /* Right shift */
if ((reg2&a) != 0)
*ecc1 |= b; /* LP14,12,10,8 -> ecc1 */
b = b>>1; /* Right shift */
a = a>>1; /* Right shift */
}
b = BIT7; /* 80h=10000000b */
for (i = 0; i < 4; ++i) {
if ((reg3&a) != 0)
*ecc2 |= b; /* LP7,5,3,1 -> ecc2 */
b = b>>1; /* Right shift */
if ((reg2&a) != 0)
*ecc2 |= b; /* LP6,4,2,0 -> ecc2 */
b = b>>1; /* Right shift */
a = a>>1; /* Right shift */
}
}
/*static void calculate_ecc(table,data,ecc1,ecc2,ecc3) */
/*
* *table; * CP0-CP5 code table
* *data; * DATA
* *ecc1; * LP15,LP14,LP13,...
* *ecc2; * LP07,LP06,LP05,...
* *ecc3; * CP5,CP4,CP3,...,"1","1"
*/
void calculate_ecc(u8 *table, u8 *data, u8 *ecc1, u8 *ecc2, u8 *ecc3)
{
u32 i; /* For counting */
u8 a; /* Working for table */
u8 reg1; /* D-all,CP5,CP4,CP3,... */
u8 reg2; /* LP14,LP12,L10,... */
u8 reg3; /* LP15,LP13,L11,... */
reg1 = reg2 = reg3 = 0; /* Clear parameter */
for (i = 0; i < 256; ++i) {
a = table[data[i]]; /* Get CP0-CP5 code from table */
reg1 ^= (a&MASK_CPS); /* XOR with a */
if ((a&BIT6) != 0) { /* If D_all(all bit XOR) = 1 */
reg3 ^= (u8)i; /* XOR with counter */
reg2 ^= ~((u8)i); /* XOR with inv. of counter */
}
}
/* Trans LP14,12,10,... & LP15,13,11,... ->
LP15,14,13,... & LP7,6,5,.. */
trans_result(reg2, reg3, ecc1, ecc2);
*ecc1 = ~(*ecc1); *ecc2 = ~(*ecc2); /* Inv. ecc2 & ecc3 */
*ecc3 = ((~reg1)<<2)|BIT1BIT0; /* Make TEL format */
}
/*
* *data; * DATA
* *eccdata; * ECC DATA
* ecc1; * LP15,LP14,LP13,...
* ecc2; * LP07,LP06,LP05,...
* ecc3; * CP5,CP4,CP3,...,"1","1"
*/
u8 correct_data(u8 *data, u8 *eccdata, u8 ecc1, u8 ecc2, u8 ecc3)
{
u32 l; /* Working to check d */
u32 d; /* Result of comparison */
u32 i; /* For counting */
u8 d1, d2, d3; /* Result of comparison */
u8 a; /* Working for add */
u8 add; /* Byte address of cor. DATA */
u8 b; /* Working for bit */
u8 bit; /* Bit address of cor. DATA */
d1 = ecc1^eccdata[1]; d2 = ecc2^eccdata[0]; /* Compare LP's */
d3 = ecc3^eccdata[2]; /* Compare CP's */
d = ((u32)d1<<16) /* Result of comparison */
+((u32)d2<<8)
+(u32)d3;
if (d == 0)
return 0; /* If No error, return */
if (((d^(d>>1))&CORRECTABLE) == CORRECTABLE) { /* If correctable */
l = BIT23;
add = 0; /* Clear parameter */
a = BIT7;
for (i = 0; i < 8; ++i) { /* Checking 8 bit */
if ((d&l) != 0)
add |= a; /* Make byte address from LP's */
l >>= 2; a >>= 1; /* Right Shift */
}
bit = 0; /* Clear parameter */
b = BIT2;
for (i = 0; i < 3; ++i) { /* Checking 3 bit */
if ((d&l) != 0)
bit |= b; /* Make bit address from CP's */
l >>= 2; b >>= 1; /* Right shift */
}
b = BIT0;
data[add] ^= (b<<bit); /* Put corrected data */
return 1;
}
i = 0; /* Clear count */
d &= 0x00ffffffL; /* Masking */
while (d) { /* If d=0 finish counting */
if (d&BIT0)
++i; /* Count number of 1 bit */
d >>= 1; /* Right shift */
}
if (i == 1) { /* If ECC error */
eccdata[1] = ecc1; eccdata[0] = ecc2; /* Put right ECC code */
eccdata[2] = ecc3;
return 2;
}
return 3; /* Uncorrectable error */
}
int _Correct_D_SwECC(u8 *buf, u8 *redundant_ecc, u8 *calculate_ecc)
{
u32 err;
err = correct_data(buf, redundant_ecc, *(calculate_ecc + 1),
*(calculate_ecc), *(calculate_ecc + 2));
if (err == 1)
memcpy(calculate_ecc, redundant_ecc, 3);
if (err == 0 || err == 1 || err == 2)
return 0;
return -1;
}
void _Calculate_D_SwECC(u8 *buf, u8 *ecc)
{
calculate_ecc(ecctable, buf, ecc+1, ecc+0, ecc+2);
}
#include <linux/slab.h>
#include "usb.h"
#include "scsiglue.h"
#include "smcommon.h"
#include "smil.h"
static int Conv_D_MediaAddr(struct us_data *, u32);
static int Inc_D_MediaAddr(struct us_data *);
static int Media_D_ReadOneSect(struct us_data *, u16, u8 *);
static int Copy_D_BlockAll(struct us_data *, u32);
static int Assign_D_WriteBlock(void);
static int Release_D_ReadBlock(struct us_data *);
static int Release_D_WriteBlock(struct us_data *);
static int Release_D_CopySector(struct us_data *);
static int Copy_D_PhyOneSect(struct us_data *);
static int Read_D_PhyOneSect(struct us_data *, u16, u8 *);
static int Erase_D_PhyOneBlock(struct us_data *);
static int Set_D_PhyFmtValue(struct us_data *);
static int Search_D_CIS(struct us_data *);
static int Make_D_LogTable(struct us_data *);
static int MarkFail_D_PhyOneBlock(struct us_data *);
static u32 ErrCode;
static u8 WorkBuf[SECTSIZE];
static u8 Redundant[REDTSIZE];
static u8 WorkRedund[REDTSIZE];
/* 128 x 1000, Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; */
static u16 *Log2Phy[MAX_ZONENUM];
static u8 Assign[MAX_ZONENUM][MAX_BLOCKNUM / 8];
static u16 AssignStart[MAX_ZONENUM];
u16 ReadBlock;
u16 WriteBlock;
u32 MediaChange;
static u32 SectCopyMode;
/* BIT Control Macro */
static u8 BitData[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
#define Set_D_Bit(a, b) (a[(u8)((b) / 8)] |= BitData[(b) % 8])
#define Clr_D_Bit(a, b) (a[(u8)((b) / 8)] &= ~BitData[(b) % 8])
#define Chk_D_Bit(a, b) (a[(u8)((b) / 8)] & BitData[(b) % 8])
/* ----- SM_FreeMem() ------------------------------------------------- */
int SM_FreeMem(void)
{
int i;
pr_info("SM_FreeMem start\n");
for (i = 0; i < MAX_ZONENUM; i++) {
if (Log2Phy[i] != NULL) {
pr_info("Free Zone = %x, Addr = %p\n", i, Log2Phy[i]);
kfree(Log2Phy[i]);
Log2Phy[i] = NULL;
}
}
return NO_ERROR;
}
/* SmartMedia Read/Write/Erase Function */
/* ----- Media_D_ReadSector() ------------------------------------------- */
int Media_D_ReadSector(struct us_data *us, u32 start, u16 count, u8 *buf)
{
u16 len, bn;
if (Conv_D_MediaAddr(us, start))
return ErrCode;
while (1) {
len = Ssfdc.MaxSectors - Media.Sector;
if (count > len)
bn = len;
else
bn = count;
if (Media_D_ReadOneSect(us, bn, buf)) {
ErrCode = ERR_EccReadErr;
return ErrCode;
}
Media.Sector += bn;
count -= bn;
if (count <= 0)
break;
buf += bn * SECTSIZE;
if (Inc_D_MediaAddr(us))
return ErrCode;
}
return NO_ERROR;
}
/* here */
/* ----- Media_D_CopySector() ------------------------------------------ */
int Media_D_CopySector(struct us_data *us, u32 start, u16 count, u8 *buf)
{
u16 len, bn;
/* pr_info("Media_D_CopySector !!!\n"); */
if (Conv_D_MediaAddr(us, start))
return ErrCode;
while (1) {
if (Assign_D_WriteBlock())
return ERROR;
len = Ssfdc.MaxSectors - Media.Sector;
if (count > len)
bn = len;
else
bn = count;
if (Ssfdc_D_CopyBlock(us, bn, buf, Redundant)) {
ErrCode = ERR_WriteFault;
return ErrCode;
}
Media.Sector = 0x1F;
if (Release_D_CopySector(us)) {
if (ErrCode == ERR_HwError) {
ErrCode = ERR_WriteFault;
return ErrCode;
}
}
count -= bn;
if (count <= 0)
break;
buf += bn * SECTSIZE;
if (Inc_D_MediaAddr(us))
return ErrCode;
}
return NO_ERROR;
}
/* SmartMedia Physical Format Test Subroutine */
/* ----- Check_D_MediaFmt() --------------------------------------------- */
int Check_D_MediaFmt(struct us_data *us)
{
pr_info("Check_D_MediaFmt\n");
if (!MediaChange)
return SMSUCCESS;
MediaChange = ERROR;
SectCopyMode = COMPLETED;
if (Set_D_PhyFmtValue(us)) {
ErrCode = ERR_UnknownMedia;
return ERROR;
}
if (Search_D_CIS(us)) {
ErrCode = ERR_IllegalFmt;
return ERROR;
}
MediaChange = SMSUCCESS;
return SMSUCCESS;
}
/* ----- Release_D_CopySector() ------------------------------------------ */
static int Release_D_CopySector(struct us_data *us)
{
Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock;
Media.PhyBlock = ReadBlock;
if (Media.PhyBlock == NO_ASSIGN) {
Media.PhyBlock = WriteBlock;
return SMSUCCESS;
}
Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock);
Media.PhyBlock = WriteBlock;
return SMSUCCESS;
}
/* SmartMedia Physical Address Control Subroutine */
/* ----- Conv_D_MediaAddr() --------------------------------------------- */
static int Conv_D_MediaAddr(struct us_data *us, u32 addr)
{
u32 temp;
temp = addr / Ssfdc.MaxSectors;
Media.Zone = (u8) (temp / Ssfdc.MaxLogBlocks);
if (Log2Phy[Media.Zone] == NULL) {
if (Make_D_LogTable(us)) {
ErrCode = ERR_IllegalFmt;
return ERROR;
}
}
Media.Sector = (u8) (addr % Ssfdc.MaxSectors);
Media.LogBlock = (u16) (temp % Ssfdc.MaxLogBlocks);
if (Media.Zone < Ssfdc.MaxZones) {
Clr_D_RedundantData(Redundant);
Set_D_LogBlockAddr(Redundant);
Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
return SMSUCCESS;
}
ErrCode = ERR_OutOfLBA;
return ERROR;
}
/* ----- Inc_D_MediaAddr() ---------------------------------------------- */
static int Inc_D_MediaAddr(struct us_data *us)
{
u16 LogBlock = Media.LogBlock;
if (++Media.Sector < Ssfdc.MaxSectors)
return SMSUCCESS;
if (Log2Phy[Media.Zone] == NULL) {
if (Make_D_LogTable(us)) {
ErrCode = ERR_IllegalFmt;
return ERROR;
}
}
Media.Sector = 0;
Media.LogBlock = LogBlock;
if (++Media.LogBlock < Ssfdc.MaxLogBlocks) {
Clr_D_RedundantData(Redundant);
Set_D_LogBlockAddr(Redundant);
Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
return SMSUCCESS;
}
Media.LogBlock = 0;
if (++Media.Zone < Ssfdc.MaxZones) {
if (Log2Phy[Media.Zone] == NULL) {
if (Make_D_LogTable(us)) {
ErrCode = ERR_IllegalFmt;
return ERROR;
}
}
Media.LogBlock = 0;
Clr_D_RedundantData(Redundant);
Set_D_LogBlockAddr(Redundant);
Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
return SMSUCCESS;
}
Media.Zone = 0;
ErrCode = ERR_OutOfLBA;
return ERROR;
}
/* SmartMedia Read/Write Subroutine with Retry */
/* ----- Media_D_ReadOneSect() ------------------------------------------ */
static int Media_D_ReadOneSect(struct us_data *us, u16 count, u8 *buf)
{
u32 err, retry;
if (!Read_D_PhyOneSect(us, count, buf))
return SMSUCCESS;
if (ErrCode == ERR_HwError)
return ERROR;
if (ErrCode == ERR_DataStatus)
return ERROR;
#ifdef RDERR_REASSIGN
if (Ssfdc.Attribute & MWP) {
if (ErrCode == ERR_CorReadErr)
return SMSUCCESS;
return ERROR;
}
err = ErrCode;
for (retry = 0; retry < 2; retry++) {
if (Copy_D_BlockAll(us,
(err == ERR_EccReadErr) ? REQ_FAIL : REQ_ERASE)) {
if (ErrCode == ERR_HwError)
return ERROR;
continue;
}
ErrCode = err;
if (ErrCode == ERR_CorReadErr)
return SMSUCCESS;
return ERROR;
}
MediaChange = ERROR;
#else
if (ErrCode == ERR_CorReadErr)
return SMSUCCESS;
#endif
return ERROR;
}
/* SmartMedia Physical Sector Data Copy Subroutine */
/* ----- Copy_D_BlockAll() ---------------------------------------------- */
static int Copy_D_BlockAll(struct us_data *us, u32 mode)
{
u8 sect;
sect = Media.Sector;
if (Assign_D_WriteBlock())
return ERROR;
if (mode == REQ_FAIL)
SectCopyMode = REQ_FAIL;
for (Media.Sector = 0; Media.Sector < Ssfdc.MaxSectors;
Media.Sector++) {
if (Copy_D_PhyOneSect(us)) {
if (ErrCode == ERR_HwError)
return ERROR;
if (Release_D_WriteBlock(us))
return ERROR;
ErrCode = ERR_WriteFault;
Media.PhyBlock = ReadBlock;
Media.Sector = sect;
return ERROR;
}
}
if (Release_D_ReadBlock(us))
return ERROR;
Media.PhyBlock = WriteBlock;
Media.Sector = sect;
return SMSUCCESS;
}
/* SmartMedia Physical Block Assign/Release Subroutine */
/* ----- Assign_D_WriteBlock() ------------------------------------------ */
static int Assign_D_WriteBlock(void)
{
ReadBlock = Media.PhyBlock;
for (WriteBlock = AssignStart[Media.Zone];
WriteBlock < Ssfdc.MaxBlocks; WriteBlock++) {
if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) {
Set_D_Bit(Assign[Media.Zone], WriteBlock);
AssignStart[Media.Zone] = WriteBlock + 1;
Media.PhyBlock = WriteBlock;
SectCopyMode = REQ_ERASE;
return SMSUCCESS;
}
}
for (WriteBlock = 0;
WriteBlock < AssignStart[Media.Zone]; WriteBlock++) {
if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) {
Set_D_Bit(Assign[Media.Zone], WriteBlock);
AssignStart[Media.Zone] = WriteBlock + 1;
Media.PhyBlock = WriteBlock;
SectCopyMode = REQ_ERASE;
return SMSUCCESS;
}
}
WriteBlock = NO_ASSIGN;
ErrCode = ERR_WriteFault;
return ERROR;
}
/* ----- Release_D_ReadBlock() ------------------------------------------ */
static int Release_D_ReadBlock(struct us_data *us)
{
u32 mode;
mode = SectCopyMode;
SectCopyMode = COMPLETED;
if (mode == COMPLETED)
return SMSUCCESS;
Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock;
Media.PhyBlock = ReadBlock;
if (Media.PhyBlock == NO_ASSIGN) {
Media.PhyBlock = WriteBlock;
return SMSUCCESS;
}
if (mode == REQ_ERASE) {
if (Erase_D_PhyOneBlock(us)) {
if (ErrCode == ERR_HwError)
return ERROR;
if (MarkFail_D_PhyOneBlock(us))
return ERROR;
} else
Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock);
} else if (MarkFail_D_PhyOneBlock(us))
return ERROR;
Media.PhyBlock = WriteBlock;
return SMSUCCESS;
}
/* ----- Release_D_WriteBlock() ----------------------------------------- */
static int Release_D_WriteBlock(struct us_data *us)
{
SectCopyMode = COMPLETED;
Media.PhyBlock = WriteBlock;
if (MarkFail_D_PhyOneBlock(us))
return ERROR;
Media.PhyBlock = ReadBlock;
return SMSUCCESS;
}
/* SmartMedia Physical Sector Data Copy Subroutine */
/* ----- Copy_D_PhyOneSect() -------------------------------------------- */
static int Copy_D_PhyOneSect(struct us_data *us)
{
int i;
u32 err, retry;
/* pr_info("Copy_D_PhyOneSect --- Sector = %x\n", Media.Sector); */
if (ReadBlock != NO_ASSIGN) {
Media.PhyBlock = ReadBlock;
for (retry = 0; retry < 2; retry++) {
if (retry != 0) {
Ssfdc_D_Reset(us);
if (Ssfdc_D_ReadCisSect(us, WorkBuf,
WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Check_D_CISdata(WorkBuf, WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
}
if (Ssfdc_D_ReadSect(us, WorkBuf, WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Check_D_DataStatus(WorkRedund)) {
err = ERROR;
break;
}
if (!Check_D_ReadError(WorkRedund)) {
err = SMSUCCESS;
break;
}
if (!Check_D_Correct(WorkBuf, WorkRedund)) {
err = SMSUCCESS;
break;
}
err = ERROR;
SectCopyMode = REQ_FAIL;
}
} else {
err = SMSUCCESS;
for (i = 0; i < SECTSIZE; i++)
WorkBuf[i] = DUMMY_DATA;
Clr_D_RedundantData(WorkRedund);
}
Set_D_LogBlockAddr(WorkRedund);
if (err == ERROR) {
Set_D_RightECC(WorkRedund);
Set_D_DataStaus(WorkRedund);
}
Media.PhyBlock = WriteBlock;
if (Ssfdc_D_WriteSectForCopy(us, WorkBuf, WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Ssfdc_D_CheckStatus()) {
ErrCode = ERR_WriteFault;
return ERROR;
}
Media.PhyBlock = ReadBlock;
return SMSUCCESS;
}
/* SmartMedia Physical Sector Read/Write/Erase Subroutine */
/* ----- Read_D_PhyOneSect() -------------------------------------------- */
static int Read_D_PhyOneSect(struct us_data *us, u16 count, u8 *buf)
{
int i;
u32 retry;
if (Media.PhyBlock == NO_ASSIGN) {
for (i = 0; i < SECTSIZE; i++)
*buf++ = DUMMY_DATA;
return SMSUCCESS;
}
for (retry = 0; retry < 2; retry++) {
if (retry != 0) {
Ssfdc_D_Reset(us);
if (Ssfdc_D_ReadCisSect(us, WorkBuf, WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Check_D_CISdata(WorkBuf, WorkRedund)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
}
if (Ssfdc_D_ReadBlock(us, count, buf, Redundant)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Check_D_DataStatus(Redundant)) {
ErrCode = ERR_DataStatus;
return ERROR;
}
if (!Check_D_ReadError(Redundant))
return SMSUCCESS;
if (!Check_D_Correct(buf, Redundant)) {
ErrCode = ERR_CorReadErr;
return ERROR;
}
}
ErrCode = ERR_EccReadErr;
return ERROR;
}
/* ----- Erase_D_PhyOneBlock() ------------------------------------------ */
static int Erase_D_PhyOneBlock(struct us_data *us)
{
if (Ssfdc_D_EraseBlock(us)) {
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
}
if (Ssfdc_D_CheckStatus()) {
ErrCode = ERR_WriteFault;
return ERROR;
}
return SMSUCCESS;
}
/* SmartMedia Physical Format Check Local Subroutine */
/* ----- Set_D_PhyFmtValue() -------------------------------------------- */
static int Set_D_PhyFmtValue(struct us_data *us)
{
if (Set_D_SsfdcModel(us->SM_DeviceID))
return ERROR;
return SMSUCCESS;
}
/* ----- Search_D_CIS() ------------------------------------------------- */
static int Search_D_CIS(struct us_data *us)
{
Media.Zone = 0;
Media.Sector = 0;
for (Media.PhyBlock = 0;
Media.PhyBlock < (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1);
Media.PhyBlock++) {
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
if (!Check_D_FailBlock(Redundant))
break;
}
if (Media.PhyBlock == (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1)) {
Ssfdc_D_Reset(us);
return ERROR;
}
while (Media.Sector < CIS_SEARCH_SECT) {
if (Media.Sector) {
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
}
if (!Check_D_DataStatus(Redundant)) {
if (Ssfdc_D_ReadSect(us, WorkBuf, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
if (Check_D_CISdata(WorkBuf, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
CisArea.PhyBlock = Media.PhyBlock;
CisArea.Sector = Media.Sector;
Ssfdc_D_Reset(us);
return SMSUCCESS;
}
Media.Sector++;
}
Ssfdc_D_Reset(us);
return ERROR;
}
/* ----- Make_D_LogTable() ---------------------------------------------- */
static int Make_D_LogTable(struct us_data *us)
{
u16 phyblock, logblock;
if (Log2Phy[Media.Zone] == NULL) {
Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK * sizeof(u16),
GFP_KERNEL);
/* pr_info("ExAllocatePool Zone = %x, Addr = %x\n",
Media.Zone, Log2Phy[Media.Zone]); */
if (Log2Phy[Media.Zone] == NULL)
return ERROR;
}
Media.Sector = 0;
/* pr_info("Make_D_LogTable --- MediaZone = 0x%x\n",
Media.Zone); */
for (Media.LogBlock = 0; Media.LogBlock < Ssfdc.MaxLogBlocks;
Media.LogBlock++)
Log2Phy[Media.Zone][Media.LogBlock] = NO_ASSIGN;
for (Media.PhyBlock = 0; Media.PhyBlock < (MAX_BLOCKNUM / 8);
Media.PhyBlock++)
Assign[Media.Zone][Media.PhyBlock] = 0x00;
for (Media.PhyBlock = 0; Media.PhyBlock < Ssfdc.MaxBlocks;
Media.PhyBlock++) {
if ((!Media.Zone) && (Media.PhyBlock <= CisArea.PhyBlock)) {
Set_D_Bit(Assign[Media.Zone], Media.PhyBlock);
continue;
}
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
if (!Check_D_DataBlank(Redundant))
continue;
Set_D_Bit(Assign[Media.Zone], Media.PhyBlock);
if (Check_D_FailBlock(Redundant))
continue;
if (Load_D_LogBlockAddr(Redundant))
continue;
if (Media.LogBlock >= Ssfdc.MaxLogBlocks)
continue;
if (Log2Phy[Media.Zone][Media.LogBlock] == NO_ASSIGN) {
Log2Phy[Media.Zone][Media.LogBlock] = Media.PhyBlock;
continue;
}
phyblock = Media.PhyBlock;
logblock = Media.LogBlock;
Media.Sector = (u8)(Ssfdc.MaxSectors - 1);
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
if (!Load_D_LogBlockAddr(Redundant) &&
(Media.LogBlock == logblock)) {
Media.PhyBlock = Log2Phy[Media.Zone][logblock];
if (Ssfdc_D_ReadRedtData(us, Redundant)) {
Ssfdc_D_Reset(us);
return ERROR;
}
Media.PhyBlock = phyblock;
if (!Load_D_LogBlockAddr(Redundant)) {
if (Media.LogBlock != logblock) {
Media.PhyBlock =
Log2Phy[Media.Zone][logblock];
Log2Phy[Media.Zone][logblock] =
phyblock;
}
} else {
Media.PhyBlock = Log2Phy[Media.Zone][logblock];
Log2Phy[Media.Zone][logblock] = phyblock;
}
}
Media.Sector = 0;
Media.PhyBlock = phyblock;
AssignStart[Media.Zone] = 0;
} /* End for (Media.Zone<MAX_ZONENUM) */
Ssfdc_D_Reset(us);
return SMSUCCESS;
}
/* ----- MarkFail_D_PhyOneBlock() --------------------------------------- */
static int MarkFail_D_PhyOneBlock(struct us_data *us)
{
u8 sect;
sect = Media.Sector;
Set_D_FailBlock(WorkRedund);
for (Media.Sector = 0; Media.Sector < Ssfdc.MaxSectors;
Media.Sector++) {
if (Ssfdc_D_WriteRedtData(us, WorkRedund)) {
Ssfdc_D_Reset(us);
Media.Sector = sect;
ErrCode = ERR_HwError;
MediaChange = ERROR;
return ERROR;
} /* NO Status Check */
}
Ssfdc_D_Reset(us);
Media.Sector = sect;
return SMSUCCESS;
}
#include <linux/slab.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
#include "smcommon.h"
#include "smil.h"
static u8 _Check_D_DevCode(u8);
static u32 ErrXDCode;
static u8 IsSSFDCCompliance;
static u8 IsXDCompliance;
struct keucr_media_info Ssfdc;
struct keucr_media_address Media;
struct keucr_media_area CisArea;
static u8 EccBuf[6];
#define EVEN 0 /* Even Page for 256byte/page */
#define ODD 1 /* Odd Page for 256byte/page */
/* SmartMedia Redundant buffer data Control Subroutine
*----- Check_D_DataBlank() --------------------------------------------
*/
int Check_D_DataBlank(u8 *redundant)
{
char i;
for (i = 0; i < REDTSIZE; i++)
if (*redundant++ != 0xFF)
return ERROR;
return SMSUCCESS;
}
/* ----- Check_D_FailBlock() -------------------------------------------- */
int Check_D_FailBlock(u8 *redundant)
{
redundant += REDT_BLOCK;
if (*redundant == 0xFF)
return SMSUCCESS;
if (!*redundant)
return ERROR;
if (hweight8(*redundant) < 7)
return ERROR;
return SMSUCCESS;
}
/* ----- Check_D_DataStatus() ------------------------------------------- */
int Check_D_DataStatus(u8 *redundant)
{
redundant += REDT_DATA;
if (*redundant == 0xFF)
return SMSUCCESS;
if (!*redundant) {
ErrXDCode = ERR_DataStatus;
return ERROR;
} else
ErrXDCode = NO_ERROR;
if (hweight8(*redundant) < 5)
return ERROR;
return SMSUCCESS;
}
/* ----- Load_D_LogBlockAddr() ------------------------------------------ */
int Load_D_LogBlockAddr(u8 *redundant)
{
u16 addr1, addr2;
addr1 = (u16)*(redundant + REDT_ADDR1H)*0x0100 +
(u16)*(redundant + REDT_ADDR1L);
addr2 = (u16)*(redundant + REDT_ADDR2H)*0x0100 +
(u16)*(redundant + REDT_ADDR2L);
if (addr1 == addr2)
if ((addr1 & 0xF000) == 0x1000) {
Media.LogBlock = (addr1 & 0x0FFF) / 2;
return SMSUCCESS;
}
if (hweight16((u16)(addr1^addr2)) != 0x01)
return ERROR;
if ((addr1 & 0xF000) == 0x1000)
if (!(hweight16(addr1) & 0x01)) {
Media.LogBlock = (addr1 & 0x0FFF) / 2;
return SMSUCCESS;
}
if ((addr2 & 0xF000) == 0x1000)
if (!(hweight16(addr2) & 0x01)) {
Media.LogBlock = (addr2 & 0x0FFF) / 2;
return SMSUCCESS;
}
return ERROR;
}
/* ----- Clr_D_RedundantData() ------------------------------------------ */
void Clr_D_RedundantData(u8 *redundant)
{
char i;
for (i = 0; i < REDTSIZE; i++)
*(redundant + i) = 0xFF;
}
/* ----- Set_D_LogBlockAddr() ------------------------------------------- */
void Set_D_LogBlockAddr(u8 *redundant)
{
u16 addr;
*(redundant + REDT_BLOCK) = 0xFF;
*(redundant + REDT_DATA) = 0xFF;
addr = Media.LogBlock*2 + 0x1000;
if ((hweight16(addr) % 2))
addr++;
*(redundant + REDT_ADDR1H) = *(redundant + REDT_ADDR2H) =
(u8)(addr / 0x0100);
*(redundant + REDT_ADDR1L) = *(redundant + REDT_ADDR2L) = (u8)addr;
}
/*----- Set_D_FailBlock() ---------------------------------------------- */
void Set_D_FailBlock(u8 *redundant)
{
char i;
for (i = 0; i < REDTSIZE; i++)
*redundant++ = (u8)((i == REDT_BLOCK) ? 0xF0 : 0xFF);
}
/* ----- Set_D_DataStaus() ---------------------------------------------- */
void Set_D_DataStaus(u8 *redundant)
{
redundant += REDT_DATA;
*redundant = 0x00;
}
/* SmartMedia Function Command Subroutine
* 6250 CMD 6
*/
/* ----- Ssfdc_D_Reset() ------------------------------------------------ */
void Ssfdc_D_Reset(struct us_data *us)
{
return;
}
/* ----- Ssfdc_D_ReadCisSect() ------------------------------------------ */
int Ssfdc_D_ReadCisSect(struct us_data *us, u8 *buf, u8 *redundant)
{
u8 zone, sector;
u16 block;
zone = Media.Zone; block = Media.PhyBlock; sector = Media.Sector;
Media.Zone = 0;
Media.PhyBlock = CisArea.PhyBlock;
Media.Sector = CisArea.Sector;
if (Ssfdc_D_ReadSect(us, buf, redundant)) {
Media.Zone = zone;
Media.PhyBlock = block;
Media.Sector = sector;
return ERROR;
}
Media.Zone = zone; Media.PhyBlock = block; Media.Sector = sector;
return SMSUCCESS;
}
/* 6250 CMD 1 */
/* ----- Ssfdc_D_ReadSect() --------------------------------------------- */
int Ssfdc_D_ReadSect(struct us_data *us, u8 *buf, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Read sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[4] = (u8)addr;
bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* Read redundant */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[4] = (u8)addr;
bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
result = ENE_SendScsiCmd(us, FDIR_READ, redundant, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- Ssfdc_D_ReadBlock() --------------------------------------------- */
int Ssfdc_D_ReadBlock(struct us_data *us, u16 count, u8 *buf,
u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Read sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*count;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[4] = (u8)addr;
bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* Read redundant */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[4] = (u8)addr;
bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
result = ENE_SendScsiCmd(us, FDIR_READ, redundant, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- Ssfdc_D_CopyBlock() -------------------------------------------- */
int Ssfdc_D_CopyBlock(struct us_data *us, u16 count, u8 *buf,
u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 ReadAddr, WriteAddr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
ReadAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + ReadBlock;
ReadAddr = ReadAddr*(u16)Ssfdc.MaxSectors;
WriteAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + WriteBlock;
WriteAddr = WriteAddr*(u16)Ssfdc.MaxSectors;
/* Write sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200*count;
bcb->Flags = 0x00;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x08;
bcb->CDB[7] = (u8)WriteAddr;
bcb->CDB[6] = (u8)(WriteAddr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
bcb->CDB[10] = Media.Sector;
if (ReadBlock != NO_ASSIGN) {
bcb->CDB[4] = (u8)ReadAddr;
bcb->CDB[3] = (u8)(ReadAddr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
} else
bcb->CDB[11] = 1;
result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- Ssfdc_D_WriteSectForCopy() ------------------------------------- */
int Ssfdc_D_WriteSectForCopy(struct us_data *us, u8 *buf, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
/* Write sect data */
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x00;
bcb->CDB[0] = 0xF0;
bcb->CDB[1] = 0x04;
bcb->CDB[7] = (u8)addr;
bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* 6250 CMD 5 */
/* ----- Ssfdc_D_EraseBlock() ------------------------------------------- */
int Ssfdc_D_EraseBlock(struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x06;
bcb->CDB[7] = (u8)addr;
bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* 6250 CMD 2 */
/*----- Ssfdc_D_ReadRedtData() ----------------------------------------- */
int Ssfdc_D_ReadRedtData(struct us_data *us, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
u8 *buf;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[4] = (u8)addr;
bcb->CDB[3] = (u8)(addr / 0x0100);
bcb->CDB[2] = Media.Zone / 2;
bcb->CDB[8] = 0;
bcb->CDB[9] = 1;
buf = kmalloc(0x10, GFP_KERNEL);
result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
memcpy(redundant, buf, 0x10);
kfree(buf);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* 6250 CMD 4 */
/* ----- Ssfdc_D_WriteRedtData() ---------------------------------------- */
int Ssfdc_D_WriteRedtData(struct us_data *us, u8 *redundant)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result;
u16 addr;
result = ENE_LoadBinCode(us, SM_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
dev_err(&us->pusb_dev->dev,
"Failed to load SmartMedia read/write code\n");
return USB_STOR_TRANSPORT_ERROR;
}
addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x10;
bcb->Flags = 0x80;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x05;
bcb->CDB[7] = (u8)addr;
bcb->CDB[6] = (u8)(addr / 0x0100);
bcb->CDB[5] = Media.Zone / 2;
bcb->CDB[8] = *(redundant + REDT_ADDR1H);
bcb->CDB[9] = *(redundant + REDT_ADDR1L);
result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- Ssfdc_D_CheckStatus() ------------------------------------------ */
int Ssfdc_D_CheckStatus(void)
{
return SMSUCCESS;
}
/* SmartMedia ID Code Check & Mode Set Subroutine
* ----- Set_D_SsfdcModel() ---------------------------------------------
*/
int Set_D_SsfdcModel(u8 dcode)
{
switch (_Check_D_DevCode(dcode)) {
case SSFDC1MB:
Ssfdc.Model = SSFDC1MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS256;
Ssfdc.MaxZones = 1;
Ssfdc.MaxBlocks = 256;
Ssfdc.MaxLogBlocks = 250;
Ssfdc.MaxSectors = 8;
break;
case SSFDC2MB:
Ssfdc.Model = SSFDC2MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS256;
Ssfdc.MaxZones = 1;
Ssfdc.MaxBlocks = 512;
Ssfdc.MaxLogBlocks = 500;
Ssfdc.MaxSectors = 8;
break;
case SSFDC4MB:
Ssfdc.Model = SSFDC4MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS512;
Ssfdc.MaxZones = 1;
Ssfdc.MaxBlocks = 512;
Ssfdc.MaxLogBlocks = 500;
Ssfdc.MaxSectors = 16;
break;
case SSFDC8MB:
Ssfdc.Model = SSFDC8MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS512;
Ssfdc.MaxZones = 1;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 16;
break;
case SSFDC16MB:
Ssfdc.Model = SSFDC16MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS32 | PS512;
Ssfdc.MaxZones = 1;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC32MB:
Ssfdc.Model = SSFDC32MB;
Ssfdc.Attribute = FLASH | AD3CYC | BS32 | PS512;
Ssfdc.MaxZones = 2;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC64MB:
Ssfdc.Model = SSFDC64MB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 4;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC128MB:
Ssfdc.Model = SSFDC128MB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 8;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC256MB:
Ssfdc.Model = SSFDC256MB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 16;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC512MB:
Ssfdc.Model = SSFDC512MB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 32;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC1GB:
Ssfdc.Model = SSFDC1GB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 64;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
case SSFDC2GB:
Ssfdc.Model = SSFDC2GB;
Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
Ssfdc.MaxZones = 128;
Ssfdc.MaxBlocks = 1024;
Ssfdc.MaxLogBlocks = 1000;
Ssfdc.MaxSectors = 32;
break;
default:
Ssfdc.Model = NOSSFDC;
return ERROR;
}
return SMSUCCESS;
}
/* ----- _Check_D_DevCode() --------------------------------------------- */
static u8 _Check_D_DevCode(u8 dcode)
{
switch (dcode) {
case 0x6E:
case 0xE8:
case 0xEC: return SSFDC1MB; /* 8Mbit (1M) NAND */
case 0x64:
case 0xEA: return SSFDC2MB; /* 16Mbit (2M) NAND */
case 0x6B:
case 0xE3:
case 0xE5: return SSFDC4MB; /* 32Mbit (4M) NAND */
case 0xE6: return SSFDC8MB; /* 64Mbit (8M) NAND */
case 0x73: return SSFDC16MB; /* 128Mbit (16M)NAND */
case 0x75: return SSFDC32MB; /* 256Mbit (32M)NAND */
case 0x76: return SSFDC64MB; /* 512Mbit (64M)NAND */
case 0x79: return SSFDC128MB; /* 1Gbit(128M)NAND */
case 0x71: return SSFDC256MB;
case 0xDC: return SSFDC512MB;
case 0xD3: return SSFDC1GB;
case 0xD5: return SSFDC2GB;
default: return NOSSFDC;
}
}
/* SmartMedia ECC Control Subroutine
* ----- Check_D_ReadError() ----------------------------------------------
*/
int Check_D_ReadError(u8 *redundant)
{
return SMSUCCESS;
}
/* ----- Check_D_Correct() ---------------------------------------------- */
int Check_D_Correct(u8 *buf, u8 *redundant)
{
return SMSUCCESS;
}
/* ----- Check_D_CISdata() ---------------------------------------------- */
int Check_D_CISdata(u8 *buf, u8 *redundant)
{
u8 cis[] = {0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02,
0xDF, 0x01, 0x20};
int cis_len = sizeof(cis);
if (!IsSSFDCCompliance && !IsXDCompliance)
return SMSUCCESS;
if (!memcmp(redundant + 0x0D, EccBuf, 3))
return memcmp(buf, cis, cis_len);
if (!_Correct_D_SwECC(buf, redundant + 0x0D, EccBuf))
return memcmp(buf, cis, cis_len);
buf += 0x100;
if (!memcmp(redundant + 0x08, EccBuf + 0x03, 3))
return memcmp(buf, cis, cis_len);
if (!_Correct_D_SwECC(buf, redundant + 0x08, EccBuf + 0x03))
return memcmp(buf, cis, cis_len);
return ERROR;
}
/* ----- Set_D_RightECC() ---------------------------------------------- */
void Set_D_RightECC(u8 *redundant)
{
/* Driver ECC Check */
return;
}
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
#include "smil.h"
static int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb);
static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb);
static int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb);
static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb);
static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb);
static int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb);
/* ----- SM_SCSIIrp() -------------------------------------------------- */
int SM_SCSIIrp(struct us_data *us, struct scsi_cmnd *srb)
{
int result;
us->SrbStatus = SS_SUCCESS;
switch (srb->cmnd[0]) {
case TEST_UNIT_READY:
result = SM_SCSI_Test_Unit_Ready(us, srb);
break; /* 0x00 */
case INQUIRY:
result = SM_SCSI_Inquiry(us, srb);
break; /* 0x12 */
case MODE_SENSE:
result = SM_SCSI_Mode_Sense(us, srb);
break; /* 0x1A */
case READ_CAPACITY:
result = SM_SCSI_Read_Capacity(us, srb);
break; /* 0x25 */
case READ_10:
result = SM_SCSI_Read(us, srb);
break; /* 0x28 */
case WRITE_10:
result = SM_SCSI_Write(us, srb);
break; /* 0x2A */
default:
us->SrbStatus = SS_ILLEGAL_REQUEST;
result = USB_STOR_TRANSPORT_FAILED;
break;
}
return result;
}
/* ----- SM_SCSI_Test_Unit_Ready() ------------------------------------- */
static int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb)
{
if (us->SM_Status.Insert && us->SM_Status.Ready)
return USB_STOR_TRANSPORT_GOOD;
else {
ENE_SMInit(us);
return USB_STOR_TRANSPORT_GOOD;
}
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- SM_SCSI_Inquiry() --------------------------------------------- */
static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb)
{
u8 data_ptr[36] = {0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x55, 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20,
0x20, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65,
0x61, 0x64, 0x65, 0x72, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30};
usb_stor_set_xfer_buf(us, data_ptr, 36, srb, TO_XFER_BUF);
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- SM_SCSI_Mode_Sense() ------------------------------------------ */
static int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb)
{
u8 mediaNoWP[12] = {0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
u8 mediaWP[12] = {0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
if (us->SM_Status.WtP)
usb_stor_set_xfer_buf(us, mediaWP, 12, srb, TO_XFER_BUF);
else
usb_stor_set_xfer_buf(us, mediaNoWP, 12, srb, TO_XFER_BUF);
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- SM_SCSI_Read_Capacity() --------------------------------------- */
static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
u32 bl_num;
u16 bl_len;
u8 buf[8];
dev_dbg(&us->pusb_dev->dev, "SM_SCSI_Read_Capacity\n");
bl_len = 0x200;
bl_num = Ssfdc.MaxLogBlocks * Ssfdc.MaxSectors * Ssfdc.MaxZones - 1;
us->bl_num = bl_num;
dev_dbg(&us->pusb_dev->dev, "bl_len = %x\n", bl_len);
dev_dbg(&us->pusb_dev->dev, "bl_num = %x\n", bl_num);
buf[0] = (bl_num >> 24) & 0xff;
buf[1] = (bl_num >> 16) & 0xff;
buf[2] = (bl_num >> 8) & 0xff;
buf[3] = (bl_num >> 0) & 0xff;
buf[4] = (bl_len >> 24) & 0xff;
buf[5] = (bl_len >> 16) & 0xff;
buf[6] = (bl_len >> 8) & 0xff;
buf[7] = (bl_len >> 0) & 0xff;
usb_stor_access_xfer_buf(us, buf, 8, srb, &sg, &offset, TO_XFER_BUF);
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- SM_SCSI_Read() -------------------------------------------------- */
static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
{
int result = 0;
u8 *Cdb = srb->cmnd;
u32 bn = ((Cdb[2] << 24) & 0xff000000) |
((Cdb[3] << 16) & 0x00ff0000) |
((Cdb[4] << 8) & 0x0000ff00) |
((Cdb[5] << 0) & 0x000000ff);
u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
u32 blenByte = blen * 0x200;
void *buf;
if (bn > us->bl_num)
return USB_STOR_TRANSPORT_ERROR;
buf = kmalloc(blenByte, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
result = Media_D_ReadSector(us, bn, blen, buf);
usb_stor_set_xfer_buf(us, buf, blenByte, srb, TO_XFER_BUF);
kfree(buf);
if (!result)
return USB_STOR_TRANSPORT_GOOD;
else
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
/* ----- SM_SCSI_Write() -------------------------------------------------- */
static int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
{
int result = 0;
u8 *Cdb = srb->cmnd;
u32 bn = ((Cdb[2] << 24) & 0xff000000) |
((Cdb[3] << 16) & 0x00ff0000) |
((Cdb[4] << 8) & 0x0000ff00) |
((Cdb[5] << 0) & 0x000000ff);
u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
u32 blenByte = blen * 0x200;
void *buf;
if (bn > us->bl_num)
return USB_STOR_TRANSPORT_ERROR;
buf = kmalloc(blenByte, GFP_KERNEL);
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
usb_stor_set_xfer_buf(us, buf, blenByte, srb, FROM_XFER_BUF);
result = Media_D_CopySector(us, bn, blen, buf);
kfree(buf);
if (!result)
return USB_STOR_TRANSPORT_GOOD;
else
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
}
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
/***********************************************************************
* Data transfer routines
***********************************************************************/
/*
* usb_stor_blocking_completion()
*/
static void usb_stor_blocking_completion(struct urb *urb)
{
struct completion *urb_done_ptr = urb->context;
/* pr_info("transport --- usb_stor_blocking_completion\n"); */
complete(urb_done_ptr);
}
/*
* usb_stor_msg_common()
*/
static int usb_stor_msg_common(struct us_data *us, int timeout)
{
struct completion urb_done;
long timeleft;
int status;
/* pr_info("transport --- usb_stor_msg_common\n"); */
if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return -EIO;
init_completion(&urb_done);
us->current_urb->context = &urb_done;
us->current_urb->actual_length = 0;
us->current_urb->error_count = 0;
us->current_urb->status = 0;
us->current_urb->transfer_flags = 0;
if (us->current_urb->transfer_buffer == us->iobuf)
us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
us->current_urb->transfer_dma = us->iobuf_dma;
us->current_urb->setup_dma = us->cr_dma;
status = usb_submit_urb(us->current_urb, GFP_NOIO);
if (status)
return status;
set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
/* pr_info("-- cancelling URB\n"); */
usb_unlink_urb(us->current_urb);
}
}
timeleft = wait_for_completion_interruptible_timeout(&urb_done,
timeout ? : MAX_SCHEDULE_TIMEOUT);
clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
if (timeleft <= 0) {
/* pr_info("%s -- cancelling URB\n",
timeleft == 0 ? "Timeout" : "Signal"); */
usb_kill_urb(us->current_urb);
}
return us->current_urb->status;
}
/*
* usb_stor_print_cmd():
*/
static void usb_stor_print_cmd(struct us_data *us, struct scsi_cmnd *srb)
{
u8 *Cdb = srb->cmnd;
u32 cmd = Cdb[0];
switch (cmd) {
case TEST_UNIT_READY:
break;
case INQUIRY:
dev_dbg(&us->pusb_dev->dev,
"scsi cmd %X --- SCSIOP_INQUIRY\n", cmd);
break;
case MODE_SENSE:
dev_dbg(&us->pusb_dev->dev,
"scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd);
break;
case START_STOP:
dev_dbg(&us->pusb_dev->dev,
"scsi cmd %X --- SCSIOP_START_STOP\n", cmd);
break;
case READ_CAPACITY:
dev_dbg(&us->pusb_dev->dev,
"scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd);
break;
case READ_10:
break;
case WRITE_10:
break;
case ALLOW_MEDIUM_REMOVAL:
dev_dbg(&us->pusb_dev->dev,
"scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd);
break;
default:
dev_dbg(&us->pusb_dev->dev, "scsi cmd %X --- Other cmd\n", cmd);
break;
}
}
/*
* usb_stor_control_msg()
*/
int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout)
{
int status;
/* pr_info("transport --- usb_stor_control_msg\n"); */
/* fill in the devrequest structure */
us->cr->bRequestType = requesttype;
us->cr->bRequest = request;
us->cr->wValue = cpu_to_le16(value);
us->cr->wIndex = cpu_to_le16(index);
us->cr->wLength = cpu_to_le16(size);
/* fill and submit the URB */
usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
(unsigned char *) us->cr, data, size,
usb_stor_blocking_completion, NULL);
status = usb_stor_msg_common(us, timeout);
/* return the actual length of the data transferred if no error */
if (status == 0)
status = us->current_urb->actual_length;
return status;
}
/*
* usb_stor_clear_halt()
*/
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe);
/* pr_info("transport --- usb_stor_clear_halt\n"); */
if (usb_pipein(pipe))
endp |= USB_DIR_IN;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, endp,
NULL, 0, 3*HZ);
/* reset the endpoint toggle */
if (result >= 0)
/* usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), 0); */
usb_reset_endpoint(us->pusb_dev, endp);
return result;
}
/*
* interpret_urb_result()
*/
static int interpret_urb_result(struct us_data *us, unsigned int pipe,
unsigned int length, int result, unsigned int partial)
{
/* pr_info("transport --- interpret_urb_result\n"); */
switch (result) {
/* no error code; did we send all the data? */
case 0:
if (partial != length) {
/* pr_info("-- short transfer\n"); */
return USB_STOR_XFER_SHORT;
}
/* pr_info("-- transfer complete\n"); */
return USB_STOR_XFER_GOOD;
case -EPIPE:
if (usb_pipecontrol(pipe)) {
/* pr_info("-- stall on control pipe\n"); */
return USB_STOR_XFER_STALLED;
}
/* pr_info("clearing endpoint halt for pipe 0x%x\n", pipe); */
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
case -EOVERFLOW:
/* pr_info("-- babble\n"); */
return USB_STOR_XFER_LONG;
case -ECONNRESET:
/* pr_info("-- transfer cancelled\n"); */
return USB_STOR_XFER_ERROR;
case -EREMOTEIO:
/* pr_info("-- short read transfer\n"); */
return USB_STOR_XFER_SHORT;
case -EIO:
/* pr_info("-- abort or disconnect in progress\n"); */
return USB_STOR_XFER_ERROR;
default:
/* pr_info("-- unknown error\n"); */
return USB_STOR_XFER_ERROR;
}
}
/*
* usb_stor_bulk_transfer_buf()
*/
int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len)
{
int result;
/* pr_info("transport --- usb_stor_bulk_transfer_buf\n"); */
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf,
length, usb_stor_blocking_completion, NULL);
result = usb_stor_msg_common(us, 0);
/* store the actual length of the data transferred */
if (act_len)
*act_len = us->current_urb->actual_length;
return interpret_urb_result(us, pipe, length, result,
us->current_urb->actual_length);
}
/*
* usb_stor_bulk_transfer_sglist()
*/
static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
struct scatterlist *sg, int num_sg, unsigned int length,
unsigned int *act_len)
{
int result;
/* pr_info("transport --- usb_stor_bulk_transfer_sglist\n"); */
if (test_bit(US_FLIDX_ABORTING, &us->dflags))
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, GFP_NOIO);
if (result) {
/* pr_info("usb_sg_init returned %d\n", result); */
return USB_STOR_XFER_ERROR;
}
/* since the block has been initialized successfully,
it's now okay to cancel it */
set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
/* did an abort/disconnect occur during the submission? */
if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
/* pr_info("-- cancelling sg request\n"); */
usb_sg_cancel(&us->current_sg);
}
}
/* wait for the completion of the transfer */
usb_sg_wait(&us->current_sg);
clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
result = us->current_sg.status;
if (act_len)
*act_len = us->current_sg.bytes;
return interpret_urb_result(us, pipe, length,
result, us->current_sg.bytes);
}
/*
* usb_stor_bulk_srb()
*/
int usb_stor_bulk_srb(struct us_data *us, unsigned int pipe,
struct scsi_cmnd *srb)
{
unsigned int partial;
int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
scsi_sg_count(srb), scsi_bufflen(srb),
&partial);
scsi_set_resid(srb, scsi_bufflen(srb) - partial);
return result;
}
/*
* usb_stor_bulk_transfer_sg()
*/
int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length_left, int use_sg, int *residual)
{
int result;
unsigned int partial;
/* pr_info("transport --- usb_stor_bulk_transfer_sg\n"); */
/* are we scatter-gathering? */
if (use_sg) {
/* use the usb core scatter-gather primitives */
result = usb_stor_bulk_transfer_sglist(us, pipe,
(struct scatterlist *) buf, use_sg,
length_left, &partial);
length_left -= partial;
} else {
/* no scatter-gather, just make the request */
result = usb_stor_bulk_transfer_buf(us, pipe, buf,
length_left, &partial);
length_left -= partial;
}
/* store the residual and return the error code */
if (residual)
*residual = length_left;
return result;
}
/***********************************************************************
* Transport routines
***********************************************************************/
/*
* usb_stor_invoke_transport()
*/
void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int need_auto_sense;
int result;
/* pr_info("transport --- usb_stor_invoke_transport\n"); */
usb_stor_print_cmd(us, srb);
/* send the command to the transport layer */
scsi_set_resid(srb, 0);
result = us->transport(srb, us); /* usb_stor_Bulk_transport; */
/* if the command gets aborted by the higher layers,
we need to short-circuit all other processing */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
/* pr_info("-- command was aborted\n"); */
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
/* pr_info("-- transport indicates error, resetting\n"); */
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
return;
}
srb->result = SAM_STAT_GOOD;
/* Determine if we need to auto-sense */
need_auto_sense = 0;
if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
srb->sc_data_direction != DMA_FROM_DEVICE) {
/* pr_info("-- CB transport device requiring auto-sense\n"); */
need_auto_sense = 1;
}
if (result == USB_STOR_TRANSPORT_FAILED) {
/* pr_info("-- transport indicates command failure\n"); */
need_auto_sense = 1;
}
/* Now, if we need to do the auto-sense, let's do it */
if (need_auto_sense) {
int temp_result;
struct scsi_eh_save ses;
pr_info("Issuing auto-REQUEST_SENSE\n");
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
/* we must do the protocol translation here */
if (us->subclass == USB_SC_RBC ||
us->subclass == USB_SC_SCSI ||
us->subclass == USB_SC_CYP_ATACB) {
srb->cmd_len = 6;
} else {
srb->cmd_len = 12;
}
/* issue the auto-sense command */
scsi_set_resid(srb, 0);
temp_result = us->transport(us->srb, us);
/* let's clean up right away */
scsi_eh_restore_cmnd(srb, &ses);
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
/* pr_info("-- auto-sense aborted\n"); */
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
/* pr_info("-- auto-sense failure\n"); */
srb->result = DID_ERROR << 16;
if (!(us->fflags & US_FL_SCM_MULT_TARG))
goto Handle_Errors;
return;
}
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
if (result == USB_STOR_TRANSPORT_GOOD &&
(srb->sense_buffer[2] & 0xaf) == 0 &&
srb->sense_buffer[12] == 0 &&
srb->sense_buffer[13] == 0) {
srb->result = SAM_STAT_GOOD;
srb->sense_buffer[0] = 0x0;
}
}
/* Did we transfer less than the minimum amount required? */
if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) -
scsi_get_resid(srb) < srb->underflow)
srb->result = (DID_ERROR << 16);
/* v02 | (SUGGEST_RETRY << 24); */
return;
Handle_Errors:
scsi_lock(us_to_host(us));
set_bit(US_FLIDX_RESETTING, &us->dflags);
clear_bit(US_FLIDX_ABORTING, &us->dflags);
scsi_unlock(us_to_host(us));
mutex_unlock(&us->dev_mutex);
result = usb_stor_port_reset(us);
mutex_lock(&us->dev_mutex);
if (result < 0) {
scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us);
scsi_unlock(us_to_host(us));
us->transport_reset(us);
}
clear_bit(US_FLIDX_RESETTING, &us->dflags);
}
/*
* ENE_stor_invoke_transport()
*/
void ENE_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result = 0;
/* pr_info("transport --- ENE_stor_invoke_transport\n"); */
usb_stor_print_cmd(us, srb);
/* send the command to the transport layer */
scsi_set_resid(srb, 0);
if (!(us->SM_Status.Ready))
result = ENE_InitMedia(us);
if (us->Power_IsResum == true) {
result = ENE_InitMedia(us);
us->Power_IsResum = false;
}
if (us->SM_Status.Ready)
result = SM_SCSIIrp(us, srb);
/* if the command gets aborted by the higher layers,
we need to short-circuit all other processing */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
/* pr_info("-- command was aborted\n"); */
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
/* pr_info("-- transport indicates error, resetting\n"); */
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
return;
}
srb->result = SAM_STAT_GOOD;
if (result == USB_STOR_TRANSPORT_FAILED) {
/* pr_info("-- transport indicates command failure\n"); */
/* need_auto_sense = 1; */
BuildSenseBuffer(srb, us->SrbStatus);
srb->result = SAM_STAT_CHECK_CONDITION;
}
/* Did we transfer less than the minimum amount required? */
if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) -
scsi_get_resid(srb) < srb->underflow)
srb->result = (DID_ERROR << 16);
/* v02 | (SUGGEST_RETRY << 24); */
return;
Handle_Errors:
scsi_lock(us_to_host(us));
set_bit(US_FLIDX_RESETTING, &us->dflags);
clear_bit(US_FLIDX_ABORTING, &us->dflags);
scsi_unlock(us_to_host(us));
mutex_unlock(&us->dev_mutex);
result = usb_stor_port_reset(us);
mutex_lock(&us->dev_mutex);
if (result < 0) {
scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us);
scsi_unlock(us_to_host(us));
us->transport_reset(us);
}
clear_bit(US_FLIDX_RESETTING, &us->dflags);
}
/*
* BuildSenseBuffer()
*/
void BuildSenseBuffer(struct scsi_cmnd *srb, int SrbStatus)
{
u8 *buf = srb->sense_buffer;
u8 asc;
pr_info("transport --- BuildSenseBuffer\n");
switch (SrbStatus) {
case SS_NOT_READY:
asc = 0x3a;
break; /* sense key = 0x02 */
case SS_MEDIUM_ERR:
asc = 0x0c;
break; /* sense key = 0x03 */
case SS_ILLEGAL_REQUEST:
asc = 0x20;
break; /* sense key = 0x05 */
default:
asc = 0x00;
break; /* ?? */
}
memset(buf, 0, 18);
buf[0x00] = 0xf0;
buf[0x02] = SrbStatus;
buf[0x07] = 0x0b;
buf[0x0c] = asc;
}
/*
* usb_stor_stop_transport()
*/
void usb_stor_stop_transport(struct us_data *us)
{
/* pr_info("transport --- usb_stor_stop_transport\n"); */
if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
/* pr_info("-- cancelling URB\n"); */
usb_unlink_urb(us->current_urb);
}
if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
/* pr_info("-- cancelling sg request\n"); */
usb_sg_cancel(&us->current_sg);
}
}
/*
* usb_stor_Bulk_max_lun()
*/
int usb_stor_Bulk_max_lun(struct us_data *us)
{
int result;
/* pr_info("transport --- usb_stor_Bulk_max_lun\n"); */
/* issue the command */
us->iobuf[0] = 0;
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
US_BULK_GET_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
0, us->ifnum, us->iobuf, 1, HZ);
/* pr_info("GetMaxLUN command result is %d, data is %d\n",
result, us->iobuf[0]); */
/* if we have a successful request, return the result */
if (result > 0)
return us->iobuf[0];
return 0;
}
/*
* usb_stor_Bulk_transport()
*/
int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
unsigned int transfer_length = scsi_bufflen(srb);
unsigned int residue;
int result;
int fake_sense = 0;
unsigned int cswlen;
unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
/* pr_info("transport --- usb_stor_Bulk_transport\n"); */
/* Take care of BULK32 devices; set extra byte to 0 */
if (unlikely(us->fflags & US_FL_BULK32)) {
cbwlen = 32;
us->iobuf[31] = 0;
}
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
if (us->fflags & US_FL_SCM_MULT_TARG)
bcb->Lun |= srb->device->id << 4;
bcb->Length = srb->cmd_len;
/* copy the command payload */
memset(bcb->CDB, 0, sizeof(bcb->CDB));
memcpy(bcb->CDB, srb->cmnd, bcb->Length);
/* send command */
/* send it to out endpoint */
/* pr_info("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
le32_to_cpu(bcb->Signature), bcb->Tag,
le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
(bcb->Lun >> 4), (bcb->Lun & 0x0F),
bcb->Length); */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
bcb, cbwlen, NULL);
/* pr_info("Bulk command transfer result=%d\n", result); */
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (unlikely(us->fflags & US_FL_GO_SLOW))
udelay(125);
/* R/W data */
if (transfer_length) {
unsigned int pipe;
if (srb->sc_data_direction == DMA_FROM_DEVICE)
pipe = us->recv_bulk_pipe;
else
pipe = us->send_bulk_pipe;
result = usb_stor_bulk_srb(us, pipe, srb);
/* pr_info("Bulk data transfer result 0x%x\n", result); */
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
if (result == USB_STOR_XFER_LONG)
fake_sense = 1;
}
/* get CSW for device status */
/* pr_info("Attempting to get CSW...\n"); */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &cswlen);
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
/* pr_info("Received 0-length CSW; retrying...\n"); */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &cswlen);
}
/* did the attempt to read the CSW fail? */
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
/* pr_info("Attempting to get CSW (2nd try)...\n"); */
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, NULL);
}
/* if we still have a failure at this point, we're in trouble */
/* pr_info("Bulk status result = %d\n", result); */
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* check bulk status */
residue = le32_to_cpu(bcs->Residue);
/* pr_info("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
le32_to_cpu(bcs->Signature),
bcs->Tag, residue, bcs->Status); */
if (!(bcs->Tag == us->tag ||
(us->fflags & US_FL_BULK_IGNORE_TAG)) ||
bcs->Status > US_BULK_STAT_PHASE) {
/* pr_info("Bulk logical error\n"); */
return USB_STOR_TRANSPORT_ERROR;
}
if (!us->bcs_signature) {
us->bcs_signature = bcs->Signature;
/* if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN)) */
/* pr_info("Learnt BCS signature 0x%08X\n",
le32_to_cpu(us->bcs_signature)); */
} else if (bcs->Signature != us->bcs_signature) {
/* pr_info("Signature mismatch: got %08X, expecting %08X\n",
le32_to_cpu(bcs->Signature),
le32_to_cpu(us->bcs_signature)); */
return USB_STOR_TRANSPORT_ERROR;
}
/* try to compute the actual residue, based on how much data
* was really transferred and what the device tells us */
if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
/* Heuristically detect devices that generate bogus residues
* by seeing what happens with INQUIRY and READ CAPACITY
* commands.
*/
if (bcs->Status == US_BULK_STAT_OK &&
scsi_get_resid(srb) == 0 &&
((srb->cmnd[0] == INQUIRY &&
transfer_length == 36) ||
(srb->cmnd[0] == READ_CAPACITY &&
transfer_length == 8))) {
us->fflags |= US_FL_IGNORE_RESIDUE;
} else {
residue = min(residue, transfer_length);
scsi_set_resid(srb, max_t(int, scsi_get_resid(srb),
residue));
}
}
/* based on the status code, we report good or bad */
switch (bcs->Status) {
case US_BULK_STAT_OK:
if (fake_sense) {
memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
return USB_STOR_TRANSPORT_NO_SENSE;
}
return USB_STOR_TRANSPORT_GOOD;
case US_BULK_STAT_FAIL:
return USB_STOR_TRANSPORT_FAILED;
case US_BULK_STAT_PHASE:
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_ERROR;
}
/***********************************************************************
* Reset routines
***********************************************************************/
/*
* usb_stor_reset_common()
*/
static int usb_stor_reset_common(struct us_data *us,
u8 request, u8 requesttype,
u16 value, u16 index, void *data, u16 size)
{
int result;
int result2;
/* pr_info("transport --- usb_stor_reset_common\n"); */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
/* pr_info("No reset during disconnect\n"); */
return -EIO;
}
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
request, requesttype, value, index, data, size, 5*HZ);
if (result < 0) {
/* pr_info("Soft reset failed: %d\n", result); */
return result;
}
wait_event_interruptible_timeout(us->delay_wait,
test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6);
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
/* pr_info("Reset interrupted by disconnect\n"); */
return -EIO;
}
/* pr_info("Soft reset: clearing bulk-in endpoint halt\n"); */
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
/* pr_info("Soft reset: clearing bulk-out endpoint halt\n"); */
result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
/* return a result code based on the result of the clear-halts */
if (result >= 0)
result = result2;
/* if (result < 0) */
/* pr_info("Soft reset failed\n"); */
/* else */
/* pr_info("Soft reset done\n"); */
return result;
}
/*
* usb_stor_Bulk_reset()
*/
int usb_stor_Bulk_reset(struct us_data *us)
{
/* pr_info("transport --- usb_stor_Bulk_reset\n"); */
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
}
/*
* usb_stor_port_reset()
*/
int usb_stor_port_reset(struct us_data *us)
{
int result;
/* pr_info("transport --- usb_stor_port_reset\n"); */
result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0)
pr_info("unable to lock device for reset: %d\n", result);
else {
/* Were we disconnected while waiting for the lock? */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
result = -EIO;
/* pr_info("No reset during disconnect\n"); */
} else {
result = usb_reset_device(us->pusb_dev);
/* pr_info("usb_reset_composite_device returns %d\n",
result); */
}
usb_unlock_device(us->pusb_dev);
}
return result;
}
#ifndef _TRANSPORT_H_
#define _TRANSPORT_H_
#include <linux/blkdev.h>
/* usb_stor_bulk_transfer_xxx() return codes, in order of severity */
#define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_LONG 3 /* device tried to send too much */
#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
/* Transport return codes */
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
/*
* We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
* return codes. But now the transport and low-level transfer routines
* treat an abort as just another error (-ENOENT for a cancelled URB).
* It is up to the invoke_transport() function to test for aborts and
* distinguish them from genuine communication errors.
*/
/* CBI accept device specific command */
#define US_CBI_ADSC 0
extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*);
extern int usb_stor_Bulk_max_lun(struct us_data *);
extern int usb_stor_Bulk_reset(struct us_data *);
extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*);
extern void usb_stor_stop_transport(struct us_data *);
extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout);
extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len);
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, int use_sg, int *residual);
extern int usb_stor_bulk_srb(struct us_data *us, unsigned int pipe,
struct scsi_cmnd *srb);
extern int usb_stor_port_reset(struct us_data *us);
/* Protocol handling routines */
enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
extern unsigned int usb_stor_access_xfer_buf(struct us_data*,
unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb,
struct scatterlist **, unsigned int *offset, enum xfer_buf_dir dir);
extern void usb_stor_set_xfer_buf(struct us_data*, unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb,
unsigned int dir);
/*
* ENE scsi function
*/
extern void ENE_stor_invoke_transport(struct scsi_cmnd *, struct us_data *);
extern int ENE_InitMedia(struct us_data *);
extern int ENE_SMInit(struct us_data *);
extern int ENE_SendScsiCmd(struct us_data*, u8, void*, int);
extern int ENE_LoadBinCode(struct us_data*, u8);
extern int ene_read_byte(struct us_data*, u16 index, void *buf);
extern int ENE_Read_Data(struct us_data*, void *buf, unsigned int length);
extern int ENE_Write_Data(struct us_data*, void *buf, unsigned int length);
extern void BuildSenseBuffer(struct scsi_cmnd *, int);
/*
* ENE scsi function
*/
extern int SM_SCSIIrp(struct us_data *us, struct scsi_cmnd *srb);
#endif
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/utsname.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include "usb.h"
#include "scsiglue.h"
#include "smil.h"
#include "transport.h"
/* Some informational data */
MODULE_AUTHOR("Domao");
MODULE_DESCRIPTION("ENE USB Mass Storage driver for Linux");
MODULE_LICENSE("GPL");
static unsigned int delay_use = 1;
static struct usb_device_id eucr_usb_ids[] = {
{ USB_DEVICE(0x058f, 0x6366) },
{ USB_DEVICE(0x0cf2, 0x6230) },
{ USB_DEVICE(0x0cf2, 0x6250) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, eucr_usb_ids);
#ifdef CONFIG_PM
static int eucr_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
pr_info("--- eucr_suspend ---\n");
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
mutex_unlock(&us->dev_mutex);
return 0;
}
static int eucr_resume(struct usb_interface *iface)
{
u8 tmp = 0;
struct us_data *us = usb_get_intfdata(iface);
pr_info("--- eucr_resume---\n");
mutex_lock(&us->dev_mutex);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
mutex_unlock(&us->dev_mutex);
us->Power_IsResum = true;
us->SM_Status = *(struct keucr_sm_status *)&tmp;
return 0;
}
static int eucr_reset_resume(struct usb_interface *iface)
{
u8 tmp = 0;
struct us_data *us = usb_get_intfdata(iface);
pr_info("--- eucr_reset_resume---\n");
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
/*
* FIXME: Notify the subdrivers that they need to reinitialize
* the device
*/
us->Power_IsResum = true;
us->SM_Status = *(struct keucr_sm_status *)&tmp;
return 0;
}
#else
#define eucr_suspend NULL
#define eucr_resume NULL
#define eucr_reset_resume NULL
#endif
static int eucr_pre_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
pr_info("usb --- eucr_pre_reset\n");
/* Make sure no command runs during the reset */
mutex_lock(&us->dev_mutex);
return 0;
}
static int eucr_post_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
pr_info("usb --- eucr_post_reset\n");
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
mutex_unlock(&us->dev_mutex);
return 0;
}
void fill_inquiry_response(struct us_data *us, unsigned char *data,
unsigned int data_len)
{
pr_info("usb --- fill_inquiry_response\n");
if (data_len < 36) /* You lose. */
return;
if (data[0]&0x20) {
memset(data+8, 0, 28);
} else {
u16 bcdDevice =
le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
memcpy(data+8, us->unusual_dev->vendorName,
strlen(us->unusual_dev->vendorName) > 8 ? 8 :
strlen(us->unusual_dev->vendorName));
memcpy(data+16, us->unusual_dev->productName,
strlen(us->unusual_dev->productName) > 16 ? 16 :
strlen(us->unusual_dev->productName));
data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
data[35] = 0x30 + ((bcdDevice) & 0x0F);
}
usb_stor_set_xfer_buf(us, data, data_len, us->srb, TO_XFER_BUF);
}
static int usb_stor_control_thread(void *__us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
pr_info("usb --- usb_stor_control_thread\n");
for (;;) {
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
/* if the device has disconnected, we are free to exit */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
mutex_unlock(&us->dev_mutex);
break;
}
/* lock access to the state */
scsi_lock(host);
/* When we are called with no command pending, we're done */
if (us->srb == NULL) {
scsi_unlock(host);
mutex_unlock(&us->dev_mutex);
break;
}
/* has the command timed out *already* ? */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
us->srb->result = DID_ABORT << 16;
goto SkipForAbort;
}
scsi_unlock(host);
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
us->srb->result = DID_ERROR << 16;
} else if (us->srb->device->id
&& !(us->fflags & US_FL_SCM_MULT_TARG)) {
us->srb->result = DID_BAD_TARGET << 16;
} else if (us->srb->device->lun > us->max_lun) {
us->srb->result = DID_BAD_TARGET << 16;
} else if ((us->srb->cmnd[0] == INQUIRY)
&& (us->fflags & US_FL_FIX_INQUIRY)) {
unsigned char data_ptr[36] = {0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = SAM_STAT_GOOD;
} else {
us->proto_handler(us->srb, us);
}
/* lock access to the state */
scsi_lock(host);
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
us->srb->scsi_done(us->srb);
} else {
SkipForAbort:
pr_info("scsi command aborted\n");
}
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
complete(&(us->notify));
/* Allow USB transfers to resume */
clear_bit(US_FLIDX_ABORTING, &us->dflags);
clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
}
/* finished working on this command */
us->srb = NULL;
scsi_unlock(host);
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
} /* for (;;) */
/* Wait until we are told to stop */
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule();
}
__set_current_state(TASK_RUNNING);
return 0;
}
static int associate_dev(struct us_data *us, struct usb_interface *intf)
{
pr_info("usb --- associate_dev\n");
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
/* Store our private data in the interface */
usb_set_intfdata(intf, us);
/* Allocate the device-related DMA-mapped buffers */
us->cr = usb_alloc_coherent(us->pusb_dev, sizeof(*us->cr), GFP_KERNEL,
&us->cr_dma);
if (!us->cr) {
pr_info("usb_ctrlrequest allocation failed\n");
return -ENOMEM;
}
us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE, GFP_KERNEL,
&us->iobuf_dma);
if (!us->iobuf) {
pr_info("I/O buffer allocation failed\n");
return -ENOMEM;
}
us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL);
if (!us->sensebuf)
return -ENOMEM;
return 0;
}
static int get_device_info(struct us_data *us, const struct usb_device_id *id)
{
struct usb_device *dev = us->pusb_dev;
struct usb_interface_descriptor *idesc =
&us->pusb_intf->cur_altsetting->desc;
pr_info("usb --- get_device_info\n");
us->subclass = idesc->bInterfaceSubClass;
us->protocol = idesc->bInterfaceProtocol;
us->fflags = id->driver_info;
us->Power_IsResum = false;
if (us->fflags & US_FL_IGNORE_DEVICE) {
pr_info("device ignored\n");
return -ENODEV;
}
if (dev->speed != USB_SPEED_HIGH)
us->fflags &= ~US_FL_GO_SLOW;
return 0;
}
static int get_transport(struct us_data *us)
{
pr_info("usb --- get_transport\n");
switch (us->protocol) {
case USB_PR_BULK:
us->transport_name = "Bulk";
us->transport = usb_stor_Bulk_transport;
us->transport_reset = usb_stor_Bulk_reset;
break;
default:
return -EIO;
}
/* fix for single-lun devices */
if (us->fflags & US_FL_SINGLE_LUN)
us->max_lun = 0;
return 0;
}
static int get_protocol(struct us_data *us)
{
pr_info("usb --- get_protocol\n");
pr_info("us->pusb_dev->descriptor.idVendor = %x\n",
us->pusb_dev->descriptor.idVendor);
pr_info("us->pusb_dev->descriptor.idProduct = %x\n",
us->pusb_dev->descriptor.idProduct);
switch (us->subclass) {
case USB_SC_SCSI:
us->protocol_name = "Transparent SCSI";
if ((us->pusb_dev->descriptor.idVendor == 0x0CF2)
&& (us->pusb_dev->descriptor.idProduct == 0x6250))
us->proto_handler = ENE_stor_invoke_transport;
else
us->proto_handler = usb_stor_invoke_transport;
break;
default:
return -EIO;
}
return 0;
}
static int get_pipes(struct us_data *us)
{
struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
int i;
struct usb_endpoint_descriptor *ep;
struct usb_endpoint_descriptor *ep_in = NULL;
struct usb_endpoint_descriptor *ep_out = NULL;
struct usb_endpoint_descriptor *ep_int = NULL;
pr_info("usb --- get_pipes\n");
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
if (usb_endpoint_xfer_bulk(ep)) {
if (usb_endpoint_dir_in(ep)) {
if (!ep_in)
ep_in = ep;
} else {
if (!ep_out)
ep_out = ep;
}
} else if (usb_endpoint_is_int_in(ep)) {
if (!ep_int)
ep_int = ep;
}
}
if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) {
pr_info("Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
/* Calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->ep_bInterval = ep_int->bInterval;
}
return 0;
}
static int usb_stor_acquire_resources(struct us_data *us)
{
struct task_struct *th;
pr_info("usb --- usb_stor_acquire_resources\n");
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
pr_info("URB allocation failed\n");
return -ENOMEM;
}
/* Start up our control thread */
th = kthread_run(usb_stor_control_thread, us, "eucr-storage");
if (IS_ERR(th)) {
pr_info("Unable to start control thread\n");
return PTR_ERR(th);
}
us->ctl_thread = th;
return 0;
}
static void usb_stor_release_resources(struct us_data *us)
{
pr_info("usb --- usb_stor_release_resources\n");
SM_FreeMem();
complete(&us->cmnd_ready);
if (us->ctl_thread)
kthread_stop(us->ctl_thread);
/* Call the destructor routine, if it exists */
if (us->extra_destructor) {
pr_info("-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* Free the extra data and the URB */
kfree(us->extra);
usb_free_urb(us->current_urb);
}
static void dissociate_dev(struct us_data *us)
{
pr_info("usb --- dissociate_dev\n");
kfree(us->sensebuf);
/* Free the device-related DMA-mapped buffers */
usb_free_coherent(us->pusb_dev, sizeof(*us->cr), us->cr, us->cr_dma);
usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
us->iobuf_dma);
/* Remove our private data from the interface */
usb_set_intfdata(us->pusb_intf, NULL);
}
static void quiesce_and_remove_host(struct us_data *us)
{
struct Scsi_Host *host = us_to_host(us);
pr_info("usb --- quiesce_and_remove_host\n");
/* If the device is really gone, cut short reset delays */
if (us->pusb_dev->state == USB_STATE_NOTATTACHED)
set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
/*
* Prevent SCSI-scanning (if it hasn't started yet)
* and wait for the SCSI-scanning thread to stop.
*/
set_bit(US_FLIDX_DONT_SCAN, &us->dflags);
wake_up(&us->delay_wait);
wait_for_completion(&us->scanning_done);
/*
* Removing the host will perform an orderly shutdown: caches
* synchronized, disks spun down, etc.
*/
scsi_remove_host(host);
/*
* Prevent any new commands from being accepted and cut short
* reset delays.
*/
scsi_lock(host);
set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
scsi_unlock(host);
wake_up(&us->delay_wait);
}
static void release_everything(struct us_data *us)
{
pr_info("usb --- release_everything\n");
usb_stor_release_resources(us);
dissociate_dev(us);
scsi_host_put(us_to_host(us));
}
static int usb_stor_scan_thread(void *__us)
{
struct us_data *us = (struct us_data *)__us;
pr_info("usb --- usb_stor_scan_thread\n");
pr_info("EUCR : device found at %d\n", us->pusb_dev->devnum);
set_freezable();
/* Wait for the timeout to expire or for a disconnect */
if (delay_use > 0) {
wait_event_freezable_timeout(us->delay_wait,
test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
delay_use * HZ);
}
/* If the device is still connected, perform the scanning */
if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {
/* For bulk-only devices, determine the max LUN value */
if (us->protocol == USB_PR_BULK
&& !(us->fflags & US_FL_SINGLE_LUN)) {
mutex_lock(&us->dev_mutex);
us->max_lun = usb_stor_Bulk_max_lun(us);
mutex_unlock(&us->dev_mutex);
}
scsi_scan_host(us_to_host(us));
pr_info("EUCR : device scan complete\n");
}
complete_and_exit(&us->scanning_done, 0);
}
static int eucr_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct Scsi_Host *host;
struct us_data *us;
int result;
u8 MiscReg03 = 0;
struct task_struct *th;
pr_info("usb --- eucr_probe\n");
host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
if (!host) {
pr_info("Unable to allocate the scsi host\n");
return -ENOMEM;
}
/* Allow 16-byte CDBs and thus > 2TB */
host->max_cmd_len = 16;
us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
init_completion(&us->scanning_done);
/* Associate the us_data structure with the USB device */
result = associate_dev(us, intf);
if (result)
goto BadDevice;
/* Get Device info */
result = get_device_info(us, id);
if (result)
goto BadDevice;
/* Get the transport, protocol, and pipe settings */
result = get_transport(us);
if (result)
goto BadDevice;
result = get_protocol(us);
if (result)
goto BadDevice;
result = get_pipes(us);
if (result)
goto BadDevice;
/* Acquire all the other resources and add the host */
result = usb_stor_acquire_resources(us);
if (result)
goto BadDevice;
result = scsi_add_host(host, &intf->dev);
if (result) {
pr_info("Unable to add the scsi host\n");
goto BadDevice;
}
/* Start up the thread for delayed SCSI-device scanning */
th = kthread_create(usb_stor_scan_thread, us, "eucr-stor-scan");
if (IS_ERR(th)) {
pr_info("Unable to start the device-scanning thread\n");
complete(&us->scanning_done);
quiesce_and_remove_host(us);
result = PTR_ERR(th);
goto BadDevice;
}
wake_up_process(th);
/* probe card type */
result = ene_read_byte(us, REG_CARD_STATUS, &MiscReg03);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
quiesce_and_remove_host(us);
goto BadDevice;
}
if (!(MiscReg03 & 0x02)) {
result = -ENODEV;
quiesce_and_remove_host(us);
pr_info("keucr: The driver only supports SM/MS card. To use SD card, please build driver/usb/storage/ums-eneub6250.ko\n");
goto BadDevice;
}
return 0;
/* We come here if there are any problems */
BadDevice:
pr_info("usb --- eucr_probe failed\n");
release_everything(us);
return result;
}
static void eucr_disconnect(struct usb_interface *intf)
{
struct us_data *us = usb_get_intfdata(intf);
pr_info("usb --- eucr_disconnect\n");
quiesce_and_remove_host(us);
release_everything(us);
}
/* Initialization and registration */
static struct usb_driver usb_storage_driver = {
.name = "eucr",
.probe = eucr_probe,
.suspend = eucr_suspend,
.resume = eucr_resume,
.reset_resume = eucr_reset_resume,
.disconnect = eucr_disconnect,
.pre_reset = eucr_pre_reset,
.post_reset = eucr_post_reset,
.id_table = eucr_usb_ids,
.soft_unbind = 1,
};
module_usb_driver(usb_storage_driver);
/* Driver for USB Mass Storage compliant devices */
#ifndef _USB_H_
#define _USB_H_
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <scsi/scsi_host.h>
#include "common.h"
struct us_data;
struct scsi_cmnd;
/*
* Unusual device list definitions
*/
struct us_unusual_dev {
const char *vendorName;
const char *productName;
__u8 useProtocol;
__u8 useTransport;
int (*initFunction)(struct us_data *);
};
/* EnE HW Register */
#define REG_CARD_STATUS 0xFF83
#define REG_HW_TRAP1 0xFF89
/* SRB Status. Refers /usr/include/wine/wine/wnaspi32.h & SCSI sense key */
#define SS_SUCCESS 0x00 /* No Sense */
#define SS_NOT_READY 0x02
#define SS_MEDIUM_ERR 0x03
#define SS_HW_ERR 0x04
#define SS_ILLEGAL_REQUEST 0x05
#define SS_UNIT_ATTENTION 0x06
/* ENE Load FW Pattern */
#define SD_INIT1_PATTERN 1
#define SD_INIT2_PATTERN 2
#define SD_RW_PATTERN 3
#define MS_INIT_PATTERN 4
#define MSP_RW_PATTERN 5
#define MS_RW_PATTERN 6
#define SM_INIT_PATTERN 7
#define SM_RW_PATTERN 8
#define FDIR_WRITE 0
#define FDIR_READ 1
struct keucr_sd_status {
u8 Insert:1;
u8 Ready:1;
u8 MediaChange:1;
u8 IsMMC:1;
u8 HiCapacity:1;
u8 HiSpeed:1;
u8 WtP:1;
u8 Reserved:1;
};
struct keucr_ms_status {
u8 Insert:1;
u8 Ready:1;
u8 MediaChange:1;
u8 IsMSPro:1;
u8 IsMSPHG:1;
u8 Reserved1:1;
u8 WtP:1;
u8 Reserved2:1;
};
struct keucr_sm_status {
u8 Insert:1;
u8 Ready:1;
u8 MediaChange:1;
u8 Reserved:3;
u8 WtP:1;
u8 IsMS:1;
};
/* SD Block Length */
#define SD_BLOCK_LEN 9 /* 2^9 = 512 Bytes,
The HW maximum read/write data length */
/* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */
#define US_FLIDX_URB_ACTIVE 0 /* current_urb is in use */
#define US_FLIDX_SG_ACTIVE 1 /* current_sg is in use */
#define US_FLIDX_ABORTING 2 /* abort is in progress */
#define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */
#define US_FLIDX_RESETTING 4 /* device reset in progress */
#define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
#define US_FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */
#define USB_STOR_STRING_LEN 32
/*
* We provide a DMA-mapped I/O buffer for use with small USB transfers.
* It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
* 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the
* size we'll allocate.
*/
#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */
#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */
typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data *);
typedef int (*trans_reset)(struct us_data *);
typedef void (*proto_cmnd)(struct scsi_cmnd *, struct us_data *);
typedef void (*extra_data_destructor)(void *); /* extra data destructor */
typedef void (*pm_hook)(struct us_data *, int); /* power management hook */
#define US_SUSPEND 0
#define US_RESUME 1
/* we allocate one of these for every device that we remember */
struct us_data {
/* The device we're working with
* It's important to note:
* (o) you must hold dev_mutex to change pusb_dev
*/
struct mutex dev_mutex; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
struct usb_interface *pusb_intf; /* this interface */
struct us_unusual_dev *unusual_dev; /* device-filter entry */
unsigned long fflags; /* fixed flags from filter */
unsigned long dflags; /* dynamic atomic bitflags */
unsigned int send_bulk_pipe; /* cached pipe values */
unsigned int recv_bulk_pipe;
unsigned int send_ctrl_pipe;
unsigned int recv_ctrl_pipe;
unsigned int recv_intr_pipe;
/* information about the device */
char *transport_name;
char *protocol_name;
__le32 bcs_signature;
u8 subclass;
u8 protocol;
u8 max_lun;
u8 ifnum; /* interface number */
u8 ep_bInterval; /* interrupt interval */
/* function pointers for this device */
trans_cmnd transport; /* transport function */
trans_reset transport_reset; /* transport device reset */
proto_cmnd proto_handler; /* protocol handler */
/* SCSI interfaces */
struct scsi_cmnd *srb; /* current srb */
unsigned int tag; /* current dCBWTag */
/* control and bulk communications data */
struct urb *current_urb; /* USB requests */
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
unsigned char *sensebuf; /* sense data buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
struct task_struct *ctl_thread; /* the control thread */
/* mutual exclusion and synchronization structures */
struct completion cmnd_ready; /* to sleep thread on */
struct completion notify; /* thread begin/end */
wait_queue_head_t delay_wait; /* wait during scan, reset */
struct completion scanning_done; /* wait for scan thread */
/* subdriver information */
void *extra; /* Any extra data */
extra_data_destructor extra_destructor;/* extra data destructor */
#ifdef CONFIG_PM
pm_hook suspend_resume_hook;
#endif
/* for 6250 code */
struct keucr_sd_status SD_Status;
struct keucr_ms_status MS_Status;
struct keucr_sm_status SM_Status;
/* ----- SD Control Data ---------------- */
/* SD_REGISTER SD_Regs; */
u16 SD_Block_Mult;
u8 SD_READ_BL_LEN;
u16 SD_C_SIZE;
u8 SD_C_SIZE_MULT;
/* SD/MMC New spec. */
u8 SD_SPEC_VER;
u8 SD_CSD_VER;
u8 SD20_HIGH_CAPACITY;
u32 HC_C_SIZE;
u8 MMC_SPEC_VER;
u8 MMC_BusWidth;
u8 MMC_HIGH_CAPACITY;
/* ----- MS Control Data ---------------- */
bool MS_SWWP;
u32 MSP_TotalBlock;
/* MS_LibControl MS_Lib; */
bool MS_IsRWPage;
u16 MS_Model;
/* ----- SM Control Data ---------------- */
u8 SM_DeviceID;
u8 SM_CardID;
u8 *testbuf;
u8 BIN_FLAG;
u32 bl_num;
int SrbStatus;
/* ------Power Managerment --------------- */
bool Power_IsResum;
};
/* Convert between us_data and the corresponding Scsi_Host */
static inline struct Scsi_Host *us_to_host(struct us_data *us)
{
return container_of((void *) us, struct Scsi_Host, hostdata);
}
static inline struct us_data *host_to_us(struct Scsi_Host *host)
{
return (struct us_data *) host->hostdata;
}
/* Function to fill an inquiry response. See usb.c for details */
extern void fill_inquiry_response(struct us_data *us,
unsigned char *data, unsigned int data_len);
/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
* single queue element srb for write access */
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
#endif
......@@ -193,7 +193,7 @@ config USB_STORAGE_ENE_UB6250
depends on USB_STORAGE
---help---
Say Y here if you wish to control a ENE SD/MS Card reader.
To use SM card, please build driver/staging/keucr/keucr.ko
Note that this driver does not support SM cards.
This option depends on 'SCSI' support being enabled, but you
probably also need 'SCSI device support: SCSI disk support'
......
......@@ -2344,8 +2344,8 @@ static int ene_ub6250_probe(struct usb_interface *intf,
}
if (!(misc_reg03 & 0x01)) {
pr_info("ums_eneub6250: The driver only supports SD/MS card. "
"To use SM card, please build driver/staging/keucr\n");
pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
"It does not support SM cards.\n");
}
return result;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment