rendered paste body/* MASS_STORAGE.C
* This demo application is used to USB Demo
*/
#ifdef linux
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#else
#include <stdio.h>
#include <errno.h>
#endif
#include "mass_strg.h"
#define debg(str) ({fprintf str ; fflush(stdout); })
#define debg1(str) //({fprintf str ; fflush(stdout); })
#define debg2(str) //({fprintf str ; fflush(stdout); })
#define debg3(str) //({fprintf str ; fflush(stdout); })
//#define OTG_MS_NUM_1K_BLKS 7988 /* Number of 1K blocks given to mkfs.msdos command for 8M FAT12*/
//#define OTG_MS_NUM_1K_BLKS 15976 /* Number of 1K blocks given to mkfs.msdos command for 16M FAT12*/
//#define OTG_MS_NUM_1K_BLKS 63904 /* Number of 1K blocks given to mkfs.msdos command for 64M FAT16*/
//#define OTG_MS_NUM_1K_BLKS 50000 /* Number of 1K blocks given to mkfs.msdos command for 64M FAT16*/
//#define OTG_MS_NUM_1K_BLKS 120808 /* Number of 1K blocks given to mkfs.msdos command for 128M FAT16*/
//#define OTG_MS_NUM_1K_BLKS 78600 /* Number of 1K blocks given to mkfs.msdos command for 128M FAT16*/
#define OTG_MS_NUM_1K_BLKS (16384*2L) /* Number of 1K blocks given to mkfs.msdos command for 32M FAT16*/
//#define OTG_MS_NUM_1K_BLKS 227000 /* Number of 1K blocks given to mkfs.msdos command for 227M FAT16*/
//#define OTG_MS_PART_TYPE 0x01 /* 1=FAT12 (<32680 sectors), 4=FAT16 (32680-65535 sectors) */
#define OTG_MS_PART_TYPE 0x04 /* 1=FAT12 (<32680 sectors), 4=FAT16 (32680-65535 sectors) */
#define OTG_MS_NUM_BLKS ((OTG_MS_NUM_1K_BLKS) << 1)
#define OTG_MS_BLOCK_SIZE 0x200
/* Enable this to enable the CBI protocol to mimic a Fuji Film Mass Storage Camera */
//#define CBI
#undef CBI
/* Variables to store the length and keep track of Control Tx Data */
int ctrltx_len, ctrltx_cnt;
/* Variables to store the Block Num and Block Count in case of Bulk Tx Data */
int txblock_num, txblock_cnt;
/* Variables to store the Block Num and Block Count in case of Bulk Rx Data */
int rxblock_num, rxblock_cnt;
/* Buffer to store the Bulk Tx Data */
int bulkrx_cnt, bulktx_len, bulktx_cnt;
#ifdef CBI
/* Variables to keep track of intr tx data length */
int intrtx_len, intrtx_cnt;
char intrtx_buf[8];
#endif
/* Buffer to store the Control Rx Data */
char ctrlrx_buf[OTG_DEV_CTRL_MAXPKTSIZE];
/* Buffer to store the Control Tx Data */
char *ctrltx_buf = " ";
/* Buffer to store the Bulk Rx Data */
char bulkrx_buf[MAX_BULK_SIZE];
/* Buffer to store the Bulk Tx Data */
char bulktx_buf[MAX_BULK_SIZE];
/* Block that needs to be accessed next from the dos file system */
int next_blk;
/* Pointer to the FileSystem File */
FILE *fs_fp;
/* buffer to store the data when the CSRs from the USB Device are read */
int otg_bus[2];
/* Mass-storage descriptors */
/* Device Descriptor */
#ifdef CBI
char ms_dev_desc[] = {
0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, OTG_DEV_CTRL_MAXPKTSIZE, // 2.0
/* len 18, dev_dsc, USB 2.00, class 0, subcls 0, prot 0, maxpkt 64, */
0xcb, 0x04, 0x00, 0x00, 0x00, 0x00, MANF_DESC, PROD_DESC, SERIALNUM_DESC, 0x01
/* vend 04CB, prod 0100, rls 10.0, manstr 0, prodstr 2, sernostr 3, numcfg 1 */
};
#else
char ms_dev_desc[] = {
0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, OTG_DEV_CTRL_MAXPKTSIZE, // 2.0
/* len 18, dev_dsc, USB 2.00, class 0, subcls 0, prot 0, maxpkt 64, */
#ifdef MAXWELL
0x0b, 0x0C, 0x01, 0xB0, 0x07, 0x03, MANF_DESC, PROD_DESC, SERIALNUM_DESC, 0x01
#else
0x3F, 0x05, 0x01, 0xB0, 0x07, 0x03, MANF_DESC, PROD_DESC, SERIALNUM_DESC, 0x01
#endif
/* vend 053F, prod B001, rls 03.07, manstr 73, prodstr 77, sernostr 101, numcfg 1 */
};
#endif
/* Device Qualifier Descriptor */
char ms_dev_qual[] = {
0xa, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, OTG_DEV_CTRL_MAXPKTSIZE, // 2.0
0x01, 0x00
/* len 10, dev_qualifier, USB 2.00, class 0, subcls 0, prot 0, maxpkt 64,
numcfg 1, resv 0 */
};
/* Configuration Descriptor */
#ifdef CBI
char ms_cfg_desc[] = {
0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0, FUJI_MAX_POWER,
/* len 9, cfg_dsc, totlen 39, numifc 1, cfgval 1, cfgstr 0, attr 0xC0, maxpow 0 */
0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x05, 0x00, 0x00,
/* if: len 9, ifc_dsc, ifc 0, alt 0, numept 3, ifccls 8 (mass-storage),
* ifcsubcls 5 (SFF-8070i [ATAPI for floppies]), ifcprot 0 (CBI, CC intr), ifcstr 0 */
0x07, 0x05, 0x81, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, FUJI_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx2-outxx 1-out, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x02, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, FUJI_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx3-inxx 1-in, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x83, 0x03, OTG_DEV_INTR_MAXPKTSIZE_LSB, OTG_DEV_INTR_MAXPKTSIZE_MSB, FUJI_INT_POLL
/* ep: len 7, ept_dsc, ep xx2-inxx 3-in, attr 3 (intr), maxpkt 2, intvl 1ms */
};
#else
char ms_cfg_desc[] = {
#ifdef MAXWELL
0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0, MAX_MAX_POWER,
#else
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, STRING_CONFIG, 0x80, 0x19,
#endif
/* len 9, cfg_dsc, totlen 39, numifc 1, cfgval 1, cfgstr 0, attr 0xC0, maxpow 0 */
0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, STRING_INTERFACE,
/* if: len 9, ifc_dsc, ifc 0, alt 0, numept 3, ifccls 8 (mass-storage),
* ifcsubcls 6 (SCSI), ifcprot 50 (BulkOnly Protocol), ifcstr 0 */
#ifdef MAXWELL
0x07, 0x05, 0x81, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, MAX_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx2-outxx 1-out, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x01, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, MAX_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx3-inxx 1-in, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x82, 0x03, OTG_DEV_INTR_MAXPKTSIZE_LSB, OTG_DEV_INTR_MAXPKTSIZE_MSB, MAX_INT_POLL
/* ep: len 7, ept_dsc, ep xx2-inxx 3-in, attr 3 (intr), maxpkt 2, intvl 1ms */
#else
0x07, 0x05, 0x81, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, 0,
/* ep: len 7, ept_dsc, ep xx2-outxx 1-out, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x01, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, 0,
/* ep: len 7, ept_dsc, ep xx3-inxx 1-in, attr 2 (bulk), maxpkt 64 */
/* 0x07, 0x05, 0x83, 0x03, OTG_DEV_INTR_MAXPKTSIZE_LSB, OTG_DEV_INTR_MAXPKTSIZE_MSB, IOMG_INT_POLL*/
/* ep: len 7, ept_dsc, ep xx2-inxx 3-in, attr 3 (intr), maxpkt 2, intvl 1ms */
#endif
};
#endif
/* FIX 3 */
char ms_other_cfg_desc[] = {
0x09, 0x02, 0x27, 0x00, 0x01, 0x01, 0x00, 0xc0, IOMG_MAX_POWER,
/* len 9, cfg_dsc, totlen 39, numifc 1, cfgval 1, cfgstr 0, attr 0xC0, maxpow 0 */
0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, 0x00,
/* if: len 9, ifc_dsc, ifc 0, alt 0, numept 3, ifccls 8 (mass-storage),
* * ifcsubcls 6 (SCSI), ifcprot 50 (BulkOnly Protocol), ifcstr 0 */
0x07, 0x05, 0x81, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, IOMG_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx2-outxx 1-out, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x01, 0x02, OTG_DEV_BULK_MAXPKTSIZE_LSB_FS, OTG_DEV_BULK_MAXPKTSIZE_MSB_FS, IOMG_BULK_POLL,
/* ep: len 7, ept_dsc, ep xx3-inxx 1-in, attr 2 (bulk), maxpkt 64 */
0x07, 0x05, 0x82, 0x03, OTG_DEV_INTR_MAXPKTSIZE_LSB, OTG_DEV_INTR_MAXPKTSIZE_MSB, IOMG_INT_POLL
/* ep: len 7, ept_dsc, ep xx2-inxx 3-in, attr 3 (intr), maxpkt 2, intvl 1ms */
};
/* Manufacturer String Dscriptor */
#ifdef CBI
char ms_manf_desc[] = { 18, 3, 'F',0, 'u',0, 'j',0, 'i',0, 'F',0, 'i',0, 'l',0, 'm',0/*, 0,0*/ };
#else
#ifdef MAXWELL
char ms_manf_desc[] = { 18, 3, 'S',0, 'Y',0, 'N',0, 'O',0, 'P',0, 'S',0, 'Y',0, 'S',0/*, 0,0*/ };
#else
char ms_manf_desc[] = { 50, 3, 'S',0, 'Y',0, 'N',0, 'O',0, 'P',0, 'S',0, 'Y',0, 'S',0, ' ',0, 'D',0, 'E',0, 'S',0, 'I',0, 'G',0, 'N' ,0, 'W',0, 'A',0, 'R',0, 'E',0, ' ',0, 'C',0, 'O',0, 'R',0, 'E',0, 'S',0};
#endif
#endif
/* Product String Descriptor */
#ifdef CBI
char ms_prod_desc[] = {
34, 3, 'U',0, 'S',0, 'B',0, ' ',0, 'M',0, 'a',0, 's',0, 's',0, ' ',0, 'S',0, 't',0, 'o',0, 'r',0, 'a',0,
'g',0, 'e',0/*, 0,0*/
};
#else
#ifdef MAXWELL
char ms_prod_desc[] = {
34, 3, 'U',0, 'S',0, 'B',0, ' ',0, 'M',0, 'a',0, 's',0, 's',0, ' ',0, 'S',0, 't',0, 'o',0, 'r',0, 'a',0,
'g',0, 'e',0/*, 0,0*/
};
#else
char ms_prod_desc[] = {
//0x28, 0x03, 'P', 0, 'o',0, 'r',0, 't',0, 'a',0, 'b',0, 'l',0, 'e',0, ' ',0, 'H',0, 'a',0, 'r',0, 'd',0, 'D',0,
// 0x24, 0x03, 'P', 0, 'o',0, 'r',0, 't',0, 'a',0, 'b',0, 'l',0, 'e',0, ' ',0, 'H',0, 'a',0, 'r',0, 'd',0, 'D',0,
// 'r',0, 'i',0, 'v',0, 'e',0
0x24, 0x03, 'U', 0, 'S',0, 'B',0, ' ',0, '2',0, '.',0, '0',0, ' ',0, 'R',0, 'e',0, 'v',0, '.',0, ' ',0, '1',0,
'.',0, '5',0, 'B',0
// 0x58, 0x03, 'U',0, 'S',0, 'B',0, '2',0, '.',0, '0',0, ' ',0, 'D',0, 'e',0, 'v',0, 'i',0, 'c',0, 'e',0, ' ',0,
// 'C',0, 'o',0, 'n',0, 't',0, 'r',0, 'o',0, 'l',0, 'l',0, 'e',0, 'r',0, ' ',0, 'S',0, 'u',0, 'b',0, 's',0, 'y',0, 's',0, 't',0, 'e',0, 'm',0, ',',0, ' ',0, 'R',0, 'e',0, 'v',0, ' ',0, '1',0, '.',0, '5',0, 'B',0
};
#endif
#endif
/* Serial Number String Descriptor */
#ifdef CBI
char ms_sernum_desc[] = {
62, 3, 'Y',0, '-',0, '2',0, '4',0, '0',0, '^',0, '^',0, '^',0, '^',0, '^',0, '0',0, '0',0, '1',0, '0',0,
'1',0, '2',0, 'X',0, '0',0, '0',0, '0',0, '0',0, '0',0, '0',0, '1',0, '0',0, '1',0, '2',0, '6',0, '8',0, '0',0/*, 0,0*/
};
#else
#ifdef MAXWELL
char ms_sernum_desc[] = {
0x22, 0x03, 0x31, 0x00, 0x33, 0x00, 0x30, 0x00, 0x30, 0x00, 0x45, 0x00, 0x30, 0x00, 0x30, 0x00,
0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x44, 0x00, 0x30, 0x00, 0x41, 0x00, 0x43, 0x00, 0x44, 0x00,
0x35, 0x00 };
#else
char ms_sernum_desc[] = {
0x0C, 0x03, 0x31, 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00 };
#endif
#endif
char string_config[]= {
0x0C, 0x03, 0x31, 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00 };
char string_interface[]= {
0x0C, 0x03, 0x31, 0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00 };
/* Status Descriptor */
char stat_desc[] = { 0, 0 };
/* Language Descriptor */
char lang_desc[] = { 0x04,0x03,0x09,0x04 };
/* Inquiry Data */
#ifdef CBI
char ms_inq_data[] = {
0x00, 0x80, 0x00, 0x01, 0x1f, 0x00, 0x00, 0x00, 'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 'U', 'S', 'B', '-',
// dvtype rmb fmt adl len vend id prod id
'D', 'R', 'I', 'V', 'E', 'U', 'N', 'I', 'T', ' ', ' ', ' ', '1', '.', '0', '0'
// prod rev
};
#else
#ifdef MAXWELL
char ms_inq_data[] = {
0x00, 0x00, 0x00, 0x01, 0x1f, 0x00, 0x00, 0x00, 'M', 'A', 'X', 'T', 'O', 'R', ' ', '4', 'K', '0', '4', '0',
// dvtype rmb fmt adl len vend id prod id
'H', '2', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', '0', '8', '.'
// prod rev
};
#else
//char ms_inq_data[] = {
// 0x00, 0x00, 0x00, 0x01, 0x1f, 0x00, 0x00, 0x00, 0x49, 0x43, 0x32, 0x35, 0x4E, 0x30, 0x32, 0x30, 0x41, 0x54, 0x43, 0x53,
//// dvtype rmb fmt adl len vend id prod id
// 0x30, 0x34, 0x2D, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x41, 0x32, 0x4F
//// prod rev
//};
char ms_inq_data[] = {
//0x00, 0x80, 0x00, 0x01, 0x1f, 0x00, 0x00, ' ', 'S', 'Y', 'N', 'O', 'P', 'S', 'Y', 'S',
0x00, 0x80, 0x02, 0x02, 0x14, 0x00, 0x00, ' ', 'A', 'M', 'S',
// dvtype rmb fmt adl len vend id prod id
' ', 'M', 'a', 's', 's', ' ', 'S', 't', 'o', 'r', 'a', 'g', 'e',00, //0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x41, 0x32, 0x4F
// prod rev
};
#endif
#endif
/* Format Data */
#ifdef CBI
char ms_fmt_data[] = {
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x3e, 0x80, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x00,
// | len | num blocks cur/max |dsc cd| block len | num blocks formattable|rsvd?| block
0x02, 0x00
};
#else
#ifdef MAXWELL
char ms_fmt_data[] = {
0x00, 0x00, 0x00, 0x08, 0x04, 0xA9, 0x37, 0xDD, 0x00, 0x00, 0x02, 0x00
// | len | num blocks cur/max |dsc cd| block len | num blocks formattable|rsvd?| block
};
#else
#ifdef RAM_6M
char ms_fmt_data[] = {
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x3e, 0x80, 0x00, 0x00, 0x02, 0x00
//0x00, 0x00, 0x00, 0x08, 0x02, 0x54, 0x29, 0x7F, 0x00, 0x00, 0x02, 0x00
// | len | num blocks cur/max |dsc cd| block len | num blocks formattable|rsvd?| block
};
#else
char ms_fmt_data[] = {
0x00, 0x00, 0x00, 0x10,
/* | len | */
((OTG_MS_NUM_BLKS >> 24) & 0xff),
((OTG_MS_NUM_BLKS >> 16) & 0xff),
((OTG_MS_NUM_BLKS >> 8) & 0xff),
(OTG_MS_NUM_BLKS & 0xff),
/* | num blocks cur/max | */
0x02, 0x00, 0x02, 0x00,
/* |dsc cd| block len | */
((OTG_MS_NUM_BLKS >> 24) & 0xff),
((OTG_MS_NUM_BLKS >> 16) & 0xff),
((OTG_MS_NUM_BLKS >> 8) & 0xff),
(OTG_MS_NUM_BLKS & 0xff),
/* | num blocks formattable | */
0x01, 0x00, 0x02, 0x00
/* |rsvd?|block| len | */
};
#endif
#endif
#endif
/* Capacity Data */
#ifdef CBI
char ms_cap_data[] = {
0x00, 0x00, 0x3e, 0x7F, 0x00, 0x00, 0x02, 0x00
// | last block | block size in bytes |
};
#else
#ifdef MAXWELL
char ms_cap_data[] = {
0x04, 0xA9, 0x37, 0xDD, 0x00, 0x00, 0x02, 0x00
// | last block | block size in bytes |
};
#else
#ifdef RAM_6M
char ms_cap_data[] = {
0x00, 0x00, 0x3e, 0x7F, 0x00, 0x00, 0x02, 0x00
//0x02, 0x54, 0x29, 0x7F, 0x00, 0x00, 0x02, 0x00
// | last block | block size in bytes |
};
#else
char ms_cap_data[] = {
(((OTG_MS_NUM_BLKS - 1) >> 24) & 0xff),
(((OTG_MS_NUM_BLKS - 1) >> 16) & 0xff),
(((OTG_MS_NUM_BLKS - 1) >> 8) & 0xff),
((OTG_MS_NUM_BLKS - 1) & 0xff),
/* | last block | */
0x00, 0x00, ((OTG_MS_BLOCK_SIZE>>8)&0xff), 0x00
/* | block size in bytes | */
};
#endif
#endif
#endif
/* Mode Sense Data */
#ifdef CBI
char modesns_data[] = { // for CURRENT VALUES, PG CODE 0x1c (informational exceptions code page)
0x00, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
// | len | mdm |dv-sp| | p cd| p ln| |MRIE | <- async event reporting
};
#else
char modesns_data[] = { // for CURRENT VALUES, PG CODE 0x1c (informational exceptions code page)
0x00, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
// | len | mdm |dv-sp| | p cd| p ln| |MRIE | <- async event reporting
};
#endif
#ifdef CBI
char modesns2_data[] = { // for CURRENT VALUES, PG CODE 0x3f (all pages)
0x00, 0x32, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
// r/w err recov
0x00, 0x00, 0x00, 0x08, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b,
// ?? rem blk cap
0x0a, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x06, 0x00, 0x01, 0x00, 0x00,
// timer & prot
0x00, 0x00
};
#else
char modesns2_data[] = { // for CURRENT VALUES, PG CODE 0x3f (all pages)
0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif
#ifdef CBI
char modesns3_data[] = { // for CURRENT VALUES, PG CODE 0x1c (informational exceptions code page)
0x00, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#else
char modesns3_data[] = { // for CURRENT VALUES, PG CODE 0x1c (informational exceptions code page)
0x00, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
/* Request Sense Data */
char reqsns_data[] = { // after 1st TEST UNIT READY returns STALL
0x70, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00
// code sk: unit-attn asl asc + ascq: pwron/rst/busrst
// IRQ after data: 0x29, 0x00
};
#ifdef CBI
#else
char ms_csw_signature[4] = {0x55, 0x53, 0x42, 0x53};
char ms_cbw_signature[4] = {0x55, 0x53, 0x42, 0x43};
char csw_str[13];
#endif
char ms_empty_desc[] = { 0x00, 0x00, 0x00, 0x00 };
/* Buffers to store the correct data / descriptors which will be actually used in the program */
char partition_data[OTG_MS_BLOCK_SIZE];
char *dev_desc, *dev_qual, *cfg_desc, *other_cfg_desc, *manf_desc, *prod_desc, *sernum_desc, *empty_desc;
char *inq_data, *fmt_data, *cap_data;
/* Size of the various buffers */
int dev_desc_size, dev_qual_size, cfg_desc_size, manf_desc_size, prod_desc_size, sernum_desc_size;
int inq_data_size, fmt_data_size, cap_data_size, part_data_size;
/* Global Variables */
char got_TUR; // Var to know, if a TestUnitReady is received or not
char mass_strg_cmd; // Var set when a mass storage command is recieved and
// clred when the command is completetely executed
char enum_not_done = 1; // Var to keep track of whether the enumeration is done or not
char csw_pending; // CSW packet needs to be sent out
char stall_bulk_in; // Bulk In Endpoint needs to be stalled
char bot_cmd; // A temporary variable to store the Bulk Only Command
int bulk_in_stalled; // Var which keeps track whether a Bulk In Endpoint is stalled or not
int otg_dev_enum_spd; // Enumerated Speed
int ferr_num; // File Error Num
/* Functions Used */
/* This function handles all the data from / to the USB Device */
int handle_device_mode(OTG_FD bus_fd, int *eret);
/* Handles the USB Suspend Process */
int handle_device_suspend(OTG_FD bus_fd, int *eret);
/* Handles a Device SetUp Request or a Mass Storage Command */
int handle_device_request(OTG_FD bus_fd, OTG_FD ctrl_rx_fd, char *ctrlrx_bfr, ssize_t ctrlrx_len);
/* Handles Control Tx Transfers */
int handle_ctrltx_xfer(OTG_FD bus_fd, OTG_FD ctrl_fd);
#ifdef CBI
/* Handles Interrupt Tx transfers */
int handle_intrtx_xfer(OTG_FD intr_fd);
#else
/* Handles mass storage Commands on Bulk Out EP */
int handle_bulkrx_cmd(OTG_FD bus_fd, OTG_FD bulk_rx_fd, char *bulkrx_buf, ssize_t bulkrx_len);
#endif
/* Handles Bulk Receive Transfers */
int handle_bulkrx_xfer(OTG_FD bulk_rx_fd, char *bulkrx_bfr, ssize_t bulkrx_len);
/* Handles Bulk Transmit Transfers */
int handle_bulktx_xfer(OTG_FD bus_fd, OTG_FD bulk_tx_fd);
/* Decodes and Executes Mass Storage Commands */
void decode_ms_cmd (OTG_FD bus_fd, char *cmd_bfr, ssize_t cmd_len, char *csw_tag, int cbw_data_len);
/* Decodes and Executes Setup Requests */
void decode_setup_req (OTG_FD bus_fd, char *cmd_bfr);
/* Sets the Stall Bit on the appropriate EPs */
void set_stall (OTG_FD bus_fd, int ep_num);
/* Clears the Stall Bit on the appropriate EPs */
void clr_stall (OTG_FD bus_fd, int ep_num);
/* Sets the expected Bulk Receive Data Length in the Device */
void set_exp_bulkrx_len (OTG_FD bus_fd, int total_bulk_pkt_len);
/* Sends out 0 len pkt on a EP, by clearing the NAK bit of that EP */
void send_0len_pkt (int ep_num);
#ifdef CBI
/* Send out status on interrupt ep */
void send_intr_sts (char intr_data, int intr_len, int intr_cnt);
#else
/* Send out CSW on Bulk ep */
void send_csw (char *csw_tag, int csw_data_residue, char csw_sts);
#endif
/* Fill Up the Bulk Tx buffer from the DOS FS for transmit */
int fill_bulktx_buff (int tx_cnt, int tx_blk);
/* Write the received data into the DOS FS on a receive */
int flush_bulkrx_buff (int rx_cnt, int rx_blk);
/* temporarily for debugging purpose */
int ioctl(int, int, int);
/* debugging. these were in handle_device_mode. */
OTG_FD ctrl_rx_fd, ctrl_tx_fd, bulk_rx_fd, bulk_tx_fd;
/* debugging. this one was in main */
OTG_FD bus_fd;
/* Program Main Routine */
int
main(int argc, char *argv[])
{
// OTG_FD bus_fd;
int err = 0;
int retval = 1;
/* Load all the appropriate descriptors, based on the type of application */
dev_desc = ms_dev_desc;
cfg_desc = ms_cfg_desc;
other_cfg_desc = ms_other_cfg_desc;
manf_desc = ms_manf_desc;
sernum_desc = ms_sernum_desc;
inq_data = ms_inq_data;
fmt_data = ms_fmt_data;
cap_data = ms_cap_data;
prod_desc = ms_prod_desc;
dev_qual = ms_dev_qual;
empty_desc = ms_empty_desc;
/* Getting the length of all the descriptors */
dev_desc_size = sizeof(ms_dev_desc);
cfg_desc_size = sizeof(ms_cfg_desc);
debg((stdout, "cfg_desc_size:%x\n ", cfg_desc_size));
manf_desc_size = sizeof(ms_manf_desc);
sernum_desc_size = sizeof(ms_sernum_desc);
inq_data_size = sizeof(ms_inq_data);
fmt_data_size = sizeof(ms_fmt_data);
cap_data_size = sizeof(ms_cap_data);
prod_desc_size = sizeof(ms_prod_desc);
dev_qual_size = sizeof(ms_dev_qual);
part_data_size = sizeof(partition_data);
/* Insert all of our modules */
// system("insmod otgdrv.ko"); // USB2.0 Subsystem
// system("insmod otgdrv.ko");
system("insmod /lib/modules/2.6.22.2/kernel/drivers/usb/gadget/driver/otgdrv.ko");
//system("modprobe ide_dev"); // IDE Controller
/* Open Device bus FD */
bus_fd = otgdev_open(otgdev_bus, OTG_O_RDWR);
enum_not_done = 1; // HK FIX: Make sure that enumeration is not done
if (bus_fd < 0)
{
err = errno;
goto open_bus_err;
}
/* This label is used to resume, after a suspend */
restart:
/* Initialise all the variables that keep track of data length tx/rs */
ctrltx_len = ctrltx_cnt = 0;
bulktx_len = bulktx_cnt = 0;
#ifdef CBI
intrtx_len = intrtx_cnt = 0;
#endif
txblock_num = txblock_cnt = 0;
rxblock_num = rxblock_cnt = 0;
next_blk = 0;
/* Call Device mode handler function */
// retval = handle_device_mode(bus_fd, &err);
retval = handle_device_suspend(bus_fd, &err);
#if 0
if (retval)
{
debg((stdout, "*E1:%d R:%d ", err, retval));
/* Positive return value is error */
if (retval > 0)
goto device_err;
}
else
{
debg1((stdout, "AR+"));
}
/* Gets here on a suspend, so go back to Start */
goto restart;
/* When a fatal error is encountered close all the files */
device_err:
otgdev_close(bus_fd);
open_bus_err:
fprintf(stdout, "E2:%d R:%d ", err, retval);
if (err)
error(retval, err, "errno: %d Error", err);
fflush(stdout);
#endif
/* Remove all of our modules */
system("rmmod otgdrv.ko");
return retval;
}
/* This function handles all the data from/to the USB Device */
int
handle_device_mode(OTG_FD bus_fd, int *eret)
{
// OTG_FD ctrl_rx_fd, ctrl_tx_fd, bulk_rx_fd, bulk_tx_fd;
#ifdef CBI
OTG_FD intr_tx_fd;
#endif
ssize_t len, ctrlrx_len, bulkrx_len;
int err = 0;
int retval = 2;
int tim = 0;
int read_cnt = 0;
/* Open the Control Out endpoint */
ctrl_rx_fd = otgdev_open(otgdev_ctrl_rx, OTG_O_RDWR);
if (ctrl_rx_fd < 0)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto open_ctrlrx_err;
}
/* Open the Control In endpoint */
ctrl_tx_fd = otgdev_open(otgdev_ctrl_tx, OTG_O_RDWR);
if (ctrl_tx_fd < 0)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto open_ctrltx_err;
}
/* Open the Bulk Out Endpoint */
retval = 3;
bulk_rx_fd = otgdev_open(otgdev_bulk_rx, OTG_O_RDWR);
if (bulk_rx_fd < 0)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto open_bulkrx_err;
}
/* Open the Bulk In Endpoint */
retval = 4;
bulk_tx_fd = otgdev_open(otgdev_bulk_tx, OTG_O_RDWR);
if (bulk_tx_fd < 0)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto open_bulktx_err;
}
#ifdef CBI
/* Open the Intr In endpoint */
retval = 5;
intr_tx_fd = otgdev_open(otgdev_intr_tx, OTG_O_RDWR);
if (intr_tx_fd < 0)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto open_intr_err;
}
/* Write an initial status value to the Intr endpoint */
retval = 6;
intrtx_buf[0] = 0;
len = otgdev_write(intr_tx_fd, &intrtx_buf[0], 2);
if (len < 2)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
goto intr_write_err;
}
#endif
/* Open the Dos FileSystem File */
// fs_fp = fopen("/mnt/dosfs", "r+b");
fs_fp = fopen("/mnt/data/dosfs", "r+b");
if (fs_fp)
{
ferr_num = fseek(fs_fp, 0, SEEK_SET);
if (ferr_num)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
debg((stdout, "*FERR0_%0d,%0d+",ferr_num,errno));
}
}
else
{
debg((stdout, "** Couldn't open file %s **\n", "/mnt/data/dosfs"));
goto open_fs_err;
}
retval = 7;
bulkrx_cnt = 0;
read_cnt = 0;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
/* Loop as long as the device is running */
while (1)
{
/* Read the Device Status and Bulk EP Status Registers */
retval = 8;
len = otgdev_read(bus_fd, &otg_bus[0], sizeof(otg_bus));
if (len < sizeof(otg_bus))
{
debg((stdout, "*Error 1 Encountered"));
err = errno;
fflush(stdout);
goto bus_read_err_2;
}
/* If cable is disconnected or the device is suspended */
// Fix_SR
/* HK FIX: Clear registers after reset */
/* This (ENUM_DONE = 0) should happen after reset */
if ( (otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) == 0)
{ // HK FIX
bulkrx_cnt = 0; // HK FIX
bulktx_cnt = 0; // HK FIX
csw_pending = 0; // HK FIX
ctrltx_len = 0; ctrltx_cnt = 0; // HK FIX
txblock_num = 0; txblock_cnt = 0; // HK FIX
rxblock_num = 0; rxblock_cnt = 0; // HK FIX
bulktx_len = 0; // HK FIX
//debg1((stdout, "r+")); // HK FIX
}
/* HK FIX: Suspend bit rises before disconnect/reconnect or suspend/resume */
if (otg_bus[OTG_REG_STS] & OTG_STS_US)
{
//debg((stdout, "SPS+"));
/* Wait Suspend release */
retval = handle_device_suspend(bus_fd, &err); // HK FIX
/* If enumeration is not done and it was done before then it's a disconnect */
if (( (otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) == 0) && enum_not_done == 0)
{ // HK FIX
debg((stdout, "AUS+"));
/* Close the Intr, Control, and Bulk FDs */
ferr_num = fclose(fs_fp);
if (ferr_num)
{
debg((stdout, "*FERR1_%0d,%0d+",ferr_num,errno));
}
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
#ifdef CBI
otgdev_close(intr_tx_fd);
#endif
otgdev_close(bulk_tx_fd);
otgdev_close(bulk_rx_fd);
otgdev_close(ctrl_tx_fd);
otgdev_close(ctrl_rx_fd);
/* Handle the suspend, Wait until the suspend bit is deasserted */
retval = handle_device_suspend(bus_fd, &err);
enum_not_done = 1;
goto out;
}
/* If the device is OK (No Suspend), then wait until the enumeration is done */
}
else if ( (otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) && (enum_not_done) )
{
enum_not_done = 0;
/* Get the enumeration Speed */
otg_dev_enum_spd = otg_bus[OTG_REG_STS] & OTG_STS_ENUM_SPD;
/* Set the speed fields in the configuration descriptor based
* on the enum speed */
if (otg_dev_enum_spd == OTG_ENUM_SPD_FS)
{
cfg_desc[22] = OTG_DEV_BULK_MAXPKTSIZE_LSB_FS;
cfg_desc[23] = OTG_DEV_BULK_MAXPKTSIZE_MSB_FS;
cfg_desc[29] = OTG_DEV_BULK_MAXPKTSIZE_LSB_FS;
cfg_desc[30] = OTG_DEV_BULK_MAXPKTSIZE_MSB_FS;
}
else
{
cfg_desc[22] = OTG_DEV_BULK_MAXPKTSIZE_LSB_HS;
cfg_desc[23] = OTG_DEV_BULK_MAXPKTSIZE_MSB_HS;
cfg_desc[29] = OTG_DEV_BULK_MAXPKTSIZE_LSB_HS;
cfg_desc[30] = OTG_DEV_BULK_MAXPKTSIZE_MSB_HS;
#ifdef CBI
debg((stdout, "\n"));
debg((stdout, "=======================================================\n"));
debg((stdout, "ERROR: This application is designed for Full Speed USB\n"));
debg((stdout, " Expect errors when using this application in HS\n"));
debg((stdout, "=======================================================\n"));
debg((stdout, "\n"));
#endif
}
}
/* Check to see if the Bulk In EP is stalled or not */
bulk_in_stalled = otg_bus[OTG_REG_BULK_IN_CTRL] & OTG_DEV_STALL;
/* Reset the BulkIn/CtrlIn Length every time, the loop is entered */
bulkrx_len = 0;
ctrlrx_len = 0;
/* Check for any out going data */
tim++;
// HK FIX: give incoming bulks highest priority
/* Check for any incoming bulk pkt (non cmd for BOT) data */
if (bulkrx_cnt > 0)
{
retval = 10;
bulkrx_len = otgdev_read(bulk_rx_fd, bulkrx_buf, bulkrx_cnt*OTG_MS_BLOCK_SIZE);
if (bulkrx_len < 0 && errno != EAGAIN)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
fflush(stdout);
goto bulk_read_err;
}
else if (bulkrx_len > 0)
{
//debg((stdout,"AIB%0d+",bulkrx_len));
/* There is Bulk RX data, handle it */
retval = handle_bulkrx_xfer(bulk_rx_fd, bulkrx_buf, bulkrx_len);
tim = 0;
read_cnt = 0;
debg1((stdout,"BR%0d+",bulkrx_cnt));
csw_pending = 1;
if (retval)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
err = errno;
if (bulktx_len != 0)
{
debg((stdout,"err+%0d+ ",err));
/* In case we need to send an error code */
retval = handle_bulktx_xfer(bus_fd, bulk_tx_fd);
}
fflush(stdout);
goto bulk_read_err;
}
}
else
{
read_cnt++;
debg((stdout,"RC,%0d+",read_cnt));
if (read_cnt == 100)
{
/* debugging */
debg((stdout,"RTO+"));
read_cnt = 0;
/* debugging. send csw to kick dma */
// handle_bulktx_xfer(bus_fd, bulk_tx_fd);
// bulkrx_cnt = 0;
usleep(2000);
/* debugging */
otgdev_ioctl(bulk_rx_fd, 2, 0);
usleep(2000);
}
}
/* Check for any control out data */
}
else if (ctrltx_len != 0)
{
debg1((stdout,"AOC%0d+",ctrltx_len));
/* A Control TX is in progress, handle it */
retval = handle_ctrltx_xfer(bus_fd, ctrl_tx_fd);
if (retval)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
err = errno;
fflush(stdout);
goto ctrl_write_err;
}
#ifdef CBI
/* If an Intr TX is in progress... */
}
else if (intrtx_len != 0 && (bulkrx_cnt == 0))
{
debg1((stdout,"AOI%0d+",intrtx_len));
retval = handle_intrtx_xfer(intr_tx_fd);
if (retval)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
err = errno;
fflush(stdout);
goto intr_write_err2;
}
#endif
/* Check for Bulk Tx Data or to transmit the CSW Packet*/
}
else if ( ( (bulktx_len != 0) || (csw_pending) || (stall_bulk_in) ) && (bulk_in_stalled==0) )
{
debg1((stdout,"AOBO%0d,%0d,%0d+",bulktx_len,csw_pending,stall_bulk_in));
/* HK FIX: make sure that all RX data has been transferred first */
// if (bulkrx_cnt==0) {
tim = 0;
/* A Bulk TX is in progress, handle it */
retval = handle_bulktx_xfer(bus_fd, bulk_tx_fd);
if (retval)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
err = errno;
fflush(stdout);
goto bulk_write_err;
}
// } else {
// debg((stdout,"bulkrx_cnt=%0d",bulkrx_cnt));
// }
/* Check for any incoming control data,
Check the Control Rx for Setup or Bulk Rx for mass storage commands,
only after all the other pending transactions are attended to */
}
else
{
/* See if there is any Control RX data */
retval = 9;
ctrlrx_len = otgdev_read(ctrl_rx_fd, ctrlrx_buf, sizeof(ctrlrx_buf));
if (ctrlrx_len < 0 && errno != EAGAIN)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
debg((stdout,"MS, CtrlInLen Err : %0d\n",ctrlrx_len));
fflush(stdout);
goto ctrl_read_err;
}
else if (ctrlrx_len > 0)
{
debg((stdout,"AIC%0d+",ctrlrx_len));
/* There is Control RX data, handle it */
retval = handle_device_request(bus_fd, ctrl_rx_fd, ctrlrx_buf,
ctrlrx_len);
if (retval)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
fflush(stdout);
goto ctrl_read_err;
}
/* There is no data on the control endpoint, check the bulk Rx for
* any mass storage commands */
}
else
{
#ifdef CBI
retval = 11;
fflush(stdout);
#else
retval = 20;
bulkrx_len = otgdev_read(bulk_rx_fd, bulkrx_buf, OTG_MS_BLOCK_SIZE);
if (bulkrx_len < 0 && errno != EAGAIN)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
fflush(stdout);
goto bulk_read_err;
}
else if (bulkrx_len > 0)
{
// debg((stdout,"AIBC%0d+",bulkrx_len));
read_cnt = 0;
/* There is Bulk Cmd RX data, handle it */
retval = handle_bulkrx_cmd (bus_fd, bulk_rx_fd, bulkrx_buf, bulkrx_len);
if (retval)
{
err = errno;
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
if (bulktx_len != 0)
{
/* In case we need to send an error code */
retval = handle_bulktx_xfer(bus_fd, bulk_tx_fd);
}
fflush(stdout);
goto bulk_read_err;
}
}
else
{
// read_cnt++;
// debg1((stdout,"NOP+",read_cnt));
retval = 11;
fflush(stdout);
}
#endif
}
}
} /* End while(1) */
debg((stdout, "*AEW+"));
fflush(stdout);
bus_read_err_2:
ctrl_write_err:
ctrl_read_err:
bulk_write_err:
bulk_read_err:
#ifdef CBI
intr_write_err2:
#endif
ferr_num = fclose(fs_fp);
if (ferr_num)
{
debg((stdout, "*FERR2_%0d,%0d+",ferr_num,errno));
}
open_fs_err:
#ifdef CBI
intr_write_err:
otgdev_close(intr_tx_fd);
open_intr_err:
#endif
otgdev_close(bulk_tx_fd);
open_bulktx_err:
otgdev_close(bulk_rx_fd);
open_bulkrx_err:
otgdev_close(ctrl_tx_fd);
open_ctrltx_err:
otgdev_close(ctrl_rx_fd);
open_ctrlrx_err:
out:
system("rmmod otgdrv.ko");
*eret = err;
return retval;
}
/* Handles the USB Suspend Process */
int
handle_device_suspend(OTG_FD bus_fd, int *eret)
{
ssize_t len;
int retval;
int err = 0;
reqsns_data[2] = 0x06;
reqsns_data[12] = 0x29;
got_TUR = 0;
mass_strg_cmd = 0;
csw_pending = 0;
stall_bulk_in = 0;
/* Wait until Suspend bit clears */
/* HK FIX: While loop changed */
while(1)
{
/* Read the Bus mode info */
retval = 12;
len = otgdev_read(bus_fd, &otg_bus[0], sizeof(otg_bus));
if (len < sizeof(otg_bus))
{
err = errno;
if (len < 0)
debg((stdout, "*ERROR %d %d FROM READ\n", len, err));
else
debg((stdout, "*SHORT READ %d\n", len));
goto out;
}
// HK FIX: exit if disconnect
if (((otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) == 0) && enum_not_done == 0)
{
debg((stdout, "EN0+"));
enum_not_done = 1;
break;
}
// HK FIX: exit if enumeration is done
if ((otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) == 1)
{
debg((stdout, "ENr+"));
break;
}
// HK FIX: exit if the suspend bit is cleared
if ((otg_bus[OTG_REG_STS] & OTG_STS_US) == 0)
{
debg((stdout, "SPr+"));
enum_not_done = 1;
break;
}
}
// HK FIX: while loops changed
//} while (otg_bus[OTG_REG_STS] & OTG_STS_US); // Fix_SR
//} while ( ((otg_bus[OTG_REG_STS] & OTG_STS_ENUM_DONE) == 0) && (otg_bus[OTG_REG_STS] & OTG_STS_US));
retval = 0;
out:
*eret = err;
return retval;
}
#ifdef CBI
#else
/* Handles Mass Storage Commands on Bulk OUT EP */
int
handle_bulkrx_cmd (OTG_FD bus_fd, OTG_FD bulk_rx_fd, char *bulkrx_buf, ssize_t bulkrx_len)
{
char csw_tag[4];
char ms_bo_cmd[16];
int max_rxcnt, max_txcnt, max_data_len;
int retval, ms_bo_cmd_len;
int iIdx;
/* The length of a CBW is always 31 Bytes and the Signature Matches,
* treat it as a ms command */
if ( (bulkrx_len == 31) && (!csw_pending) && (!memcmp(bulkrx_buf,ms_cbw_signature,4)) )
{
/* Check the LUN to be 0 */
/* Check for the reserved bits*/
if ( (bulkrx_buf[13]==0x00) && ((bulkrx_buf[14] & 0xE0)==0x00) &&
((bulkrx_buf[12] & 0x7F)==0x00) )
{
/* Valid and MeaningFul Mass Storage Cmd */
mass_strg_cmd = 1;
/* Save the Tag for the CSW */
memcpy(csw_tag,&bulkrx_buf[4], 4);
/* Save the mass storage command */
memcpy(ms_bo_cmd,&bulkrx_buf[15],16);
max_data_len = (bulkrx_buf[11] << 24) | (bulkrx_buf[10] << 16) |
(bulkrx_buf[9] << 8) | bulkrx_buf[8];
/* Data Out from Host to Device */
if (bulkrx_buf[12] & 0x80)
{
max_rxcnt = max_data_len;
/* Data In from Device to Host */
}
else
{
max_txcnt = max_data_len;
}
/* save the cmd len */
ms_bo_cmd_len = bulkrx_buf[14] & 0x1F;
debg1((stdout, "AMS%2x+",ms_bo_cmd[0]));
bot_cmd = ms_bo_cmd[0];
decode_ms_cmd (bus_fd, ms_bo_cmd, ms_bo_cmd_len, csw_tag, max_data_len);
}
else
{
debg((stdout, "ss1 "));
set_stall (bus_fd, OTG_DEV_BULK_EPS);
}
// HK FIX: I guess we have lost the signature.
// 4 bytes are missing. I don't know is this still needed?
// All indexes has changed: [original - 4]
}
else if ( (bulkrx_len == 31) && (!csw_pending) )
{
/* Check the LUN to be 0 */
/* Check for the reserved bits*/
if ( (bulkrx_buf[9]==0x00) && ((bulkrx_buf[10] & 0xE0)==0x00) &&
((bulkrx_buf[8] & 0x7F)==0x00) )
{
/* Valid and MeaningFul Mass Storage Cmd */
mass_strg_cmd = 1;
/* Save the Tag for the CSW */
memcpy(csw_tag,&bulkrx_buf[0], 4);
/* Save the mass storage command */
memcpy(ms_bo_cmd,&bulkrx_buf[11],16);
max_data_len = (bulkrx_buf[7] << 24) | (bulkrx_buf[6] << 16) |
(bulkrx_buf[5] << 8) | bulkrx_buf[4];
/* Data Out from Host to Device */
if (bulkrx_buf[8] & 0x80)
{
max_rxcnt = max_data_len;
/* Data In from Device to Host */
}
else
{
max_txcnt = max_data_len;
}
/* save the cmd len */
ms_bo_cmd_len = bulkrx_buf[10] & 0x1F;
debg((stdout, "AMS%2x+",ms_bo_cmd[0]));
bot_cmd = ms_bo_cmd[0];
decode_ms_cmd (bus_fd, ms_bo_cmd, ms_bo_cmd_len, csw_tag, max_data_len);
}
else
{
debg((stdout, "ss2 "));
set_stall (bus_fd, OTG_DEV_BULK_EPS);
}
// HK FIX ---------------------------- ^^^^^^^^
/* It is an unexpected bulk out pkt */
}
else
{
/*
debg((stdout,"bulkrx_buf: %0x,%0x,%0x,%0x, %0x,%0x,%0x,%0x, %0x,%0x,%0x,%0x, %0x,%0x,%0x,%0x,
%0x,%0x,%0x,%0x, %0x,%0x,%0x,%0x, %0x,%0x,%0x,%0x, %0x,%0x,%0x+",
bulkrx_buf[0], bulkrx_buf[1], bulkrx_buf[2], bulkrx_buf[3],
bulkrx_buf[4], bulkrx_buf[5], bulkrx_buf[6], bulkrx_buf[7],
bulkrx_buf[8], bulkrx_buf[9], bulkrx_buf[10], bulkrx_buf[11],
bulkrx_buf[12], bulkrx_buf[13], bulkrx_buf[14], bulkrx_buf[15],
bulkrx_buf[16], bulkrx_buf[17], bulkrx_buf[18], bulkrx_buf[19],
bulkrx_buf[20], bulkrx_buf[21], bulkrx_buf[22], bulkrx_buf[23],
bulkrx_buf[24], bulkrx_buf[25], bulkrx_buf[26], bulkrx_buf[27],
bulkrx_buf[28], bulkrx_buf[29], bulkrx_buf[30]));
debg((stdout, "bl%0d",bulkrx_len));
debg((stdout, "cp%0d",csw_pending));
debg((stdout, "mc%0d",memcmp(bulkrx_buf,ms_cbw_signature,4)));
*/
/* debugging */
debg((stdout, "ss3 "));
set_stall (bus_fd, OTG_DEV_BULK_OUT_EP);
}
retval = 0;
return retval;
}
#endif
int
handle_device_request(OTG_FD bus_fd, OTG_FD ctrl_rx_fd, char *ctrlrx_bfr, ssize_t ctrlrx_len)
{
char *null_str = "";
if (ctrlrx_len < 8)
{
fprintf(stdout, "bad request length %d\n", ctrlrx_len);
errno = 0;
return 30;
}
/* Is a mass storage command */
if (ctrlrx_len > 8)
{
if (!mass_strg_cmd)
{
fprintf(stdout, "unexpected non-setup request\n");
errno = 0;
return 31;
}
mass_strg_cmd = 0;
if (ctrlrx_len != 12)
{
fprintf(stdout, "bad non-setup request length %d\n", ctrlrx_len);
errno = 0;
return 32;
}
decode_ms_cmd (bus_fd, ctrlrx_bfr, ctrlrx_len, null_str, 0xff);
}
else
{
/* This should not happen, unless a mass storage cmd is not received */
if (mass_strg_cmd)
{
fprintf(stdout, "<*****************************!cs!>");
mass_strg_cmd = 0;
/* debugging */
// otgdev_ioctl(bulk_rx_fd, 0, 0);
// otgdev_ioctl(bulk_tx_fd, 0, 0);
}
decode_setup_req (bus_fd, ctrlrx_bfr);
}
return 0;
}
int
handle_ctrltx_xfer(OTG_FD bus_fd, OTG_FD ctrl_fd)
{
int len = ctrltx_len - ctrltx_cnt;
char send0 = 0;
if (len > 0)
{
// if (len == OTG_DEV_CTRL_MAXPKTSIZE)
// send0 = 1;
debg1((stdout, "xfer l=%d,t=%d\n",ctrltx_len,ctrltx_cnt));
if (len > OTG_DEV_CTRL_MAXPKTSIZE)
len = OTG_DEV_CTRL_MAXPKTSIZE;
len = otgdev_write(ctrl_fd, ctrltx_buf + ctrltx_cnt, len);
debg1((stdout, "xfer l=%d\n",len));
if (len < 0 && errno != EAGAIN)
{
debg1((stdout, "len=%x,errno=%x\n",len,errno));
return 40;
}
if (len > 0)
{
ctrltx_cnt += len;
if (ctrltx_cnt >= ctrltx_len)
{
debg1((stdout, "control send complete\n"));
ctrltx_cnt = ctrltx_len = 0;
if (send0)
ctrltx_len = -1;
}
}
}
else if (ctrltx_len < 0)
{
if (ctrltx_cnt < 0)
len = otgdev_write(ctrl_fd, ctrltx_buf, -1);
else
len = otgdev_write(ctrl_fd, ctrltx_buf, 0);
if (len < 0 && errno != EAGAIN)
return 41;
if (len >= 0)
ctrltx_len = 0;
}
return 0;
}
int
handle_bulkrx_xfer (OTG_FD bulk_fd, char *bulkrx_bfr, ssize_t rx_len)
{
if (rxblock_cnt > 0)
{
int blk, cnt, len, wr_cnt;
/* Get data block number and length */
blk = rxblock_num;
cnt = rxblock_cnt;
wr_cnt = rx_len/OTG_MS_BLOCK_SIZE;
flush_bulkrx:
len = flush_bulkrx_buff (wr_cnt, blk);
blk += len;
cnt -= len;
if (len < wr_cnt)
{
wr_cnt = wr_cnt - len;
goto flush_bulkrx;
}
debg1((stdout, "[wr2: %d %d %d]", len, blk, cnt));
if (cnt < 0)
cnt = 0;
rxblock_num = blk;
bulkrx_cnt = rxblock_cnt = cnt;
if (bulkrx_cnt > (sizeof(bulkrx_buf)/OTG_MS_BLOCK_SIZE))
bulkrx_cnt = (sizeof(bulkrx_buf)/OTG_MS_BLOCK_SIZE);
}
return 0;
}
int
handle_bulktx_xfer(OTG_FD bus_fd, OTG_FD bulk_fd)
{
static int bulktx_tries;
int len = bulktx_len - bulktx_cnt;
if (len > 0)
{
// if (len > 8192)
// len = 8192;
/* debugging. the device crashes when max length is
* set to 8k (8192). set it to 4k for now.
*/
if (len > 4096)
len = 4096;
len = otgdev_write(bulk_fd, bulktx_buf + bulktx_cnt, len);
if (len < 0 && errno != EAGAIN)
{
debg((stdout, "** fd %d ptr %u len %d **\n", bulk_fd,
(unsigned)(bulktx_buf + bulktx_cnt),
bulktx_len - bulktx_cnt));
return 60;
}
if (len > 0)
{
debg1((stdout,"AOB%0d+",len));
bulktx_cnt += len;
bulktx_tries = 0;
if (bulktx_cnt >= bulktx_len)
{
bulktx_cnt = bulktx_len = 0;
if (txblock_cnt > 0)
{
bulktx_len = fill_bulktx_buff (txblock_cnt, txblock_num);
return 0;
}
}
else
{
debg1((stdout, "bulk send, %d bytes left\n", bulktx_len - bulktx_cnt));
}
}
else
{
if (++bulktx_tries > 1000000)
{
debg((stdout, "** Timeout in handle_bulktx_xfer() with %d bytes left **\n",
bulktx_len - bulktx_cnt));
bulktx_tries = 0;
bulktx_cnt = bulktx_len = 0;
}
}
}
else if (bulktx_len < 0)
{
debg((stdout, "*AINV+"));
len = otgdev_write(bulk_fd, bulktx_buf, 0);
if (len < 0 && errno != EAGAIN)
return 61;
if (len >= 0)
{
debg1((stdout, "0-length bulk send complete\n"));
bulktx_tries = 0;
bulktx_len = 0;
}
else
{
if (++bulktx_tries > 1000000)
{
debg((stdout, "*Timeout in handle_bulktx_xfer() sending 0-length packet **\n"));
bulktx_tries = 0;
bulktx_len = 0;
}
}
#ifdef CBI
#else
/* Stall the next Bulk In Pkt */
}
else if (stall_bulk_in)
{
debg((stdout, "ss4 "));
set_stall (bus_fd, OTG_DEV_BULK_IN_EP);
stall_bulk_in = 0;
debg((stdout,"AST8*+"));
/* Send out the CSW Packet */
}
else if (csw_pending)
{
memcpy (bulktx_buf, csw_str, 13);
bulktx_len = 13;
bulktx_cnt = 0;
csw_pending = 0;
return 0;
#endif
}
else
{
debg1((stdout, "handle_bulktx_xfer() called but nothing to send\n"));
bulktx_tries = 0;
}
return 0;
}
#ifdef CBI
int
handle_intrtx_xfer(OTG_FD intr_fd)
{
int len = intrtx_len - intrtx_cnt;
if (len > 0)
{
if (len > 8)
len = 8;
len = otgdev_write(intr_fd, intrtx_buf + intrtx_cnt, len);
if (len < 0 && errno != EAGAIN)
{
debg((stdout, "** fd %d ptr %u len %d **\n", intr_fd,
(unsigned)(intrtx_buf + intrtx_cnt),
intrtx_len - intrtx_cnt));
return 70;
}
if (len > 0)
{
intrtx_cnt += len;
if (intrtx_cnt >= intrtx_len)
{
intrtx_cnt = intrtx_len = 0;
}
}
}
else
{
debg1((stdout, "No Intr Data to send\n"));
}
return 0;
}
#endif
/* Set the stall bit in the driver */
void
set_stall (OTG_FD bus_fd, int ep_num)
{
otg_bus[0] = OTG_DEV_SET_STALL;
otg_bus[1] = ep_num;
// debg((stdout,"1SS%0d+",ep_num));
otgdev_write(bus_fd, &otg_bus[0], sizeof(otg_bus));
debg((stdout,"SS%0d+",ep_num));
}
#if 0
/* Clear the stall bit in the driver */
void
clr_stall (OTG_FD bus_fd, int ep_num)
{
otg_bus[0] = OTG_DEV_CLR_STALL;
otg_bus[1] = ep_num;
otgdev_write(bus_fd, &otg_bus[0], sizeof(otg_bus));
debg((stdout,"ACS%0d+",ep_num));
}
/* Set the NAK bit in the driver */
void
set_nak (OTG_FD bus_fd, int ep_num)
{
otg_bus[0] = OTG_DEV_SET_NAK;
otg_bus[1] = ep_num;
otgdev_write(bus_fd, &otg_bus[0], sizeof(otg_bus));
debg((stdout,"ASN+"));
}
#endif
/* Set the length vars to send a 0 len pkt */
void
send_0len_pkt (int ep_num)
{
if (ep_num == OTG_DEV_CTRL_IN_EP)
{
ctrltx_len = -1;
ctrltx_cnt = -1;
}
else if (ep_num == OTG_DEV_BULK_IN_EP)
{
bulktx_len = -1;
bulktx_cnt = -1;
}
}
#ifdef CBI
void
send_intr_sts (char intr_data, int intr_len, int intr_cnt)
{
intrtx_buf[0] = intr_data;
intrtx_buf[1] = 0x00;
intrtx_len = intr_len;
intrtx_cnt = intr_cnt;
}
#endif
void
set_exp_bulkrx_len (OTG_FD bus_fd, int total_bulk_pkt_len)
{
otg_bus[0] = OTG_DEV_SET_BULK_PKT_LEN;
otg_bus[1] = total_bulk_pkt_len;
otgdev_write(bus_fd, &otg_bus[0], sizeof(otg_bus));
debg1((stdout,"AEB+"));
}
#if 0
char ramdisk_buff[16*1024*1024L];
int
fill_bulktx_buff (int tx_cnt, int tx_blk)
{
memcpy(bulktx_buf,ramdisk_buff+OTG_MS_BLOCK_SIZE*tx_blk,tx_cnt*OTG_MS_BLOCK_SIZE);
return tx_cnt * OTG_MS_BLOCK_SIZE;
}
int
flush_bulkrx_buff (int rx_cnt, int rx_blk)
{
memcpy(ramdisk_buff+OTG_MS_BLOCK_SIZE*rx_blk ,bulkrx_buf,rx_cnt*OTG_MS_BLOCK_SIZE);
return rx_cnt;
}
#else
int
fill_bulktx_buff (int tx_cnt, int tx_blk)
{
int len;
int nsects = 0;
/* Seek to requested block */
if (tx_blk != next_blk)
{
ferr_num = fseek(fs_fp, tx_blk * OTG_MS_BLOCK_SIZE, SEEK_SET);
if ( ferr_num )
{
debg((stdout, "*FERR3_%0d,%0d+",ferr_num,errno));
}
}
/* While blocks left to send, and room in buffer */
while (tx_cnt && (nsects < sizeof(bulktx_buf) / OTG_MS_BLOCK_SIZE) )
{
/* Fill buffer with FS data */
len = (ssize_t) fread(&bulktx_buf[nsects * OTG_MS_BLOCK_SIZE], OTG_MS_BLOCK_SIZE, 1, fs_fp);
if (len != 1)
{
debg((stdout, "(!!!N%x)", len));
next_blk = -1;
}
else
{
next_blk = tx_blk + 1;
}
tx_cnt--;
nsects++;
tx_blk++;
}
// ferr_num = fflush(fs_fp);
// if ( ferr_num )
{
// debg((stdout, "*FERR4_%0d,%0d+",ferr_num,errno));
}
if (tx_cnt)
{
/* Set block info for next send */
txblock_num = tx_blk;
txblock_cnt = tx_cnt;
// debg ((stdout, "OBC%0d+",txblock_num));
}
else
{
txblock_num = txblock_cnt = 0;
}
return nsects * OTG_MS_BLOCK_SIZE;
}
int
flush_bulkrx_buff (int rx_cnt, int rx_blk)
{
int len;
int nsects = 0;
if (rx_blk != next_blk)
{
/* Seek to requested block */
ferr_num = fseek(fs_fp, rx_blk * OTG_MS_BLOCK_SIZE, SEEK_SET);
if ( ferr_num )
{
debg((stdout, "*FERR5_%0d,%0d+",ferr_num,errno));
}
}
/* While blocks left to retrieve, and data in buffer */
while (rx_cnt && nsects < sizeof(bulkrx_buf) / OTG_MS_BLOCK_SIZE)
{
{
debg1((stdout, "Bi%0d+", rx_blk));
/* Write buffer data to FS */
len = (ssize_t) fwrite(&bulkrx_buf[nsects * OTG_MS_BLOCK_SIZE], OTG_MS_BLOCK_SIZE, 1, fs_fp);
if (len != 1)
{
debg((stdout, "*WE%0d,%0d+",len,nsects));
next_blk = -1;
}
else
next_blk = rx_blk + 1;
}
rx_cnt--;
nsects++;
rx_blk++;
}
// ferr_num = fflush(fs_fp);
// if ( ferr_num )
// {
// debg((stdout, "*FERR6_%0d,%0d+",ferr_num,errno));
// }
return nsects;
}
#endif
void
decode_ms_cmd (OTG_FD bus_fd, char *cmd_bfr, ssize_t cmd_len, char *csw_tag, int cbw_data_len)
{
int blk, cnt, maxlen = 0;
#ifdef CBI
#else
int csw_data_residue;
#endif
debg((stdout,"CMD:%x\n",cmd_bfr[0]));
switch (cmd_bfr[0])
{
case 0x00: /* TEST UNIT READY */
#ifdef CBI
if (got_TUR)
{
reqsns_data[2] = 0;
reqsns_data[12] = 0;
debg1((stdout, "AGT+"));
}
else if (reqsns_data[2] != 0)
{
maxlen = 0;
got_TUR = 1;
debg1((stdout, "AGS+"));
goto decode_ms_stall;
}
#endif
case 0x01: /* REZERO */
case 0x2b: /* SEEK */
case 0x2f: /* VERIFY */
case 0x1b: /* START-STOP UNIT */
case 0x1d: /* SEND DIAGNOSTIC */
case 0x1e: /* PREVENT-ALLOW MEDIUM REMOVAL */
maxlen = 0;
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
/* Send status */
send_intr_sts (1, 2, 0);
#else
send_csw (csw_tag, cbw_data_len, 0x00);
#endif
break;
case 0x03: /* REQUEST SENSE */ // 4 alloc len
maxlen = cmd_bfr[4];
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
#else
reqsns_data[2] = 0x05;
reqsns_data[12] = 0x20;
#endif
/* Send bulk data */
memcpy(bulktx_buf, reqsns_data, sizeof(reqsns_data));
bulktx_len = sizeof(reqsns_data);
bulktx_cnt = 0;
/* Send status */
#ifdef CBI
if (reqsns_data[2] != 0)
{
send_intr_sts (0x29, 2, 0);
reqsns_data[2] = 0;
reqsns_data[12] = 0;
}
else
{
send_intr_sts (0x0, 2, 0);
}
#else
csw_data_residue = cbw_data_len - sizeof(reqsns_data);
send_csw (csw_tag, csw_data_residue, 0x00);
#endif
break;
case 0x12: /* INQUIRY */ // 4 alloc len
maxlen = cmd_bfr[4];
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
#else
csw_data_residue = cbw_data_len - inq_data_size;
#endif
debg1((stdout, "INQ+"));
/* Send bulk data */
memcpy(bulktx_buf, inq_data, inq_data_size);
bulktx_len = inq_data_size;
bulktx_cnt = 0;
#ifdef CBI
/* Send status on Intr EP */
send_intr_sts (0x0, 2, 0);
#else
/* Send CSW, with status = 00 */
send_csw (csw_tag, csw_data_residue, 0x0);
#endif
break;
case 0x23: /* READ FORMAT CAPACITIES */ // 7-8 alloc len
maxlen = (cmd_bfr[7] << 8) | cmd_bfr[8];
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
#endif
/* Send bulk data */
memcpy(bulktx_buf, fmt_data, fmt_data_size);
bulktx_len = fmt_data_size;
bulktx_cnt = 0;
#ifdef CBI
/* Send intr status */
send_intr_sts (0x0, 2, 0);
#else
csw_data_residue = cbw_data_len - fmt_data_size;
/* Send CSW, with status = 00 */
send_csw (csw_tag, csw_data_residue, 0x0);
#endif
break;
case 0x25: /* READ CAPACITY */
maxlen = 8;
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
#else
csw_data_residue = cbw_data_len - cap_data_size;
#endif
/* Send bulk data */
memcpy(bulktx_buf, cap_data, cap_data_size);
bulktx_len = cap_data_size;
bulktx_cnt = 0;
#ifdef CBI
/* Send intr status */
send_intr_sts (0x0, 2, 0);
#else
/* Send CSW, with status = 00 */
send_csw (csw_tag, csw_data_residue, 0x0);
#endif
break;
case 0x28: /* READ(10) */ // 2-5 LBA, 7-8 len (blocks)
/* Get length */
cnt = (cmd_bfr[7] << 8) | cmd_bfr[8];
goto read_common;
case 0xa8: /* READ(12) */ // 2-5 LBA, 7-8 len (blocks)
/* Get length */
cnt = (cmd_bfr[6] << 24) | (cmd_bfr[7] << 16) | (cmd_bfr[8] << 8) | cmd_bfr[9];
read_common:
/* Get data block number */
blk = (cmd_bfr[2] << 24) | (cmd_bfr[3] << 16) | (cmd_bfr[4] << 8) | cmd_bfr[5];
debg1((stdout, "ABO%0d,%0d",cnt,blk));
debg1((stdout, "ABO%0d+",cnt));
maxlen = bulktx_len = fill_bulktx_buff (cnt, blk);
bulktx_cnt = 0;
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
/* Send Intr Status */
send_intr_sts (0x00, 2, 0);
#else
/* Send CSW */
csw_data_residue = cbw_data_len - (cnt*OTG_MS_BLOCK_SIZE);
if (csw_data_residue)
{
debg((stdout, "***DTL:%0d+",cbw_data_len));
debg((stdout, "***cnt:%0d+",cnt));
}
send_csw (csw_tag, csw_data_residue, 0x00);
#endif
break;
case 0x2a: /* WRITE(10) */ // 2-5 LBA, 7-8 len (blocks)
case 0x2e: /* WRITE and VERIFY */ // 2-5 LBA, 7-8 len (blocks)
/* Get length */
cnt = (cmd_bfr[7] << 8) | cmd_bfr[8];
goto write_common;
case 0xaa: /* WRITE(12) */ // 2-5 LBA, 6-9 len (blocks)
/* Get length */
cnt = (cmd_bfr[6] << 24) | (cmd_bfr[7] << 16) | (cmd_bfr[8] << 8) | cmd_bfr[9];
write_common:
/* Get data block number */
blk = (cmd_bfr[2] << 24) | (cmd_bfr[3] << 16) | (cmd_bfr[4] << 8) | cmd_bfr[5];
maxlen = 0;
rxblock_num = blk;
bulkrx_cnt = rxblock_cnt = cnt;
debg((stdout,"ABI%0d,%0d+",cnt,blk));
if (bulkrx_cnt > (sizeof(bulkrx_buf)/OTG_MS_BLOCK_SIZE) )
{
bulkrx_cnt = (sizeof(bulkrx_buf)/OTG_MS_BLOCK_SIZE);
debg((stdout, "*INCnt > MAX_SIZE+"));
}
/* Prog the total exp bulk pkt size */
set_exp_bulkrx_len (bus_fd, (cnt*OTG_MS_BLOCK_SIZE) );
/*
{
int len ;
do
{
len = otgdev_read(bulk_rx_fd, bulkrx_buf, bulkrx_cnt*OTG_MS_BLOCK_SIZE);
debg((stdout, "*INRD:%d,%d",len,errno));
}while ((len < 0) && (errno == EAGAIN));
if (len < 0 && errno != EAGAIN)
{
fprintf(stdout, "%s,%d\n",__FUNCTION__,__LINE__);
fflush(stdout);
while(1);
}
else if (len > 0)
{
//debg((stdout,"AIB%0d+",bulkrx_len));
flush_bulkrx_buff (bulkrx_cnt, blk);
bulkrx_cnt= 0;
rxblock_num+=cnt;
}
}
*/
#ifdef CBI
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
/* Send intr status */
send_intr_sts (0x0, 2, 0);
#else
csw_data_residue = cbw_data_len - (cnt*OTG_MS_BLOCK_SIZE);
if (csw_data_residue)
{
debg((stdout, "***DTL:%0d+",cbw_data_len));
debg((stdout, "***cnt:%0d+",cnt));
}
send_csw (csw_tag, csw_data_residue, 0x00);
csw_pending =0;
#endif
break;
#if 0
case 0x55: /* MODE SELECT(10) */ // 2 PG CTRL/PG CODE, 7-8 alloc len
#ifdef CBI
/* Stall the endpoint */
debg((stdout, "ss5 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
#else
debg((stdout, "ss6 "));
set_stall (bus_fd, OTG_DEV_BULK_IN_EP);
send_csw (csw_tag, cbw_data_residue, 0x01);
#endif
debg((stdout,"*AST2+"));
break;
#endif
case 0x5a: /* MODE SENSE(10) */ // 2 PG CTRL/PG CODE, 7-8 alloc len
maxlen = (cmd_bfr[7] << 8) | cmd_bfr[8];
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
/* Send bulk data */
if ((cmd_bfr[2] & 0x3f) == 0x1c)
{
memcpy(bulktx_buf, modesns_data, sizeof(modesns_data));
bulktx_len = sizeof(modesns_data);
}
else if ((cmd_bfr[2] & 0x3f) == 0x3f)
{
memcpy(bulktx_buf, modesns2_data, sizeof(modesns2_data));
bulktx_len = sizeof(modesns2_data);
}
else
{
memcpy(bulktx_buf, modesns3_data, sizeof(modesns3_data));
bulktx_len = sizeof(modesns3_data);
}
bulktx_cnt = 0;
/* Send status */
#ifdef CBI
send_intr_sts (0x0, 2, 0);
#else
csw_data_residue = cbw_data_len - bulktx_len;
send_csw (csw_tag, csw_data_residue, 0x00);
#endif
break;
#ifdef CBI
#else
#ifdef MAXWELL
#else
case 0x1a: /* MODE SENSE (6) */
maxlen = cmd_bfr[4];
bulktx_len = 0;
bulktx_cnt = 0;
/* send bulk data */
if (((cmd_bfr[2] & 0x3f) == 0x3f) ||((cmd_bfr[2] & 0x3f) == 0x0A))
{
int idx;
// memcpy(bulktx_buf, modesns2_data, sizeof(modesns2_data));
// bulktx_len = sizeof(modesns2_data);
// csw_data_residue = cbw_data_len - bulktx_len;
bulktx_buf[1] =0;
bulktx_buf[2] =0;
bulktx_buf[3] =0x08;
bulktx_buf[4] =0;
bulktx_buf[5] =((OTG_MS_NUM_BLKS >> 16) & 0xff);
bulktx_buf[6] =((OTG_MS_NUM_BLKS >> 8) & 0xff);
bulktx_buf[7] =(OTG_MS_NUM_BLKS & 0xff);
bulktx_buf[8] =0;
bulktx_buf[9] =0;
bulktx_buf[10] =0x02;
bulktx_buf[11] =0x00;
idx = 12;
if ( ( cmd_bfr[1] & 0x08 ) == 0 ) // check DisableBlockDescriptor-bit
{
int i;
bulktx_buf[idx++] = 0x0A; // return page code, P(age)S(aveable)-bit set to 0
bulktx_buf[idx++] = 0x0A; // page length
for (i=0; i<0x0A; i++) {
bulktx_buf[idx++] = 0; //
}
}
bulktx_buf[0] =idx -1;
bulktx_len= idx;
csw_data_residue = cbw_data_len - bulktx_len;
}
else
{
csw_data_residue = cbw_data_len;
stall_bulk_in = 1; // stall the bulkin
}
send_csw (csw_tag, csw_data_residue, 0x00);
break;
#endif // MAXWELL
#endif // CBI
default:
#ifdef CBI
decode_ms_stall:
/* Stall the endpoints, when an unrecognised command is received */
/* Stall the control in/out endpoint */
debg((stdout, "ss7 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
#else
/* Stall the control in/out endpoint */
debg((stdout, "ss8 "));
set_stall (bus_fd, OTG_DEV_BULK_IN_EP);
/* Send a CSW with a error status and the data residue equal to data len */
send_csw (csw_tag, cbw_data_len, 0x01);
#endif
debg((stdout,"*AST3:%2x+",cmd_bfr[0]));
}
if (bulktx_len > maxlen)
bulktx_len = maxlen;
}
#ifdef CBI
#else
void
send_csw (char *csw_tag, int csw_data_residue, char csw_sts)
{
if (csw_data_residue != 0)
{
debg((stdout,"*ARS:%0d,%2x+",csw_data_residue,bot_cmd));
}
if (csw_data_residue < 0)
{
csw_data_residue = 0;
}
/* Copy the CSW Signature into CSW Str Buffer */
memcpy (&csw_str[0], ms_csw_signature, 4);
/* Copy the CSW Tag into CSW Str Buffer */
memcpy (&csw_str[4], csw_tag, 4);
csw_str[8] = csw_data_residue;
csw_str[9] = csw_data_residue>>8;
csw_str[10] = csw_data_residue>>16;
csw_str[11] = csw_data_residue>>24;
csw_str[12] = csw_sts;
csw_pending = 1;
}
#endif
void
decode_setup_req (OTG_FD bus_fd, char *cmd_bfr)
{
int addr;
switch (cmd_bfr[0])
{
case 0: /* Standard device request, data to device */
switch (cmd_bfr[1])
{
case 1: /* CLEAR_FEAT */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
case 3: /* SET_FEAT */
addr = (cmd_bfr[2] & 0xff) | ((cmd_bfr[3] & 0xff) << 8);
debg2((stdout, "got SET_FEAT request, feature %d\n", addr));
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
#if 1
case 5: /* SET_ADDR */
addr = (cmd_bfr[2] & 0xff) | ((cmd_bfr[3] & 0xff) << 8);
debg((stdout, "got SET_ADDR request, addr %d\n", addr));
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
debg((stdout, "sending 0-length response\n"));
break;
case 7: /* SET_DESC */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
case 9: /* SET_CONFIG */
debg((stdout, "got SET_CONFIG reques\n"));
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
case 11: /* SET_INTFC */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
#endif
default:
/* Stall the endpoint */
debg((stdout, "ss9 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
debg((stdout,"*AST4+"));
}
break;
case 0x02: /* Endpoint Request Type */
#if 0
if (cmd_bfr[1] == 0x01)
{ /* CLEAR FEAT */
debg((stdout, "CST+"));
/* Set/Clear the stall bit on the appropriate EP */
switch (cmd_bfr[5])
{ // EP Num
case 0x00 :
clr_stall (bus_fd, OTG_DEV_CTRL_IN_EP);
break;
case 0x01 :
clr_stall (bus_fd, OTG_DEV_CTRL_OUT_EP);
break;
case 0x02 :
clr_stall (bus_fd, OTG_DEV_BULK_IN_EP);
break;
case 0x03 :
clr_stall (bus_fd, OTG_DEV_BULK_OUT_EP);
break;
default:
goto decode_setup_stall_0;
}
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
}
else
{
decode_setup_stall_0:
#endif
/* Stall the endpoint */
debg((stdout, "ss10 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
#if 0
}
#endif
break;
case 0x80: /* Standard device request, data to host */
switch (cmd_bfr[1])
{
case 0: /* GET_STATUS */
ctrltx_buf = stat_desc;
ctrltx_len = sizeof(stat_desc);
ctrltx_cnt = 0;
break;
case 6: /* GET_DESC */
debg1((stdout, "got GET_DESC request, type %d\n", cmd_bfr[3]));
switch (cmd_bfr[3])
{
int n;
case 1: /* DEVICE_DESC */
ctrltx_buf = dev_desc;
n = (cmd_bfr[6] & 0xff) | ((cmd_bfr[7] & 0xff) << 8);
debg1((stdout, "n=%d\n",n));
#ifdef CBI
#ifdef WIN98
if (n > OTG_DEV_CTRL_MAXPKTSIZE)
#else
if (n > dev_desc_size)
#endif
{
debg((stdout, "ss11 "));
set_stall (bus_fd, OTG_DEV_CTRL_OUT_EP);
debg((stdout,"*AST1+"));
}
#endif
#ifdef CBI
if (n > dev_desc_size)
{
#ifdef WIN98
n = dev_desc_size;
#else
n = 8;
#endif
}
#else
n = dev_desc_size;
#endif
if (n > dev_desc_size)
n = dev_desc_size;
ctrltx_len = n;
ctrltx_cnt = 0;
debg((stdout,"ADD%0d+",ctrltx_len));
break;
case 2: /* CONFIG_DESC */
ctrltx_buf = cfg_desc;
n = (cmd_bfr[6] & 0xff) | ((cmd_bfr[7] & 0xff) << 8);
debg1((stdout, "n=%d\n",n));
if (n > cfg_desc_size)
n = cfg_desc_size;
ctrltx_len = n;
ctrltx_cnt = 0;
debg((stdout,"ACD%0d+",ctrltx_len));
break;
case 3: /* STRING_DESC */
n = (cmd_bfr[6] & 0xff) | ((cmd_bfr[7] & 0xff) << 8);
switch (cmd_bfr[2])
{
case LANG_DESC: /* Language Descriptor */
ctrltx_buf = lang_desc;
if (n > sizeof(lang_desc))
n = sizeof(lang_desc);
break;
case MANF_DESC: /* Manufacturer Descriptor */
ctrltx_buf = manf_desc;
if (n > manf_desc_size)
n = manf_desc_size;
break;
case PROD_DESC: /* Product Descriptor */
ctrltx_buf = prod_desc;
if (n > prod_desc_size)
n = prod_desc_size;
break;
case SERIALNUM_DESC: /* SerialNum Descriptor */
ctrltx_buf = sernum_desc;
if (n > sernum_desc_size)
n = sernum_desc_size;
case STRING_CONFIG:
ctrltx_buf = string_config;
if (n > sizeof(string_config))
n = sizeof(string_config);
break;
case STRING_INTERFACE:
ctrltx_buf = string_interface;
if (n > sizeof(string_interface))
n = sizeof(string_interface);
break;
}
ctrltx_len = n;
ctrltx_cnt = 0;
debg((stdout,"ASD%0d,%0d+",cmd_bfr[2],ctrltx_len));
break;
case 6: /* DEVICE_QUALIFIER */
ctrltx_buf = dev_qual;
n = (cmd_bfr[6] & 0xff) | ((cmd_bfr[7] & 0xff) << 8);
if (n > dev_qual_size)
n = dev_qual_size;
ctrltx_len = n;
ctrltx_cnt = 0;
debg((stdout,"AQD%0d+",ctrltx_len));
break;
case 7: /* OTHER_CONFIG_DESC */
ctrltx_buf = other_cfg_desc;
if (otg_dev_enum_spd == OTG_ENUM_SPD_FS)
{
ctrltx_buf[22] = OTG_DEV_BULK_MAXPKTSIZE_LSB_HS;
ctrltx_buf[23] = OTG_DEV_BULK_MAXPKTSIZE_MSB_HS;
ctrltx_buf[29] = OTG_DEV_BULK_MAXPKTSIZE_LSB_HS;
ctrltx_buf[30] = OTG_DEV_BULK_MAXPKTSIZE_MSB_HS;
}
n = (cmd_bfr[6] & 0xff) | ((cmd_bfr[7] & 0xff) << 8);
if (n > cfg_desc_size)
n = cfg_desc_size;
ctrltx_buf[1] = 0x07; // Other Speed Configuraion Desc
ctrltx_len = n;
ctrltx_cnt = 0;
debg((stdout,"AOD%0d+",ctrltx_len));
break;
#if 0
case 4: /* INTFC_DESC */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
case 5: /* ENDPT_DESC */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
break;
#endif
default:
/* Stall the endpoint */
debg((stdout, "ss12 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
debg((stdout,"*AST5+"));
}
break;
#if 0
case 8: /* GET_CONFIG */
break;
case 10: /* GET_INTFC */
break;
#endif
default:
/* Stall the endpoint */
debg((stdout, "ss13 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
debg((stdout,"*AST6+"));
}
break;
case 0x21: /* CBI Mass storage device request, data to device */
if (cmd_bfr[1] == 0xFF)
{ /* Bulk Only Mass Storage Reset */
csw_pending = 0; /* Clear on Reset or Suspend */
/* Clear the NAK bit to send a 0 data len pkt
* in the ctrl tx sts phase */
send_0len_pkt(OTG_DEV_CTRL_IN_EP);
debg((stdout, "ABR+"));
}
else
{
mass_strg_cmd = 1;
debg1((stdout, "@+"));
}
break;
case 0xA1: /* Get Max LUN for Mass Storage BulkOnly Device */
ctrltx_buf = empty_desc;
ctrltx_buf[0] = 0x00;
ctrltx_len = 1;
ctrltx_cnt = 0;
debg1((stdout, "ALN+"));
break;
default:
/* Stall the endpoint */
debg((stdout, "ss14 "));
set_stall (bus_fd, OTG_DEV_CTRL_EPS);
debg((stdout,"*AST7+"));
}
}