/* MASS_STORAGE.C * This demo application is used to USB Demo */ #ifdef linux #include #include #include #include #include #include #include #include #include #include #else #include #include #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+")); } }