15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
241e568d1Shuajun li #include <linux/jiffies.h>
341e568d1Shuajun li #include <linux/errno.h>
441e568d1Shuajun li #include <linux/module.h>
541e568d1Shuajun li #include <linux/slab.h>
641e568d1Shuajun li
741e568d1Shuajun li #include <scsi/scsi.h>
841e568d1Shuajun li #include <scsi/scsi_cmnd.h>
941e568d1Shuajun li
1041e568d1Shuajun li #include <linux/firmware.h>
1141e568d1Shuajun li
1241e568d1Shuajun li #include "usb.h"
1341e568d1Shuajun li #include "transport.h"
1441e568d1Shuajun li #include "protocol.h"
1541e568d1Shuajun li #include "debug.h"
16aa519be3SAkinobu Mita #include "scsiglue.h"
1741e568d1Shuajun li
18595c8970STim Gardner #define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
19595c8970STim Gardner #define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
20595c8970STim Gardner #define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
21595c8970STim Gardner #define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
22595c8970STim Gardner #define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
23595c8970STim Gardner #define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
24595c8970STim Gardner
25aa519be3SAkinobu Mita #define DRV_NAME "ums_eneub6250"
26aa519be3SAkinobu Mita
2741e568d1Shuajun li MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
2841e568d1Shuajun li MODULE_LICENSE("GPL");
2932bca2dfSMatthias Maennich MODULE_IMPORT_NS(USB_STORAGE);
30595c8970STim Gardner MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
31595c8970STim Gardner MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
32595c8970STim Gardner MODULE_FIRMWARE(SD_RW_FIRMWARE);
33595c8970STim Gardner MODULE_FIRMWARE(MS_INIT_FIRMWARE);
34595c8970STim Gardner MODULE_FIRMWARE(MSP_RW_FIRMWARE);
35595c8970STim Gardner MODULE_FIRMWARE(MS_RW_FIRMWARE);
3641e568d1Shuajun li
3741e568d1Shuajun li /*
3841e568d1Shuajun li * The table of devices
3941e568d1Shuajun li */
4041e568d1Shuajun li #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
4141e568d1Shuajun li vendorName, productName, useProtocol, useTransport, \
4241e568d1Shuajun li initFunction, flags) \
4341e568d1Shuajun li { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
44f61870eeSSebastian Andrzej Siewior .driver_info = (flags)}
4541e568d1Shuajun li
4636f3a14dSFelipe Balbi static struct usb_device_id ene_ub6250_usb_ids[] = {
4741e568d1Shuajun li # include "unusual_ene_ub6250.h"
4841e568d1Shuajun li { } /* Terminating entry */
4941e568d1Shuajun li };
5041e568d1Shuajun li MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids);
5141e568d1Shuajun li
5241e568d1Shuajun li #undef UNUSUAL_DEV
5341e568d1Shuajun li
5441e568d1Shuajun li /*
5541e568d1Shuajun li * The flags table
5641e568d1Shuajun li */
5741e568d1Shuajun li #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
5841e568d1Shuajun li vendor_name, product_name, use_protocol, use_transport, \
5941e568d1Shuajun li init_function, Flags) \
6041e568d1Shuajun li { \
6141e568d1Shuajun li .vendorName = vendor_name, \
6241e568d1Shuajun li .productName = product_name, \
6341e568d1Shuajun li .useProtocol = use_protocol, \
6441e568d1Shuajun li .useTransport = use_transport, \
6541e568d1Shuajun li .initFunction = init_function, \
6641e568d1Shuajun li }
6741e568d1Shuajun li
6841e568d1Shuajun li static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
6941e568d1Shuajun li # include "unusual_ene_ub6250.h"
7041e568d1Shuajun li { } /* Terminating entry */
7141e568d1Shuajun li };
7241e568d1Shuajun li
7341e568d1Shuajun li #undef UNUSUAL_DEV
7441e568d1Shuajun li
7541e568d1Shuajun li
7641e568d1Shuajun li
7741e568d1Shuajun li /* ENE bin code len */
7841e568d1Shuajun li #define ENE_BIN_CODE_LEN 0x800
7941e568d1Shuajun li /* EnE HW Register */
8041e568d1Shuajun li #define REG_CARD_STATUS 0xFF83
8141e568d1Shuajun li #define REG_HW_TRAP1 0xFF89
8241e568d1Shuajun li
8341e568d1Shuajun li /* SRB Status */
84ce553bd1SAlan Stern #define SS_SUCCESS 0x000000 /* No Sense */
85ce553bd1SAlan Stern #define SS_NOT_READY 0x023A00 /* Medium not present */
86ce553bd1SAlan Stern #define SS_MEDIUM_ERR 0x031100 /* Unrecovered read error */
87ce553bd1SAlan Stern #define SS_HW_ERR 0x040800 /* Communication failure */
88ce553bd1SAlan Stern #define SS_ILLEGAL_REQUEST 0x052000 /* Invalid command */
89ce553bd1SAlan Stern #define SS_UNIT_ATTENTION 0x062900 /* Reset occurred */
9041e568d1Shuajun li
9141e568d1Shuajun li /* ENE Load FW Pattern */
9241e568d1Shuajun li #define SD_INIT1_PATTERN 1
9341e568d1Shuajun li #define SD_INIT2_PATTERN 2
9441e568d1Shuajun li #define SD_RW_PATTERN 3
9541e568d1Shuajun li #define MS_INIT_PATTERN 4
9641e568d1Shuajun li #define MSP_RW_PATTERN 5
9741e568d1Shuajun li #define MS_RW_PATTERN 6
9841e568d1Shuajun li #define SM_INIT_PATTERN 7
9941e568d1Shuajun li #define SM_RW_PATTERN 8
10041e568d1Shuajun li
10141e568d1Shuajun li #define FDIR_WRITE 0
10241e568d1Shuajun li #define FDIR_READ 1
10341e568d1Shuajun li
10433842cedSCho, Yu-Chen /* For MS Card */
10533842cedSCho, Yu-Chen
10633842cedSCho, Yu-Chen /* Status Register 1 */
10733842cedSCho, Yu-Chen #define MS_REG_ST1_MB 0x80 /* media busy */
10833842cedSCho, Yu-Chen #define MS_REG_ST1_FB1 0x40 /* flush busy 1 */
10933842cedSCho, Yu-Chen #define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */
11033842cedSCho, Yu-Chen #define MS_REG_ST1_UCDT 0x10 /* unable to correct data */
11133842cedSCho, Yu-Chen #define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */
11233842cedSCho, Yu-Chen #define MS_REG_ST1_UCEX 0x04 /* unable to correct extra */
11333842cedSCho, Yu-Chen #define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */
11433842cedSCho, Yu-Chen #define MS_REG_ST1_UCFG 0x01 /* unable to correct overwrite flag */
11533842cedSCho, Yu-Chen #define MS_REG_ST1_DEFAULT (MS_REG_ST1_MB | MS_REG_ST1_FB1 | MS_REG_ST1_DTER | MS_REG_ST1_UCDT | MS_REG_ST1_EXER | MS_REG_ST1_UCEX | MS_REG_ST1_FGER | MS_REG_ST1_UCFG)
11633842cedSCho, Yu-Chen
11733842cedSCho, Yu-Chen /* Overwrite Area */
11833842cedSCho, Yu-Chen #define MS_REG_OVR_BKST 0x80 /* block status */
11933842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */
12033842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG 0x00 /* NG */
12133842cedSCho, Yu-Chen #define MS_REG_OVR_PGST0 0x40 /* page status */
12233842cedSCho, Yu-Chen #define MS_REG_OVR_PGST1 0x20
12333842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_MASK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1)
12433842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_OK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */
12533842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_NG MS_REG_OVR_PGST1 /* NG */
12633842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_DATA_ERROR 0x00 /* data error */
12733842cedSCho, Yu-Chen #define MS_REG_OVR_UDST 0x10 /* update status */
12833842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_UPDATING 0x00 /* updating */
12933842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_NO_UPDATE MS_REG_OVR_UDST
13033842cedSCho, Yu-Chen #define MS_REG_OVR_RESERVED 0x08
13133842cedSCho, Yu-Chen #define MS_REG_OVR_DEFAULT (MS_REG_OVR_BKST_OK | MS_REG_OVR_PGST_OK | MS_REG_OVR_UDST_NO_UPDATE | MS_REG_OVR_RESERVED)
13233842cedSCho, Yu-Chen
13333842cedSCho, Yu-Chen /* Management Flag */
13433842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS0 0x20 /* serial copy management system */
13533842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS1 0x10
13633842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_MASK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
13733842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_COPY_OK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
13833842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_ONE_COPY MS_REG_MNG_SCMS1
13933842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_NO_COPY 0x00
14033842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG 0x08 /* address transfer table flag */
14133842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_OTHER MS_REG_MNG_ATFLG /* other */
14233842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_ATTBL 0x00 /* address transfer table */
14333842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG 0x04 /* system flag */
14433842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */
14533842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_BOOT 0x00 /* system block */
14633842cedSCho, Yu-Chen #define MS_REG_MNG_RESERVED 0xc3
14733842cedSCho, Yu-Chen #define MS_REG_MNG_DEFAULT (MS_REG_MNG_SCMS_COPY_OK | MS_REG_MNG_ATFLG_OTHER | MS_REG_MNG_SYSFLG_USER | MS_REG_MNG_RESERVED)
14833842cedSCho, Yu-Chen
14933842cedSCho, Yu-Chen
15033842cedSCho, Yu-Chen #define MS_MAX_PAGES_PER_BLOCK 32
15133842cedSCho, Yu-Chen #define MS_MAX_INITIAL_ERROR_BLOCKS 10
15233842cedSCho, Yu-Chen #define MS_LIB_BITS_PER_BYTE 8
15333842cedSCho, Yu-Chen
15433842cedSCho, Yu-Chen #define MS_SYSINF_FORMAT_FAT 1
15533842cedSCho, Yu-Chen #define MS_SYSINF_USAGE_GENERAL 0
15633842cedSCho, Yu-Chen
15733842cedSCho, Yu-Chen #define MS_SYSINF_MSCLASS_TYPE_1 1
15833842cedSCho, Yu-Chen #define MS_SYSINF_PAGE_SIZE MS_BYTES_PER_PAGE /* fixed */
15933842cedSCho, Yu-Chen
16033842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDONLY 1
16133842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDWR 2
16233842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_HYBRID 3
16333842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY 0x01
16433842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_NO_SUPPORT MS_SYSINF_SECURITY
16533842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_SUPPORT 0
16633842cedSCho, Yu-Chen
16733842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED1 1
16833842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED2 1
16933842cedSCho, Yu-Chen
17033842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_INVALID_BLOCK 0x01
17133842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_CIS_IDI 0x0a /* CIS/IDI */
17233842cedSCho, Yu-Chen
17333842cedSCho, Yu-Chen #define SIZE_OF_KIRO 1024
17433842cedSCho, Yu-Chen #define BYTE_MASK 0xff
17533842cedSCho, Yu-Chen
17633842cedSCho, Yu-Chen /* ms error code */
17733842cedSCho, Yu-Chen #define MS_STATUS_WRITE_PROTECT 0x0106
17833842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS 0x0000
17933842cedSCho, Yu-Chen #define MS_ERROR_FLASH_READ 0x8003
18033842cedSCho, Yu-Chen #define MS_ERROR_FLASH_ERASE 0x8005
18133842cedSCho, Yu-Chen #define MS_LB_ERROR 0xfff0
18233842cedSCho, Yu-Chen #define MS_LB_BOOT_BLOCK 0xfff1
18333842cedSCho, Yu-Chen #define MS_LB_INITIAL_ERROR 0xfff2
18433842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS_WITH_ECC 0xfff3
18533842cedSCho, Yu-Chen #define MS_LB_ACQUIRED_ERROR 0xfff4
18633842cedSCho, Yu-Chen #define MS_LB_NOT_USED_ERASED 0xfff5
18733842cedSCho, Yu-Chen #define MS_NOCARD_ERROR 0xfff8
18833842cedSCho, Yu-Chen #define MS_NO_MEMORY_ERROR 0xfff9
18933842cedSCho, Yu-Chen #define MS_STATUS_INT_ERROR 0xfffa
19033842cedSCho, Yu-Chen #define MS_STATUS_ERROR 0xfffe
19133842cedSCho, Yu-Chen #define MS_LB_NOT_USED 0xffff
19233842cedSCho, Yu-Chen
19333842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG 0x04 /* system flag */
19433842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */
19533842cedSCho, Yu-Chen
19633842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_ID 0x0001
19733842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_FORMAT_VERSION 0x0100
19833842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_DATA_ENTRIES 2
19933842cedSCho, Yu-Chen
20033842cedSCho, Yu-Chen #define MS_NUMBER_OF_SYSTEM_ENTRY 4
20133842cedSCho, Yu-Chen #define MS_NUMBER_OF_BOOT_BLOCK 2
20233842cedSCho, Yu-Chen #define MS_BYTES_PER_PAGE 512
20333842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_PER_SEGMENT 496
20433842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT 494
20533842cedSCho, Yu-Chen
20633842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT 0x200 /* 512 */
20733842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK 0x1ff
20833842cedSCho, Yu-Chen
20933842cedSCho, Yu-Chen /* overwrite area */
21033842cedSCho, Yu-Chen #define MS_REG_OVR_BKST 0x80 /* block status */
21133842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */
21233842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG 0x00 /* NG */
21333842cedSCho, Yu-Chen
21433842cedSCho, Yu-Chen /* Status Register 1 */
21533842cedSCho, Yu-Chen #define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */
21633842cedSCho, Yu-Chen #define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */
21733842cedSCho, Yu-Chen #define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */
21833842cedSCho, Yu-Chen
21933842cedSCho, Yu-Chen /* MemoryStick Register */
22033842cedSCho, Yu-Chen /* Status Register 0 */
22133842cedSCho, Yu-Chen #define MS_REG_ST0_WP 0x01 /* write protected */
22233842cedSCho, Yu-Chen #define MS_REG_ST0_WP_ON MS_REG_ST0_WP
22333842cedSCho, Yu-Chen
22433842cedSCho, Yu-Chen #define MS_LIB_CTRL_RDONLY 0
22533842cedSCho, Yu-Chen #define MS_LIB_CTRL_WRPROTECT 1
22633842cedSCho, Yu-Chen
22733842cedSCho, Yu-Chen /*dphy->log table */
22833842cedSCho, Yu-Chen #define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock])
22933842cedSCho, Yu-Chen #define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock])
23033842cedSCho, Yu-Chen
23133842cedSCho, Yu-Chen #define ms_lib_ctrl_set(pdx, Flag) ((pdx)->MS_Lib.flags |= (1 << (Flag)))
23233842cedSCho, Yu-Chen #define ms_lib_ctrl_reset(pdx, Flag) ((pdx)->MS_Lib.flags &= ~(1 << (Flag)))
23333842cedSCho, Yu-Chen #define ms_lib_ctrl_check(pdx, Flag) ((pdx)->MS_Lib.flags & (1 << (Flag)))
23433842cedSCho, Yu-Chen
23533842cedSCho, Yu-Chen #define ms_lib_iswritable(pdx) ((ms_lib_ctrl_check((pdx), MS_LIB_CTRL_RDONLY) == 0) && (ms_lib_ctrl_check(pdx, MS_LIB_CTRL_WRPROTECT) == 0))
23633842cedSCho, Yu-Chen #define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap))
23733842cedSCho, Yu-Chen #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0))
23833842cedSCho, Yu-Chen
23941e568d1Shuajun li
2401892bf90SAlan Stern /* SD_STATUS bits */
2411892bf90SAlan Stern #define SD_Insert BIT(0)
2421892bf90SAlan Stern #define SD_Ready BIT(1)
2431892bf90SAlan Stern #define SD_MediaChange BIT(2)
2441892bf90SAlan Stern #define SD_IsMMC BIT(3)
2451892bf90SAlan Stern #define SD_HiCapacity BIT(4)
2461892bf90SAlan Stern #define SD_HiSpeed BIT(5)
2471892bf90SAlan Stern #define SD_WtP BIT(6)
2481892bf90SAlan Stern /* Bit 7 reserved */
24941e568d1Shuajun li
2501892bf90SAlan Stern /* MS_STATUS bits */
2511892bf90SAlan Stern #define MS_Insert BIT(0)
2521892bf90SAlan Stern #define MS_Ready BIT(1)
2531892bf90SAlan Stern #define MS_MediaChange BIT(2)
2541892bf90SAlan Stern #define MS_IsMSPro BIT(3)
2551892bf90SAlan Stern #define MS_IsMSPHG BIT(4)
2561892bf90SAlan Stern /* Bit 5 reserved */
2571892bf90SAlan Stern #define MS_WtP BIT(6)
2581892bf90SAlan Stern /* Bit 7 reserved */
25941e568d1Shuajun li
2601892bf90SAlan Stern /* SM_STATUS bits */
2611892bf90SAlan Stern #define SM_Insert BIT(0)
2621892bf90SAlan Stern #define SM_Ready BIT(1)
2631892bf90SAlan Stern #define SM_MediaChange BIT(2)
2641892bf90SAlan Stern /* Bits 3-5 reserved */
2651892bf90SAlan Stern #define SM_WtP BIT(6)
2661892bf90SAlan Stern #define SM_IsMS BIT(7)
26741e568d1Shuajun li
26833842cedSCho, Yu-Chen struct ms_bootblock_cis {
26933842cedSCho, Yu-Chen u8 bCistplDEVICE[6]; /* 0 */
27033842cedSCho, Yu-Chen u8 bCistplDEVICE0C[6]; /* 6 */
27133842cedSCho, Yu-Chen u8 bCistplJEDECC[4]; /* 12 */
27233842cedSCho, Yu-Chen u8 bCistplMANFID[6]; /* 16 */
27333842cedSCho, Yu-Chen u8 bCistplVER1[32]; /* 22 */
27433842cedSCho, Yu-Chen u8 bCistplFUNCID[4]; /* 54 */
27533842cedSCho, Yu-Chen u8 bCistplFUNCE0[4]; /* 58 */
27633842cedSCho, Yu-Chen u8 bCistplFUNCE1[5]; /* 62 */
27733842cedSCho, Yu-Chen u8 bCistplCONF[7]; /* 67 */
27833842cedSCho, Yu-Chen u8 bCistplCFTBLENT0[10];/* 74 */
27933842cedSCho, Yu-Chen u8 bCistplCFTBLENT1[8]; /* 84 */
28033842cedSCho, Yu-Chen u8 bCistplCFTBLENT2[12];/* 92 */
28133842cedSCho, Yu-Chen u8 bCistplCFTBLENT3[8]; /* 104 */
28233842cedSCho, Yu-Chen u8 bCistplCFTBLENT4[17];/* 112 */
28333842cedSCho, Yu-Chen u8 bCistplCFTBLENT5[8]; /* 129 */
28433842cedSCho, Yu-Chen u8 bCistplCFTBLENT6[17];/* 137 */
28533842cedSCho, Yu-Chen u8 bCistplCFTBLENT7[8]; /* 154 */
28633842cedSCho, Yu-Chen u8 bCistplNOLINK[3]; /* 162 */
28733842cedSCho, Yu-Chen } ;
28833842cedSCho, Yu-Chen
28933842cedSCho, Yu-Chen struct ms_bootblock_idi {
29033842cedSCho, Yu-Chen #define MS_IDI_GENERAL_CONF 0x848A
29133842cedSCho, Yu-Chen u16 wIDIgeneralConfiguration; /* 0 */
29233842cedSCho, Yu-Chen u16 wIDInumberOfCylinder; /* 1 */
29333842cedSCho, Yu-Chen u16 wIDIreserved0; /* 2 */
29433842cedSCho, Yu-Chen u16 wIDInumberOfHead; /* 3 */
29533842cedSCho, Yu-Chen u16 wIDIbytesPerTrack; /* 4 */
29633842cedSCho, Yu-Chen u16 wIDIbytesPerSector; /* 5 */
29733842cedSCho, Yu-Chen u16 wIDIsectorsPerTrack; /* 6 */
29833842cedSCho, Yu-Chen u16 wIDItotalSectors[2]; /* 7-8 high,low */
29933842cedSCho, Yu-Chen u16 wIDIreserved1[11]; /* 9-19 */
30033842cedSCho, Yu-Chen u16 wIDIbufferType; /* 20 */
30133842cedSCho, Yu-Chen u16 wIDIbufferSize; /* 21 */
30233842cedSCho, Yu-Chen u16 wIDIlongCmdECC; /* 22 */
30333842cedSCho, Yu-Chen u16 wIDIfirmVersion[4]; /* 23-26 */
30433842cedSCho, Yu-Chen u16 wIDImodelName[20]; /* 27-46 */
30533842cedSCho, Yu-Chen u16 wIDIreserved2; /* 47 */
30633842cedSCho, Yu-Chen u16 wIDIlongWordSupported; /* 48 */
30733842cedSCho, Yu-Chen u16 wIDIdmaSupported; /* 49 */
30833842cedSCho, Yu-Chen u16 wIDIreserved3; /* 50 */
30933842cedSCho, Yu-Chen u16 wIDIpioTiming; /* 51 */
31033842cedSCho, Yu-Chen u16 wIDIdmaTiming; /* 52 */
31133842cedSCho, Yu-Chen u16 wIDItransferParameter; /* 53 */
31233842cedSCho, Yu-Chen u16 wIDIformattedCylinder; /* 54 */
31333842cedSCho, Yu-Chen u16 wIDIformattedHead; /* 55 */
31433842cedSCho, Yu-Chen u16 wIDIformattedSectorsPerTrack;/* 56 */
31533842cedSCho, Yu-Chen u16 wIDIformattedTotalSectors[2];/* 57-58 */
31633842cedSCho, Yu-Chen u16 wIDImultiSector; /* 59 */
31733842cedSCho, Yu-Chen u16 wIDIlbaSectors[2]; /* 60-61 */
31833842cedSCho, Yu-Chen u16 wIDIsingleWordDMA; /* 62 */
31933842cedSCho, Yu-Chen u16 wIDImultiWordDMA; /* 63 */
32033842cedSCho, Yu-Chen u16 wIDIreserved4[192]; /* 64-255 */
32133842cedSCho, Yu-Chen };
32233842cedSCho, Yu-Chen
32333842cedSCho, Yu-Chen struct ms_bootblock_sysent_rec {
32433842cedSCho, Yu-Chen u32 dwStart;
32533842cedSCho, Yu-Chen u32 dwSize;
32633842cedSCho, Yu-Chen u8 bType;
32733842cedSCho, Yu-Chen u8 bReserved[3];
32833842cedSCho, Yu-Chen };
32933842cedSCho, Yu-Chen
33033842cedSCho, Yu-Chen struct ms_bootblock_sysent {
33133842cedSCho, Yu-Chen struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY];
33233842cedSCho, Yu-Chen };
33333842cedSCho, Yu-Chen
33433842cedSCho, Yu-Chen struct ms_bootblock_sysinf {
33533842cedSCho, Yu-Chen u8 bMsClass; /* must be 1 */
33633842cedSCho, Yu-Chen u8 bCardType; /* see below */
33733842cedSCho, Yu-Chen u16 wBlockSize; /* n KB */
33833842cedSCho, Yu-Chen u16 wBlockNumber; /* number of physical block */
33933842cedSCho, Yu-Chen u16 wTotalBlockNumber; /* number of logical block */
34033842cedSCho, Yu-Chen u16 wPageSize; /* must be 0x200 */
34133842cedSCho, Yu-Chen u8 bExtraSize; /* 0x10 */
34233842cedSCho, Yu-Chen u8 bSecuritySupport;
34333842cedSCho, Yu-Chen u8 bAssemblyDate[8];
34433842cedSCho, Yu-Chen u8 bFactoryArea[4];
34533842cedSCho, Yu-Chen u8 bAssemblyMakerCode;
34633842cedSCho, Yu-Chen u8 bAssemblyMachineCode[3];
34733842cedSCho, Yu-Chen u16 wMemoryMakerCode;
34833842cedSCho, Yu-Chen u16 wMemoryDeviceCode;
34933842cedSCho, Yu-Chen u16 wMemorySize;
35033842cedSCho, Yu-Chen u8 bReserved1;
35133842cedSCho, Yu-Chen u8 bReserved2;
35233842cedSCho, Yu-Chen u8 bVCC;
35333842cedSCho, Yu-Chen u8 bVPP;
35433842cedSCho, Yu-Chen u16 wControllerChipNumber;
35533842cedSCho, Yu-Chen u16 wControllerFunction; /* New MS */
35633842cedSCho, Yu-Chen u8 bReserved3[9]; /* New MS */
35733842cedSCho, Yu-Chen u8 bParallelSupport; /* New MS */
35833842cedSCho, Yu-Chen u16 wFormatValue; /* New MS */
35933842cedSCho, Yu-Chen u8 bFormatType;
36033842cedSCho, Yu-Chen u8 bUsage;
36133842cedSCho, Yu-Chen u8 bDeviceType;
36233842cedSCho, Yu-Chen u8 bReserved4[22];
36333842cedSCho, Yu-Chen u8 bFUValue3;
36433842cedSCho, Yu-Chen u8 bFUValue4;
36533842cedSCho, Yu-Chen u8 bReserved5[15];
36633842cedSCho, Yu-Chen };
36733842cedSCho, Yu-Chen
36833842cedSCho, Yu-Chen struct ms_bootblock_header {
36933842cedSCho, Yu-Chen u16 wBlockID;
37033842cedSCho, Yu-Chen u16 wFormatVersion;
37133842cedSCho, Yu-Chen u8 bReserved1[184];
37233842cedSCho, Yu-Chen u8 bNumberOfDataEntry;
37333842cedSCho, Yu-Chen u8 bReserved2[179];
37433842cedSCho, Yu-Chen };
37533842cedSCho, Yu-Chen
37633842cedSCho, Yu-Chen struct ms_bootblock_page0 {
37733842cedSCho, Yu-Chen struct ms_bootblock_header header;
37833842cedSCho, Yu-Chen struct ms_bootblock_sysent sysent;
37933842cedSCho, Yu-Chen struct ms_bootblock_sysinf sysinf;
38033842cedSCho, Yu-Chen };
38133842cedSCho, Yu-Chen
38233842cedSCho, Yu-Chen struct ms_bootblock_cis_idi {
38333842cedSCho, Yu-Chen union {
38433842cedSCho, Yu-Chen struct ms_bootblock_cis cis;
38533842cedSCho, Yu-Chen u8 dmy[256];
38633842cedSCho, Yu-Chen } cis;
38733842cedSCho, Yu-Chen
38833842cedSCho, Yu-Chen union {
38933842cedSCho, Yu-Chen struct ms_bootblock_idi idi;
39033842cedSCho, Yu-Chen u8 dmy[256];
39133842cedSCho, Yu-Chen } idi;
39233842cedSCho, Yu-Chen
39333842cedSCho, Yu-Chen };
39433842cedSCho, Yu-Chen
39533842cedSCho, Yu-Chen /* ENE MS Lib struct */
39633842cedSCho, Yu-Chen struct ms_lib_type_extdat {
39733842cedSCho, Yu-Chen u8 reserved;
39833842cedSCho, Yu-Chen u8 intr;
39933842cedSCho, Yu-Chen u8 status0;
40033842cedSCho, Yu-Chen u8 status1;
40133842cedSCho, Yu-Chen u8 ovrflg;
40233842cedSCho, Yu-Chen u8 mngflg;
40333842cedSCho, Yu-Chen u16 logadr;
40433842cedSCho, Yu-Chen };
40533842cedSCho, Yu-Chen
40633842cedSCho, Yu-Chen struct ms_lib_ctrl {
40733842cedSCho, Yu-Chen u32 flags;
40833842cedSCho, Yu-Chen u32 BytesPerSector;
40933842cedSCho, Yu-Chen u32 NumberOfCylinder;
41033842cedSCho, Yu-Chen u32 SectorsPerCylinder;
41133842cedSCho, Yu-Chen u16 cardType; /* R/W, RO, Hybrid */
41233842cedSCho, Yu-Chen u16 blockSize;
41333842cedSCho, Yu-Chen u16 PagesPerBlock;
41433842cedSCho, Yu-Chen u16 NumberOfPhyBlock;
41533842cedSCho, Yu-Chen u16 NumberOfLogBlock;
41633842cedSCho, Yu-Chen u16 NumberOfSegment;
41733842cedSCho, Yu-Chen u16 *Phy2LogMap; /* phy2log table */
41833842cedSCho, Yu-Chen u16 *Log2PhyMap; /* log2phy table */
41933842cedSCho, Yu-Chen u16 wrtblk;
42033842cedSCho, Yu-Chen unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE];
42133842cedSCho, Yu-Chen unsigned char *blkpag;
42233842cedSCho, Yu-Chen struct ms_lib_type_extdat *blkext;
42333842cedSCho, Yu-Chen unsigned char copybuf[512];
42433842cedSCho, Yu-Chen };
42533842cedSCho, Yu-Chen
42641e568d1Shuajun li
42741e568d1Shuajun li /* SD Block Length */
42841e568d1Shuajun li /* 2^9 = 512 Bytes, The HW maximum read/write data length */
42941e568d1Shuajun li #define SD_BLOCK_LEN 9
43041e568d1Shuajun li
43141e568d1Shuajun li struct ene_ub6250_info {
432628c2893SAlan Stern
433628c2893SAlan Stern /* I/O bounce buffer */
434628c2893SAlan Stern u8 *bbuf;
435628c2893SAlan Stern
43641e568d1Shuajun li /* for 6250 code */
4371892bf90SAlan Stern u8 SD_Status;
4381892bf90SAlan Stern u8 MS_Status;
4391892bf90SAlan Stern u8 SM_Status;
44041e568d1Shuajun li
44141e568d1Shuajun li /* ----- SD Control Data ---------------- */
44241e568d1Shuajun li /*SD_REGISTER SD_Regs; */
44341e568d1Shuajun li u16 SD_Block_Mult;
44441e568d1Shuajun li u8 SD_READ_BL_LEN;
44541e568d1Shuajun li u16 SD_C_SIZE;
44641e568d1Shuajun li u8 SD_C_SIZE_MULT;
44741e568d1Shuajun li
44841e568d1Shuajun li /* SD/MMC New spec. */
44941e568d1Shuajun li u8 SD_SPEC_VER;
45041e568d1Shuajun li u8 SD_CSD_VER;
45141e568d1Shuajun li u8 SD20_HIGH_CAPACITY;
45241e568d1Shuajun li u32 HC_C_SIZE;
45341e568d1Shuajun li u8 MMC_SPEC_VER;
45441e568d1Shuajun li u8 MMC_BusWidth;
45541e568d1Shuajun li u8 MMC_HIGH_CAPACITY;
45641e568d1Shuajun li
45741e568d1Shuajun li /*----- MS Control Data ---------------- */
45841e568d1Shuajun li bool MS_SWWP;
45941e568d1Shuajun li u32 MSP_TotalBlock;
46033842cedSCho, Yu-Chen struct ms_lib_ctrl MS_Lib;
46141e568d1Shuajun li bool MS_IsRWPage;
46241e568d1Shuajun li u16 MS_Model;
46341e568d1Shuajun li
46441e568d1Shuajun li /*----- SM Control Data ---------------- */
46541e568d1Shuajun li u8 SM_DeviceID;
46641e568d1Shuajun li u8 SM_CardID;
46741e568d1Shuajun li
46841e568d1Shuajun li unsigned char *testbuf;
46941e568d1Shuajun li u8 BIN_FLAG;
47041e568d1Shuajun li u32 bl_num;
47141e568d1Shuajun li int SrbStatus;
47241e568d1Shuajun li
47341e568d1Shuajun li /*------Power Managerment ---------------*/
47441e568d1Shuajun li bool Power_IsResum;
47541e568d1Shuajun li };
47641e568d1Shuajun li
47741e568d1Shuajun li static int ene_sd_init(struct us_data *us);
47833842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us);
47941e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag);
48041e568d1Shuajun li
ene_ub6250_info_destructor(void * extra)48141e568d1Shuajun li static void ene_ub6250_info_destructor(void *extra)
48241e568d1Shuajun li {
483628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
484628c2893SAlan Stern
48541e568d1Shuajun li if (!extra)
48641e568d1Shuajun li return;
487628c2893SAlan Stern kfree(info->bbuf);
48841e568d1Shuajun li }
48941e568d1Shuajun li
ene_send_scsi_cmd(struct us_data * us,u8 fDir,void * buf,int use_sg)49041e568d1Shuajun li static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
49141e568d1Shuajun li {
49241e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
49341e568d1Shuajun li struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
49441e568d1Shuajun li
49541e568d1Shuajun li int result;
49641e568d1Shuajun li unsigned int residue;
49741e568d1Shuajun li unsigned int cswlen = 0, partial = 0;
49841e568d1Shuajun li unsigned int transfer_length = bcb->DataTransferLength;
49941e568d1Shuajun li
500191648d0SJoe Perches /* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
50141e568d1Shuajun li /* send cmd to out endpoint */
50241e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
50341e568d1Shuajun li bcb, US_BULK_CB_WRAP_LEN, NULL);
50441e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
505191648d0SJoe Perches usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
50641e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
50741e568d1Shuajun li }
50841e568d1Shuajun li
50941e568d1Shuajun li if (buf) {
51041e568d1Shuajun li unsigned int pipe = fDir;
51141e568d1Shuajun li
51241e568d1Shuajun li if (fDir == FDIR_READ)
51341e568d1Shuajun li pipe = us->recv_bulk_pipe;
51441e568d1Shuajun li else
51541e568d1Shuajun li pipe = us->send_bulk_pipe;
51641e568d1Shuajun li
51741e568d1Shuajun li /* Bulk */
51841e568d1Shuajun li if (use_sg) {
51941e568d1Shuajun li result = usb_stor_bulk_srb(us, pipe, us->srb);
52041e568d1Shuajun li } else {
52141e568d1Shuajun li result = usb_stor_bulk_transfer_sg(us, pipe, buf,
52241e568d1Shuajun li transfer_length, 0, &partial);
52341e568d1Shuajun li }
52441e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
525191648d0SJoe Perches usb_stor_dbg(us, "data transfer fail ---\n");
52641e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
52741e568d1Shuajun li }
52841e568d1Shuajun li }
52941e568d1Shuajun li
53041e568d1Shuajun li /* Get CSW for device status */
53141e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
53241e568d1Shuajun li US_BULK_CS_WRAP_LEN, &cswlen);
53341e568d1Shuajun li
53441e568d1Shuajun li if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
535191648d0SJoe Perches usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
53641e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
53741e568d1Shuajun li bcs, US_BULK_CS_WRAP_LEN, &cswlen);
53841e568d1Shuajun li }
53941e568d1Shuajun li
54041e568d1Shuajun li if (result == USB_STOR_XFER_STALLED) {
54141e568d1Shuajun li /* get the status again */
542191648d0SJoe Perches usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
54341e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
54441e568d1Shuajun li bcs, US_BULK_CS_WRAP_LEN, NULL);
54541e568d1Shuajun li }
54641e568d1Shuajun li
54741e568d1Shuajun li if (result != USB_STOR_XFER_GOOD)
54841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
54941e568d1Shuajun li
55041e568d1Shuajun li /* check bulk status */
55141e568d1Shuajun li residue = le32_to_cpu(bcs->Residue);
55241e568d1Shuajun li
553f0183a33SFelipe Balbi /*
554f0183a33SFelipe Balbi * try to compute the actual residue, based on how much data
555f0183a33SFelipe Balbi * was really transferred and what the device tells us
556f0183a33SFelipe Balbi */
55741e568d1Shuajun li if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
55841e568d1Shuajun li residue = min(residue, transfer_length);
55941e568d1Shuajun li if (us->srb != NULL)
56041e568d1Shuajun li scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
5619237f04eSDamien Le Moal residue));
56241e568d1Shuajun li }
56341e568d1Shuajun li
56441e568d1Shuajun li if (bcs->Status != US_BULK_STAT_OK)
56541e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
56641e568d1Shuajun li
56741e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
56841e568d1Shuajun li }
56941e568d1Shuajun li
do_scsi_request_sense(struct us_data * us,struct scsi_cmnd * srb)570ce553bd1SAlan Stern static int do_scsi_request_sense(struct us_data *us, struct scsi_cmnd *srb)
571ce553bd1SAlan Stern {
572ce553bd1SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
573ce553bd1SAlan Stern unsigned char buf[18];
574ce553bd1SAlan Stern
575ce553bd1SAlan Stern memset(buf, 0, 18);
576ce553bd1SAlan Stern buf[0] = 0x70; /* Current error */
577ce553bd1SAlan Stern buf[2] = info->SrbStatus >> 16; /* Sense key */
578ce553bd1SAlan Stern buf[7] = 10; /* Additional length */
579ce553bd1SAlan Stern buf[12] = info->SrbStatus >> 8; /* ASC */
580ce553bd1SAlan Stern buf[13] = info->SrbStatus; /* ASCQ */
581ce553bd1SAlan Stern
582ce553bd1SAlan Stern usb_stor_set_xfer_buf(buf, sizeof(buf), srb);
583ce553bd1SAlan Stern return USB_STOR_TRANSPORT_GOOD;
584ce553bd1SAlan Stern }
585ce553bd1SAlan Stern
do_scsi_inquiry(struct us_data * us,struct scsi_cmnd * srb)586f8efdabdSAlan Stern static int do_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
587f8efdabdSAlan Stern {
588f8efdabdSAlan Stern unsigned char data_ptr[36] = {
5895fcf9379SAlan Stern 0x00, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
590f8efdabdSAlan Stern 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
591f8efdabdSAlan Stern 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
592f8efdabdSAlan Stern 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
593f8efdabdSAlan Stern
594f8efdabdSAlan Stern usb_stor_set_xfer_buf(data_ptr, 36, srb);
595f8efdabdSAlan Stern return USB_STOR_TRANSPORT_GOOD;
596f8efdabdSAlan Stern }
597f8efdabdSAlan Stern
sd_scsi_test_unit_ready(struct us_data * us,struct scsi_cmnd * srb)59841e568d1Shuajun li static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
59941e568d1Shuajun li {
60041e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
60141e568d1Shuajun li
6021892bf90SAlan Stern if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready))
60341e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
60441e568d1Shuajun li else {
60541e568d1Shuajun li ene_sd_init(us);
60641e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
60741e568d1Shuajun li }
60841e568d1Shuajun li
60941e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
61041e568d1Shuajun li }
61141e568d1Shuajun li
sd_scsi_mode_sense(struct us_data * us,struct scsi_cmnd * srb)61241e568d1Shuajun li static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
61341e568d1Shuajun li {
61441e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
61541e568d1Shuajun li unsigned char mediaNoWP[12] = {
61641e568d1Shuajun li 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
61741e568d1Shuajun li 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
61841e568d1Shuajun li unsigned char mediaWP[12] = {
61941e568d1Shuajun li 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
62041e568d1Shuajun li 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
62141e568d1Shuajun li
6221892bf90SAlan Stern if (info->SD_Status & SD_WtP)
62341e568d1Shuajun li usb_stor_set_xfer_buf(mediaWP, 12, srb);
62441e568d1Shuajun li else
62541e568d1Shuajun li usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
62641e568d1Shuajun li
62741e568d1Shuajun li
62841e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
62941e568d1Shuajun li }
63041e568d1Shuajun li
sd_scsi_read_capacity(struct us_data * us,struct scsi_cmnd * srb)63141e568d1Shuajun li static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
63241e568d1Shuajun li {
63341e568d1Shuajun li u32 bl_num;
63436f3a14dSFelipe Balbi u32 bl_len;
63541e568d1Shuajun li unsigned int offset = 0;
63641e568d1Shuajun li unsigned char buf[8];
63741e568d1Shuajun li struct scatterlist *sg = NULL;
63841e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
63941e568d1Shuajun li
640191648d0SJoe Perches usb_stor_dbg(us, "sd_scsi_read_capacity\n");
6411892bf90SAlan Stern if (info->SD_Status & SD_HiCapacity) {
64241e568d1Shuajun li bl_len = 0x200;
6431892bf90SAlan Stern if (info->SD_Status & SD_IsMMC)
64441e568d1Shuajun li bl_num = info->HC_C_SIZE-1;
64541e568d1Shuajun li else
64641e568d1Shuajun li bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
64741e568d1Shuajun li } else {
64841e568d1Shuajun li bl_len = 1 << (info->SD_READ_BL_LEN);
64941e568d1Shuajun li bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
65041e568d1Shuajun li * (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
65141e568d1Shuajun li }
65241e568d1Shuajun li info->bl_num = bl_num;
653191648d0SJoe Perches usb_stor_dbg(us, "bl_len = %x\n", bl_len);
654191648d0SJoe Perches usb_stor_dbg(us, "bl_num = %x\n", bl_num);
65541e568d1Shuajun li
65641e568d1Shuajun li /*srb->request_bufflen = 8; */
65741e568d1Shuajun li buf[0] = (bl_num >> 24) & 0xff;
65841e568d1Shuajun li buf[1] = (bl_num >> 16) & 0xff;
65941e568d1Shuajun li buf[2] = (bl_num >> 8) & 0xff;
66041e568d1Shuajun li buf[3] = (bl_num >> 0) & 0xff;
66141e568d1Shuajun li buf[4] = (bl_len >> 24) & 0xff;
66241e568d1Shuajun li buf[5] = (bl_len >> 16) & 0xff;
66341e568d1Shuajun li buf[6] = (bl_len >> 8) & 0xff;
66441e568d1Shuajun li buf[7] = (bl_len >> 0) & 0xff;
66541e568d1Shuajun li
66641e568d1Shuajun li usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
66741e568d1Shuajun li
66841e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
66941e568d1Shuajun li }
67041e568d1Shuajun li
sd_scsi_read(struct us_data * us,struct scsi_cmnd * srb)67141e568d1Shuajun li static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
67241e568d1Shuajun li {
67341e568d1Shuajun li int result;
67441e568d1Shuajun li unsigned char *cdb = srb->cmnd;
67541e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
67641e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
67741e568d1Shuajun li
67841e568d1Shuajun li u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
67941e568d1Shuajun li ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
68041e568d1Shuajun li u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
68141e568d1Shuajun li u32 bnByte = bn * 0x200;
68241e568d1Shuajun li u32 blenByte = blen * 0x200;
68341e568d1Shuajun li
68441e568d1Shuajun li if (bn > info->bl_num)
68541e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
68641e568d1Shuajun li
68741e568d1Shuajun li result = ene_load_bincode(us, SD_RW_PATTERN);
68841e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
689191648d0SJoe Perches usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
69041e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
69141e568d1Shuajun li }
69241e568d1Shuajun li
6931892bf90SAlan Stern if (info->SD_Status & SD_HiCapacity)
69441e568d1Shuajun li bnByte = bn;
69541e568d1Shuajun li
69641e568d1Shuajun li /* set up the command wrapper */
69741e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
69841e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
69941e568d1Shuajun li bcb->DataTransferLength = blenByte;
700b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
70141e568d1Shuajun li bcb->CDB[0] = 0xF1;
70241e568d1Shuajun li bcb->CDB[5] = (unsigned char)(bnByte);
70341e568d1Shuajun li bcb->CDB[4] = (unsigned char)(bnByte>>8);
70441e568d1Shuajun li bcb->CDB[3] = (unsigned char)(bnByte>>16);
70541e568d1Shuajun li bcb->CDB[2] = (unsigned char)(bnByte>>24);
70641e568d1Shuajun li
70741e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
70841e568d1Shuajun li return result;
70941e568d1Shuajun li }
71041e568d1Shuajun li
sd_scsi_write(struct us_data * us,struct scsi_cmnd * srb)71141e568d1Shuajun li static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
71241e568d1Shuajun li {
71341e568d1Shuajun li int result;
71441e568d1Shuajun li unsigned char *cdb = srb->cmnd;
71541e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
71641e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
71741e568d1Shuajun li
71841e568d1Shuajun li u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
71941e568d1Shuajun li ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
72041e568d1Shuajun li u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
72141e568d1Shuajun li u32 bnByte = bn * 0x200;
72241e568d1Shuajun li u32 blenByte = blen * 0x200;
72341e568d1Shuajun li
72441e568d1Shuajun li if (bn > info->bl_num)
72541e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
72641e568d1Shuajun li
72741e568d1Shuajun li result = ene_load_bincode(us, SD_RW_PATTERN);
72841e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
729191648d0SJoe Perches usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
73041e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
73141e568d1Shuajun li }
73241e568d1Shuajun li
7331892bf90SAlan Stern if (info->SD_Status & SD_HiCapacity)
73441e568d1Shuajun li bnByte = bn;
73541e568d1Shuajun li
73641e568d1Shuajun li /* set up the command wrapper */
73741e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
73841e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
73941e568d1Shuajun li bcb->DataTransferLength = blenByte;
74041e568d1Shuajun li bcb->Flags = 0x00;
74141e568d1Shuajun li bcb->CDB[0] = 0xF0;
74241e568d1Shuajun li bcb->CDB[5] = (unsigned char)(bnByte);
74341e568d1Shuajun li bcb->CDB[4] = (unsigned char)(bnByte>>8);
74441e568d1Shuajun li bcb->CDB[3] = (unsigned char)(bnByte>>16);
74541e568d1Shuajun li bcb->CDB[2] = (unsigned char)(bnByte>>24);
74641e568d1Shuajun li
74741e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
74841e568d1Shuajun li return result;
74941e568d1Shuajun li }
75041e568d1Shuajun li
75133842cedSCho, Yu-Chen /*
75233842cedSCho, Yu-Chen * ENE MS Card
75333842cedSCho, Yu-Chen */
75433842cedSCho, Yu-Chen
ms_lib_set_logicalpair(struct us_data * us,u16 logblk,u16 phyblk)75533842cedSCho, Yu-Chen static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk)
75633842cedSCho, Yu-Chen {
75733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
75833842cedSCho, Yu-Chen
75933842cedSCho, Yu-Chen if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock))
76033842cedSCho, Yu-Chen return (u32)-1;
76133842cedSCho, Yu-Chen
76233842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = logblk;
76333842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[logblk] = phyblk;
76433842cedSCho, Yu-Chen
76533842cedSCho, Yu-Chen return 0;
76633842cedSCho, Yu-Chen }
76733842cedSCho, Yu-Chen
ms_lib_set_logicalblockmark(struct us_data * us,u16 phyblk,u16 mark)76833842cedSCho, Yu-Chen static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark)
76933842cedSCho, Yu-Chen {
77033842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
77133842cedSCho, Yu-Chen
77233842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
77333842cedSCho, Yu-Chen return (u32)-1;
77433842cedSCho, Yu-Chen
77533842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = mark;
77633842cedSCho, Yu-Chen
77733842cedSCho, Yu-Chen return 0;
77833842cedSCho, Yu-Chen }
77933842cedSCho, Yu-Chen
ms_lib_set_initialerrorblock(struct us_data * us,u16 phyblk)78033842cedSCho, Yu-Chen static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk)
78133842cedSCho, Yu-Chen {
78233842cedSCho, Yu-Chen return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR);
78333842cedSCho, Yu-Chen }
78433842cedSCho, Yu-Chen
ms_lib_set_bootblockmark(struct us_data * us,u16 phyblk)78533842cedSCho, Yu-Chen static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk)
78633842cedSCho, Yu-Chen {
78733842cedSCho, Yu-Chen return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK);
78833842cedSCho, Yu-Chen }
78933842cedSCho, Yu-Chen
ms_lib_free_logicalmap(struct us_data * us)79033842cedSCho, Yu-Chen static int ms_lib_free_logicalmap(struct us_data *us)
79133842cedSCho, Yu-Chen {
79233842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
79333842cedSCho, Yu-Chen
79433842cedSCho, Yu-Chen kfree(info->MS_Lib.Phy2LogMap);
79533842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap = NULL;
79633842cedSCho, Yu-Chen
79733842cedSCho, Yu-Chen kfree(info->MS_Lib.Log2PhyMap);
79833842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap = NULL;
79933842cedSCho, Yu-Chen
80033842cedSCho, Yu-Chen return 0;
80133842cedSCho, Yu-Chen }
80233842cedSCho, Yu-Chen
ms_lib_alloc_logicalmap(struct us_data * us)80336f3a14dSFelipe Balbi static int ms_lib_alloc_logicalmap(struct us_data *us)
80433842cedSCho, Yu-Chen {
80533842cedSCho, Yu-Chen u32 i;
80633842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
80733842cedSCho, Yu-Chen
8086da2ec56SKees Cook info->MS_Lib.Phy2LogMap = kmalloc_array(info->MS_Lib.NumberOfPhyBlock,
8096da2ec56SKees Cook sizeof(u16),
8106da2ec56SKees Cook GFP_KERNEL);
8116da2ec56SKees Cook info->MS_Lib.Log2PhyMap = kmalloc_array(info->MS_Lib.NumberOfLogBlock,
8126da2ec56SKees Cook sizeof(u16),
8136da2ec56SKees Cook GFP_KERNEL);
81433842cedSCho, Yu-Chen
81533842cedSCho, Yu-Chen if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) {
81633842cedSCho, Yu-Chen ms_lib_free_logicalmap(us);
81733842cedSCho, Yu-Chen return (u32)-1;
81833842cedSCho, Yu-Chen }
81933842cedSCho, Yu-Chen
82033842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++)
82133842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED;
82233842cedSCho, Yu-Chen
82333842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++)
82433842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED;
82533842cedSCho, Yu-Chen
82633842cedSCho, Yu-Chen return 0;
82733842cedSCho, Yu-Chen }
82833842cedSCho, Yu-Chen
ms_lib_clear_writebuf(struct us_data * us)82933842cedSCho, Yu-Chen static void ms_lib_clear_writebuf(struct us_data *us)
83033842cedSCho, Yu-Chen {
83133842cedSCho, Yu-Chen int i;
83233842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
83333842cedSCho, Yu-Chen
83433842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1;
83533842cedSCho, Yu-Chen ms_lib_clear_pagemap(info);
83633842cedSCho, Yu-Chen
83733842cedSCho, Yu-Chen if (info->MS_Lib.blkpag)
83833842cedSCho, Yu-Chen memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector);
83933842cedSCho, Yu-Chen
84033842cedSCho, Yu-Chen if (info->MS_Lib.blkext) {
84133842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) {
84233842cedSCho, Yu-Chen info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT;
84333842cedSCho, Yu-Chen info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT;
84433842cedSCho, Yu-Chen info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT;
84533842cedSCho, Yu-Chen info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED;
84633842cedSCho, Yu-Chen }
84733842cedSCho, Yu-Chen }
84833842cedSCho, Yu-Chen }
84933842cedSCho, Yu-Chen
ms_count_freeblock(struct us_data * us,u16 PhyBlock)85033842cedSCho, Yu-Chen static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
85133842cedSCho, Yu-Chen {
85233842cedSCho, Yu-Chen u32 Ende, Count;
85333842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
85433842cedSCho, Yu-Chen
85533842cedSCho, Yu-Chen Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT;
85633842cedSCho, Yu-Chen for (Count = 0; PhyBlock < Ende; PhyBlock++) {
85733842cedSCho, Yu-Chen switch (info->MS_Lib.Phy2LogMap[PhyBlock]) {
85833842cedSCho, Yu-Chen case MS_LB_NOT_USED:
85933842cedSCho, Yu-Chen case MS_LB_NOT_USED_ERASED:
86033842cedSCho, Yu-Chen Count++;
86193c747edSGustavo A. R. Silva break;
86233842cedSCho, Yu-Chen default:
86333842cedSCho, Yu-Chen break;
86433842cedSCho, Yu-Chen }
86533842cedSCho, Yu-Chen }
86633842cedSCho, Yu-Chen
86733842cedSCho, Yu-Chen return Count;
86833842cedSCho, Yu-Chen }
86933842cedSCho, Yu-Chen
ms_read_readpage(struct us_data * us,u32 PhyBlockAddr,u8 PageNum,u32 * PageBuf,struct ms_lib_type_extdat * ExtraDat)87033842cedSCho, Yu-Chen static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
87133842cedSCho, Yu-Chen u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
87233842cedSCho, Yu-Chen {
87333842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
874628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
875628c2893SAlan Stern u8 *bbuf = info->bbuf;
87633842cedSCho, Yu-Chen int result;
87733842cedSCho, Yu-Chen u32 bn = PhyBlockAddr * 0x20 + PageNum;
87833842cedSCho, Yu-Chen
87933842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
88033842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
88133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
88233842cedSCho, Yu-Chen
88333842cedSCho, Yu-Chen /* Read Page Data */
88433842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
88533842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
88633842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200;
887b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
88833842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
88933842cedSCho, Yu-Chen
89033842cedSCho, Yu-Chen bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */
89133842cedSCho, Yu-Chen
89233842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn);
89333842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8);
89433842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16);
89533842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24);
89633842cedSCho, Yu-Chen
89733842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0);
89833842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
89933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
90033842cedSCho, Yu-Chen
90133842cedSCho, Yu-Chen
90233842cedSCho, Yu-Chen /* Read Extra Data */
90333842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
90433842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
90533842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4;
906b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
90733842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
90833842cedSCho, Yu-Chen bcb->CDB[1] = 0x03;
90933842cedSCho, Yu-Chen
91033842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum);
91133842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
91233842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
91333842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
91433842cedSCho, Yu-Chen bcb->CDB[6] = 0x01;
91533842cedSCho, Yu-Chen
916628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
91733842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
91833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
91933842cedSCho, Yu-Chen
92033842cedSCho, Yu-Chen ExtraDat->reserved = 0;
92133842cedSCho, Yu-Chen ExtraDat->intr = 0x80; /* Not yet,fireware support */
92233842cedSCho, Yu-Chen ExtraDat->status0 = 0x10; /* Not yet,fireware support */
92333842cedSCho, Yu-Chen
92433842cedSCho, Yu-Chen ExtraDat->status1 = 0x00; /* Not yet,fireware support */
925628c2893SAlan Stern ExtraDat->ovrflg = bbuf[0];
926628c2893SAlan Stern ExtraDat->mngflg = bbuf[1];
927628c2893SAlan Stern ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
92833842cedSCho, Yu-Chen
92933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
93033842cedSCho, Yu-Chen }
93133842cedSCho, Yu-Chen
ms_lib_process_bootblock(struct us_data * us,u16 PhyBlock,u8 * PageData)93233842cedSCho, Yu-Chen static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData)
93333842cedSCho, Yu-Chen {
93433842cedSCho, Yu-Chen struct ms_bootblock_sysent *SysEntry;
93533842cedSCho, Yu-Chen struct ms_bootblock_sysinf *SysInfo;
93633842cedSCho, Yu-Chen u32 i, result;
93733842cedSCho, Yu-Chen u8 PageNumber;
93833842cedSCho, Yu-Chen u8 *PageBuffer;
93933842cedSCho, Yu-Chen struct ms_lib_type_extdat ExtraData;
94033842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
94133842cedSCho, Yu-Chen
942*ce33e64cSKees Cook PageBuffer = kzalloc(MS_BYTES_PER_PAGE * 2, GFP_KERNEL);
94333842cedSCho, Yu-Chen if (PageBuffer == NULL)
94433842cedSCho, Yu-Chen return (u32)-1;
94533842cedSCho, Yu-Chen
94633842cedSCho, Yu-Chen result = (u32)-1;
94733842cedSCho, Yu-Chen
94833842cedSCho, Yu-Chen SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf);
94933842cedSCho, Yu-Chen
95033842cedSCho, Yu-Chen if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) ||
95133842cedSCho, Yu-Chen (be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) ||
95233842cedSCho, Yu-Chen ((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) ||
95333842cedSCho, Yu-Chen (SysInfo->bReserved1 != MS_SYSINF_RESERVED1) ||
95433842cedSCho, Yu-Chen (SysInfo->bReserved2 != MS_SYSINF_RESERVED2) ||
95533842cedSCho, Yu-Chen (SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) ||
95633842cedSCho, Yu-Chen (SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL))
95733842cedSCho, Yu-Chen goto exit;
95833842cedSCho, Yu-Chen /* */
95933842cedSCho, Yu-Chen switch (info->MS_Lib.cardType = SysInfo->bCardType) {
96033842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_RDONLY:
96133842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY);
96233842cedSCho, Yu-Chen break;
96333842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_RDWR:
96433842cedSCho, Yu-Chen ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY);
96533842cedSCho, Yu-Chen break;
96633842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_HYBRID:
96733842cedSCho, Yu-Chen default:
96833842cedSCho, Yu-Chen goto exit;
96933842cedSCho, Yu-Chen }
97033842cedSCho, Yu-Chen
97133842cedSCho, Yu-Chen info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize);
97233842cedSCho, Yu-Chen info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber);
97333842cedSCho, Yu-Chen info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2;
97433842cedSCho, Yu-Chen info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE;
97533842cedSCho, Yu-Chen info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT;
97633842cedSCho, Yu-Chen info->MS_Model = be16_to_cpu(SysInfo->wMemorySize);
97733842cedSCho, Yu-Chen
97833842cedSCho, Yu-Chen /*Allocate to all number of logicalblock and physicalblock */
97933842cedSCho, Yu-Chen if (ms_lib_alloc_logicalmap(us))
98033842cedSCho, Yu-Chen goto exit;
98133842cedSCho, Yu-Chen
98233842cedSCho, Yu-Chen /* Mark the book block */
98333842cedSCho, Yu-Chen ms_lib_set_bootblockmark(us, PhyBlock);
98433842cedSCho, Yu-Chen
98533842cedSCho, Yu-Chen SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent);
98633842cedSCho, Yu-Chen
98733842cedSCho, Yu-Chen for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) {
98833842cedSCho, Yu-Chen u32 EntryOffset, EntrySize;
98933842cedSCho, Yu-Chen
99033842cedSCho, Yu-Chen EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart);
99133842cedSCho, Yu-Chen
99233842cedSCho, Yu-Chen if (EntryOffset == 0xffffff)
99333842cedSCho, Yu-Chen continue;
99433842cedSCho, Yu-Chen EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize);
99533842cedSCho, Yu-Chen
99633842cedSCho, Yu-Chen if (EntrySize == 0)
99733842cedSCho, Yu-Chen continue;
99833842cedSCho, Yu-Chen
99933842cedSCho, Yu-Chen if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO)
100033842cedSCho, Yu-Chen continue;
100133842cedSCho, Yu-Chen
100233842cedSCho, Yu-Chen if (i == 0) {
100333842cedSCho, Yu-Chen u8 PrevPageNumber = 0;
100433842cedSCho, Yu-Chen u16 phyblk;
100533842cedSCho, Yu-Chen
100633842cedSCho, Yu-Chen if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK)
100733842cedSCho, Yu-Chen goto exit;
100833842cedSCho, Yu-Chen
100933842cedSCho, Yu-Chen while (EntrySize > 0) {
101033842cedSCho, Yu-Chen
101133842cedSCho, Yu-Chen PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1);
101233842cedSCho, Yu-Chen if (PageNumber != PrevPageNumber) {
101333842cedSCho, Yu-Chen switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) {
101433842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
101533842cedSCho, Yu-Chen break;
101633842cedSCho, Yu-Chen case MS_STATUS_WRITE_PROTECT:
101733842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ:
101833842cedSCho, Yu-Chen case MS_STATUS_ERROR:
101933842cedSCho, Yu-Chen default:
102033842cedSCho, Yu-Chen goto exit;
102133842cedSCho, Yu-Chen }
102233842cedSCho, Yu-Chen
102333842cedSCho, Yu-Chen PrevPageNumber = PageNumber;
102433842cedSCho, Yu-Chen }
102533842cedSCho, Yu-Chen
102633842cedSCho, Yu-Chen phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)));
102733842cedSCho, Yu-Chen if (phyblk < 0x0fff)
102833842cedSCho, Yu-Chen ms_lib_set_initialerrorblock(us, phyblk);
102933842cedSCho, Yu-Chen
103033842cedSCho, Yu-Chen EntryOffset += 2;
103133842cedSCho, Yu-Chen EntrySize -= 2;
103233842cedSCho, Yu-Chen }
103333842cedSCho, Yu-Chen } else if (i == 1) { /* CIS/IDI */
103433842cedSCho, Yu-Chen struct ms_bootblock_idi *idi;
103533842cedSCho, Yu-Chen
103633842cedSCho, Yu-Chen if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI)
103733842cedSCho, Yu-Chen goto exit;
103833842cedSCho, Yu-Chen
103933842cedSCho, Yu-Chen switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) {
104033842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
104133842cedSCho, Yu-Chen break;
104233842cedSCho, Yu-Chen case MS_STATUS_WRITE_PROTECT:
104333842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ:
104433842cedSCho, Yu-Chen case MS_STATUS_ERROR:
104533842cedSCho, Yu-Chen default:
104633842cedSCho, Yu-Chen goto exit;
104733842cedSCho, Yu-Chen }
104833842cedSCho, Yu-Chen
104933842cedSCho, Yu-Chen idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi;
105033842cedSCho, Yu-Chen if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF)
105133842cedSCho, Yu-Chen goto exit;
105233842cedSCho, Yu-Chen
105333842cedSCho, Yu-Chen info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector);
105433842cedSCho, Yu-Chen if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE)
105533842cedSCho, Yu-Chen goto exit;
105633842cedSCho, Yu-Chen }
105733842cedSCho, Yu-Chen } /* End for .. */
105833842cedSCho, Yu-Chen
105933842cedSCho, Yu-Chen result = 0;
106033842cedSCho, Yu-Chen
106133842cedSCho, Yu-Chen exit:
106233842cedSCho, Yu-Chen if (result)
106333842cedSCho, Yu-Chen ms_lib_free_logicalmap(us);
106433842cedSCho, Yu-Chen
106533842cedSCho, Yu-Chen kfree(PageBuffer);
106633842cedSCho, Yu-Chen
106733842cedSCho, Yu-Chen result = 0;
106833842cedSCho, Yu-Chen return result;
106933842cedSCho, Yu-Chen }
107033842cedSCho, Yu-Chen
ms_lib_free_writebuf(struct us_data * us)107133842cedSCho, Yu-Chen static void ms_lib_free_writebuf(struct us_data *us)
107233842cedSCho, Yu-Chen {
107333842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
107433842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */
107533842cedSCho, Yu-Chen
107633842cedSCho, Yu-Chen /* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */
107733842cedSCho, Yu-Chen
107833842cedSCho, Yu-Chen ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */
107933842cedSCho, Yu-Chen
108033842cedSCho, Yu-Chen if (info->MS_Lib.blkpag) {
1081e6533e87SAmitoj Kaur Chawla kfree(info->MS_Lib.blkpag); /* Arnold test ... */
108233842cedSCho, Yu-Chen info->MS_Lib.blkpag = NULL;
108333842cedSCho, Yu-Chen }
108433842cedSCho, Yu-Chen
108533842cedSCho, Yu-Chen if (info->MS_Lib.blkext) {
1086e6533e87SAmitoj Kaur Chawla kfree(info->MS_Lib.blkext); /* Arnold test ... */
108733842cedSCho, Yu-Chen info->MS_Lib.blkext = NULL;
108833842cedSCho, Yu-Chen }
108933842cedSCho, Yu-Chen }
109033842cedSCho, Yu-Chen
109133842cedSCho, Yu-Chen
ms_lib_free_allocatedarea(struct us_data * us)109233842cedSCho, Yu-Chen static void ms_lib_free_allocatedarea(struct us_data *us)
109333842cedSCho, Yu-Chen {
109433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
109533842cedSCho, Yu-Chen
109633842cedSCho, Yu-Chen ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */
109733842cedSCho, Yu-Chen ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */
109833842cedSCho, Yu-Chen
109933842cedSCho, Yu-Chen /* set struct us point flag to 0 */
110033842cedSCho, Yu-Chen info->MS_Lib.flags = 0;
110133842cedSCho, Yu-Chen info->MS_Lib.BytesPerSector = 0;
110233842cedSCho, Yu-Chen info->MS_Lib.SectorsPerCylinder = 0;
110333842cedSCho, Yu-Chen
110433842cedSCho, Yu-Chen info->MS_Lib.cardType = 0;
110533842cedSCho, Yu-Chen info->MS_Lib.blockSize = 0;
110633842cedSCho, Yu-Chen info->MS_Lib.PagesPerBlock = 0;
110733842cedSCho, Yu-Chen
110833842cedSCho, Yu-Chen info->MS_Lib.NumberOfPhyBlock = 0;
110933842cedSCho, Yu-Chen info->MS_Lib.NumberOfLogBlock = 0;
111033842cedSCho, Yu-Chen }
111133842cedSCho, Yu-Chen
111233842cedSCho, Yu-Chen
ms_lib_alloc_writebuf(struct us_data * us)111333842cedSCho, Yu-Chen static int ms_lib_alloc_writebuf(struct us_data *us)
111433842cedSCho, Yu-Chen {
111533842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
111633842cedSCho, Yu-Chen
111733842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1;
111833842cedSCho, Yu-Chen
11196da2ec56SKees Cook info->MS_Lib.blkpag = kmalloc_array(info->MS_Lib.PagesPerBlock,
11206da2ec56SKees Cook info->MS_Lib.BytesPerSector,
11216da2ec56SKees Cook GFP_KERNEL);
11226da2ec56SKees Cook info->MS_Lib.blkext = kmalloc_array(info->MS_Lib.PagesPerBlock,
11236da2ec56SKees Cook sizeof(struct ms_lib_type_extdat),
11246da2ec56SKees Cook GFP_KERNEL);
112533842cedSCho, Yu-Chen
112633842cedSCho, Yu-Chen if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) {
112733842cedSCho, Yu-Chen ms_lib_free_writebuf(us);
112833842cedSCho, Yu-Chen return (u32)-1;
112933842cedSCho, Yu-Chen }
113033842cedSCho, Yu-Chen
113133842cedSCho, Yu-Chen ms_lib_clear_writebuf(us);
113233842cedSCho, Yu-Chen
113333842cedSCho, Yu-Chen return 0;
113433842cedSCho, Yu-Chen }
113533842cedSCho, Yu-Chen
ms_lib_force_setlogical_pair(struct us_data * us,u16 logblk,u16 phyblk)113633842cedSCho, Yu-Chen static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk)
113733842cedSCho, Yu-Chen {
113833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
113933842cedSCho, Yu-Chen
114033842cedSCho, Yu-Chen if (logblk == MS_LB_NOT_USED)
114133842cedSCho, Yu-Chen return 0;
114233842cedSCho, Yu-Chen
114333842cedSCho, Yu-Chen if ((logblk >= info->MS_Lib.NumberOfLogBlock) ||
114433842cedSCho, Yu-Chen (phyblk >= info->MS_Lib.NumberOfPhyBlock))
114533842cedSCho, Yu-Chen return (u32)-1;
114633842cedSCho, Yu-Chen
114733842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = logblk;
114833842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[logblk] = phyblk;
114933842cedSCho, Yu-Chen
115033842cedSCho, Yu-Chen return 0;
115133842cedSCho, Yu-Chen }
115233842cedSCho, Yu-Chen
ms_read_copyblock(struct us_data * us,u16 oldphy,u16 newphy,u16 PhyBlockAddr,u8 PageNum,unsigned char * buf,u16 len)115333842cedSCho, Yu-Chen static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
115433842cedSCho, Yu-Chen u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len)
115533842cedSCho, Yu-Chen {
115633842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
115733842cedSCho, Yu-Chen int result;
115833842cedSCho, Yu-Chen
115933842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
116033842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
116133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
116233842cedSCho, Yu-Chen
116333842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
116433842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
116533842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200*len;
116633842cedSCho, Yu-Chen bcb->Flags = 0x00;
116733842cedSCho, Yu-Chen bcb->CDB[0] = 0xF0;
116833842cedSCho, Yu-Chen bcb->CDB[1] = 0x08;
116933842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(oldphy);
117033842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(oldphy>>8);
117133842cedSCho, Yu-Chen bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */
117233842cedSCho, Yu-Chen bcb->CDB[7] = (unsigned char)(newphy);
117333842cedSCho, Yu-Chen bcb->CDB[6] = (unsigned char)(newphy>>8);
117433842cedSCho, Yu-Chen bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */
117533842cedSCho, Yu-Chen bcb->CDB[9] = (unsigned char)(PhyBlockAddr);
117633842cedSCho, Yu-Chen bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8);
117733842cedSCho, Yu-Chen bcb->CDB[10] = PageNum;
117833842cedSCho, Yu-Chen
117933842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
118033842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
118133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
118233842cedSCho, Yu-Chen
118333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
118433842cedSCho, Yu-Chen }
118533842cedSCho, Yu-Chen
ms_read_eraseblock(struct us_data * us,u32 PhyBlockAddr)118633842cedSCho, Yu-Chen static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
118733842cedSCho, Yu-Chen {
118833842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
118933842cedSCho, Yu-Chen int result;
119033842cedSCho, Yu-Chen u32 bn = PhyBlockAddr;
119133842cedSCho, Yu-Chen
119233842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
119333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
119433842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
119533842cedSCho, Yu-Chen
119633842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
119733842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
119833842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200;
1199b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
120033842cedSCho, Yu-Chen bcb->CDB[0] = 0xF2;
120133842cedSCho, Yu-Chen bcb->CDB[1] = 0x06;
120233842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn);
120333842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>8);
120433842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>16);
120533842cedSCho, Yu-Chen
120633842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
120733842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
120833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
120933842cedSCho, Yu-Chen
121033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
121133842cedSCho, Yu-Chen }
121233842cedSCho, Yu-Chen
ms_lib_check_disableblock(struct us_data * us,u16 PhyBlock)121333842cedSCho, Yu-Chen static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock)
121433842cedSCho, Yu-Chen {
121533842cedSCho, Yu-Chen unsigned char *PageBuf = NULL;
121633842cedSCho, Yu-Chen u16 result = MS_STATUS_SUCCESS;
121733842cedSCho, Yu-Chen u16 blk, index = 0;
121833842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat;
121933842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
122033842cedSCho, Yu-Chen
122133842cedSCho, Yu-Chen PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
122233842cedSCho, Yu-Chen if (PageBuf == NULL) {
122333842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR;
122433842cedSCho, Yu-Chen goto exit;
122533842cedSCho, Yu-Chen }
122633842cedSCho, Yu-Chen
122733842cedSCho, Yu-Chen ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat);
122833842cedSCho, Yu-Chen do {
122933842cedSCho, Yu-Chen blk = be16_to_cpu(PageBuf[index]);
123033842cedSCho, Yu-Chen if (blk == MS_LB_NOT_USED)
123133842cedSCho, Yu-Chen break;
123233842cedSCho, Yu-Chen if (blk == info->MS_Lib.Log2PhyMap[0]) {
123333842cedSCho, Yu-Chen result = MS_ERROR_FLASH_READ;
123433842cedSCho, Yu-Chen break;
123533842cedSCho, Yu-Chen }
123633842cedSCho, Yu-Chen index++;
123733842cedSCho, Yu-Chen } while (1);
123833842cedSCho, Yu-Chen
123933842cedSCho, Yu-Chen exit:
124033842cedSCho, Yu-Chen kfree(PageBuf);
124133842cedSCho, Yu-Chen return result;
124233842cedSCho, Yu-Chen }
124333842cedSCho, Yu-Chen
ms_lib_setacquired_errorblock(struct us_data * us,u16 phyblk)124433842cedSCho, Yu-Chen static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk)
124533842cedSCho, Yu-Chen {
124633842cedSCho, Yu-Chen u16 log;
124733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
124833842cedSCho, Yu-Chen
124933842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
125033842cedSCho, Yu-Chen return (u32)-1;
125133842cedSCho, Yu-Chen
125233842cedSCho, Yu-Chen log = info->MS_Lib.Phy2LogMap[phyblk];
125333842cedSCho, Yu-Chen
125433842cedSCho, Yu-Chen if (log < info->MS_Lib.NumberOfLogBlock)
125533842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
125633842cedSCho, Yu-Chen
125733842cedSCho, Yu-Chen if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR)
125833842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR;
125933842cedSCho, Yu-Chen
126033842cedSCho, Yu-Chen return 0;
126133842cedSCho, Yu-Chen }
126233842cedSCho, Yu-Chen
ms_lib_overwrite_extra(struct us_data * us,u32 PhyBlockAddr,u8 PageNum,u8 OverwriteFlag)126333842cedSCho, Yu-Chen static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
126433842cedSCho, Yu-Chen u8 PageNum, u8 OverwriteFlag)
126533842cedSCho, Yu-Chen {
126633842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
126733842cedSCho, Yu-Chen int result;
126833842cedSCho, Yu-Chen
126933842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
127033842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
127133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
127233842cedSCho, Yu-Chen
127333842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
127433842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
127533842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4;
1276b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
127733842cedSCho, Yu-Chen bcb->CDB[0] = 0xF2;
127833842cedSCho, Yu-Chen bcb->CDB[1] = 0x05;
127933842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum);
128033842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
128133842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
128233842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
128333842cedSCho, Yu-Chen bcb->CDB[6] = OverwriteFlag;
128433842cedSCho, Yu-Chen bcb->CDB[7] = 0xFF;
128533842cedSCho, Yu-Chen bcb->CDB[8] = 0xFF;
128633842cedSCho, Yu-Chen bcb->CDB[9] = 0xFF;
128733842cedSCho, Yu-Chen
128833842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
128933842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
129033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
129133842cedSCho, Yu-Chen
129233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
129333842cedSCho, Yu-Chen }
129433842cedSCho, Yu-Chen
ms_lib_error_phyblock(struct us_data * us,u16 phyblk)129533842cedSCho, Yu-Chen static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk)
129633842cedSCho, Yu-Chen {
129733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
129833842cedSCho, Yu-Chen
129933842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
130033842cedSCho, Yu-Chen return MS_STATUS_ERROR;
130133842cedSCho, Yu-Chen
130233842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk);
130333842cedSCho, Yu-Chen
130433842cedSCho, Yu-Chen if (ms_lib_iswritable(info))
130533842cedSCho, Yu-Chen return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK));
130633842cedSCho, Yu-Chen
130733842cedSCho, Yu-Chen return MS_STATUS_SUCCESS;
130833842cedSCho, Yu-Chen }
130933842cedSCho, Yu-Chen
ms_lib_erase_phyblock(struct us_data * us,u16 phyblk)131033842cedSCho, Yu-Chen static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk)
131133842cedSCho, Yu-Chen {
131233842cedSCho, Yu-Chen u16 log;
131333842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
131433842cedSCho, Yu-Chen
131533842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
131633842cedSCho, Yu-Chen return MS_STATUS_ERROR;
131733842cedSCho, Yu-Chen
131833842cedSCho, Yu-Chen log = info->MS_Lib.Phy2LogMap[phyblk];
131933842cedSCho, Yu-Chen
132033842cedSCho, Yu-Chen if (log < info->MS_Lib.NumberOfLogBlock)
132133842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
132233842cedSCho, Yu-Chen
132333842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED;
132433842cedSCho, Yu-Chen
132533842cedSCho, Yu-Chen if (ms_lib_iswritable(info)) {
132633842cedSCho, Yu-Chen switch (ms_read_eraseblock(us, phyblk)) {
132733842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
132833842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED;
132933842cedSCho, Yu-Chen return MS_STATUS_SUCCESS;
133033842cedSCho, Yu-Chen case MS_ERROR_FLASH_ERASE:
133133842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR:
133233842cedSCho, Yu-Chen ms_lib_error_phyblock(us, phyblk);
133333842cedSCho, Yu-Chen return MS_ERROR_FLASH_ERASE;
133433842cedSCho, Yu-Chen case MS_STATUS_ERROR:
133533842cedSCho, Yu-Chen default:
133633842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); /* MS_LibCtrlSet will used by ENE_MSInit ,need check, and why us to info*/
133733842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk);
133833842cedSCho, Yu-Chen return MS_STATUS_ERROR;
133933842cedSCho, Yu-Chen }
134033842cedSCho, Yu-Chen }
134133842cedSCho, Yu-Chen
134233842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk);
134333842cedSCho, Yu-Chen
134433842cedSCho, Yu-Chen return MS_STATUS_SUCCESS;
134533842cedSCho, Yu-Chen }
134633842cedSCho, Yu-Chen
ms_lib_read_extra(struct us_data * us,u32 PhyBlock,u8 PageNum,struct ms_lib_type_extdat * ExtraDat)134733842cedSCho, Yu-Chen static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
134833842cedSCho, Yu-Chen u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
134933842cedSCho, Yu-Chen {
135033842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
1351628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
1352628c2893SAlan Stern u8 *bbuf = info->bbuf;
135333842cedSCho, Yu-Chen int result;
135433842cedSCho, Yu-Chen
135533842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
135633842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
135733842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4;
1358b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
135933842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
136033842cedSCho, Yu-Chen bcb->CDB[1] = 0x03;
136133842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum);
136233842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlock);
136333842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlock>>8);
136433842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
136533842cedSCho, Yu-Chen bcb->CDB[6] = 0x01;
136633842cedSCho, Yu-Chen
1367628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
136833842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
136933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
137033842cedSCho, Yu-Chen
137133842cedSCho, Yu-Chen ExtraDat->reserved = 0;
137233842cedSCho, Yu-Chen ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */
137333842cedSCho, Yu-Chen ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */
137433842cedSCho, Yu-Chen ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */
1375628c2893SAlan Stern ExtraDat->ovrflg = bbuf[0];
1376628c2893SAlan Stern ExtraDat->mngflg = bbuf[1];
1377628c2893SAlan Stern ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
137833842cedSCho, Yu-Chen
137933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
138033842cedSCho, Yu-Chen }
138133842cedSCho, Yu-Chen
ms_libsearch_block_from_physical(struct us_data * us,u16 phyblk)138233842cedSCho, Yu-Chen static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk)
138333842cedSCho, Yu-Chen {
138433842cedSCho, Yu-Chen u16 blk;
138533842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat; /* need check */
138633842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
138733842cedSCho, Yu-Chen
138833842cedSCho, Yu-Chen
138933842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
139033842cedSCho, Yu-Chen return MS_LB_ERROR;
139133842cedSCho, Yu-Chen
139233842cedSCho, Yu-Chen for (blk = phyblk + 1; blk != phyblk; blk++) {
139333842cedSCho, Yu-Chen if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0)
139433842cedSCho, Yu-Chen blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
139533842cedSCho, Yu-Chen
139633842cedSCho, Yu-Chen if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) {
139733842cedSCho, Yu-Chen return blk;
139833842cedSCho, Yu-Chen } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) {
139933842cedSCho, Yu-Chen switch (ms_lib_read_extra(us, blk, 0, &extdat)) {
140033842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
140133842cedSCho, Yu-Chen case MS_STATUS_SUCCESS_WITH_ECC:
140233842cedSCho, Yu-Chen break;
140333842cedSCho, Yu-Chen case MS_NOCARD_ERROR:
140433842cedSCho, Yu-Chen return MS_NOCARD_ERROR;
140533842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR:
140633842cedSCho, Yu-Chen return MS_LB_ERROR;
140733842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ:
140833842cedSCho, Yu-Chen default:
140933842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, blk);
141033842cedSCho, Yu-Chen continue;
141133842cedSCho, Yu-Chen } /* End switch */
141233842cedSCho, Yu-Chen
141333842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
141433842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, blk);
141533842cedSCho, Yu-Chen continue;
141633842cedSCho, Yu-Chen }
141733842cedSCho, Yu-Chen
141833842cedSCho, Yu-Chen switch (ms_lib_erase_phyblock(us, blk)) {
141933842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
142033842cedSCho, Yu-Chen return blk;
142133842cedSCho, Yu-Chen case MS_STATUS_ERROR:
142233842cedSCho, Yu-Chen return MS_LB_ERROR;
142333842cedSCho, Yu-Chen case MS_ERROR_FLASH_ERASE:
142433842cedSCho, Yu-Chen default:
142533842cedSCho, Yu-Chen ms_lib_error_phyblock(us, blk);
142633842cedSCho, Yu-Chen break;
142733842cedSCho, Yu-Chen }
142833842cedSCho, Yu-Chen }
142933842cedSCho, Yu-Chen } /* End for */
143033842cedSCho, Yu-Chen
143133842cedSCho, Yu-Chen return MS_LB_ERROR;
143233842cedSCho, Yu-Chen }
ms_libsearch_block_from_logical(struct us_data * us,u16 logblk)143333842cedSCho, Yu-Chen static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk)
143433842cedSCho, Yu-Chen {
143533842cedSCho, Yu-Chen u16 phyblk;
143633842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
143733842cedSCho, Yu-Chen
143833842cedSCho, Yu-Chen phyblk = ms_libconv_to_physical(info, logblk);
143933842cedSCho, Yu-Chen if (phyblk >= MS_LB_ERROR) {
144033842cedSCho, Yu-Chen if (logblk >= info->MS_Lib.NumberOfLogBlock)
144133842cedSCho, Yu-Chen return MS_LB_ERROR;
144233842cedSCho, Yu-Chen
144333842cedSCho, Yu-Chen phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT;
144433842cedSCho, Yu-Chen phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
144533842cedSCho, Yu-Chen phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1;
144633842cedSCho, Yu-Chen }
144733842cedSCho, Yu-Chen
144833842cedSCho, Yu-Chen return ms_libsearch_block_from_physical(us, phyblk);
144933842cedSCho, Yu-Chen }
145033842cedSCho, Yu-Chen
ms_scsi_test_unit_ready(struct us_data * us,struct scsi_cmnd * srb)145133842cedSCho, Yu-Chen static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
145233842cedSCho, Yu-Chen {
145333842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
145433842cedSCho, Yu-Chen
145533842cedSCho, Yu-Chen /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */
14561892bf90SAlan Stern if ((info->MS_Status & MS_Insert) && (info->MS_Status & MS_Ready)) {
145733842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
145833842cedSCho, Yu-Chen } else {
145933842cedSCho, Yu-Chen ene_ms_init(us);
146033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
146133842cedSCho, Yu-Chen }
146233842cedSCho, Yu-Chen
146333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
146433842cedSCho, Yu-Chen }
146533842cedSCho, Yu-Chen
ms_scsi_mode_sense(struct us_data * us,struct scsi_cmnd * srb)146633842cedSCho, Yu-Chen static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
146733842cedSCho, Yu-Chen {
146833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
146933842cedSCho, Yu-Chen unsigned char mediaNoWP[12] = {
147033842cedSCho, Yu-Chen 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
147133842cedSCho, Yu-Chen 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
147233842cedSCho, Yu-Chen unsigned char mediaWP[12] = {
147333842cedSCho, Yu-Chen 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
147433842cedSCho, Yu-Chen 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
147533842cedSCho, Yu-Chen
14761892bf90SAlan Stern if (info->MS_Status & MS_WtP)
147733842cedSCho, Yu-Chen usb_stor_set_xfer_buf(mediaWP, 12, srb);
147833842cedSCho, Yu-Chen else
147933842cedSCho, Yu-Chen usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
148033842cedSCho, Yu-Chen
148133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
148233842cedSCho, Yu-Chen }
148333842cedSCho, Yu-Chen
ms_scsi_read_capacity(struct us_data * us,struct scsi_cmnd * srb)148433842cedSCho, Yu-Chen static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
148533842cedSCho, Yu-Chen {
148633842cedSCho, Yu-Chen u32 bl_num;
148733842cedSCho, Yu-Chen u16 bl_len;
148833842cedSCho, Yu-Chen unsigned int offset = 0;
148933842cedSCho, Yu-Chen unsigned char buf[8];
149033842cedSCho, Yu-Chen struct scatterlist *sg = NULL;
149133842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
149233842cedSCho, Yu-Chen
1493191648d0SJoe Perches usb_stor_dbg(us, "ms_scsi_read_capacity\n");
149433842cedSCho, Yu-Chen bl_len = 0x200;
14951892bf90SAlan Stern if (info->MS_Status & MS_IsMSPro)
149633842cedSCho, Yu-Chen bl_num = info->MSP_TotalBlock - 1;
149733842cedSCho, Yu-Chen else
149833842cedSCho, Yu-Chen bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1;
149933842cedSCho, Yu-Chen
150033842cedSCho, Yu-Chen info->bl_num = bl_num;
1501191648d0SJoe Perches usb_stor_dbg(us, "bl_len = %x\n", bl_len);
1502191648d0SJoe Perches usb_stor_dbg(us, "bl_num = %x\n", bl_num);
150333842cedSCho, Yu-Chen
150433842cedSCho, Yu-Chen /*srb->request_bufflen = 8; */
150533842cedSCho, Yu-Chen buf[0] = (bl_num >> 24) & 0xff;
150633842cedSCho, Yu-Chen buf[1] = (bl_num >> 16) & 0xff;
150733842cedSCho, Yu-Chen buf[2] = (bl_num >> 8) & 0xff;
150833842cedSCho, Yu-Chen buf[3] = (bl_num >> 0) & 0xff;
150933842cedSCho, Yu-Chen buf[4] = (bl_len >> 24) & 0xff;
151033842cedSCho, Yu-Chen buf[5] = (bl_len >> 16) & 0xff;
151133842cedSCho, Yu-Chen buf[6] = (bl_len >> 8) & 0xff;
151233842cedSCho, Yu-Chen buf[7] = (bl_len >> 0) & 0xff;
151333842cedSCho, Yu-Chen
151433842cedSCho, Yu-Chen usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
151533842cedSCho, Yu-Chen
151633842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
151733842cedSCho, Yu-Chen }
151833842cedSCho, Yu-Chen
ms_lib_phy_to_log_range(u16 PhyBlock,u16 * LogStart,u16 * LogEnde)151933842cedSCho, Yu-Chen static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde)
152033842cedSCho, Yu-Chen {
152133842cedSCho, Yu-Chen PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
152233842cedSCho, Yu-Chen
152333842cedSCho, Yu-Chen if (PhyBlock) {
152433842cedSCho, Yu-Chen *LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
152533842cedSCho, Yu-Chen *LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
152633842cedSCho, Yu-Chen } else {
152733842cedSCho, Yu-Chen *LogStart = 0;
152833842cedSCho, Yu-Chen *LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/
152933842cedSCho, Yu-Chen }
153033842cedSCho, Yu-Chen }
153133842cedSCho, Yu-Chen
ms_lib_read_extrablock(struct us_data * us,u32 PhyBlock,u8 PageNum,u8 blen,void * buf)153233842cedSCho, Yu-Chen static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
153333842cedSCho, Yu-Chen u8 PageNum, u8 blen, void *buf)
153433842cedSCho, Yu-Chen {
153533842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
153633842cedSCho, Yu-Chen int result;
153733842cedSCho, Yu-Chen
153833842cedSCho, Yu-Chen /* Read Extra Data */
153933842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
154033842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
154133842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4 * blen;
1542b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
154333842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
154433842cedSCho, Yu-Chen bcb->CDB[1] = 0x03;
154533842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum);
154633842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlock);
154733842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlock>>8);
154833842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
154933842cedSCho, Yu-Chen bcb->CDB[6] = blen;
155033842cedSCho, Yu-Chen
155133842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
155233842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
155333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
155433842cedSCho, Yu-Chen
155533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
155633842cedSCho, Yu-Chen }
155733842cedSCho, Yu-Chen
ms_lib_scan_logicalblocknumber(struct us_data * us,u16 btBlk1st)155833842cedSCho, Yu-Chen static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
155933842cedSCho, Yu-Chen {
156033842cedSCho, Yu-Chen u16 PhyBlock, newblk, i;
156133842cedSCho, Yu-Chen u16 LogStart, LogEnde;
156233842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat;
156333842cedSCho, Yu-Chen u32 count = 0, index = 0;
156433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
1565628c2893SAlan Stern u8 *bbuf = info->bbuf;
156633842cedSCho, Yu-Chen
156733842cedSCho, Yu-Chen for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
156833842cedSCho, Yu-Chen ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
156933842cedSCho, Yu-Chen
157033842cedSCho, Yu-Chen for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) {
157133842cedSCho, Yu-Chen switch (ms_libconv_to_logical(info, PhyBlock)) {
157233842cedSCho, Yu-Chen case MS_STATUS_ERROR:
157333842cedSCho, Yu-Chen continue;
157433842cedSCho, Yu-Chen default:
157533842cedSCho, Yu-Chen break;
157633842cedSCho, Yu-Chen }
157733842cedSCho, Yu-Chen
157833842cedSCho, Yu-Chen if (count == PhyBlock) {
1579628c2893SAlan Stern ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
1580628c2893SAlan Stern bbuf);
158133842cedSCho, Yu-Chen count += 0x80;
158233842cedSCho, Yu-Chen }
158333842cedSCho, Yu-Chen index = (PhyBlock % 0x80) * 4;
158433842cedSCho, Yu-Chen
1585628c2893SAlan Stern extdat.ovrflg = bbuf[index];
1586628c2893SAlan Stern extdat.mngflg = bbuf[index+1];
1587628c2893SAlan Stern extdat.logadr = memstick_logaddr(bbuf[index+2],
1588628c2893SAlan Stern bbuf[index+3]);
158933842cedSCho, Yu-Chen
159033842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
159133842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, PhyBlock);
159233842cedSCho, Yu-Chen continue;
159333842cedSCho, Yu-Chen }
159433842cedSCho, Yu-Chen
159533842cedSCho, Yu-Chen if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) {
159633842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock);
159733842cedSCho, Yu-Chen continue;
159833842cedSCho, Yu-Chen }
159933842cedSCho, Yu-Chen
160033842cedSCho, Yu-Chen if (extdat.logadr != MS_LB_NOT_USED) {
160133842cedSCho, Yu-Chen if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) {
160233842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock);
160333842cedSCho, Yu-Chen continue;
160433842cedSCho, Yu-Chen }
160533842cedSCho, Yu-Chen
160633842cedSCho, Yu-Chen newblk = ms_libconv_to_physical(info, extdat.logadr);
160733842cedSCho, Yu-Chen
160833842cedSCho, Yu-Chen if (newblk != MS_LB_NOT_USED) {
160933842cedSCho, Yu-Chen if (extdat.logadr == 0) {
161033842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
161133842cedSCho, Yu-Chen if (ms_lib_check_disableblock(us, btBlk1st)) {
161233842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, newblk);
161333842cedSCho, Yu-Chen continue;
161433842cedSCho, Yu-Chen }
161533842cedSCho, Yu-Chen }
161633842cedSCho, Yu-Chen
161733842cedSCho, Yu-Chen ms_lib_read_extra(us, newblk, 0, &extdat);
161833842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) {
161933842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock);
162033842cedSCho, Yu-Chen continue;
162133842cedSCho, Yu-Chen } else {
162233842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, newblk);
162333842cedSCho, Yu-Chen }
162433842cedSCho, Yu-Chen }
162533842cedSCho, Yu-Chen
162633842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
162733842cedSCho, Yu-Chen }
162833842cedSCho, Yu-Chen }
162933842cedSCho, Yu-Chen } /* End for ... */
163033842cedSCho, Yu-Chen
163133842cedSCho, Yu-Chen return MS_STATUS_SUCCESS;
163233842cedSCho, Yu-Chen }
163333842cedSCho, Yu-Chen
163433842cedSCho, Yu-Chen
ms_scsi_read(struct us_data * us,struct scsi_cmnd * srb)163533842cedSCho, Yu-Chen static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
163633842cedSCho, Yu-Chen {
163733842cedSCho, Yu-Chen int result;
163833842cedSCho, Yu-Chen unsigned char *cdb = srb->cmnd;
163933842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
164033842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
164133842cedSCho, Yu-Chen
164233842cedSCho, Yu-Chen u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
164333842cedSCho, Yu-Chen ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
164433842cedSCho, Yu-Chen u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
164533842cedSCho, Yu-Chen u32 blenByte = blen * 0x200;
164633842cedSCho, Yu-Chen
164733842cedSCho, Yu-Chen if (bn > info->bl_num)
164833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
164933842cedSCho, Yu-Chen
16501892bf90SAlan Stern if (info->MS_Status & MS_IsMSPro) {
165133842cedSCho, Yu-Chen result = ene_load_bincode(us, MSP_RW_PATTERN);
165233842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
1653191648d0SJoe Perches usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n");
165433842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
165533842cedSCho, Yu-Chen }
165633842cedSCho, Yu-Chen
165733842cedSCho, Yu-Chen /* set up the command wrapper */
165833842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
165933842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
166033842cedSCho, Yu-Chen bcb->DataTransferLength = blenByte;
1661b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
166233842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
166333842cedSCho, Yu-Chen bcb->CDB[1] = 0x02;
166433842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn);
166533842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8);
166633842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16);
166733842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24);
166833842cedSCho, Yu-Chen
166933842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
167033842cedSCho, Yu-Chen } else {
167133842cedSCho, Yu-Chen void *buf;
167233842cedSCho, Yu-Chen int offset = 0;
167333842cedSCho, Yu-Chen u16 phyblk, logblk;
167433842cedSCho, Yu-Chen u8 PageNum;
167533842cedSCho, Yu-Chen u16 len;
167633842cedSCho, Yu-Chen u32 blkno;
167733842cedSCho, Yu-Chen
167833842cedSCho, Yu-Chen buf = kmalloc(blenByte, GFP_KERNEL);
167933842cedSCho, Yu-Chen if (buf == NULL)
168033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
168133842cedSCho, Yu-Chen
168233842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
168333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
168433842cedSCho, Yu-Chen pr_info("Load MS RW pattern Fail !!\n");
168533842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR;
168633842cedSCho, Yu-Chen goto exit;
168733842cedSCho, Yu-Chen }
168833842cedSCho, Yu-Chen
168933842cedSCho, Yu-Chen logblk = (u16)(bn / info->MS_Lib.PagesPerBlock);
169033842cedSCho, Yu-Chen PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
169133842cedSCho, Yu-Chen
169233842cedSCho, Yu-Chen while (1) {
169333842cedSCho, Yu-Chen if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
169433842cedSCho, Yu-Chen len = info->MS_Lib.PagesPerBlock-PageNum;
169533842cedSCho, Yu-Chen else
169633842cedSCho, Yu-Chen len = blen;
169733842cedSCho, Yu-Chen
169833842cedSCho, Yu-Chen phyblk = ms_libconv_to_physical(info, logblk);
169933842cedSCho, Yu-Chen blkno = phyblk * 0x20 + PageNum;
170033842cedSCho, Yu-Chen
170133842cedSCho, Yu-Chen /* set up the command wrapper */
170233842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
170333842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
170433842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200 * len;
1705b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
170633842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
170733842cedSCho, Yu-Chen bcb->CDB[1] = 0x02;
170833842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(blkno);
170933842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(blkno>>8);
171033842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(blkno>>16);
171133842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(blkno>>24);
171233842cedSCho, Yu-Chen
171333842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0);
171433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
171533842cedSCho, Yu-Chen pr_info("MS_SCSI_Read --- result = %x\n", result);
171633842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR;
171733842cedSCho, Yu-Chen goto exit;
171833842cedSCho, Yu-Chen }
171933842cedSCho, Yu-Chen
172033842cedSCho, Yu-Chen blen -= len;
172133842cedSCho, Yu-Chen if (blen <= 0)
172233842cedSCho, Yu-Chen break;
172333842cedSCho, Yu-Chen logblk++;
172433842cedSCho, Yu-Chen PageNum = 0;
172533842cedSCho, Yu-Chen offset += MS_BYTES_PER_PAGE*len;
172633842cedSCho, Yu-Chen }
172733842cedSCho, Yu-Chen usb_stor_set_xfer_buf(buf, blenByte, srb);
172833842cedSCho, Yu-Chen exit:
172933842cedSCho, Yu-Chen kfree(buf);
173033842cedSCho, Yu-Chen }
173133842cedSCho, Yu-Chen return result;
173233842cedSCho, Yu-Chen }
173333842cedSCho, Yu-Chen
ms_scsi_write(struct us_data * us,struct scsi_cmnd * srb)173433842cedSCho, Yu-Chen static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
173533842cedSCho, Yu-Chen {
173633842cedSCho, Yu-Chen int result;
173733842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
173833842cedSCho, Yu-Chen unsigned char *cdb = srb->cmnd;
173933842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
174033842cedSCho, Yu-Chen
174133842cedSCho, Yu-Chen u32 bn = ((cdb[2] << 24) & 0xff000000) |
174233842cedSCho, Yu-Chen ((cdb[3] << 16) & 0x00ff0000) |
174333842cedSCho, Yu-Chen ((cdb[4] << 8) & 0x0000ff00) |
174433842cedSCho, Yu-Chen ((cdb[5] << 0) & 0x000000ff);
174533842cedSCho, Yu-Chen u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
174633842cedSCho, Yu-Chen u32 blenByte = blen * 0x200;
174733842cedSCho, Yu-Chen
174833842cedSCho, Yu-Chen if (bn > info->bl_num)
174933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
175033842cedSCho, Yu-Chen
17511892bf90SAlan Stern if (info->MS_Status & MS_IsMSPro) {
175233842cedSCho, Yu-Chen result = ene_load_bincode(us, MSP_RW_PATTERN);
175333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
175433842cedSCho, Yu-Chen pr_info("Load MSP RW pattern Fail !!\n");
175533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
175633842cedSCho, Yu-Chen }
175733842cedSCho, Yu-Chen
175833842cedSCho, Yu-Chen /* set up the command wrapper */
175933842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
176033842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
176133842cedSCho, Yu-Chen bcb->DataTransferLength = blenByte;
176233842cedSCho, Yu-Chen bcb->Flags = 0x00;
176333842cedSCho, Yu-Chen bcb->CDB[0] = 0xF0;
176433842cedSCho, Yu-Chen bcb->CDB[1] = 0x04;
176533842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn);
176633842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8);
176733842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16);
176833842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24);
176933842cedSCho, Yu-Chen
177033842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
177133842cedSCho, Yu-Chen } else {
177233842cedSCho, Yu-Chen void *buf;
1773bc985c10SFelipe Balbi int offset = 0;
177433842cedSCho, Yu-Chen u16 PhyBlockAddr;
177533842cedSCho, Yu-Chen u8 PageNum;
177633842cedSCho, Yu-Chen u16 len, oldphy, newphy;
177733842cedSCho, Yu-Chen
177833842cedSCho, Yu-Chen buf = kmalloc(blenByte, GFP_KERNEL);
177933842cedSCho, Yu-Chen if (buf == NULL)
178033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
178133842cedSCho, Yu-Chen usb_stor_set_xfer_buf(buf, blenByte, srb);
178233842cedSCho, Yu-Chen
178333842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN);
178433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
178533842cedSCho, Yu-Chen pr_info("Load MS RW pattern Fail !!\n");
178633842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR;
178733842cedSCho, Yu-Chen goto exit;
178833842cedSCho, Yu-Chen }
178933842cedSCho, Yu-Chen
179033842cedSCho, Yu-Chen PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock);
179133842cedSCho, Yu-Chen PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
179233842cedSCho, Yu-Chen
179333842cedSCho, Yu-Chen while (1) {
179433842cedSCho, Yu-Chen if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
179533842cedSCho, Yu-Chen len = info->MS_Lib.PagesPerBlock-PageNum;
179633842cedSCho, Yu-Chen else
179733842cedSCho, Yu-Chen len = blen;
179833842cedSCho, Yu-Chen
179933842cedSCho, Yu-Chen oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */
180033842cedSCho, Yu-Chen newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr);
180133842cedSCho, Yu-Chen
180233842cedSCho, Yu-Chen result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len);
180333842cedSCho, Yu-Chen
180433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
180533842cedSCho, Yu-Chen pr_info("MS_SCSI_Write --- result = %x\n", result);
180633842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR;
180733842cedSCho, Yu-Chen goto exit;
180833842cedSCho, Yu-Chen }
180933842cedSCho, Yu-Chen
181033842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED;
181133842cedSCho, Yu-Chen ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy);
181233842cedSCho, Yu-Chen
181333842cedSCho, Yu-Chen blen -= len;
181433842cedSCho, Yu-Chen if (blen <= 0)
181533842cedSCho, Yu-Chen break;
181633842cedSCho, Yu-Chen PhyBlockAddr++;
181733842cedSCho, Yu-Chen PageNum = 0;
181833842cedSCho, Yu-Chen offset += MS_BYTES_PER_PAGE*len;
181933842cedSCho, Yu-Chen }
182033842cedSCho, Yu-Chen exit:
182133842cedSCho, Yu-Chen kfree(buf);
182233842cedSCho, Yu-Chen }
182333842cedSCho, Yu-Chen return result;
182433842cedSCho, Yu-Chen }
182533842cedSCho, Yu-Chen
182633842cedSCho, Yu-Chen /*
182733842cedSCho, Yu-Chen * ENE MS Card
182833842cedSCho, Yu-Chen */
182933842cedSCho, Yu-Chen
ene_get_card_type(struct us_data * us,u16 index,void * buf)183041e568d1Shuajun li static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
183141e568d1Shuajun li {
183241e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
183341e568d1Shuajun li int result;
183441e568d1Shuajun li
183541e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
183641e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
183741e568d1Shuajun li bcb->DataTransferLength = 0x01;
1838b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
183941e568d1Shuajun li bcb->CDB[0] = 0xED;
184041e568d1Shuajun li bcb->CDB[2] = (unsigned char)(index>>8);
184141e568d1Shuajun li bcb->CDB[3] = (unsigned char)index;
184241e568d1Shuajun li
184341e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
184441e568d1Shuajun li return result;
184541e568d1Shuajun li }
184641e568d1Shuajun li
ene_get_card_status(struct us_data * us,u8 * buf)184741e568d1Shuajun li static int ene_get_card_status(struct us_data *us, u8 *buf)
184841e568d1Shuajun li {
184941e568d1Shuajun li u16 tmpreg;
185041e568d1Shuajun li u32 reg4b;
185141e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
185241e568d1Shuajun li
1853191648d0SJoe Perches /*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/
185441e568d1Shuajun li reg4b = *(u32 *)&buf[0x18];
185541e568d1Shuajun li info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
185641e568d1Shuajun li
185741e568d1Shuajun li tmpreg = (u16) reg4b;
185841e568d1Shuajun li reg4b = *(u32 *)(&buf[0x14]);
18591892bf90SAlan Stern if ((info->SD_Status & SD_HiCapacity) && !(info->SD_Status & SD_IsMMC))
186041e568d1Shuajun li info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
186141e568d1Shuajun li
186241e568d1Shuajun li info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22);
186341e568d1Shuajun li info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07;
18641892bf90SAlan Stern if ((info->SD_Status & SD_HiCapacity) && (info->SD_Status & SD_IsMMC))
186541e568d1Shuajun li info->HC_C_SIZE = *(u32 *)(&buf[0x100]);
186641e568d1Shuajun li
186741e568d1Shuajun li if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) {
186841e568d1Shuajun li info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN);
186941e568d1Shuajun li info->SD_READ_BL_LEN = SD_BLOCK_LEN;
187041e568d1Shuajun li } else {
187141e568d1Shuajun li info->SD_Block_Mult = 1;
187241e568d1Shuajun li }
187341e568d1Shuajun li
187441e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
187541e568d1Shuajun li }
187641e568d1Shuajun li
ene_load_bincode(struct us_data * us,unsigned char flag)187741e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag)
187841e568d1Shuajun li {
187941e568d1Shuajun li int err;
188041e568d1Shuajun li char *fw_name = NULL;
188141e568d1Shuajun li unsigned char *buf = NULL;
188241e568d1Shuajun li const struct firmware *sd_fw = NULL;
188341e568d1Shuajun li int result = USB_STOR_TRANSPORT_ERROR;
188441e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
188541e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
188641e568d1Shuajun li
188741e568d1Shuajun li if (info->BIN_FLAG == flag)
188841e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
188941e568d1Shuajun li
189041e568d1Shuajun li switch (flag) {
189141e568d1Shuajun li /* For SD */
189241e568d1Shuajun li case SD_INIT1_PATTERN:
1893191648d0SJoe Perches usb_stor_dbg(us, "SD_INIT1_PATTERN\n");
1894595c8970STim Gardner fw_name = SD_INIT1_FIRMWARE;
189541e568d1Shuajun li break;
189641e568d1Shuajun li case SD_INIT2_PATTERN:
1897191648d0SJoe Perches usb_stor_dbg(us, "SD_INIT2_PATTERN\n");
1898595c8970STim Gardner fw_name = SD_INIT2_FIRMWARE;
189941e568d1Shuajun li break;
190041e568d1Shuajun li case SD_RW_PATTERN:
1901191648d0SJoe Perches usb_stor_dbg(us, "SD_RW_PATTERN\n");
1902595c8970STim Gardner fw_name = SD_RW_FIRMWARE;
190341e568d1Shuajun li break;
190433842cedSCho, Yu-Chen /* For MS */
190533842cedSCho, Yu-Chen case MS_INIT_PATTERN:
1906191648d0SJoe Perches usb_stor_dbg(us, "MS_INIT_PATTERN\n");
1907595c8970STim Gardner fw_name = MS_INIT_FIRMWARE;
190833842cedSCho, Yu-Chen break;
190933842cedSCho, Yu-Chen case MSP_RW_PATTERN:
1910191648d0SJoe Perches usb_stor_dbg(us, "MSP_RW_PATTERN\n");
1911595c8970STim Gardner fw_name = MSP_RW_FIRMWARE;
191233842cedSCho, Yu-Chen break;
191333842cedSCho, Yu-Chen case MS_RW_PATTERN:
1914191648d0SJoe Perches usb_stor_dbg(us, "MS_RW_PATTERN\n");
1915595c8970STim Gardner fw_name = MS_RW_FIRMWARE;
191633842cedSCho, Yu-Chen break;
191741e568d1Shuajun li default:
1918191648d0SJoe Perches usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n");
191941e568d1Shuajun li goto nofw;
192041e568d1Shuajun li }
192141e568d1Shuajun li
192241e568d1Shuajun li err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
192341e568d1Shuajun li if (err) {
1924191648d0SJoe Perches usb_stor_dbg(us, "load firmware %s failed\n", fw_name);
192541e568d1Shuajun li goto nofw;
192641e568d1Shuajun li }
1927a328512dSBenoit Taine buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL);
1928191648d0SJoe Perches if (buf == NULL)
192941e568d1Shuajun li goto nofw;
1930191648d0SJoe Perches
193141e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
193241e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
193341e568d1Shuajun li bcb->DataTransferLength = sd_fw->size;
193441e568d1Shuajun li bcb->Flags = 0x00;
193541e568d1Shuajun li bcb->CDB[0] = 0xEF;
193641e568d1Shuajun li
193741e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
1938aa18c4b6SAlan Stern if (us->srb != NULL)
1939aa18c4b6SAlan Stern scsi_set_resid(us->srb, 0);
194041e568d1Shuajun li info->BIN_FLAG = flag;
194141e568d1Shuajun li kfree(buf);
194241e568d1Shuajun li
194341e568d1Shuajun li nofw:
194441e568d1Shuajun li release_firmware(sd_fw);
194541e568d1Shuajun li return result;
194641e568d1Shuajun li }
194741e568d1Shuajun li
ms_card_init(struct us_data * us)194833842cedSCho, Yu-Chen static int ms_card_init(struct us_data *us)
194933842cedSCho, Yu-Chen {
195033842cedSCho, Yu-Chen u32 result;
195133842cedSCho, Yu-Chen u16 TmpBlock;
195233842cedSCho, Yu-Chen unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL;
195333842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat;
195433842cedSCho, Yu-Chen u16 btBlk1st, btBlk2nd;
195533842cedSCho, Yu-Chen u32 btBlk1stErred;
195633842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
195733842cedSCho, Yu-Chen
195833842cedSCho, Yu-Chen printk(KERN_INFO "MS_CardInit start\n");
195933842cedSCho, Yu-Chen
196033842cedSCho, Yu-Chen ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */
196133842cedSCho, Yu-Chen
196233842cedSCho, Yu-Chen /* get two PageBuffer */
196333842cedSCho, Yu-Chen PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
196433842cedSCho, Yu-Chen PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
196533842cedSCho, Yu-Chen if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) {
196633842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR;
196733842cedSCho, Yu-Chen goto exit;
196833842cedSCho, Yu-Chen }
196933842cedSCho, Yu-Chen
197033842cedSCho, Yu-Chen btBlk1st = btBlk2nd = MS_LB_NOT_USED;
197133842cedSCho, Yu-Chen btBlk1stErred = 0;
197233842cedSCho, Yu-Chen
197333842cedSCho, Yu-Chen for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) {
197433842cedSCho, Yu-Chen
197533842cedSCho, Yu-Chen switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) {
197633842cedSCho, Yu-Chen case MS_STATUS_SUCCESS:
197733842cedSCho, Yu-Chen break;
197833842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR:
197933842cedSCho, Yu-Chen break;
198033842cedSCho, Yu-Chen case MS_STATUS_ERROR:
198133842cedSCho, Yu-Chen default:
198233842cedSCho, Yu-Chen continue;
198333842cedSCho, Yu-Chen }
198433842cedSCho, Yu-Chen
198533842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG)
198633842cedSCho, Yu-Chen continue;
198733842cedSCho, Yu-Chen
198833842cedSCho, Yu-Chen if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) ||
198933842cedSCho, Yu-Chen (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) ||
199033842cedSCho, Yu-Chen (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) ||
199133842cedSCho, Yu-Chen (((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES))
199233842cedSCho, Yu-Chen continue;
199333842cedSCho, Yu-Chen
199433842cedSCho, Yu-Chen if (btBlk1st != MS_LB_NOT_USED) {
199533842cedSCho, Yu-Chen btBlk2nd = TmpBlock;
199633842cedSCho, Yu-Chen break;
199733842cedSCho, Yu-Chen }
199833842cedSCho, Yu-Chen
199933842cedSCho, Yu-Chen btBlk1st = TmpBlock;
200033842cedSCho, Yu-Chen memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE);
200133842cedSCho, Yu-Chen if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER))
200233842cedSCho, Yu-Chen btBlk1stErred = 1;
200333842cedSCho, Yu-Chen }
200433842cedSCho, Yu-Chen
200533842cedSCho, Yu-Chen if (btBlk1st == MS_LB_NOT_USED) {
200633842cedSCho, Yu-Chen result = MS_STATUS_ERROR;
200733842cedSCho, Yu-Chen goto exit;
200833842cedSCho, Yu-Chen }
200933842cedSCho, Yu-Chen
201033842cedSCho, Yu-Chen /* write protect */
201133842cedSCho, Yu-Chen if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON)
201233842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
201333842cedSCho, Yu-Chen
201433842cedSCho, Yu-Chen result = MS_STATUS_ERROR;
201533842cedSCho, Yu-Chen /* 1st Boot Block */
201633842cedSCho, Yu-Chen if (btBlk1stErred == 0)
201733842cedSCho, Yu-Chen result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1);
201833842cedSCho, Yu-Chen /* 1st */
201933842cedSCho, Yu-Chen /* 2nd Boot Block */
202033842cedSCho, Yu-Chen if (result && (btBlk2nd != MS_LB_NOT_USED))
202133842cedSCho, Yu-Chen result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0);
202233842cedSCho, Yu-Chen
202333842cedSCho, Yu-Chen if (result) {
202433842cedSCho, Yu-Chen result = MS_STATUS_ERROR;
202533842cedSCho, Yu-Chen goto exit;
202633842cedSCho, Yu-Chen }
202733842cedSCho, Yu-Chen
202833842cedSCho, Yu-Chen for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++)
202933842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
203033842cedSCho, Yu-Chen
203133842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK;
203233842cedSCho, Yu-Chen
203333842cedSCho, Yu-Chen if (btBlk2nd != MS_LB_NOT_USED) {
203433842cedSCho, Yu-Chen for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++)
203533842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
203633842cedSCho, Yu-Chen
203733842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK;
203833842cedSCho, Yu-Chen }
203933842cedSCho, Yu-Chen
204033842cedSCho, Yu-Chen result = ms_lib_scan_logicalblocknumber(us, btBlk1st);
204133842cedSCho, Yu-Chen if (result)
204233842cedSCho, Yu-Chen goto exit;
204333842cedSCho, Yu-Chen
204433842cedSCho, Yu-Chen for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT;
204533842cedSCho, Yu-Chen TmpBlock < info->MS_Lib.NumberOfPhyBlock;
204633842cedSCho, Yu-Chen TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) {
204733842cedSCho, Yu-Chen if (ms_count_freeblock(us, TmpBlock) == 0) {
204833842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
204933842cedSCho, Yu-Chen break;
205033842cedSCho, Yu-Chen }
205133842cedSCho, Yu-Chen }
205233842cedSCho, Yu-Chen
205333842cedSCho, Yu-Chen /* write */
205433842cedSCho, Yu-Chen if (ms_lib_alloc_writebuf(us)) {
205533842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR;
205633842cedSCho, Yu-Chen goto exit;
205733842cedSCho, Yu-Chen }
205833842cedSCho, Yu-Chen
205933842cedSCho, Yu-Chen result = MS_STATUS_SUCCESS;
206033842cedSCho, Yu-Chen
206133842cedSCho, Yu-Chen exit:
206233842cedSCho, Yu-Chen kfree(PageBuffer1);
206333842cedSCho, Yu-Chen kfree(PageBuffer0);
206433842cedSCho, Yu-Chen
206533842cedSCho, Yu-Chen printk(KERN_INFO "MS_CardInit end\n");
206633842cedSCho, Yu-Chen return result;
206733842cedSCho, Yu-Chen }
206833842cedSCho, Yu-Chen
ene_ms_init(struct us_data * us)206933842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us)
207033842cedSCho, Yu-Chen {
207133842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
207233842cedSCho, Yu-Chen int result;
207333842cedSCho, Yu-Chen u16 MSP_BlockSize, MSP_UserAreaBlocks;
207433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
2075628c2893SAlan Stern u8 *bbuf = info->bbuf;
20761892bf90SAlan Stern unsigned int s;
207733842cedSCho, Yu-Chen
207833842cedSCho, Yu-Chen printk(KERN_INFO "transport --- ENE_MSInit\n");
207933842cedSCho, Yu-Chen
208033842cedSCho, Yu-Chen /* the same part to test ENE */
208133842cedSCho, Yu-Chen
208233842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_INIT_PATTERN);
208333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
208433842cedSCho, Yu-Chen printk(KERN_ERR "Load MS Init Code Fail !!\n");
208533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
208633842cedSCho, Yu-Chen }
208733842cedSCho, Yu-Chen
208833842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap));
208933842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
209033842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200;
2091b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
209233842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1;
209333842cedSCho, Yu-Chen bcb->CDB[1] = 0x01;
209433842cedSCho, Yu-Chen
2095628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
209633842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) {
209733842cedSCho, Yu-Chen printk(KERN_ERR "Execution MS Init Code Fail !!\n");
209833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
209933842cedSCho, Yu-Chen }
210033842cedSCho, Yu-Chen /* the same part to test ENE */
21011892bf90SAlan Stern info->MS_Status = bbuf[0];
210233842cedSCho, Yu-Chen
21031892bf90SAlan Stern s = info->MS_Status;
21041892bf90SAlan Stern if ((s & MS_Insert) && (s & MS_Ready)) {
21051892bf90SAlan Stern printk(KERN_INFO "Insert = %x\n", !!(s & MS_Insert));
21061892bf90SAlan Stern printk(KERN_INFO "Ready = %x\n", !!(s & MS_Ready));
21071892bf90SAlan Stern printk(KERN_INFO "IsMSPro = %x\n", !!(s & MS_IsMSPro));
21081892bf90SAlan Stern printk(KERN_INFO "IsMSPHG = %x\n", !!(s & MS_IsMSPHG));
21091892bf90SAlan Stern printk(KERN_INFO "WtP= %x\n", !!(s & MS_WtP));
21101892bf90SAlan Stern if (s & MS_IsMSPro) {
2111628c2893SAlan Stern MSP_BlockSize = (bbuf[6] << 8) | bbuf[7];
2112628c2893SAlan Stern MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
211333842cedSCho, Yu-Chen info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
211433842cedSCho, Yu-Chen } else {
211533842cedSCho, Yu-Chen ms_card_init(us); /* Card is MS (to ms.c)*/
211633842cedSCho, Yu-Chen }
2117191648d0SJoe Perches usb_stor_dbg(us, "MS Init Code OK !!\n");
211833842cedSCho, Yu-Chen } else {
2119628c2893SAlan Stern usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]);
212033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
212133842cedSCho, Yu-Chen }
212233842cedSCho, Yu-Chen
212333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD;
212433842cedSCho, Yu-Chen }
212533842cedSCho, Yu-Chen
ene_sd_init(struct us_data * us)212641e568d1Shuajun li static int ene_sd_init(struct us_data *us)
212741e568d1Shuajun li {
212841e568d1Shuajun li int result;
212941e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
213041e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
2131628c2893SAlan Stern u8 *bbuf = info->bbuf;
213241e568d1Shuajun li
2133191648d0SJoe Perches usb_stor_dbg(us, "transport --- ENE_SDInit\n");
213441e568d1Shuajun li /* SD Init Part-1 */
213541e568d1Shuajun li result = ene_load_bincode(us, SD_INIT1_PATTERN);
213641e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
2137191648d0SJoe Perches usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n");
213841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
213941e568d1Shuajun li }
214041e568d1Shuajun li
214141e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
214241e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
2143b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
214441e568d1Shuajun li bcb->CDB[0] = 0xF2;
214541e568d1Shuajun li
214641e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
214741e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
2148191648d0SJoe Perches usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
214941e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
215041e568d1Shuajun li }
215141e568d1Shuajun li
215241e568d1Shuajun li /* SD Init Part-2 */
215341e568d1Shuajun li result = ene_load_bincode(us, SD_INIT2_PATTERN);
215441e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
2155191648d0SJoe Perches usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n");
215641e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
215741e568d1Shuajun li }
215841e568d1Shuajun li
215941e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap));
216041e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
216141e568d1Shuajun li bcb->DataTransferLength = 0x200;
2162b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN;
216341e568d1Shuajun li bcb->CDB[0] = 0xF1;
216441e568d1Shuajun li
2165628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
216641e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
2167191648d0SJoe Perches usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
216841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
216941e568d1Shuajun li }
217041e568d1Shuajun li
21711892bf90SAlan Stern info->SD_Status = bbuf[0];
21721892bf90SAlan Stern if ((info->SD_Status & SD_Insert) && (info->SD_Status & SD_Ready)) {
21731892bf90SAlan Stern unsigned int s = info->SD_Status;
2174191648d0SJoe Perches
2175628c2893SAlan Stern ene_get_card_status(us, bbuf);
21761892bf90SAlan Stern usb_stor_dbg(us, "Insert = %x\n", !!(s & SD_Insert));
21771892bf90SAlan Stern usb_stor_dbg(us, "Ready = %x\n", !!(s & SD_Ready));
21781892bf90SAlan Stern usb_stor_dbg(us, "IsMMC = %x\n", !!(s & SD_IsMMC));
21791892bf90SAlan Stern usb_stor_dbg(us, "HiCapacity = %x\n", !!(s & SD_HiCapacity));
21801892bf90SAlan Stern usb_stor_dbg(us, "HiSpeed = %x\n", !!(s & SD_HiSpeed));
21811892bf90SAlan Stern usb_stor_dbg(us, "WtP = %x\n", !!(s & SD_WtP));
218241e568d1Shuajun li } else {
2183628c2893SAlan Stern usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]);
218441e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
218541e568d1Shuajun li }
218641e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD;
218741e568d1Shuajun li }
218841e568d1Shuajun li
218941e568d1Shuajun li
ene_init(struct us_data * us)219041e568d1Shuajun li static int ene_init(struct us_data *us)
219141e568d1Shuajun li {
219241e568d1Shuajun li int result;
2193628c2893SAlan Stern u8 misc_reg03;
219441e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
2195628c2893SAlan Stern u8 *bbuf = info->bbuf;
219641e568d1Shuajun li
2197628c2893SAlan Stern result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
219841e568d1Shuajun li if (result != USB_STOR_XFER_GOOD)
219941e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
220041e568d1Shuajun li
2201628c2893SAlan Stern misc_reg03 = bbuf[0];
220241e568d1Shuajun li if (misc_reg03 & 0x01) {
22031892bf90SAlan Stern if (!(info->SD_Status & SD_Ready)) {
220441e568d1Shuajun li result = ene_sd_init(us);
220541e568d1Shuajun li if (result != USB_STOR_XFER_GOOD)
220641e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
220741e568d1Shuajun li }
220841e568d1Shuajun li }
220933842cedSCho, Yu-Chen if (misc_reg03 & 0x02) {
22101892bf90SAlan Stern if (!(info->MS_Status & MS_Ready)) {
221133842cedSCho, Yu-Chen result = ene_ms_init(us);
221233842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD)
221333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR;
221433842cedSCho, Yu-Chen }
221533842cedSCho, Yu-Chen }
221641e568d1Shuajun li return result;
221741e568d1Shuajun li }
221841e568d1Shuajun li
221941e568d1Shuajun li /*----- sd_scsi_irp() ---------*/
sd_scsi_irp(struct us_data * us,struct scsi_cmnd * srb)222041e568d1Shuajun li static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
222141e568d1Shuajun li {
222241e568d1Shuajun li int result;
222341e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
222441e568d1Shuajun li
222541e568d1Shuajun li switch (srb->cmnd[0]) {
222641e568d1Shuajun li case TEST_UNIT_READY:
222741e568d1Shuajun li result = sd_scsi_test_unit_ready(us, srb);
222841e568d1Shuajun li break; /* 0x00 */
2229ce553bd1SAlan Stern case REQUEST_SENSE:
2230ce553bd1SAlan Stern result = do_scsi_request_sense(us, srb);
2231ce553bd1SAlan Stern break; /* 0x03 */
223241e568d1Shuajun li case INQUIRY:
2233f8efdabdSAlan Stern result = do_scsi_inquiry(us, srb);
223441e568d1Shuajun li break; /* 0x12 */
223541e568d1Shuajun li case MODE_SENSE:
223641e568d1Shuajun li result = sd_scsi_mode_sense(us, srb);
223741e568d1Shuajun li break; /* 0x1A */
223841e568d1Shuajun li /*
223941e568d1Shuajun li case START_STOP:
224041e568d1Shuajun li result = SD_SCSI_Start_Stop(us, srb);
224141e568d1Shuajun li break; //0x1B
224241e568d1Shuajun li */
224341e568d1Shuajun li case READ_CAPACITY:
224441e568d1Shuajun li result = sd_scsi_read_capacity(us, srb);
224541e568d1Shuajun li break; /* 0x25 */
224641e568d1Shuajun li case READ_10:
224741e568d1Shuajun li result = sd_scsi_read(us, srb);
224841e568d1Shuajun li break; /* 0x28 */
224941e568d1Shuajun li case WRITE_10:
225041e568d1Shuajun li result = sd_scsi_write(us, srb);
225141e568d1Shuajun li break; /* 0x2A */
225241e568d1Shuajun li default:
225341e568d1Shuajun li info->SrbStatus = SS_ILLEGAL_REQUEST;
225441e568d1Shuajun li result = USB_STOR_TRANSPORT_FAILED;
225541e568d1Shuajun li break;
225641e568d1Shuajun li }
2257ce553bd1SAlan Stern if (result == USB_STOR_TRANSPORT_GOOD)
2258ce553bd1SAlan Stern info->SrbStatus = SS_SUCCESS;
225941e568d1Shuajun li return result;
226041e568d1Shuajun li }
226141e568d1Shuajun li
226233842cedSCho, Yu-Chen /*
226333842cedSCho, Yu-Chen * ms_scsi_irp()
226433842cedSCho, Yu-Chen */
ms_scsi_irp(struct us_data * us,struct scsi_cmnd * srb)226536f3a14dSFelipe Balbi static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
226633842cedSCho, Yu-Chen {
226733842cedSCho, Yu-Chen int result;
226833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
2269ce553bd1SAlan Stern
227033842cedSCho, Yu-Chen switch (srb->cmnd[0]) {
227133842cedSCho, Yu-Chen case TEST_UNIT_READY:
227233842cedSCho, Yu-Chen result = ms_scsi_test_unit_ready(us, srb);
227333842cedSCho, Yu-Chen break; /* 0x00 */
2274ce553bd1SAlan Stern case REQUEST_SENSE:
2275ce553bd1SAlan Stern result = do_scsi_request_sense(us, srb);
2276ce553bd1SAlan Stern break; /* 0x03 */
227733842cedSCho, Yu-Chen case INQUIRY:
2278f8efdabdSAlan Stern result = do_scsi_inquiry(us, srb);
227933842cedSCho, Yu-Chen break; /* 0x12 */
228033842cedSCho, Yu-Chen case MODE_SENSE:
228133842cedSCho, Yu-Chen result = ms_scsi_mode_sense(us, srb);
228233842cedSCho, Yu-Chen break; /* 0x1A */
228333842cedSCho, Yu-Chen case READ_CAPACITY:
228433842cedSCho, Yu-Chen result = ms_scsi_read_capacity(us, srb);
228533842cedSCho, Yu-Chen break; /* 0x25 */
228633842cedSCho, Yu-Chen case READ_10:
228733842cedSCho, Yu-Chen result = ms_scsi_read(us, srb);
228833842cedSCho, Yu-Chen break; /* 0x28 */
228933842cedSCho, Yu-Chen case WRITE_10:
229033842cedSCho, Yu-Chen result = ms_scsi_write(us, srb);
229133842cedSCho, Yu-Chen break; /* 0x2A */
229233842cedSCho, Yu-Chen default:
229333842cedSCho, Yu-Chen info->SrbStatus = SS_ILLEGAL_REQUEST;
229433842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_FAILED;
229533842cedSCho, Yu-Chen break;
229633842cedSCho, Yu-Chen }
2297ce553bd1SAlan Stern if (result == USB_STOR_TRANSPORT_GOOD)
2298ce553bd1SAlan Stern info->SrbStatus = SS_SUCCESS;
229933842cedSCho, Yu-Chen return result;
230033842cedSCho, Yu-Chen }
230133842cedSCho, Yu-Chen
ene_transport(struct scsi_cmnd * srb,struct us_data * us)230241e568d1Shuajun li static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
230341e568d1Shuajun li {
23044b309f1cSAlan Stern int result = USB_STOR_XFER_GOOD;
230541e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
230641e568d1Shuajun li
2307191648d0SJoe Perches /*US_DEBUG(usb_stor_show_command(us, srb)); */
230841e568d1Shuajun li scsi_set_resid(srb, 0);
23091892bf90SAlan Stern if (unlikely(!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready)))
231041e568d1Shuajun li result = ene_init(us);
23114b309f1cSAlan Stern if (result == USB_STOR_XFER_GOOD) {
23124b309f1cSAlan Stern result = USB_STOR_TRANSPORT_ERROR;
23131892bf90SAlan Stern if (info->SD_Status & SD_Ready)
231441e568d1Shuajun li result = sd_scsi_irp(us, srb);
231541e568d1Shuajun li
23161892bf90SAlan Stern if (info->MS_Status & MS_Ready)
231733842cedSCho, Yu-Chen result = ms_scsi_irp(us, srb);
231833842cedSCho, Yu-Chen }
23194b309f1cSAlan Stern return result;
232041e568d1Shuajun li }
232141e568d1Shuajun li
2322aa519be3SAkinobu Mita static struct scsi_host_template ene_ub6250_host_template;
232341e568d1Shuajun li
ene_ub6250_probe(struct usb_interface * intf,const struct usb_device_id * id)232441e568d1Shuajun li static int ene_ub6250_probe(struct usb_interface *intf,
232541e568d1Shuajun li const struct usb_device_id *id)
232641e568d1Shuajun li {
232741e568d1Shuajun li int result;
2328628c2893SAlan Stern u8 misc_reg03;
232941e568d1Shuajun li struct us_data *us;
2330628c2893SAlan Stern struct ene_ub6250_info *info;
233141e568d1Shuajun li
233241e568d1Shuajun li result = usb_stor_probe1(&us, intf, id,
2333aa519be3SAkinobu Mita (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
2334aa519be3SAkinobu Mita &ene_ub6250_host_template);
233541e568d1Shuajun li if (result)
233641e568d1Shuajun li return result;
233741e568d1Shuajun li
233841e568d1Shuajun li /* FIXME: where should the code alloc extra buf ? */
233941e568d1Shuajun li us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
234041e568d1Shuajun li if (!us->extra)
234141e568d1Shuajun li return -ENOMEM;
234241e568d1Shuajun li us->extra_destructor = ene_ub6250_info_destructor;
2343628c2893SAlan Stern
2344628c2893SAlan Stern info = (struct ene_ub6250_info *)(us->extra);
2345628c2893SAlan Stern info->bbuf = kmalloc(512, GFP_KERNEL);
2346628c2893SAlan Stern if (!info->bbuf) {
2347628c2893SAlan Stern kfree(us->extra);
2348628c2893SAlan Stern return -ENOMEM;
234941e568d1Shuajun li }
235041e568d1Shuajun li
235141e568d1Shuajun li us->transport_name = "ene_ub6250";
235241e568d1Shuajun li us->transport = ene_transport;
235341e568d1Shuajun li us->max_lun = 0;
235441e568d1Shuajun li
235541e568d1Shuajun li result = usb_stor_probe2(us);
235641e568d1Shuajun li if (result)
235741e568d1Shuajun li return result;
235841e568d1Shuajun li
235941e568d1Shuajun li /* probe card type */
2360628c2893SAlan Stern result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
236141e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) {
236241e568d1Shuajun li usb_stor_disconnect(intf);
236341e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR;
236441e568d1Shuajun li }
236541e568d1Shuajun li
2366628c2893SAlan Stern misc_reg03 = info->bbuf[0];
236741e568d1Shuajun li if (!(misc_reg03 & 0x01)) {
236816fae052SKristina Martšenko pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
236916fae052SKristina Martšenko "It does not support SM cards.\n");
237041e568d1Shuajun li }
237141e568d1Shuajun li
237241e568d1Shuajun li return result;
237341e568d1Shuajun li }
237441e568d1Shuajun li
237541e568d1Shuajun li
237641e568d1Shuajun li #ifdef CONFIG_PM
237741e568d1Shuajun li
ene_ub6250_resume(struct usb_interface * iface)237841e568d1Shuajun li static int ene_ub6250_resume(struct usb_interface *iface)
237941e568d1Shuajun li {
238041e568d1Shuajun li struct us_data *us = usb_get_intfdata(iface);
238141e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
238241e568d1Shuajun li
238341e568d1Shuajun li mutex_lock(&us->dev_mutex);
238441e568d1Shuajun li
238541e568d1Shuajun li if (us->suspend_resume_hook)
238641e568d1Shuajun li (us->suspend_resume_hook)(us, US_RESUME);
238741e568d1Shuajun li
238841e568d1Shuajun li mutex_unlock(&us->dev_mutex);
238941e568d1Shuajun li
239041e568d1Shuajun li info->Power_IsResum = true;
23911892bf90SAlan Stern /* info->SD_Status &= ~SD_Ready; */
23921892bf90SAlan Stern info->SD_Status = 0;
23931892bf90SAlan Stern info->MS_Status = 0;
23941892bf90SAlan Stern info->SM_Status = 0;
239541e568d1Shuajun li
239641e568d1Shuajun li return 0;
239741e568d1Shuajun li }
239841e568d1Shuajun li
ene_ub6250_reset_resume(struct usb_interface * iface)239941e568d1Shuajun li static int ene_ub6250_reset_resume(struct usb_interface *iface)
240041e568d1Shuajun li {
240141e568d1Shuajun li struct us_data *us = usb_get_intfdata(iface);
240241e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
2403191648d0SJoe Perches
240441e568d1Shuajun li /* Report the reset to the SCSI core */
240541e568d1Shuajun li usb_stor_reset_resume(iface);
240641e568d1Shuajun li
2407f0183a33SFelipe Balbi /*
2408f0183a33SFelipe Balbi * FIXME: Notify the subdrivers that they need to reinitialize
2409f0183a33SFelipe Balbi * the device
2410f0183a33SFelipe Balbi */
241141e568d1Shuajun li info->Power_IsResum = true;
24121892bf90SAlan Stern /* info->SD_Status &= ~SD_Ready; */
24131892bf90SAlan Stern info->SD_Status = 0;
24141892bf90SAlan Stern info->MS_Status = 0;
24151892bf90SAlan Stern info->SM_Status = 0;
241641e568d1Shuajun li
241741e568d1Shuajun li return 0;
241841e568d1Shuajun li }
241941e568d1Shuajun li
242041e568d1Shuajun li #else
242141e568d1Shuajun li
242241e568d1Shuajun li #define ene_ub6250_resume NULL
242341e568d1Shuajun li #define ene_ub6250_reset_resume NULL
242441e568d1Shuajun li
242541e568d1Shuajun li #endif
242641e568d1Shuajun li
242741e568d1Shuajun li static struct usb_driver ene_ub6250_driver = {
2428aa519be3SAkinobu Mita .name = DRV_NAME,
242941e568d1Shuajun li .probe = ene_ub6250_probe,
243041e568d1Shuajun li .disconnect = usb_stor_disconnect,
243141e568d1Shuajun li .suspend = usb_stor_suspend,
243241e568d1Shuajun li .resume = ene_ub6250_resume,
243341e568d1Shuajun li .reset_resume = ene_ub6250_reset_resume,
243441e568d1Shuajun li .pre_reset = usb_stor_pre_reset,
243541e568d1Shuajun li .post_reset = usb_stor_post_reset,
243641e568d1Shuajun li .id_table = ene_ub6250_usb_ids,
243741e568d1Shuajun li .soft_unbind = 1,
2438e73b2db6SHuajun Li .no_dynamic_id = 1,
243941e568d1Shuajun li };
244041e568d1Shuajun li
2441aa519be3SAkinobu Mita module_usb_stor_driver(ene_ub6250_driver, ene_ub6250_host_template, DRV_NAME);
2442