├── .gitignore ├── release ├── SataTo3DO.uf2 └── SataTo3do.jpg ├── PCB ├── SATA23DO_final.zip └── LocODE_3DO_2022-05-28.zip ├── .gitmodules ├── include └── interfaces │ ├── TOC.h │ ├── CDROM.h │ ├── CDFormat.h │ ├── USB.h │ ├── MSC.h │ ├── 3DO.h │ └── tusb_config.h ├── src ├── main.c └── interfaces │ ├── read.pio │ ├── write.pio │ ├── write_hs_fc.pio │ ├── USB.c │ ├── CDROM.c │ ├── MSC.c │ └── 3DO.c ├── FATFs ├── 00readme.txt ├── integer.h ├── diskio.h ├── diskio.c ├── ffsystem.c ├── 00history.txt ├── ffconf.h └── ff.h ├── LICENSE ├── CMakeLists.txt ├── README.md └── interface_explanation_note_from_fixel /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | CMakeFiles 3 | CMakeCache.txt 4 | elf2uf2 5 | pioasm 6 | generated 7 | -------------------------------------------------------------------------------- /release/SataTo3DO.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FCare/SataTo3DO/HEAD/release/SataTo3DO.uf2 -------------------------------------------------------------------------------- /release/SataTo3do.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FCare/SataTo3DO/HEAD/release/SataTo3do.jpg -------------------------------------------------------------------------------- /PCB/SATA23DO_final.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FCare/SataTo3DO/HEAD/PCB/SATA23DO_final.zip -------------------------------------------------------------------------------- /PCB/LocODE_3DO_2022-05-28.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FCare/SataTo3DO/HEAD/PCB/LocODE_3DO_2022-05-28.zip -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pico-sdk"] 2 | path = pico-sdk 3 | url = https://github.com/raspberrypi/pico-sdk.git 4 | [submodule "tinyusb"] 5 | path = tinyusb 6 | url = https://github.com/FCare/tinyusb.git 7 | -------------------------------------------------------------------------------- /include/interfaces/TOC.h: -------------------------------------------------------------------------------- 1 | #ifndef __TOC_H_INCLUDE__ 2 | #define __TOC_H_INCLUDE__ 3 | 4 | #define TOC_FLAG_FILE 0x1 5 | #define TOC_FLAG_DIR 0x2 6 | #define TOC_FLAG_INVALID 0xffffffff 7 | 8 | typedef struct{ 9 | uint32_t flags; 10 | uint32_t toc_id; //local toc id 11 | uint32_t name_length; //strlen 12 | char* name; //0 terminated 13 | }toc_entry; 14 | 15 | #endif -------------------------------------------------------------------------------- /include/interfaces/CDROM.h: -------------------------------------------------------------------------------- 1 | #ifndef __CDROM_HOST_H_INCLUDE__ 2 | #define __CDROM_HOST_H_INCLUDE__ 3 | 4 | extern bool CDROM_Host_loop(device_s *dev); 5 | 6 | extern bool CDROM_Inquiry(uint8_t dev_addr, uint8_t lun); 7 | 8 | extern bool CDROM_ExecuteEject(); 9 | 10 | extern void CDROM_ready(uint8_t dev_addr, bool ready); 11 | 12 | extern void wakeUpCDRom(uint8_t dev_addr, uint8_t lun); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "USB.h" //USB Setup 2 | #include "3DO.h" 3 | 4 | #include "bsp/board.h" 5 | #include 6 | #include "pico/stdlib.h" 7 | 8 | int main(void) 9 | { 10 | board_init(); 11 | sleep_ms(100); 12 | _3DO_init(); 13 | sleep_ms(500); 14 | USB_Host_init(); 15 | LOG_SATA("SLOCODE 3DO\r\n"); 16 | 17 | while(1) { 18 | // LCD_loop(); 19 | USB_Host_loop(); 20 | } 21 | 22 | // LCD_0in96_deinit(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /include/interfaces/CDFormat.h: -------------------------------------------------------------------------------- 1 | #ifndef __CDROM_FORMAT_H_INCLUDE__ 2 | #define __CDROM_FORMAT_H_INCLUDE__ 3 | 4 | #include "diskio.h" 5 | 6 | typedef enum { 7 | MODE_0 = 0, 8 | MODE_1, 9 | MODE_2, 10 | CDDA 11 | } mode_s; 12 | 13 | typedef struct dir_s{ 14 | DIR dir; 15 | int nbSubDir; 16 | struct dir_s *subDirs; 17 | } dir_t; 18 | 19 | typedef struct { 20 | uint8_t id; 21 | uint8_t CTRL_ADR; 22 | uint8_t msf[3]; 23 | uint32_t lba; 24 | mode_s mode; 25 | } track_s; 26 | 27 | typedef struct { 28 | bool multiSession; 29 | uint8_t first_track; 30 | uint8_t last_track; 31 | uint8_t format; 32 | uint8_t nb_track; 33 | uint8_t msf[3]; 34 | uint32_t nb_block; 35 | uint16_t block_size; 36 | uint16_t block_size_read; 37 | bool hasOnlyAudio; 38 | track_s tracks[100]; 39 | uint8_t offset; 40 | uint8_t dev_addr; 41 | uint8_t lun; 42 | dir_t *curDir; 43 | char *curPath; 44 | } cd_s; 45 | 46 | extern cd_s currentImage; 47 | 48 | #endif -------------------------------------------------------------------------------- /FATFs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.13a 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | 00history.txt Revision history. 8 | ff.c FatFs module. 9 | ffconf.h Configuration file of FatFs module. 10 | ff.h Common include file for FatFs and application module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | ffunicode.c Optional Unicode utility functions. 15 | ffsystem.c An example of optional O/S related functions. 16 | 17 | 18 | Low level disk I/O module is not included in this archive because the FatFs 19 | module is only a generic file system layer and it does not depend on any specific 20 | storage device. You need to provide a low level disk I/O module written to 21 | control the storage device that attached to the target system. 22 | 23 | -------------------------------------------------------------------------------- /FATFs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef FF_INTEGER 6 | #define FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/interfaces/read.pio: -------------------------------------------------------------------------------- 1 | .program read 2 | 3 | ; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is 4 | ; empty. Write the least significant bit to the OUT pin group. 5 | 6 | ; Pin list shall be CDEN, CDHWR, CDCMD, CDD7, CDD6, CDD5, CDD4, CDD3, CDD2, CDD1, CDD0 7 | 8 | .define CDHWR 15 9 | 10 | public entry_point: 11 | .wrap_target 12 | wait 0 gpio CDHWR 13 | jmp pin invalid 14 | in pins, 32 15 | invalid: 16 | wait 1 gpio CDHWR 17 | .wrap 18 | 19 | % c-sdk { 20 | 21 | static inline void read_program_init_pin(PIO pio, uint sm, bool active) { 22 | } 23 | 24 | static inline void read_program_init(PIO pio, uint sm, uint offset) { 25 | pio_sm_config c = read_program_get_default_config(offset); 26 | 27 | sm_config_set_in_pins(&c, 0); 28 | sm_config_set_in_shift(&c, true, true, 32); 29 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); 30 | 31 | sm_config_set_jmp_pin(&c, CDEN); 32 | 33 | pio_sm_set_pindirs_with_mask(pio, sm, 0x0, 0xFF< 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/interfaces/write.pio: -------------------------------------------------------------------------------- 1 | .program write 2 | 3 | ; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is 4 | ; empty. Write the least significant bit to the OUT pin group. 5 | 6 | ; Pin list shall be CDEN, CDHWR, CDCMD, CDD7, CDD6, CDD5, CDD4, CDD3, CDD2, CDD1, CDD0 7 | .define CDHRD 14 8 | 9 | public entry_point: 10 | .wrap_target 11 | pull block 12 | wait_start: 13 | wait 0 pin CDHRD ;wait for request to read 14 | jmp pin invalid 15 | out pins,8 ;output data 16 | jmp continue 17 | invalid: 18 | wait 1 pin CDHRD ;wait for end of request 19 | jmp wait_start 20 | continue: 21 | wait 1 pin CDHRD ;wait for end of request 22 | .wrap 23 | 24 | % c-sdk { 25 | 26 | static inline void write_program_init(PIO pio, uint sm, uint offset) { 27 | pio_sm_config c = write_program_get_default_config(offset); 28 | 29 | sm_config_set_out_pins(&c, CDD0, 8); 30 | sm_config_set_out_shift(&c, true, false, 8); 31 | 32 | sm_config_set_jmp_pin(&c, CDEN); 33 | 34 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 35 | 36 | // Load our configuration, and jump to the start of the program 37 | pio_sm_init(pio, sm, offset, &c); 38 | pio_sm_set_enabled(pio, sm, true); 39 | } 40 | 41 | %} -------------------------------------------------------------------------------- /src/interfaces/write_hs_fc.pio: -------------------------------------------------------------------------------- 1 | .program write 2 | 3 | ; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is 4 | ; empty. Write the least significant bit to the OUT pin group. 5 | 6 | ; Pin list shall be CDEN, CDHWR, CDCMD, CDD7, CDD6, CDD5, CDD4, CDD3, CDD2, CDD1, CDD0 7 | .define CDHRD 17 8 | 9 | public entry_point: 10 | .wrap_target 11 | pull block 12 | wait_start: 13 | wait 0 pin CDHRD ;wait for request to read 14 | jmp pin invalid 15 | out pins,8 ;output data 16 | jmp continue 17 | invalid: 18 | wait 1 pin CDHRD ;wait for end of request 19 | jmp wait_start 20 | continue: 21 | wait 1 pin CDHRD ;wait for end of request 22 | .wrap 23 | 24 | % c-sdk { 25 | 26 | static inline void write_program_init(PIO pio, uint sm, uint offset) { 27 | pio_sm_config c = write_program_get_default_config(offset); 28 | 29 | sm_config_set_out_pins(&c, CDD0, 8); 30 | sm_config_set_out_shift(&c, true, false, 8); 31 | 32 | sm_config_set_jmp_pin(&c, CDEN); 33 | 34 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 35 | 36 | // Load our configuration, and jump to the start of the program 37 | pio_sm_init(pio, sm, offset, &c); 38 | pio_sm_set_enabled(pio, sm, true); 39 | } 40 | 41 | %} -------------------------------------------------------------------------------- /include/interfaces/USB.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_HOST_H_INCLUDE__ 2 | #define __USB_HOST_H_INCLUDE__ 3 | 4 | #include "tusb.h" 5 | #include "diskio.h" 6 | #include "CDFormat.h" 7 | 8 | 9 | typedef enum { 10 | DETACHED = 0x00, 11 | INQUIRY, 12 | ATTACHED, 13 | ENUMERATED, 14 | CONFIGURED, 15 | MOUNTED, 16 | EJECTING, 17 | } usb_state_t; 18 | 19 | typedef enum { 20 | UNKNOWN_TYPE = 0x00, 21 | MSC_TYPE = 0x1, 22 | CD_TYPE = 0x2, 23 | } device_type_t; 24 | 25 | typedef struct { 26 | // bool mounted; 27 | uint8_t dev_addr; 28 | uint8_t lun; 29 | bool canBeEjected; 30 | bool canBeLoaded; 31 | bool isFatFs; 32 | bool useable; 33 | device_type_t type; 34 | usb_state_t state; 35 | bool tray_open; 36 | FATFS DiskFATState; 37 | cd_s rawImage; 38 | } device_s; 39 | 40 | 41 | typedef enum { 42 | DONE = 0x0, 43 | OPEN, 44 | READ, 45 | WRITE, 46 | CLOSE 47 | } fileCmd_s; 48 | 49 | extern uint8_t usb_state; 50 | extern volatile int8_t requestLoad; 51 | 52 | extern bool usb_cmd_on_going; 53 | 54 | extern void USB_Host_init(); 55 | extern void USB_Host_loop(); 56 | extern void USB_reset(void); 57 | 58 | extern device_s* getDevice(uint8_t dev_addr); 59 | extern device_s* getDeviceIndex(uint8_t idx); 60 | 61 | extern bool read_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); 62 | 63 | #endif -------------------------------------------------------------------------------- /include/interfaces/MSC.h: -------------------------------------------------------------------------------- 1 | #ifndef __MSC_H_INCLUDE__ 2 | #define __MSC_H_INCLUDE__ 3 | 4 | #include "USB.h" 5 | #include "TOC.h" 6 | 7 | extern char *curPath; 8 | 9 | extern bool MSC_Host_loop(device_s *dev); 10 | 11 | extern bool MSC_Inquiry(uint8_t dev_addr, uint8_t lun); 12 | 13 | extern bool MSC_ExecuteEject(bool eject); 14 | 15 | extern void setTocLevel(int index); 16 | extern int getTocLevel(void); 17 | extern int getTocIndex(void); 18 | extern int getTocEntry(int index); 19 | 20 | extern bool getNextTOCEntry(toc_entry* toc); 21 | extern bool getReturnTocEntry(toc_entry* toc); 22 | extern void getToc(int index, int offset, uint8_t* buffer); 23 | extern void getTocFull(int index, int nb); 24 | 25 | extern char* getPathForTOC(int entry); 26 | 27 | extern void printPlaylist(); 28 | extern void clearPlaylist(void); 29 | extern void addToPlaylist(int entry, bool *valid, bool *added); 30 | 31 | extern bool seekTocTo(int index); 32 | 33 | extern void requestOpenFile(char* name, uint16_t name_length, bool write); 34 | extern void requestWriteFile(uint8_t* buf, uint16_t length); 35 | extern void requestReadFile(uint8_t* buf, uint16_t length); 36 | extern void requestCloseFile(); 37 | 38 | extern void requestBootImage(); 39 | extern void waitForLoad(); 40 | 41 | extern int getPlaylistEntries(); 42 | extern void updatePlayListEntries(); 43 | 44 | 45 | #endif -------------------------------------------------------------------------------- /include/interfaces/3DO.h: -------------------------------------------------------------------------------- 1 | #ifndef _3DO_INTERFACE_H_ 2 | #define _3DO_INTERFACE_H_ 3 | 4 | #include 5 | #include "tusb.h" 6 | 7 | #define UART_LED 28 8 | 9 | #define DATA_0 2 10 | #define DATA_1 3 11 | #define DATA_2 4 12 | #define DATA_3 5 13 | #define DATA_4 6 14 | #define DATA_5 7 15 | #define DATA_6 8 16 | #define DATA_7 9 17 | #define CTRL0 11 18 | #define CTRL1 12 19 | #define CTRL2 13 20 | #define CTRL3 14 21 | #define CTRL4 15 22 | #define CTRL5 20 23 | #define CTRL6 21 24 | #define CTRL7 10 25 | #define CTRL8 22 26 | 27 | #define EJECT_3V 26 28 | #define DIR_DATA 27 29 | 30 | #define XTRA0 16 31 | #define XTRA1 18 32 | #define XTRA2 17 33 | #define XTRA3 19 34 | 35 | //Input or output 36 | #define CDD0 DATA_0 37 | #define CDD1 DATA_1 38 | #define CDD2 DATA_2 39 | #define CDD3 DATA_3 40 | #define CDD4 DATA_4 41 | #define CDD5 DATA_5 42 | #define CDD6 DATA_6 43 | #define CDD7 DATA_7 44 | 45 | //Always input 46 | #define EJECT EJECT_3V 47 | #define CDEN CTRL8 48 | #define CDRST CTRL5 49 | #ifdef HW_HS_FC 50 | #define CDHRD XTRA2 51 | #else 52 | #define CDHRD CTRL3 53 | #endif 54 | #define CDHWR CTRL4 55 | 56 | #define CDCMD CTRL7 57 | 58 | //output 59 | #define LED UART_LED 60 | #define CDSTEN CTRL0 61 | #define CDDTEN CTRL1 62 | #define CDWAIT CTRL2 63 | #define CDMDCHG CTRL6 64 | 65 | 66 | #define CDEN_SNIFF XTRA0 67 | #define CDRST_SNIFF XTRA1 68 | 69 | 70 | #define DATA_MASK ((1< 17 | #include 18 | #include 19 | #include 20 | 21 | #include "tusb.h" 22 | 23 | #define TIMEOUT_WAIT_US 5000000 24 | 25 | /* Status of Disk Functions */ 26 | typedef BYTE DSTATUS; 27 | 28 | /* Results of Disk Functions */ 29 | typedef enum { 30 | RES_OK = 0, /* 0: Successful */ 31 | RES_ERROR, /* 1: R/W Error */ 32 | RES_WRPRT, /* 2: Write Protected */ 33 | RES_NOTRDY, /* 3: Not Ready */ 34 | RES_PARERR /* 4: Invalid Parameter */ 35 | } DRESULT; 36 | 37 | 38 | /*---------------------------------------*/ 39 | /* Prototypes for disk control functions */ 40 | 41 | 42 | void diskio_init(void); 43 | void disk_deinitialize ( BYTE pdrv ); 44 | DSTATUS disk_initialize (BYTE); 45 | DSTATUS disk_status (BYTE); 46 | DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); 47 | #if _READONLY == 0 48 | DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); 49 | #endif 50 | DRESULT disk_ioctl (BYTE, BYTE, void*); 51 | 52 | /* Disk Status Bits (DSTATUS) */ 53 | 54 | #define STA_NOINIT 0x01 /* Drive not initialized */ 55 | #define STA_NODISK 0x02 /* No medium in the drive */ 56 | #define STA_PROTECT 0x04 /* Write protected */ 57 | 58 | 59 | /* Command code for disk_ioctrl() */ 60 | 61 | /* Generic command */ 62 | #define CTRL_SYNC 0 /* Mandatory for write functions */ 63 | #define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */ 64 | #define GET_SECTOR_SIZE 2 /* Mandatory for multiple sector size cfg */ 65 | #define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */ 66 | #define CTRL_POWER 4 67 | #define CTRL_LOCK 5 68 | #define CTRL_EJECT 6 69 | /* MMC/SDC command */ 70 | #define MMC_GET_TYPE 10 71 | #define MMC_GET_CSD 11 72 | #define MMC_GET_CID 12 73 | #define MMC_GET_OCR 13 74 | #define MMC_GET_SDSTAT 14 75 | /* ATA/CF command */ 76 | #define ATA_GET_REV 20 77 | #define ATA_GET_MODEL 21 78 | #define ATA_GET_SN 22 79 | 80 | 81 | 82 | static inline bool disk_is_ready(BYTE pdrv); 83 | static inline bool disk_is_ready(BYTE pdrv) 84 | { 85 | return (pdrv < CFG_TUH_DEVICE_MAX) && 86 | ( (disk_status(pdrv) & (STA_NOINIT | STA_NODISK)) == 0 ); 87 | } 88 | 89 | 90 | #define _DISKIO 91 | #endif 92 | 93 | #endif // DISKIO_H_INCLUDED -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SataTo3DO 2 | The goal of this project is to replace the physical drive of my NTSC FZ-1 with a low-cost ODE. 3 | 4 | ## Hardware Construction 5 | In the `PCB` directory, the `SATA23DO_final.zip` gerbers for the PCB can be found and ordered from a fabricator such as PCBWay or JLCPCB. 6 | 7 | For the BOM: 8 | - 1x RP2040 module: RP2040-Plus from WaveShare: https://www.waveshare.com/wiki/RP2040-Plus 9 | - 6x bi-directional level shifter modules: https://fr.aliexpress.com/item/32890488553.html 10 | - 1x Octal bus tranceiver 74HC245N in DIP format 11 | - 1x 2x6 connector 1.25mm (to be populated on POWER_1) 12 | - 1x 2x15 connector 1.25mm (to be populated on CDROM) 13 | Connectors can be found on aliexpress (https://m.fr.aliexpress.com/item/1005002262284714.html) 14 | All other parts are not required to be populated. If you want to debug code, you can add a header on the UART port, and connect a UART to USB adapter (I am using minicom on Linux as a serial console to see the traces.) 15 | 16 | Regarding connectors, take care to order the right one depending your 3DO's cable. 17 | 18 | ## Building Source Code 19 | Use the attached source to compile a uf2 image using cmake, and copy it onto the RP2040 module (connected via USB.) 20 | 21 | Note that `tinyusb` and `pico-sdk` come from git submodules. They can be cloned using the command: 22 | 23 | ```bash 24 | git submodule update --init --recursive 25 | ``` 26 | In order to build: 27 | ```bash 28 | sudo apt install cmake gcc-arm-none-eabi build-essential 29 | mkdir build 30 | cd build 31 | cmake ../ 32 | make -j8 33 | ``` 34 | Per default, the setup is done for waveshare_rp2040_plus_4mb. 35 | For a 16mb, you need to edit the CMakeLists.txt file and change the PICO_BOARD to waveshare_rp2040_plus_16mb 36 | 37 | Otherwise, cmake will raise errors that it cannot find the necessary include files. 38 | 39 | ## Setup 40 | Plug a USB-C usb flash drive key (CDROM support is preliminary, it requires extra power), do not use a SSD (consuming lot of power). 41 | 42 | USB flash drive must be formatted as either the FAT32 or exFat file systems. 43 | 44 | At the root of the usb key, copy the [boot.iso](https://github.com/fixelsan/3do-ode-firmware/blob/master/boot.iso) you can find on fixel's homepage (it is compatible). 45 | 46 | Copy your desired game ISOs to the USB disk. 47 | 48 | There is no sorting algorithm supported, so the order displayed on the 3DO will follow the FAT entry order. This means the first game you will transfer to the USB stick will be the first one in the list. 49 | 50 | Do not hesitate to contribute with MR. 51 | 52 | ## License 53 | 54 | Files specific to this project is licensed under the [MIT 55 | License](LICENSE). 56 | 57 | Dependencies have their own licenses: 58 | * tinyusb: https://github.com/hathach/tinyusb (MIT) 59 | * pico-sdk: https://github.com/raspberrypi/pico-sdk (BSD 3 Clause) 60 | -------------------------------------------------------------------------------- /include/interfaces/tusb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Ha Thach (tinyusb.org) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef _TUSB_CONFIG_H_ 27 | #define _TUSB_CONFIG_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | //-------------------------------------------------------------------- 34 | // COMMON CONFIGURATION 35 | //-------------------------------------------------------------------- 36 | 37 | // defined by compiler flags for flexibility 38 | #ifndef CFG_TUSB_MCU 39 | #error CFG_TUSB_MCU must be defined 40 | #endif 41 | 42 | #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX 43 | #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) 44 | #else 45 | #define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST 46 | #endif 47 | 48 | #ifndef CFG_TUSB_OS 49 | #define CFG_TUSB_OS OPT_OS_NONE 50 | #endif 51 | 52 | // CFG_TUSB_DEBUG is defined by compiler in DEBUG build 53 | #ifdef USE_TRACE 54 | #define CFG_TUSB_DEBUG 1 55 | #else 56 | #define CFG_TUSB_DEBUG 0 57 | #endif 58 | 59 | /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. 60 | * Tinyusb use follows macros to declare transferring memory so that they can be put 61 | * into those specific section. 62 | * e.g 63 | * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) 64 | * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) 65 | */ 66 | #ifndef CFG_TUSB_MEM_SECTION 67 | #define CFG_TUSB_MEM_SECTION 68 | #endif 69 | 70 | #ifndef CFG_TUSB_MEM_ALIGN 71 | #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) 72 | #endif 73 | 74 | // #define CFG_TUSB_DEBUG 3 75 | 76 | //-------------------------------------------------------------------- 77 | // CONFIGURATION 78 | //-------------------------------------------------------------------- 79 | 80 | // Size of buffer to hold descriptors and other data used for enumeration 81 | #define CFG_TUH_ENUMERATION_BUFSIZE 512 82 | 83 | #define CFG_TUH_HUB 1 84 | #define CFG_TUH_CDC 0 85 | #define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces 86 | #define CFG_TUH_MSC 1 87 | #define CFG_TUH_VENDOR 0 88 | 89 | // max device support (excluding hub device) 90 | // 1 hub typically has 4 ports 91 | #define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) 92 | 93 | //------------- HID -------------// 94 | 95 | #define CFG_TUH_HID_EP_BUFSIZE 64 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif 100 | 101 | #endif /* _TUSB_CONFIG_H_ */ 102 | -------------------------------------------------------------------------------- /FATFs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* This is a stub disk I/O module that acts as front end of the existing */ 5 | /* disk I/O modules and attach it to FatFs module with common interface. */ 6 | /*-----------------------------------------------------------------------*/ 7 | #include "ffconf.h" 8 | #include "diskio.h" 9 | 10 | static DSTATUS disk_state[CFG_TUH_DEVICE_MAX]; 11 | 12 | void diskio_init(void) 13 | { 14 | memset(disk_state, STA_NOINIT, CFG_TUH_DEVICE_MAX); 15 | } 16 | 17 | /*-----------------------------------------------------------------------*/ 18 | /* Initialize a Drive */ 19 | 20 | DSTATUS disk_initialize ( 21 | BYTE drv /* Physical drive nmuber (0..) */ 22 | ) 23 | { 24 | disk_state[drv] &= (~STA_NOINIT); // clear NOINIT bit 25 | return disk_state[drv]; 26 | } 27 | 28 | void disk_deinitialize ( BYTE drv ) 29 | { 30 | disk_state[drv] |= STA_NOINIT; // set NOINIT bit 31 | } 32 | 33 | /*-----------------------------------------------------------------------*/ 34 | /* Return Disk Status */ 35 | 36 | DSTATUS disk_status ( 37 | BYTE drv /* Physical drive nmuber (0..) */ 38 | ) 39 | { 40 | return disk_state[drv]; 41 | } 42 | 43 | /*-----------------------------------------------------------------------*/ 44 | /* Read Sector(s) */ 45 | 46 | volatile bool read_flag; 47 | volatile bool write_flag; 48 | 49 | bool tuh_msc_read10_cb(uint8_t dev_addr, const msc_cbw_t *cbw, const msc_csw_t *csw) { 50 | read_flag = true; 51 | } 52 | bool tuh_msc_write10_cb(uint8_t dev_addr, const msc_cbw_t *cbw, const msc_csw_t *csw) { 53 | write_flag = true; 54 | } 55 | 56 | DRESULT disk_read ( 57 | BYTE drv, /* Physical drive nmuber (0..) */ 58 | BYTE *buff, /* Data buffer to store read data */ 59 | DWORD sector, /* Sector address (LBA) */ 60 | BYTE count /* Number of sectors to read (1..255) */ 61 | ) 62 | { 63 | uint8_t usb_addr = drv+1; 64 | read_flag = false; 65 | if ( !tuh_msc_read10(usb_addr, 0, buff, sector, count, tuh_msc_read10_cb)) { 66 | return RES_ERROR; 67 | } 68 | uint64_t time_limit = time_us_64() + TIMEOUT_WAIT_US; 69 | while (!read_flag) { 70 | tuh_task(); 71 | if (time_us_64() > time_limit) { 72 | return RES_ERROR; 73 | } 74 | } 75 | return RES_OK; 76 | } 77 | 78 | /*-----------------------------------------------------------------------*/ 79 | /* Write Sector(s) */ 80 | 81 | #if _READONLY == 0 82 | DRESULT disk_write ( 83 | BYTE drv, /* Physical drive nmuber (0..) */ 84 | const BYTE *buff, /* Data to be written */ 85 | DWORD sector, /* Sector address (LBA) */ 86 | BYTE count /* Number of sectors to write (1..255) */ 87 | ) 88 | { 89 | uint8_t usb_addr = drv+1; 90 | write_flag = false; 91 | if ( !tuh_msc_write10(usb_addr, 0, buff, sector, count, tuh_msc_write10_cb) ) { 92 | return RES_ERROR; 93 | } 94 | uint64_t time_limit = time_us_64() + TIMEOUT_WAIT_US; 95 | while (!write_flag) { 96 | tuh_task(); 97 | if (time_us_64() > time_limit) { 98 | return RES_ERROR; 99 | } 100 | } 101 | return RES_OK; 102 | } 103 | #endif /* _READONLY */ 104 | 105 | /*-----------------------------------------------------------------------*/ 106 | /* Miscellaneous Functions */ 107 | 108 | DRESULT disk_ioctl ( 109 | BYTE drv, /* Physical drive nmuber (0..) */ 110 | BYTE ctrl, /* Control code */ 111 | void *buff /* Buffer to send/receive control data */ 112 | ) 113 | { 114 | if (ctrl == CTRL_SYNC) 115 | return RES_OK; 116 | else 117 | return RES_PARERR; 118 | } 119 | 120 | DWORD get_fattime (void) 121 | { 122 | return ((DWORD)(20 + 1) << 25) | 123 | ((DWORD)1 << 21) | 124 | ((DWORD)1 << 16) | 125 | ((DWORD)1 << 11) | 126 | ((DWORD)1 << 5) | 127 | (((DWORD)1 >> 1) << 0); 128 | } 129 | -------------------------------------------------------------------------------- /FATFs/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2017 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | 11 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 12 | 13 | /*------------------------------------------------------------------------*/ 14 | /* Allocate a memory block */ 15 | /*------------------------------------------------------------------------*/ 16 | 17 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ 18 | UINT msize /* Number of bytes to allocate */ 19 | ) 20 | { 21 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 22 | } 23 | 24 | 25 | /*------------------------------------------------------------------------*/ 26 | /* Free a memory block */ 27 | /*------------------------------------------------------------------------*/ 28 | 29 | void ff_memfree ( 30 | void* mblock /* Pointer to the memory block to free (nothing to do for null) */ 31 | ) 32 | { 33 | free(mblock); /* Free the memory block with POSIX API */ 34 | } 35 | 36 | #endif 37 | 38 | 39 | 40 | #if FF_FS_REENTRANT /* Mutal exclusion */ 41 | 42 | /*------------------------------------------------------------------------*/ 43 | /* Create a Synchronization Object */ 44 | /*------------------------------------------------------------------------*/ 45 | /* This function is called in f_mount() function to create a new 46 | / synchronization object for the volume, such as semaphore and mutex. 47 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 48 | */ 49 | 50 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ 51 | 52 | 53 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 54 | BYTE vol, /* Corresponding volume (logical drive number) */ 55 | FF_SYNC_t *sobj /* Pointer to return the created sync object */ 56 | ) 57 | { 58 | /* Win32 */ 59 | *sobj = CreateMutex(NULL, FALSE, NULL); 60 | return (int)(*sobj != INVALID_HANDLE_VALUE); 61 | 62 | /* uITRON */ 63 | // T_CSEM csem = {TA_TPRI,1,1}; 64 | // *sobj = acre_sem(&csem); 65 | // return (int)(*sobj > 0); 66 | 67 | /* uC/OS-II */ 68 | // OS_ERR err; 69 | // *sobj = OSMutexCreate(0, &err); 70 | // return (int)(err == OS_NO_ERR); 71 | 72 | /* FreeRTOS */ 73 | // *sobj = xSemaphoreCreateMutex(); 74 | // return (int)(*sobj != NULL); 75 | 76 | /* CMSIS-RTOS */ 77 | // *sobj = osMutexCreate(Mutex + vol); 78 | // return (int)(*sobj != NULL); 79 | } 80 | 81 | 82 | /*------------------------------------------------------------------------*/ 83 | /* Delete a Synchronization Object */ 84 | /*------------------------------------------------------------------------*/ 85 | /* This function is called in f_mount() function to delete a synchronization 86 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 87 | / the f_mount() function fails with FR_INT_ERR. 88 | */ 89 | 90 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 91 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 92 | ) 93 | { 94 | /* Win32 */ 95 | return (int)CloseHandle(sobj); 96 | 97 | /* uITRON */ 98 | // return (int)(del_sem(sobj) == E_OK); 99 | 100 | /* uC/OS-II */ 101 | // OS_ERR err; 102 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 103 | // return (int)(err == OS_NO_ERR); 104 | 105 | /* FreeRTOS */ 106 | // vSemaphoreDelete(sobj); 107 | // return 1; 108 | 109 | /* CMSIS-RTOS */ 110 | // return (int)(osMutexDelete(sobj) == osOK); 111 | } 112 | 113 | 114 | /*------------------------------------------------------------------------*/ 115 | /* Request Grant to Access the Volume */ 116 | /*------------------------------------------------------------------------*/ 117 | /* This function is called on entering file functions to lock the volume. 118 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 119 | */ 120 | 121 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 122 | FF_SYNC_t sobj /* Sync object to wait */ 123 | ) 124 | { 125 | /* Win32 */ 126 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 127 | 128 | /* uITRON */ 129 | // return (int)(wai_sem(sobj) == E_OK); 130 | 131 | /* uC/OS-II */ 132 | // OS_ERR err; 133 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 134 | // return (int)(err == OS_NO_ERR); 135 | 136 | /* FreeRTOS */ 137 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 138 | 139 | /* CMSIS-RTOS */ 140 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 141 | } 142 | 143 | 144 | /*------------------------------------------------------------------------*/ 145 | /* Release Grant to Access the Volume */ 146 | /*------------------------------------------------------------------------*/ 147 | /* This function is called on leaving file functions to unlock the volume. 148 | */ 149 | 150 | void ff_rel_grant ( 151 | FF_SYNC_t sobj /* Sync object to be signaled */ 152 | ) 153 | { 154 | /* Win32 */ 155 | ReleaseMutex(sobj); 156 | 157 | /* uITRON */ 158 | // sig_sem(sobj); 159 | 160 | /* uC/OS-II */ 161 | // OSMutexPost(sobj); 162 | 163 | /* FreeRTOS */ 164 | // xSemaphoreGive(sobj); 165 | 166 | /* CMSIS-RTOS */ 167 | // osMutexRelease(sobj); 168 | } 169 | 170 | #endif 171 | 172 | -------------------------------------------------------------------------------- /interface_explanation_note_from_fixel: -------------------------------------------------------------------------------- 1 | case 0x93: dev_cd_extid(); break; 2 | 3 | 4 | case 0xc0: dev_ode_changetoc(); break; 5 | case 0xc1: dev_ode_gettoc(); break; 6 | case 0xc2: dev_ode_getdesc(); break; 7 | case 0xc3: dev_ode_clearpl(); break; 8 | case 0xc4: dev_ode_addpl(); break; 9 | case 0xc5: dev_ode_launchpl(); break; 10 | 11 | case 0xd1: dev_ode_gettoclist(); break; 12 | 13 | 14 | case 0xe0: dev_ode_createfile(); break; 15 | case 0xe1: dev_ode_openfile(); break; 16 | case 0xe2: dev_ode_seekfile(); break; 17 | case 0xe3: dev_ode_readfile(); break; 18 | case 0xe4: dev_ode_writefile(); break; 19 | case 0xe5: dev_ode_closefile(); break; 20 | case 0xe6: dev_ode_bufsend(); break; 21 | case 0xe7: dev_ode_bufrecv(); break; 22 | 23 | case 0xf0: dev_ode_startupdate(); break; 24 | 25 | 26 | 93: extended id : 27 | return status : 28 | 0x93 02 '3' 'D' 'S' 'A' 'T' 'A' 0x1 0x1 0x0 mei_status 29 | 30 | 0x93 status reply struct 31 | { 32 | uint8_t boot_device; // 33 | char name[6]; // device friendly name 34 | uint8_t rev_major; 35 | uint8_t rev_minor; 36 | uint8_t rev_patch; 37 | } 38 | boot device : enum{ 39 | microsd=1, 40 | usbmsc=2, 41 | flash=4, 42 | sata=8 43 | } 44 | 45 | 0xc0 II II II II -- change toc... (change current directory to ... tocid IIIIIIII ). reply - 0xc0 mei_status 46 | -- all numbers are big endian 47 | 48 | 0xc0 II II II II SS SS 49 | get 16 bytes toc entry IIIIIIII from the TOCBuffer and buffer offset SSSS 50 | when SSSS==0, the toc is read from filesystem into the toc buffer. if SSSS>0 -- the buffer is not changed 51 | 52 | status : 53 | 0xC0 HH HH HH HH ..... HH mei_status 54 | 55 | where HH HH HH ... HH are 16 bytes from the TOCBuffer[SSSS] 56 | 57 | f(offs==0) 58 | { 59 | memset(tocbuffer,0xff,sizeof(tocbuffer)); 60 | res=toc_read(id,&te); 61 | if(res>0) 62 | { 63 | tocbuffer[toclen++]=te.flags>>24; 64 | tocbuffer[toclen++]=te.flags>>16; 65 | tocbuffer[toclen++]=te.flags>>8; 66 | tocbuffer[toclen++]=te.flags&0xff; 67 | tocbuffer[toclen++]=te.toc_id>>24; 68 | tocbuffer[toclen++]=te.toc_id>>16; 69 | tocbuffer[toclen++]=te.toc_id>>8; 70 | tocbuffer[toclen++]=te.toc_id&0xff; 71 | te.name_length++; //inlude 0 72 | tocbuffer[toclen++]=te.name_length>>24; 73 | tocbuffer[toclen++]=te.name_length>>16; 74 | tocbuffer[toclen++]=te.name_length>>8; 75 | tocbuffer[toclen++]=te.name_length&0xff; 76 | for(uint32_t t=0;t0) 101 | { 102 | //estimate actual len : 103 | if((te.name_length+13)>=2048) 104 | break; //can't fit anymore 105 | 106 | tocbuffer[toclen++]=te.flags>>24; 107 | tocbuffer[toclen++]=te.flags>>16; 108 | tocbuffer[toclen++]=te.flags>>8; 109 | tocbuffer[toclen++]=te.flags&0xff; 110 | tocbuffer[toclen++]=te.toc_id>>24; 111 | tocbuffer[toclen++]=te.toc_id>>16; 112 | tocbuffer[toclen++]=te.toc_id>>8; 113 | tocbuffer[toclen++]=te.toc_id&0xff; 114 | if(te.flags!=TOC_FLAG_INVALID) 115 | { 116 | 117 | te.name[127]=0; //hard limit -- (128+13)*14=1974, still fits in buffer 118 | te.name_length=strlen(te.name)+1; //inlude 0 119 | 120 | tocbuffer[toclen++]=te.name_length>>24; 121 | tocbuffer[toclen++]=te.name_length>>16; 122 | tocbuffer[toclen++]=te.name_length>>8; 123 | tocbuffer[toclen++]=te.name_length&0xff; 124 | for(uint32_t t=0;t= CFG_TUH_DEVICE_MAX) return NULL; 36 | else return &devices[idx]; 37 | } 38 | 39 | void USB_Host_init() { 40 | for (int i = 0; istate) { 67 | case EJECTING: 68 | check_eject(dev); 69 | case MOUNTED: 70 | return true; 71 | break; 72 | default: 73 | return false; 74 | } 75 | } 76 | #endif 77 | return false; 78 | } 79 | 80 | void USB_Host_loop() 81 | { 82 | // tinyusb host task 83 | bool ret = true; 84 | tuh_task(); 85 | for (int i =0; idev_addr == 0xFF) continue; 88 | switch (dev->type) { 89 | case CD_TYPE: 90 | ret = CDROM_Host_loop(dev); 91 | break; 92 | case MSC_TYPE: 93 | ret = MSC_Host_loop(dev); 94 | break; 95 | default: 96 | ret = Default_Host_loop(dev); 97 | } 98 | if (!ret) { 99 | if(dev->state==INQUIRY) { 100 | dev->state = ATTACHED; 101 | tuh_msc_inquiry(dev->dev_addr, 0, &inquiry_resp, inquiry_complete_cb); 102 | } 103 | } 104 | } 105 | } 106 | 107 | 108 | #if CFG_TUH_MSC 109 | 110 | //--------------------------------------------------------------------+ 111 | // MACRO TYPEDEF CONSTANT ENUM DECLARATION 112 | //--------------------------------------------------------------------+ 113 | 114 | volatile int8_t requestLoad = -1; 115 | cd_s currentImage = {0}; 116 | 117 | static bool startClose = true; 118 | 119 | volatile bool read_done; 120 | volatile bool is_audio; 121 | volatile bool has_subQ; 122 | 123 | volatile bool usb_result; 124 | 125 | uint32_t start_Block; 126 | uint32_t nb_block_Block; 127 | uint8_t *buffer_Block; 128 | bool blockRequired = false; 129 | bool subqRequired = false; 130 | uint8_t *buffer_subq; 131 | 132 | fileCmd_s fileCmdRequired; 133 | 134 | static bool check_eject(device_s *dev) { 135 | //Execute right now 136 | LOG_SATA("Eject\n"); 137 | if (CDROM_ExecuteEject(dev)) dev->state = INQUIRY; 138 | return true; 139 | } 140 | 141 | void USB_reset() { 142 | LOG_SATA("reset usb\n"); 143 | startClose = false; 144 | for (int i=0; idev_addr); 147 | } 148 | tusb_reset(); 149 | } 150 | 151 | static bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) 152 | { 153 | device_s *dev = getDevice(dev_addr); 154 | if (csw->status != MSC_CSW_STATUS_GOOD) 155 | { 156 | TU_LOG1("Inquiry failed %x\r\n", csw->status); 157 | dev->state = INQUIRY; 158 | return false; 159 | } 160 | //At least consider we are enumerated so that configuration can be read 161 | if (dev->state < ENUMERATED) dev->state = ENUMERATED; 162 | // Print out Vendor ID, Product ID and Rev 163 | TU_LOG1("%.8s %.16s rev %.4s Type 0x%x Lun %d\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev, inquiry_resp.peripheral_device_type, cbw->lun); 164 | 165 | dev->dev_addr = dev_addr; 166 | 167 | dev->lun = cbw->lun; 168 | 169 | if (inquiry_resp.peripheral_device_type == 0x5) { 170 | deviceCnt++; 171 | dev->type = CD_TYPE; 172 | } 173 | if (inquiry_resp.peripheral_device_type == 0x0) { 174 | deviceCnt++; 175 | dev->type = MSC_TYPE; 176 | } 177 | checkForMedia(dev_addr, dev->lun); 178 | 179 | return true; 180 | } 181 | 182 | int64_t alarm_callback(alarm_id_t id, void *user_data) { 183 | device_s *dev = (device_s *)user_data; 184 | checkForMedia(dev->dev_addr, dev->lun); 185 | // Can return a value here in us to fire in the future 186 | return 0; 187 | } 188 | 189 | void tryCheckForMedia(device_s *dev) { 190 | add_alarm_in_ms(500, alarm_callback, (void*)dev, false); 191 | } 192 | 193 | void tuh_msc_ready_cb(uint8_t dev_addr, bool ready) { 194 | device_s *dev=getDevice(dev_addr); 195 | if (dev->type == CD_TYPE) 196 | CDROM_ready(dev_addr, ready); 197 | if (!ready) { 198 | tryCheckForMedia(dev); 199 | //Voir pour executer le check for media tous les 300 ms au plus rapide 200 | } 201 | } 202 | 203 | void tuh_msc_enumerate_cb (uint8_t dev_addr) { 204 | device_s *dev = getDevice(dev_addr); 205 | TU_LOG1("Usb device enumerated %x\n", dev_addr); 206 | dev->dev_addr = dev_addr; 207 | dev->state = INQUIRY; 208 | } 209 | 210 | bool read_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { 211 | if (csw->status != MSC_CSW_STATUS_GOOD) { 212 | set3doDriveError(); 213 | } 214 | read_done = true; 215 | usb_cmd_on_going = false; 216 | return true; 217 | } 218 | 219 | bool block_is_ready() { 220 | return read_done; 221 | } 222 | 223 | bool cmd_is_ready(bool *success) { 224 | if (success != NULL) *success = usb_result; 225 | return fileCmdRequired == DONE; 226 | } 227 | 228 | bool write_is_ready(bool *success) { 229 | *success = usb_result; 230 | return fileCmdRequired == DONE; 231 | } 232 | 233 | bool USBDriveEject(uint8_t dev_addr, bool eject) { 234 | device_s *dev = getDevice(dev_addr); 235 | if (dev->type == CD_TYPE) { 236 | dev->state = EJECTING; 237 | return true; 238 | } 239 | if (dev->type == MSC_TYPE) { 240 | return true; 241 | } 242 | return false; 243 | } 244 | 245 | int getDeviceCount(void) { 246 | return deviceCnt; 247 | } 248 | 249 | 250 | bool readSubQChannel(uint8_t *buffer) { 251 | buffer_subq = buffer; 252 | read_done = false; 253 | subqRequired = true; 254 | return true; 255 | } 256 | 257 | bool isAudioBlock(uint32_t start) { 258 | bool res = false; 259 | for (int i = 0; i < currentImage.nb_track-1; i++) { 260 | if (currentImage.tracks[i].lba <= start) { 261 | res = ((currentImage.tracks[i].CTRL_ADR & 0x4) == 0x0); 262 | } 263 | } 264 | return res; 265 | } 266 | 267 | bool readBlock(uint32_t start, uint16_t nb_block, uint16_t block_size, uint8_t *buffer) { 268 | is_audio = false; 269 | has_subQ = false; 270 | read_done = false; 271 | start_Block = start; 272 | nb_block_Block = nb_block; 273 | buffer_Block = buffer; 274 | for (int i = 0; i < currentImage.nb_track-1; i++) { 275 | if (currentImage.tracks[i].lba <= start) { 276 | is_audio = ((currentImage.tracks[i].CTRL_ADR & 0x4) == 0x0); 277 | has_subQ = (block_size >= 2448); 278 | } 279 | } 280 | blockRequired = true; 281 | return true; 282 | } 283 | //------------- IMPLEMENTATION -------------// 284 | 285 | void tuh_msc_enumerated_cb(uint8_t dev_addr) 286 | { 287 | TU_LOG1("##### enumerated ######\n"); 288 | } 289 | 290 | void tuh_msc_mount_cb(uint8_t dev_addr) 291 | { 292 | bool ret = false; 293 | device_s *dev = getDevice(dev_addr); 294 | LOG_SATA("A USB MassStorage device is mounted %d\r\n", dev_addr); 295 | dev->state = MOUNTED; 296 | 297 | if (dev->type == CD_TYPE) { 298 | CDROM_Inquiry(dev_addr, dev->lun); 299 | } 300 | if (dev->type == MSC_TYPE) { 301 | MSC_Inquiry(dev_addr, dev->lun); 302 | } 303 | } 304 | 305 | void tuh_msc_umount_cb(uint8_t dev_addr) 306 | { 307 | device_s *dev = getDevice(dev_addr); 308 | 309 | LOG_SATA("A USB MassStorage device is unmounted\r\n"); 310 | 311 | //A voir si la currentImage utilise le dev_addr en question... 312 | //Pour le moment on va dire oui 313 | { 314 | set3doCDReady(dev_addr, false); 315 | set3doDriveMounted(dev_addr, false); 316 | } 317 | 318 | if (currentImage.dev_addr == dev_addr) { 319 | LOG_SATA("Unmount USB key used for the currentImage!\n"); 320 | if (currentImage.curDir != NULL) free(currentImage.curDir); 321 | if (currentImage.curPath != NULL) free(currentImage.curPath); 322 | currentImage.curDir = NULL; 323 | currentImage.curPath = NULL; 324 | currentImage.dev_addr = 0xFF; 325 | currentImage.lun = 0x0; 326 | } 327 | dev->dev_addr = 0xFF; 328 | dev->useable = false; 329 | dev->canBeLoaded = false; 330 | dev->canBeEjected = false; 331 | dev->state = DETACHED; 332 | dev->type = UNKNOWN_TYPE; 333 | deviceCnt--; 334 | mediaInterrupt(); 335 | } 336 | 337 | #endif 338 | -------------------------------------------------------------------------------- /FATFs/00history.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | Revision history of FatFs module 3 | ---------------------------------------------------------------------------- 4 | 5 | R0.00 (February 26, 2006) 6 | 7 | Prototype. 8 | 9 | 10 | 11 | R0.01 (April 29, 2006) 12 | 13 | The first release. 14 | 15 | 16 | 17 | R0.02 (June 01, 2006) 18 | 19 | Added FAT12 support. 20 | Removed unbuffered mode. 21 | Fixed a problem on small (<32M) partition. 22 | 23 | 24 | 25 | R0.02a (June 10, 2006) 26 | 27 | Added a configuration option (_FS_MINIMUM). 28 | 29 | 30 | 31 | R0.03 (September 22, 2006) 32 | 33 | Added f_rename(). 34 | Changed option _FS_MINIMUM to _FS_MINIMIZE. 35 | 36 | 37 | 38 | R0.03a (December 11, 2006) 39 | 40 | Improved cluster scan algorithm to write files fast. 41 | Fixed f_mkdir() creates incorrect directory on FAT32. 42 | 43 | 44 | 45 | R0.04 (February 04, 2007) 46 | 47 | Added f_mkfs(). 48 | Supported multiple drive system. 49 | Changed some interfaces for multiple drive system. 50 | Changed f_mountdrv() to f_mount(). 51 | 52 | 53 | 54 | R0.04a (April 01, 2007) 55 | 56 | Supported multiple partitions on a physical drive. 57 | Added a capability of extending file size to f_lseek(). 58 | Added minimization level 3. 59 | Fixed an endian sensitive code in f_mkfs(). 60 | 61 | 62 | 63 | R0.04b (May 05, 2007) 64 | 65 | Added a configuration option _USE_NTFLAG. 66 | Added FSINFO support. 67 | Fixed DBCS name can result FR_INVALID_NAME. 68 | Fixed short seek (<= csize) collapses the file object. 69 | 70 | 71 | 72 | R0.05 (August 25, 2007) 73 | 74 | Changed arguments of f_read(), f_write() and f_mkfs(). 75 | Fixed f_mkfs() on FAT32 creates incorrect FSINFO. 76 | Fixed f_mkdir() on FAT32 creates incorrect directory. 77 | 78 | 79 | 80 | R0.05a (February 03, 2008) 81 | 82 | Added f_truncate() and f_utime(). 83 | Fixed off by one error at FAT sub-type determination. 84 | Fixed btr in f_read() can be mistruncated. 85 | Fixed cached sector is not flushed when create and close without write. 86 | 87 | 88 | 89 | R0.06 (April 01, 2008) 90 | 91 | Added fputc(), fputs(), fprintf() and fgets(). 92 | Improved performance of f_lseek() on moving to the same or following cluster. 93 | 94 | 95 | 96 | R0.07 (April 01, 2009) 97 | 98 | Merged Tiny-FatFs as a configuration option. (_FS_TINY) 99 | Added long file name feature. (_USE_LFN) 100 | Added multiple code page feature. (_CODE_PAGE) 101 | Added re-entrancy for multitask operation. (_FS_REENTRANT) 102 | Added auto cluster size selection to f_mkfs(). 103 | Added rewind option to f_readdir(). 104 | Changed result code of critical errors. 105 | Renamed string functions to avoid name collision. 106 | 107 | 108 | 109 | R0.07a (April 14, 2009) 110 | 111 | Septemberarated out OS dependent code on reentrant cfg. 112 | Added multiple sector size feature. 113 | 114 | 115 | 116 | R0.07c (June 21, 2009) 117 | 118 | Fixed f_unlink() can return FR_OK on error. 119 | Fixed wrong cache control in f_lseek(). 120 | Added relative path feature. 121 | Added f_chdir() and f_chdrive(). 122 | Added proper case conversion to extended character. 123 | 124 | 125 | 126 | R0.07e (November 03, 2009) 127 | 128 | Septemberarated out configuration options from ff.h to ffconf.h. 129 | Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. 130 | Fixed name matching error on the 13 character boundary. 131 | Added a configuration option, _LFN_UNICODE. 132 | Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. 133 | 134 | 135 | 136 | R0.08 (May 15, 2010) 137 | 138 | Added a memory configuration option. (_USE_LFN = 3) 139 | Added file lock feature. (_FS_SHARE) 140 | Added fast seek feature. (_USE_FASTSEEK) 141 | Changed some types on the API, XCHAR->TCHAR. 142 | Changed .fname in the FILINFO structure on Unicode cfg. 143 | String functions support UTF-8 encoding files on Unicode cfg. 144 | 145 | 146 | 147 | R0.08a (August 16, 2010) 148 | 149 | Added f_getcwd(). (_FS_RPATH = 2) 150 | Added sector erase feature. (_USE_ERASE) 151 | Moved file lock semaphore table from fs object to the bss. 152 | Fixed f_mkfs() creates wrong FAT32 volume. 153 | 154 | 155 | 156 | R0.08b (January 15, 2011) 157 | 158 | Fast seek feature is also applied to f_read() and f_write(). 159 | f_lseek() reports required table size on creating CLMP. 160 | Extended format syntax of f_printf(). 161 | Ignores duplicated directory separators in given path name. 162 | 163 | 164 | 165 | R0.09 (September 06, 2011) 166 | 167 | f_mkfs() supports multiple partition to complete the multiple partition feature. 168 | Added f_fdisk(). 169 | 170 | 171 | 172 | R0.09a (August 27, 2012) 173 | 174 | Changed f_open() and f_opendir() reject null object pointer to avoid crash. 175 | Changed option name _FS_SHARE to _FS_LOCK. 176 | Fixed assertion failure due to OS/2 EA on FAT12/16 volume. 177 | 178 | 179 | 180 | R0.09b (January 24, 2013) 181 | 182 | Added f_setlabel() and f_getlabel(). 183 | 184 | 185 | 186 | R0.10 (October 02, 2013) 187 | 188 | Added selection of character encoding on the file. (_STRF_ENCODE) 189 | Added f_closedir(). 190 | Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) 191 | Added forced mount feature with changes of f_mount(). 192 | Improved behavior of volume auto detection. 193 | Improved write throughput of f_puts() and f_printf(). 194 | Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). 195 | Fixed f_write() can be truncated when the file size is close to 4GB. 196 | Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. 197 | 198 | 199 | 200 | R0.10a (January 15, 2014) 201 | 202 | Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) 203 | Added a configuration option of minimum sector size. (_MIN_SS) 204 | 2nd argument of f_rename() can have a drive number and it will be ignored. 205 | Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) 206 | Fixed f_close() invalidates the file object without volume lock. 207 | Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) 208 | Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) 209 | 210 | 211 | 212 | R0.10b (May 19, 2014) 213 | 214 | Fixed a hard error in the disk I/O layer can collapse the directory entry. 215 | Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) 216 | 217 | 218 | 219 | R0.10c (November 09, 2014) 220 | 221 | Added a configuration option for the platforms without RTC. (_FS_NORTC) 222 | Changed option name _USE_ERASE to _USE_TRIM. 223 | Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) 224 | Fixed a potential problem of FAT access that can appear on disk error. 225 | Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) 226 | 227 | 228 | 229 | R0.11 (February 09, 2015) 230 | 231 | Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) 232 | Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) 233 | Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) 234 | 235 | 236 | 237 | R0.11a (September 05, 2015) 238 | 239 | Fixed wrong media change can lead a deadlock at thread-safe configuration. 240 | Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) 241 | Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) 242 | Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). 243 | Fixed errors in the case conversion teble of Unicode (cc*.c). 244 | 245 | 246 | 247 | R0.12 (April 12, 2016) 248 | 249 | Added support for exFAT file system. (_FS_EXFAT) 250 | Added f_expand(). (_USE_EXPAND) 251 | Changed some members in FINFO structure and behavior of f_readdir(). 252 | Added an option _USE_CHMOD. 253 | Removed an option _WORD_ACCESS. 254 | Fixed errors in the case conversion table of Unicode (cc*.c). 255 | 256 | 257 | 258 | R0.12a (July 10, 2016) 259 | 260 | Added support for creating exFAT volume with some changes of f_mkfs(). 261 | Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. 262 | f_forward() is available regardless of _FS_TINY. 263 | Fixed f_mkfs() creates wrong volume. (appeared at R0.12) 264 | Fixed wrong memory read in create_name(). (appeared at R0.12) 265 | Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. 266 | 267 | 268 | 269 | R0.12b (September 04, 2016) 270 | 271 | Made f_rename() be able to rename objects with the same name but case. 272 | Fixed an error in the case conversion teble of code page 866. (ff.c) 273 | Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) 274 | Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) 275 | Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) 276 | Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) 277 | Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) 278 | Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) 279 | 280 | 281 | 282 | R0.12c (March 04, 2017) 283 | 284 | Improved write throughput at the fragmented file on the exFAT volume. 285 | Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. 286 | Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) 287 | Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) 288 | 289 | 290 | 291 | R0.13 (May 21, 2017) 292 | 293 | Changed heading character of configuration keywords "_" to "FF_". 294 | Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead. 295 | Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0) 296 | Improved cluster allocation time on stretch a deep buried cluster chain. 297 | Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3. 298 | Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous. 299 | Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12) 300 | Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) 301 | Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) 302 | 303 | 304 | 305 | R0.13a (October 14, 2017) 306 | 307 | Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2) 308 | Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF). 309 | Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk(). 310 | Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09) 311 | Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c) 312 | Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) 313 | 314 | 315 | -------------------------------------------------------------------------------- /src/interfaces/CDROM.c: -------------------------------------------------------------------------------- 1 | #include "USB.h" 2 | #include "3DO.h" 3 | #include "CDFormat.h" 4 | #include "pico/stdio.h" 5 | 6 | #if CFG_TUH_MSC 7 | static bool check_eject(uint8_t dev_addr); 8 | static void check_speed(uint8_t dev_addr); 9 | static void check_block(uint8_t dev_addr); 10 | static bool check_subq(uint8_t dev_addr); 11 | #endif 12 | 13 | bool CDROM_Host_loop(device_s *dev) 14 | { 15 | #if CFG_TUH_MSC 16 | if (!usb_cmd_on_going) { 17 | switch(dev->state) { 18 | case EJECTING: 19 | check_eject(dev->dev_addr); 20 | case MOUNTED: 21 | check_speed(dev->dev_addr); 22 | check_block(dev->dev_addr); 23 | check_subq(dev->dev_addr); 24 | return true; 25 | break; 26 | default: 27 | return false; 28 | } 29 | } 30 | #endif 31 | return false; 32 | } 33 | 34 | 35 | #if CFG_TUH_MSC 36 | 37 | //--------------------------------------------------------------------+ 38 | // MACRO TYPEDEF CONSTANT ENUM DECLARATION 39 | //--------------------------------------------------------------------+ 40 | 41 | static bool startClose = true; 42 | 43 | uint8_t readBuffer[20480]; 44 | 45 | 46 | extern volatile bool is_audio; 47 | extern volatile bool has_subQ; 48 | 49 | static bool command_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { 50 | device_s *dev = getDevice(dev_addr); 51 | if (csw->status != MSC_CSW_STATUS_GOOD) { 52 | set3doDriveError(); 53 | } 54 | dev->tray_open = !dev->tray_open; 55 | usb_cmd_on_going = false; 56 | } 57 | 58 | void wakeUpCDRom(uint8_t dev_addr, uint8_t lun) { 59 | tuh_msc_test_unit_ready(dev_addr, lun, NULL); 60 | } 61 | 62 | bool CDROM_ExecuteEject(uint8_t dev_addr) { 63 | usb_cmd_on_going = true; 64 | device_s *dev= getDevice(dev_addr); 65 | LOG_SATA("Eject CDROM %d\n", dev->tray_open); 66 | if (!dev->canBeLoaded && !dev->canBeEjected) { 67 | LOG_SATA("Can not load or eject\n"); 68 | set3doCDReady(dev_addr, false); 69 | set3doDriveMounted(dev_addr, false); 70 | return true; 71 | } 72 | 73 | if (!dev->canBeLoaded && dev->tray_open) { 74 | LOG_SATA("Can not be loaded - force tray to false\n"); 75 | dev->tray_open = false; 76 | } 77 | if (!dev->canBeEjected && !dev->tray_open) { 78 | LOG_SATA("Can not eject - force tray to true\n"); 79 | dev->tray_open = true; 80 | } 81 | 82 | if ( !tuh_msc_start_stop(dev->dev_addr, dev->lun, dev->tray_open, true, command_complete_cb)) { 83 | LOG_SATA("Got error while eject command\n"); 84 | } 85 | else { 86 | set3doCDReady(dev_addr, false); 87 | set3doDriveMounted(dev_addr, false); 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | static bool check_eject(uint8_t dev_addr) { 94 | //Execute right now 95 | device_s *dev= getDevice(dev_addr); 96 | LOG_SATA("Eject %d\n", dev_addr); 97 | if (CDROM_ExecuteEject(dev_addr)) dev->state = INQUIRY; 98 | return true; 99 | } 100 | 101 | extern uint32_t start_Block; 102 | extern uint32_t nb_block_Block; 103 | extern uint8_t *buffer_Block; 104 | extern bool blockRequired; 105 | extern bool subqRequired; 106 | extern uint8_t *buffer_subq; 107 | 108 | static bool speedChange = false; 109 | static uint16_t CDSpeed; 110 | 111 | static void check_block(uint8_t dev_addr) { 112 | if (blockRequired && (dev_addr == currentImage.dev_addr)) { 113 | usb_cmd_on_going = true; 114 | blockRequired = false; 115 | if (!is_audio) { 116 | if ( !tuh_msc_read10_sync(currentImage.dev_addr, currentImage.lun, buffer_Block, start_Block, nb_block_Block, read_complete_cb)) { 117 | LOG_SATA("Got error with block read\n"); 118 | currentImage.dev_addr = 0xFF; 119 | mediaInterrupt(); 120 | return; 121 | } 122 | } else { 123 | if ( !tuh_msc_read_cd(currentImage.dev_addr, currentImage.lun, buffer_Block, start_Block, nb_block_Block, has_subQ, read_complete_cb)) { 124 | LOG_SATA("Got error with block read\n"); 125 | currentImage.dev_addr = 0xFF; 126 | mediaInterrupt(); 127 | return; 128 | } 129 | } 130 | } 131 | } 132 | 133 | static bool check_subq(uint8_t dev_addr) { 134 | if (subqRequired && (dev_addr == currentImage.dev_addr)) { 135 | usb_cmd_on_going = true; 136 | subqRequired = false; 137 | if (!tuh_msc_read_sub_channel(currentImage.dev_addr, currentImage.lun, buffer_subq, read_complete_cb)) { 138 | LOG_SATA("Got error with sub Channel read\n"); 139 | currentImage.dev_addr = 0xFF; 140 | mediaInterrupt(); 141 | return false; 142 | } 143 | } 144 | return true; 145 | } 146 | 147 | static void check_speed(uint8_t dev_addr) { 148 | if (speedChange && (dev_addr == currentImage.dev_addr)) { 149 | usb_cmd_on_going = true; 150 | speedChange = false; 151 | if ( !tuh_msc_set_speed(currentImage.dev_addr, currentImage.lun, CDSpeed, 0xFFFF, read_complete_cb)) { 152 | LOG_SATA("Got error with block read\n"); 153 | return; 154 | } 155 | } 156 | } 157 | 158 | static bool setCDSpeed(uint16_t speed) { 159 | CDSpeed = speed; 160 | speedChange = true; 161 | return true; 162 | } 163 | 164 | static bool read_header_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { 165 | usb_cmd_on_going = false; 166 | LOG_SATA("read_header_complete_cb\n"); 167 | device_s *dev = getDevice(dev_addr); 168 | if (readBuffer[0] == 0x2) { 169 | /* 00h - audio; 01h - Mode 1 (games) - Mode 2 (CD-XA photoCD) */ 170 | //Photo CD shall have an audio track. CD-i are Mode 2 but without audio. 171 | dev->rawImage.format = 0x20; //Only CD-ROM, CD-DA and CD-XA are supported 172 | } 173 | if (currentImage.dev_addr == 0xFF) { 174 | memcpy(¤tImage, &dev->rawImage, sizeof(cd_s)); 175 | if (dev->state < MOUNTED) dev->state = MOUNTED; 176 | set3doCDReady(dev_addr, true); 177 | set3doDriveMounted(dev_addr, true); 178 | mediaInterrupt(); 179 | } 180 | return true; 181 | } 182 | 183 | static bool read_toc_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { 184 | device_s *dev = getDevice(dev_addr); 185 | dev->rawImage.nb_track = ((readBuffer[0]<<8)+readBuffer[1] - 2)/8; 186 | 187 | dev->rawImage.first_track = readBuffer[2]; 188 | dev->rawImage.last_track = readBuffer[3]; 189 | 190 | LOG_SATA("First %d, last %d nb %d\n", dev->rawImage.first_track, dev->rawImage.last_track, dev->rawImage.nb_track); 191 | for (int i = 0; i < dev->rawImage.nb_track-1; i++) { 192 | int index = 4+8*i; 193 | //OxAA as id mean lead out 194 | dev->rawImage.tracks[i].id = readBuffer[index + 2]; 195 | dev->rawImage.tracks[i].CTRL_ADR = readBuffer[index + 1]; 196 | dev->rawImage.tracks[i].msf[0] = readBuffer[index + 5]; //MSF 197 | dev->rawImage.tracks[i].msf[1] = readBuffer[index + 6]; 198 | dev->rawImage.tracks[i].msf[2] = readBuffer[index + 7]; 199 | if ((dev->rawImage.tracks[i].CTRL_ADR & 0x4) != 0) dev->rawImage.hasOnlyAudio = false; 200 | dev->rawImage.tracks[i].lba = dev->rawImage.tracks[i].msf[0]*60*75+dev->rawImage.tracks[i].msf[1]*75+dev->rawImage.tracks[i].msf[2] - 150; 201 | LOG_SATA("Track[%d] 0x%x (0x%x)=> %d:%d:%d\n", i, dev->rawImage.tracks[i].id, dev->rawImage.tracks[i].CTRL_ADR, dev->rawImage.tracks[i].msf[0], dev->rawImage.tracks[i].msf[1], dev->rawImage.tracks[i].msf[2]); 202 | } 203 | 204 | uint32_t first_track = dev->rawImage.tracks[0].msf[0]*60*75+dev->rawImage.tracks[0].msf[1]*75+dev->rawImage.tracks[0].msf[2] - 150; 205 | if (dev->rawImage.tracks[0].CTRL_ADR & 0x4) { 206 | if (!tuh_msc_read_header(dev_addr, cbw->lun, readBuffer, first_track, read_header_complete_cb)) { 207 | LOG_SATA("Got error with header read\n"); 208 | return false; 209 | } 210 | } else { 211 | readBuffer[0] = 0x0; 212 | read_header_complete_cb(dev_addr, cbw, csw); 213 | } 214 | return true; 215 | } 216 | 217 | static bool read_toc_light_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { 218 | device_s *dev = getDevice(dev_addr); 219 | dev->rawImage.nb_track = (((readBuffer[0]<<8)+readBuffer[1]) - 2)/8; 220 | 221 | dev->rawImage.first_track = readBuffer[2]; 222 | dev->rawImage.last_track = readBuffer[3]; 223 | 224 | LOG_SATA("First %d, last %d nbTrack %d\n", dev->rawImage.first_track, dev->rawImage.last_track, dev->rawImage.nb_track); 225 | 226 | if (dev->rawImage.nb_track > 1) { 227 | if (!tuh_msc_read_toc(dev_addr, cbw->lun, readBuffer, 1, 0, dev->rawImage.nb_track-1, read_toc_complete_cb)) { 228 | LOG_SATA("Got error with toc read\n"); 229 | return false; 230 | } 231 | } else { 232 | return read_toc_complete_cb(dev_addr, cbw, csw); 233 | } 234 | return true; 235 | } 236 | 237 | static uint8_t capabilties_buffer[256]; 238 | 239 | static bool mode_sense_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) 240 | { 241 | device_s *dev = getDevice(dev_addr); 242 | 243 | dev->canBeLoaded = true; 244 | dev->canBeEjected = true; 245 | 246 | uint16_t length = (capabilties_buffer[0]<<8)+capabilties_buffer[1]; 247 | uint16_t block_descriptor_length = (capabilties_buffer[6]<<8)+capabilties_buffer[7]+8; 248 | if ((length < 128) && (block_descriptor_length> 5) == 0) dev->canBeLoaded = false; 250 | if ((capabilties_buffer[block_descriptor_length + 6] & 0x8) == 0) dev->canBeEjected = false; 251 | LOG_SATA("Can Load %d, Can Eject %d %d\n", dev->canBeLoaded, dev->canBeEjected); 252 | dev->state = CONFIGURED; 253 | return true; 254 | } 255 | } 256 | 257 | static bool CheckCDCapabilities(uint8_t dev_addr) { 258 | device_s *dev = getDevice(dev_addr); 259 | 260 | return tuh_msc_mode_sense(dev_addr, dev->lun, 0x2A, 0x0, 0x0, 128, &capabilties_buffer[0], mode_sense_complete_cb); 261 | } 262 | 263 | void CDROM_ready(uint8_t dev_addr, bool ready) { 264 | //Get capabilities in sync 265 | device_s *dev = getDevice(dev_addr); 266 | if (dev->state == ENUMERATED) { 267 | CheckCDCapabilities(dev_addr); 268 | } 269 | if (!ready) return; 270 | } 271 | 272 | bool CDROM_Inquiry(uint8_t dev_addr, uint8_t lun) { 273 | 274 | device_s *dev = getDevice(dev_addr); 275 | if (tuh_msc_get_block_size(dev_addr, lun) == 0) { 276 | return false; 277 | } 278 | dev->tray_open = false; //In case of slot-in consider it has started and tray is closed 279 | dev->useable = true; 280 | 281 | 282 | LOG_SATA("Use the CD as potential source\n"); 283 | dev->rawImage.dev_addr = dev->dev_addr; 284 | dev->rawImage.lun = dev->lun; 285 | // Get capacity of device 286 | dev->rawImage.hasOnlyAudio = true; 287 | dev->rawImage.nb_block = tuh_msc_get_block_count(dev_addr, lun); 288 | dev->rawImage.block_size = tuh_msc_get_block_size(dev_addr, lun); 289 | dev->rawImage.block_size_read = dev->rawImage.block_size; 290 | 291 | int lba = dev->rawImage.nb_block + 150; 292 | dev->rawImage.msf[0] = lba/(60*75); 293 | lba %= 60*75; 294 | dev->rawImage.msf[1] = lba / 75; 295 | dev->rawImage.msf[2] = lba % 75; 296 | 297 | //Assume type is CD-DA or CD-ROM always 298 | dev->rawImage.format = 0x0; /*00 CD-DA or CD-ROM / 10 CD-I / 20 XA */ 299 | 300 | LOG_SATA("Disk Size: %lu MB\r\n", dev->rawImage.nb_block / ((1024*1024)/dev->rawImage.block_size)); 301 | LOG_SATA("Block Count = %lu, Block Size: %lu\r\n", dev->rawImage.nb_block, dev->rawImage.block_size); 302 | LOG_SATA("Disc duration is %02d:%02d:%02d\n", dev->rawImage.msf[0], dev->rawImage.msf[1], dev->rawImage.msf[2]); 303 | 304 | if (!tuh_msc_read_toc(dev_addr, lun, readBuffer, 1, 0, 0, read_toc_light_complete_cb)) { 305 | LOG_SATA("Got error with toc read\n"); 306 | return false; 307 | } 308 | 309 | setCDSpeed(706); //4x speed 310 | 311 | return true; 312 | } 313 | 314 | #endif 315 | -------------------------------------------------------------------------------- /FATFs/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - Configuration file 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define FFCONF_DEF 89352 /* Revision ID */ 6 | 7 | #ifdef PLATFORM_RP2040 8 | #include "tusb_config.h" 9 | #endif 10 | 11 | /*---------------------------------------------------------------------------/ 12 | / Function Configurations 13 | /---------------------------------------------------------------------------*/ 14 | 15 | #define FF_FS_READONLY 0 16 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 17 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 18 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 19 | / and optional writing functions as well. */ 20 | 21 | 22 | #define FF_FS_MINIMIZE 0 23 | /* This option defines minimization level to remove some basic API functions. 24 | / 25 | / 0: Basic functions are fully enabled. 26 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 27 | / are removed. 28 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 29 | / 3: f_lseek() function is removed in addition to 2. */ 30 | 31 | 32 | #define FF_USE_STRFUNC 1 33 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). 34 | / 35 | / 0: Disable string functions. 36 | / 1: Enable without LF-CRLF conversion. 37 | / 2: Enable with LF-CRLF conversion. */ 38 | 39 | 40 | #define FF_USE_FIND 1 41 | /* This option switches filtered directory read functions, f_findfirst() and 42 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 43 | 44 | 45 | #define FF_USE_MKFS 0 46 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 47 | 48 | 49 | #define FF_USE_FASTSEEK 1 50 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 51 | 52 | 53 | #define FF_USE_EXPAND 0 54 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 55 | 56 | 57 | #define FF_USE_CHMOD 0 58 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 59 | / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ 60 | 61 | 62 | #define FF_USE_LABEL 0 63 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 64 | / (0:Disable or 1:Enable) */ 65 | 66 | 67 | #define FF_USE_FORWARD 0 68 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 69 | 70 | 71 | /*---------------------------------------------------------------------------/ 72 | / Locale and Namespace Configurations 73 | /---------------------------------------------------------------------------*/ 74 | 75 | #define FF_CODE_PAGE 437 76 | /* This option specifies the OEM code page to be used on the target system. 77 | / Incorrect code page setting can cause a file open failure. 78 | / 79 | / 437 - U.S. 80 | / 720 - Arabic 81 | / 737 - Greek 82 | / 771 - KBL 83 | / 775 - Baltic 84 | / 850 - Latin 1 85 | / 852 - Latin 2 86 | / 855 - Cyrillic 87 | / 857 - Turkish 88 | / 860 - Portuguese 89 | / 861 - Icelandic 90 | / 862 - Hebrew 91 | / 863 - Canadian French 92 | / 864 - Arabic 93 | / 865 - Nordic 94 | / 866 - Russian 95 | / 869 - Greek 2 96 | / 932 - Japanese (DBCS) 97 | / 936 - Simplified Chinese (DBCS) 98 | / 949 - Korean (DBCS) 99 | / 950 - Traditional Chinese (DBCS) 100 | / 0 - Include all code pages above and configured by f_setcp() 101 | */ 102 | 103 | 104 | #define FF_USE_LFN 1 105 | #define FF_MAX_LFN 127 106 | /* The FF_USE_LFN switches the support for LFN (long file name). 107 | / 108 | / 0: Disable LFN. FF_MAX_LFN has no effect. 109 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 110 | / 2: Enable LFN with dynamic working buffer on the STACK. 111 | / 3: Enable LFN with dynamic working buffer on the HEAP. 112 | / 113 | / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function 114 | / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and 115 | / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. 116 | / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can 117 | / be in range of 12 to 255. It is recommended to be set 255 to fully support LFN 118 | / specification. 119 | / When use stack for the working buffer, take care on stack overflow. When use heap 120 | / memory for the working buffer, memory management functions, ff_memalloc() and 121 | / ff_memfree() in ffsystem.c, need to be added to the project. */ 122 | 123 | 124 | #define FF_LFN_UNICODE 2 125 | /* This option switches the character encoding on the API when LFN is enabled. 126 | / 127 | / 0: ANSI/OEM in current CP (TCHAR = char) 128 | / 1: Unicode in UTF-16 (TCHAR = WCHAR) 129 | / 2: Unicode in UTF-8 (TCHAR = char) 130 | / 131 | / Also behavior of string I/O functions will be affected by this option. 132 | / When LFN is not enabled, this option has no effect. */ 133 | 134 | 135 | #define FF_LFN_BUF 127 136 | #define FF_SFN_BUF 12 137 | /* This set of options defines size of file name members in the FILINFO structure 138 | / which is used to read out directory items. These values should be suffcient for 139 | / the file names to read. The maximum possible length of the read file name depends 140 | / on character encoding. When LFN is not enabled, these options have no effect. */ 141 | 142 | 143 | #define FF_STRF_ENCODE 3 144 | /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), 145 | / f_putc(), f_puts and f_printf() convert the character encoding in it. 146 | / This option selects assumption of character encoding ON THE FILE to be 147 | / read/written via those functions. 148 | / 149 | / 0: ANSI/OEM in current CP 150 | / 1: Unicode in UTF-16LE 151 | / 2: Unicode in UTF-16BE 152 | / 3: Unicode in UTF-8 153 | */ 154 | 155 | 156 | #define FF_FS_RPATH 0 157 | /* This option configures support for relative path. 158 | / 159 | / 0: Disable relative path and remove related functions. 160 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 161 | / 2: f_getcwd() function is available in addition to 1. 162 | */ 163 | 164 | 165 | /*---------------------------------------------------------------------------/ 166 | / Drive/Volume Configurations 167 | /---------------------------------------------------------------------------*/ 168 | 169 | #define FF_VOLUMES 4 170 | /* Number of volumes (logical drives) to be used. (1-10) */ 171 | 172 | 173 | #define FF_STR_VOLUME_ID 0 174 | #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" 175 | /* FF_STR_VOLUME_ID switches string support for volume ID. 176 | / When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive 177 | / number in the path name. FF_VOLUME_STRS defines the drive ID strings for each 178 | / logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for 179 | / the drive ID strings are: A-Z and 0-9. */ 180 | 181 | 182 | #define FF_MULTI_PARTITION 0 183 | /* This option switches support for multiple volumes on the physical drive. 184 | / By default (0), each logical drive number is bound to the same physical drive 185 | / number and only an FAT volume found on the physical drive will be mounted. 186 | / When this function is enabled (1), each logical drive number can be bound to 187 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 188 | / funciton will be available. */ 189 | 190 | 191 | #define FF_MIN_SS 512 192 | #define FF_MAX_SS 512 193 | /* This set of options configures the range of sector size to be supported. (512, 194 | / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and 195 | / harddisk. But a larger value may be required for on-board flash memory and some 196 | / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured 197 | / for variable sector size mode and disk_ioctl() function needs to implement 198 | / GET_SECTOR_SIZE command. */ 199 | 200 | 201 | #define FF_USE_TRIM 0 202 | /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) 203 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 204 | / disk_ioctl() function. */ 205 | 206 | 207 | #define FF_FS_NOFSINFO 0 208 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 209 | / option, and f_getfree() function at first time after volume mount will force 210 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 211 | / 212 | / bit0=0: Use free cluster count in the FSINFO if available. 213 | / bit0=1: Do not trust free cluster count in the FSINFO. 214 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 215 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 216 | */ 217 | 218 | 219 | 220 | /*---------------------------------------------------------------------------/ 221 | / System Configurations 222 | /---------------------------------------------------------------------------*/ 223 | 224 | #define FF_FS_TINY 1 225 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 226 | / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. 227 | / Instead of private sector buffer eliminated from the file object, common sector 228 | / buffer in the filesystem object (FATFS) is used for the file data transfer. */ 229 | 230 | 231 | #define FF_FS_EXFAT 1 232 | /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) 233 | / When enable exFAT, also LFN needs to be enabled. 234 | / Note that enabling exFAT discards ANSI C (C89) compatibility. */ 235 | 236 | 237 | #define FF_FS_NORTC 0 238 | #define FF_NORTC_MON 1 239 | #define FF_NORTC_MDAY 1 240 | #define FF_NORTC_YEAR 2017 241 | /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have 242 | / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable 243 | / the timestamp function. All objects modified by FatFs will have a fixed timestamp 244 | / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. 245 | / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be 246 | / added to the project to read current time form real-time clock. FF_NORTC_MON, 247 | / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. 248 | / These options have no effect at read-only configuration (FF_FS_READONLY = 1). */ 249 | 250 | 251 | #define FF_FS_LOCK 10 252 | /* The option FF_FS_LOCK switches file lock function to control duplicated file open 253 | / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY 254 | / is 1. 255 | / 256 | / 0: Disable file lock function. To avoid volume corruption, application program 257 | / should avoid illegal open, remove and rename to the open objects. 258 | / >0: Enable file lock function. The value defines how many files/sub-directories 259 | / can be opened simultaneously under file lock control. Note that the file 260 | / lock control is independent of re-entrancy. */ 261 | 262 | 263 | #define FF_FS_REENTRANT 0 264 | #define FF_FS_TIMEOUT 1000 265 | #define FF_SYNC_t HANDLE 266 | /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 267 | / module itself. Note that regardless of this option, file access to different 268 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 269 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 270 | / to the same volume is under control of this function. 271 | / 272 | / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. 273 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 274 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 275 | / function, must be added to the project. Samples are available in 276 | / option/syscall.c. 277 | / 278 | / The FF_FS_TIMEOUT defines timeout period in unit of time tick. 279 | / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 280 | / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be 281 | / included somewhere in the scope of ff.h. */ 282 | 283 | /* #include // O/S definitions */ 284 | 285 | 286 | 287 | /*--- End of configuration options ---*/ 288 | -------------------------------------------------------------------------------- /FATFs/ff.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / FatFs - Generic FAT Filesystem module R0.13a / 3 | /-----------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2017, ChaN, all right reserved. 6 | / 7 | / FatFs module is an open source software. Redistribution and use of FatFs in 8 | / source and binary forms, with or without modification, are permitted provided 9 | / that the following condition is met: 10 | 11 | / 1. Redistributions of source code must retain the above copyright notice, 12 | / this condition and the following disclaimer. 13 | / 14 | / This software is provided by the copyright holder and contributors "AS IS" 15 | / and any warranties related to this software are DISCLAIMED. 16 | / The copyright owner or contributors be NOT LIABLE for any damages caused 17 | / by use of this software. 18 | / 19 | /----------------------------------------------------------------------------*/ 20 | 21 | 22 | #ifndef FF_DEFINED 23 | #define FF_DEFINED 89352 /* Revision ID */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "integer.h" /* Basic integer types */ 30 | #include "ffconf.h" /* FatFs configuration options */ 31 | 32 | #if FF_DEFINED != FFCONF_DEF 33 | #error Wrong configuration file (ffconf.h). 34 | #endif 35 | 36 | 37 | 38 | /* Definitions of volume management */ 39 | 40 | #if FF_MULTI_PARTITION /* Multiple partition configuration */ 41 | typedef struct { 42 | BYTE pd; /* Physical drive number */ 43 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 44 | } PARTITION; 45 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ 46 | #endif 47 | 48 | 49 | 50 | /* Type of path name strings on FatFs API */ 51 | 52 | #ifndef _INC_TCHAR 53 | #define _INC_TCHAR 54 | 55 | #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ 56 | typedef WCHAR TCHAR; 57 | #define _T(x) L ## x 58 | #define _TEXT(x) L ## x 59 | #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ 60 | typedef char TCHAR; 61 | #define _T(x) u8 ## x 62 | #define _TEXT(x) u8 ## x 63 | #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2) 64 | #error Wrong FF_LFN_UNICODE setting 65 | #else /* ANSI/OEM code in SBCS/DBCS */ 66 | typedef char TCHAR; 67 | #define _T(x) x 68 | #define _TEXT(x) x 69 | #endif 70 | 71 | #endif 72 | 73 | 74 | 75 | /* Type of file size variables */ 76 | 77 | #if FF_FS_EXFAT 78 | typedef QWORD FSIZE_t; 79 | #else 80 | typedef DWORD FSIZE_t; 81 | #endif 82 | 83 | 84 | 85 | /* Filesystem object structure (FATFS) */ 86 | 87 | typedef struct { 88 | BYTE fs_type; /* Filesystem type (0:N/A) */ 89 | BYTE pdrv; /* Physical drive number */ 90 | BYTE n_fats; /* Number of FATs (1 or 2) */ 91 | BYTE wflag; /* win[] flag (b0:dirty) */ 92 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 93 | WORD id; /* Volume mount ID */ 94 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 95 | WORD csize; /* Cluster size [sectors] */ 96 | #if FF_MAX_SS != FF_MIN_SS 97 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ 98 | #endif 99 | #if FF_USE_LFN 100 | WCHAR* lfnbuf; /* LFN working buffer */ 101 | #endif 102 | #if FF_FS_EXFAT 103 | BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ 104 | #endif 105 | #if FF_FS_REENTRANT 106 | FF_SYNC_t sobj; /* Identifier of sync object */ 107 | #endif 108 | #if !FF_FS_READONLY 109 | DWORD last_clst; /* Last allocated cluster */ 110 | DWORD free_clst; /* Number of free clusters */ 111 | #endif 112 | #if FF_FS_RPATH 113 | DWORD cdir; /* Current directory start cluster (0:root) */ 114 | #if FF_FS_EXFAT 115 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ 116 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ 117 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ 118 | #endif 119 | #endif 120 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ 121 | DWORD fsize; /* Size of an FAT [sectors] */ 122 | DWORD volbase; /* Volume base sector */ 123 | DWORD fatbase; /* FAT base sector */ 124 | DWORD dirbase; /* Root directory base sector/cluster */ 125 | DWORD database; /* Data base sector */ 126 | DWORD winsect; /* Current sector appearing in the win[] */ 127 | BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 128 | } FATFS; 129 | 130 | 131 | 132 | /* Object ID and allocation information (FFOBJID) */ 133 | 134 | typedef struct { 135 | FATFS* fs; /* Pointer to the hosting volume of this object */ 136 | WORD id; /* Hosting volume mount ID */ 137 | BYTE attr; /* Object attribute */ 138 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ 139 | DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ 140 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */ 141 | #if FF_FS_EXFAT 142 | DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ 143 | DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ 144 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ 145 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ 146 | DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ 147 | #endif 148 | #if FF_FS_LOCK 149 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 150 | #endif 151 | } FFOBJID; 152 | 153 | 154 | 155 | /* File object structure (FIL) */ 156 | 157 | typedef struct { 158 | FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ 159 | BYTE flag; /* File status flags */ 160 | BYTE err; /* Abort flag (error code) */ 161 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ 162 | DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ 163 | DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ 164 | #if !FF_FS_READONLY 165 | DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ 166 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ 167 | #endif 168 | #if FF_USE_FASTSEEK 169 | DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ 170 | #endif 171 | #if !FF_FS_TINY 172 | BYTE buf[FF_MAX_SS]; /* File private data read/write window */ 173 | #endif 174 | } FIL; 175 | 176 | 177 | 178 | /* Directory object structure (DIR) */ 179 | 180 | typedef struct { 181 | FFOBJID obj; /* Object identifier */ 182 | DWORD dptr; /* Current read/write offset */ 183 | DWORD clust; /* Current cluster */ 184 | DWORD sect; /* Current sector (0:Read operation has terminated) */ 185 | BYTE* dir; /* Pointer to the directory item in the win[] */ 186 | BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ 187 | #if FF_USE_LFN 188 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ 189 | #endif 190 | #if FF_USE_FIND 191 | const TCHAR* pat; /* Pointer to the name matching pattern */ 192 | #endif 193 | } DIR; 194 | 195 | 196 | 197 | /* File information structure (FILINFO) */ 198 | 199 | typedef struct { 200 | FSIZE_t fsize; /* File size */ 201 | WORD fdate; /* Modified date */ 202 | WORD ftime; /* Modified time */ 203 | BYTE fattrib; /* File attribute */ 204 | #if FF_USE_LFN 205 | TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ 206 | TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ 207 | #else 208 | TCHAR fname[12 + 1]; /* File name */ 209 | #endif 210 | } FILINFO; 211 | 212 | 213 | 214 | /* File function return code (FRESULT) */ 215 | 216 | typedef enum { 217 | FR_OK = 0, /* (0) Succeeded */ 218 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 219 | FR_INT_ERR, /* (2) Assertion failed */ 220 | FR_NOT_READY, /* (3) The physical drive cannot work */ 221 | FR_NO_FILE, /* (4) Could not find the file */ 222 | FR_NO_PATH, /* (5) Could not find the path */ 223 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 224 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 225 | FR_EXIST, /* (8) Access denied due to prohibited access */ 226 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 227 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 228 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 229 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 230 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 231 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ 232 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 233 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 234 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 235 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ 236 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 237 | } FRESULT; 238 | 239 | 240 | 241 | /*--------------------------------------------------------------*/ 242 | /* FatFs module application interface */ 243 | 244 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 245 | FRESULT f_close (FIL* fp); /* Close an open file object */ 246 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ 247 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ 248 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ 249 | FRESULT f_truncate (FIL* fp); /* Truncate the file */ 250 | FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ 251 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 252 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 253 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 254 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 255 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 256 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 257 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 258 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 259 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 260 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ 261 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ 262 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 263 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 264 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 265 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 266 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 267 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 268 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 269 | FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ 270 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 271 | FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ 272 | FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ 273 | FRESULT f_setcp (WORD cp); /* Set current code page */ 274 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 275 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 276 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 277 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 278 | 279 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) 280 | #define f_error(fp) ((fp)->err) 281 | #define f_tell(fp) ((fp)->fptr) 282 | #define f_size(fp) ((fp)->obj.objsize) 283 | #define f_rewind(fp) f_lseek((fp), 0) 284 | #define f_rewinddir(dp) f_readdir((dp), 0) 285 | #define f_rmdir(path) f_unlink(path) 286 | #define f_unmount(path) f_mount(0, path, 0) 287 | 288 | 289 | #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 290 | int pattern_matching (const TCHAR* pat, const TCHAR* nam, int skip, int inf); 291 | #define f_path_contains(path, pattern) pattern_matching(pattern, path, 0, 0) 292 | #endif 293 | #ifndef EOF 294 | #define EOF (-1) 295 | #endif 296 | 297 | 298 | 299 | 300 | /*--------------------------------------------------------------*/ 301 | /* Additional user defined functions */ 302 | 303 | /* RTC function */ 304 | #if !FF_FS_READONLY && !FF_FS_NORTC 305 | DWORD get_fattime (void); 306 | #endif 307 | 308 | /* LFN support functions */ 309 | #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ 310 | WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ 311 | WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ 312 | DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ 313 | #endif 314 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 315 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 316 | void ff_memfree (void* mblock); /* Free memory block */ 317 | #endif 318 | 319 | /* Sync functions */ 320 | #if FF_FS_REENTRANT 321 | int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ 322 | int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ 323 | void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ 324 | int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ 325 | #endif 326 | 327 | 328 | 329 | 330 | /*--------------------------------------------------------------*/ 331 | /* Flags and offset address */ 332 | 333 | 334 | /* File access mode and open method flags (3rd argument of f_open) */ 335 | #define FA_READ 0x01 336 | #define FA_WRITE 0x02 337 | #define FA_OPEN_EXISTING 0x00 338 | #define FA_CREATE_NEW 0x04 339 | #define FA_CREATE_ALWAYS 0x08 340 | #define FA_OPEN_ALWAYS 0x10 341 | #define FA_OPEN_APPEND 0x30 342 | 343 | /* Fast seek controls (2nd argument of f_lseek) */ 344 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1) 345 | 346 | /* Format options (2nd argument of f_mkfs) */ 347 | #define FM_FAT 0x01 348 | #define FM_FAT32 0x02 349 | #define FM_EXFAT 0x04 350 | #define FM_ANY 0x07 351 | #define FM_SFD 0x08 352 | 353 | /* Filesystem type (FATFS.fs_type) */ 354 | #define FS_FAT12 1 355 | #define FS_FAT16 2 356 | #define FS_FAT32 3 357 | #define FS_EXFAT 4 358 | 359 | /* File attribute bits for directory entry (FILINFO.fattrib) */ 360 | #define AM_RDO 0x01 /* Read only */ 361 | #define AM_HID 0x02 /* Hidden */ 362 | #define AM_SYS 0x04 /* System */ 363 | #define AM_DIR 0x10 /* Directory */ 364 | #define AM_ARC 0x20 /* Archive */ 365 | 366 | 367 | #ifdef __cplusplus 368 | } 369 | #endif 370 | 371 | #endif /* FF_DEFINED */ 372 | -------------------------------------------------------------------------------- /src/interfaces/MSC.c: -------------------------------------------------------------------------------- 1 | #include "3DO.h" 2 | #include "MSC.h" 3 | #include "CDFormat.h" 4 | #include "pico/stdio.h" 5 | 6 | #include "diskio.h" 7 | 8 | 9 | /* ------------------------------------------- 10 | - Thanks to https://github.com/trapexit/3dt for 3do image detection and filesystem extraction 11 | ---------------------------------------------*/ 12 | 13 | FIL curDataFile; 14 | char *curFilePath = NULL; 15 | static bool curFileMode = false; 16 | 17 | typedef enum { 18 | BOOT_ISO = 1, 19 | BOOT_PLAYLIST, 20 | } mount_mode; 21 | 22 | static mount_mode onMountMode = BOOT_ISO; 23 | 24 | #define PLAYLIST_MAX 16 25 | typedef struct playlist_entry_s{ 26 | char *path[PLAYLIST_MAX]; 27 | int tocid[PLAYLIST_MAX]; 28 | int nb_entries; 29 | int current_entry; 30 | } playlist_entry; 31 | 32 | playlist_entry playlist = {0}; 33 | 34 | extern uint32_t start_Block; 35 | extern uint32_t nb_block_Block; 36 | extern uint8_t *buffer_Block; 37 | extern bool blockRequired; 38 | 39 | extern bool read_done; 40 | extern fileCmd_s fileCmdRequired; 41 | 42 | extern bool subqRequired; 43 | extern uint8_t *buffer_subq; 44 | 45 | extern volatile bool usb_result; 46 | 47 | bool onBootIso = false; 48 | 49 | 50 | #define SELECTED_IMAGE 22 51 | 52 | #define TOC_NAME_LIMIT 128 53 | 54 | #if CFG_TUH_MSC 55 | static bool check_eject(uint8_t dev_addr); 56 | static void check_load(uint8_t dev_addr); 57 | static void check_block(uint8_t dev_addr); 58 | static void check_file(uint8_t dev_addr); 59 | static void check_subq(uint8_t dev_addr); 60 | #endif 61 | 62 | static bool handleBootImage(uint8_t dev_addr); 63 | 64 | static FSIZE_t last_pos = 0; 65 | 66 | static FIL file; 67 | 68 | static int current_toc = 0x00000000; 69 | static int current_toc_level = 0; 70 | // static int current_toc_index = 0xFF; 71 | static int current_toc_offset = 0; 72 | 73 | int getPlaylistEntries() { 74 | return playlist.nb_entries; 75 | } 76 | 77 | void updatePlayListEntries() { 78 | if (getPlaylistEntries() != 0) { 79 | if (playlist.current_entry == playlist.nb_entries) { 80 | LOG_SATA("Playlist done - clearing\n"); 81 | clearPlaylist(); 82 | current_toc_level = 0; 83 | current_toc = 0x00000000; 84 | f_closedir(¤tImage.curDir->dir); 85 | if (currentImage.curPath != NULL) free(currentImage.curPath); 86 | currentImage.curPath = NULL; 87 | } 88 | } 89 | } 90 | 91 | bool MSC_Host_loop(device_s *dev) 92 | { 93 | #if CFG_TUH_MSC 94 | if (!usb_cmd_on_going) { 95 | switch(dev->state) { 96 | case EJECTING: 97 | check_eject(dev->dev_addr); 98 | case MOUNTED: 99 | check_load(dev->dev_addr); 100 | check_file(dev->dev_addr); 101 | check_block(dev->dev_addr); 102 | check_subq(dev->dev_addr); 103 | return true; 104 | break; 105 | default: 106 | return false; 107 | } 108 | } 109 | #endif 110 | return false; 111 | } 112 | 113 | 114 | #if CFG_TUH_MSC 115 | 116 | //--------------------------------------------------------------------+ 117 | // MACRO TYPEDEF CONSTANT ENUM DECLARATION 118 | //--------------------------------------------------------------------+ 119 | 120 | static bool startClose = true; 121 | 122 | static bool validateFile(FILINFO* fileInfo); 123 | static bool getNextValidToc(FILINFO *fileInfo); 124 | 125 | 126 | extern volatile bool is_audio; 127 | extern volatile bool has_subQ; 128 | 129 | #define NB_SUPPORTED_GAMES 100 130 | 131 | char* curBinPath; //same number as tracks number 132 | FIL curBinFile; 133 | 134 | char *curBuf = NULL; 135 | uint16_t curBufLength = 0; 136 | 137 | static void print_error_text(FRESULT e) { 138 | switch (e) { 139 | case 0: return; //FR_OK = 0, /* (0) Succeeded */ 140 | case 1: printf("FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */"); break; 141 | case 2: printf("FR_INT_ERR, /* (2) Assertion failed */"); break; 142 | case 3: printf("FR_NOT_READY, /* (3) The physical drive cannot work */"); break; 143 | case 4: printf("FR_NO_FILE, /* (4) Could not find the file */"); break; 144 | case 5: printf("FR_NO_PATH, /* (5) Could not find the path */"); break; 145 | case 6: printf("FR_INVALID_NAME, /* (6) The path name format is invalid */"); break; 146 | case 7: printf("FR_DENIED, /* (7) Access denied due to prohibited access or directory full */"); break; 147 | case 8: printf("FR_EXIST, /* (8) Access denied due to prohibited access */"); break; 148 | case 9: printf("FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */"); break; 149 | case 10: printf("FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */"); break; 150 | case 11: printf("FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */"); break; 151 | case 12: printf("FR_NOT_ENABLED, /* (12) The volume has no work area */"); break; 152 | case 13: printf("FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */"); break; 153 | case 14: printf("FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */"); break; 154 | case 15: printf("FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */"); break; 155 | case 16: printf("FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */"); break; 156 | case 17: printf("FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */"); break; 157 | case 18: printf("FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */"); break; 158 | case 19: printf("FR_INVALID_PARAMETER /* (19) Given parameter is invalid */"); break; 159 | default: printf("Unrecognised error %d", e); 160 | } 161 | printf("\n"); 162 | } 163 | 164 | static bool check_eject(uint8_t dev_addr) { 165 | //Execute right now 166 | if (dev_addr == currentImage.dev_addr) return false; 167 | LOG_SATA("Eject\n"); 168 | return true; 169 | } 170 | 171 | 172 | void requestBootImage() { 173 | requestLoad = true; 174 | } 175 | 176 | void waitForLoad() { 177 | while(requestLoad); 178 | } 179 | 180 | static void check_load(uint8_t dev_addr) { 181 | device_s *dev = getDevice(dev_addr); 182 | if (requestLoad && dev->isFatFs) { 183 | //Execute right now 184 | requestLoad = !handleBootImage(dev_addr); 185 | } 186 | } 187 | 188 | 189 | static void check_subq(uint8_t dev_addr) { 190 | if (currentImage.dev_addr == 0xFF) return; 191 | if (subqRequired && (dev_addr == currentImage.dev_addr)) { 192 | bool found = false; 193 | usb_cmd_on_going = true; 194 | cd_s *target_track = ¤tImage; 195 | memset(buffer_subq, 0x0, 16); 196 | uint lba = start_Block + 150; 197 | buffer_subq[9] = lba/(60*75); 198 | lba %= 60*75; 199 | buffer_subq[10] = lba / 75; 200 | buffer_subq[11] = lba % 75; 201 | lba = start_Block; 202 | for (int i = 0; ilast_track; i++) 203 | { 204 | if (target_track->tracks[i].lba <= start_Block) { 205 | buffer_subq[5] = target_track->tracks[i].CTRL_ADR; 206 | buffer_subq[6] = target_track->tracks[i].id; 207 | buffer_subq[7] = 1; 208 | lba = start_Block - target_track->tracks[i].lba; 209 | buffer_subq[13] = lba/(60*75); 210 | lba %= 60*75; 211 | buffer_subq[14] = lba / 75; 212 | buffer_subq[15] = lba % 75; 213 | found = true; 214 | } else { 215 | break; 216 | } 217 | } 218 | usb_cmd_on_going = false; 219 | subqRequired = false; 220 | read_done = true; 221 | } 222 | } 223 | 224 | void printPlaylist(void) { 225 | LOG_SATA("Playlist:\n"); 226 | for (int i =0; i= PLAYLIST_MAX) { 255 | *valid = false; 256 | *added = false; 257 | return; 258 | } 259 | *added = true; 260 | playlist.tocid[playlist.nb_entries] = entry; 261 | playlist.path[playlist.nb_entries++] = entry_path; 262 | LOG_SATA("Add to playlist %s %d\n", entry_path, playlist.nb_entries); 263 | } 264 | 265 | static void check_block(uint8_t dev_addr) { 266 | if (currentImage.dev_addr == 0xFF) return; 267 | if (blockRequired && (dev_addr == currentImage.dev_addr)) { 268 | usb_cmd_on_going = true; 269 | 270 | cd_s *target_track = ¤tImage; 271 | FIL *fileOpen = &curBinFile; 272 | uint read_nb = 0; 273 | FSIZE_t offset = (start_Block - target_track->tracks[0].lba)*currentImage.block_size + currentImage.offset; 274 | if (currentImage.block_size != currentImage.block_size_read) { 275 | if (currentImage.format != 0) { 276 | //Assuming a XA format has only MODE_2 and CDDA track 277 | if (currentImage.block_size_read == 2048) { 278 | //Mode 2 Form1 279 | offset += 12 + 4 + 8; //Skip Sync, Header and subHeader 280 | } 281 | } else { 282 | //Mode 1 or CDDA 283 | if (currentImage.block_size_read == 2048) { 284 | //Mode 1 285 | offset += 12 + 4; //Skip Sync and Header 286 | } 287 | } 288 | } 289 | if (last_pos != offset) 290 | if (f_lseek(fileOpen, offset) != FR_OK) LOG_SATA("Can not seek %s\n", curBinPath); 291 | last_pos = offset; 292 | if (is_audio) { 293 | if (has_subQ) { 294 | //Work only for 1 block here 295 | FSIZE_t data_offset = 0; 296 | 297 | if (f_read(fileOpen, &buffer_Block[data_offset], currentImage.block_size, &read_nb) != FR_OK) LOG_SATA("Can not read %s\n", curBinPath); 298 | data_offset += read_nb; 299 | for (int i = currentImage.block_size; i < currentImage.block_size_read; i++) { 300 | buffer_Block[data_offset++] = 0; 301 | } 302 | } else { 303 | if (f_read(fileOpen, &buffer_Block[0], currentImage.block_size_read, &read_nb) != FR_OK) LOG_SATA("Can not read %s\n", curBinPath); 304 | } 305 | } else { 306 | if (f_read(fileOpen, buffer_Block, nb_block_Block*currentImage.block_size_read, &read_nb) != FR_OK) LOG_SATA("Can not read %s\n", curBinPath); 307 | if (read_nb != nb_block_Block*currentImage.block_size_read) LOG_SATA("Bad read %d %d\n", read_nb, nb_block_Block*currentImage.block_size_read); 308 | last_pos += read_nb; 309 | } 310 | usb_cmd_on_going = false; 311 | blockRequired = false; 312 | read_done = true; 313 | } 314 | } 315 | 316 | static bool is_3do_iso(uint8_t* buf) { 317 | uint8_t VOLUME_SYNC_BYTES[] = {0x5A,0x5A,0x5A,0x5A,0x5A}; 318 | 319 | if(buf[0] != 0x01) 320 | return false; 321 | 322 | if(memcmp(&buf[1],&VOLUME_SYNC_BYTES[0],sizeof(VOLUME_SYNC_BYTES)) != 0) 323 | return false; 324 | 325 | if(buf[6] != 0x01) 326 | return false; 327 | 328 | return true; 329 | } 330 | 331 | 332 | static bool is_mode1_2352(uint8_t* buf) { 333 | uint8_t MODE1_SYNC_PATTERN[] = {0x00,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x00}; 334 | if(memcmp(&buf[0],&MODE1_SYNC_PATTERN[0],sizeof(MODE1_SYNC_PATTERN))!= 0) 335 | return false; 336 | 337 | if(buf[0x0F] != 0x01) 338 | return false; 339 | 340 | return is_3do_iso(&buf[0x10]); 341 | } 342 | 343 | static bool isA3doImage(char * path) { 344 | FIL myFile; 345 | FRESULT fr; 346 | uint8_t buf[0x20]; 347 | uint read_nb = 0; 348 | bool ret = false; 349 | fr = f_open(&myFile, path, FA_READ); 350 | if (fr){ 351 | return false; 352 | } 353 | 354 | if (f_read(&myFile, &buf, 0x20, &read_nb) != FR_OK) { 355 | f_close(&myFile); 356 | return false; 357 | } 358 | if (read_nb != 0x20) { 359 | f_close(&myFile); 360 | return false; 361 | } 362 | 363 | ret = ((is_mode1_2352(&buf[0])) || (is_3do_iso(&buf[0]))); 364 | f_close(&myFile); 365 | return ret; 366 | } 367 | 368 | static bool LoadfromCue(char *filePath) { 369 | if (currentImage.dev_addr == 0xFF) return; 370 | FIL myFile; 371 | FRESULT fr; 372 | bool valid = false; 373 | char line[100]; 374 | unsigned int track_num = 0; 375 | LOG_SATA("Load From Cue %s\n", filePath); 376 | fr = f_open(&myFile, filePath, FA_READ); 377 | if (fr){ 378 | LOG_SATA("can not open %s for reading\n",filePath); 379 | return false; 380 | } 381 | 382 | // Time to generate TOC 383 | for (;;) 384 | { 385 | currentImage.nb_track = 0; 386 | /* Read every line and display it */ 387 | while (f_gets(line, sizeof line, &myFile)) { 388 | valid = true; 389 | char line_end[100]; 390 | char line_start[100]; 391 | if (sscanf(line, " %s %[^\r\n]\r\n", line_start, line_end) != EOF) { 392 | if (strncmp(line_start, "FILE", 4) == 0) { 393 | FILINFO binInfo; 394 | char filename[100]; 395 | char *lastDir = rindex(filePath, '\\'); 396 | char * testPath; 397 | char *newPath = malloc(lastDir - filePath + 1); 398 | memcpy(newPath, filePath, lastDir - filePath); 399 | newPath[lastDir-filePath] = 0; 400 | 401 | sscanf(line_end, " \"%[^\"]\"", filename); 402 | testPath = malloc(strlen(newPath)+strlen(filename)+2); 403 | sprintf(&testPath[0], "%s\\%s", newPath, filename); 404 | free(newPath); 405 | if (curBinPath != NULL) free(curBinPath); 406 | curBinPath = testPath; 407 | fr = f_stat(curBinPath, &binInfo); 408 | if (fr == FR_NO_FILE) { 409 | free(curBinPath); 410 | curBinPath = NULL; 411 | valid = false; 412 | break; //Bin file does not exists 413 | } 414 | if (binInfo.fattrib & AM_DIR) { 415 | free(curBinPath); 416 | curBinPath = NULL; 417 | valid = false; 418 | break; //not a file 419 | } 420 | currentImage.nb_block = binInfo.fsize; 421 | continue; 422 | } 423 | if (strncmp(line_start, "TRACK", 5) == 0) { 424 | unsigned int sector_size = 0; 425 | unsigned int ctl_addr = 0; 426 | if (sscanf(line_end, " %u %[^\r\n]\r\n", &track_num, line_end) != EOF) 427 | { 428 | if (strncmp(line_end, "MODE1", 5) == 0) 429 | { 430 | // Figure out the track sector size 431 | if (!isA3doImage(curBinPath)) { 432 | valid = false; 433 | break; 434 | } 435 | currentImage.block_size = atoi(line_end + 6); 436 | currentImage.block_size_read = 2048; 437 | currentImage.tracks[track_num - 1].CTRL_ADR = 0x4; 438 | currentImage.tracks[track_num - 1].id = track_num; 439 | currentImage.tracks[track_num - 1].mode = MODE_1; 440 | } 441 | else if (strncmp(line_end, "MODE2", 5) == 0) 442 | { 443 | //PhotoCD cue file 444 | // Figure out the track sector size 445 | currentImage.block_size = currentImage.block_size_read = atoi(line_end + 6); 446 | currentImage.block_size_read = 2048; 447 | currentImage.tracks[track_num - 1].CTRL_ADR = 0x4; 448 | currentImage.tracks[track_num - 1].id = track_num; 449 | currentImage.tracks[track_num - 1].mode = MODE_2; 450 | } 451 | else if (strncmp(line_end, "AUDIO", 5) == 0) 452 | { 453 | // // Update toc entry 454 | currentImage.block_size = 2352; //(98 * (24)) 455 | currentImage.block_size_read = 2352; // 98*24 456 | currentImage.tracks[track_num - 1].CTRL_ADR = 0x0; 457 | currentImage.tracks[track_num - 1].id = track_num; 458 | currentImage.tracks[track_num - 1].mode = CDDA; 459 | } 460 | else { 461 | valid = false; 462 | break; 463 | } 464 | currentImage.nb_track++; 465 | } else { 466 | valid = false; 467 | break; 468 | } 469 | continue; 470 | } 471 | else if (strncmp(line_start, "INDEX", 5) == 0) 472 | { 473 | unsigned int indexnum, min, sec, frame; 474 | if (sscanf(line_end, " %u %u:%u:%u\r\n", &indexnum, &min, &sec, &frame) == EOF) { 475 | valid = false; 476 | break; 477 | } 478 | 479 | if (indexnum == 1) 480 | { 481 | currentImage.tracks[track_num - 1].msf[0] = min; 482 | currentImage.tracks[track_num - 1].msf[1] = sec + 2; 483 | currentImage.tracks[track_num - 1].msf[2] = frame; 484 | currentImage.tracks[track_num - 1].lba = min*60*75+sec*75+frame; 485 | } 486 | } 487 | #ifdef USE_PRE_POST_GAP 488 | else if (strncmp(line_start, "PREGAP", 6) == 0) 489 | { 490 | if (sscanf(line_end, " %d:%d:%d\r\n", &min, &sec, &frame) == EOF) 491 | break; 492 | 493 | // pregap += MSF_TO_FAD(min, sec, frame); 494 | } 495 | else if (strncmp(line_start, "POSTGAP", 7) == 0) 496 | { 497 | if (sscanf(line_end, " %d:%d:%d\r\n", &min, &sec, &frame) == EOF) 498 | break; 499 | } 500 | #endif 501 | } 502 | } 503 | /* Close the file */ 504 | f_close(&myFile); 505 | break; 506 | } 507 | if (valid) { 508 | currentImage.first_track = 1; 509 | currentImage.last_track = currentImage.nb_track; 510 | currentImage.hasOnlyAudio = true; 511 | currentImage.format = 0x0; 512 | for (int i = 0; ifname); 535 | FRESULT fr; 536 | bool valid = false; 537 | char line[100]; 538 | unsigned int track_num = 0; 539 | char *newPath = malloc(strlen(currentImage.curPath)+i+2); 540 | sprintf(&newPath[0], "%s\\%s", currentImage.curPath, fileInfo->fname); 541 | fr = f_open(&myFile, newPath, FA_READ); 542 | if (fr){ 543 | LOG_SATA("can not open %s for reading\n",newPath); 544 | return false; 545 | } 546 | 547 | LOG_SATA("Validate Game %s\n", newPath); 548 | // Time to generate TOC 549 | for (;;) 550 | { 551 | /* Read every line and display it */ 552 | while (f_gets(line, sizeof line, &myFile)) { 553 | valid = true; 554 | char line_end[100]; 555 | char line_start[100]; 556 | if (sscanf(line, " %s %[^\r\n]\r\n", line_start, line_end) != EOF) { 557 | if (strncmp(line_start, "FILE", 4) == 0) { 558 | FILINFO binInfo; 559 | char filename[100]; 560 | char * testPath; 561 | sscanf(line_end, " \"%[^\"]\"", filename); 562 | testPath = malloc(strlen(currentImage.curPath)+strlen(filename)+2); 563 | sprintf(&testPath[0], "%s\\%s", currentImage.curPath, filename); 564 | fr = f_stat(testPath, &binInfo); 565 | free(testPath); 566 | if (fr == FR_NO_FILE) { 567 | valid = false; 568 | break; //Bin file does not exists 569 | } 570 | if (binInfo.fattrib & AM_DIR) { 571 | valid = false; 572 | break; //not a file 573 | } 574 | // currentImage.nb_block = binInfo.fsize; 575 | continue; 576 | } 577 | if (strncmp(line_start, "TRACK", 5) == 0) { 578 | unsigned int sector_size = 0; 579 | unsigned int ctl_addr = 0; 580 | if (sscanf(line_end, " %u %[^\r\n]\r\n", &track_num, line_end) != EOF) 581 | { 582 | if (strncmp(line_end, "MODE1", 5) == 0) 583 | { 584 | // Figure out the track sector size 585 | if (!isA3doImage(curBinPath)) { 586 | valid = false; 587 | break; 588 | } 589 | // currentImage.block_size = atoi(line_end + 6); 590 | // currentImage.block_size_read = 2048; 591 | // currentImage.tracks[track_num - 1].CTRL_ADR = 0x4; 592 | // currentImage.tracks[track_num - 1].id = track_num; 593 | // currentImage.tracks[track_num - 1].mode = MODE_1; 594 | } 595 | else if (strncmp(line_end, "MODE2", 5) == 0) 596 | { 597 | //PhotoCD cue file 598 | // Figure out the track sector size 599 | // currentImage.block_size = currentImage.block_size_read = atoi(line_end + 6); 600 | // currentImage.block_size_read = 2048; 601 | // currentImage.tracks[track_num - 1].CTRL_ADR = 0x4; 602 | // currentImage.tracks[track_num - 1].id = track_num; 603 | // currentImage.tracks[track_num - 1].mode = MODE_2; 604 | } 605 | else if (strncmp(line_end, "AUDIO", 5) == 0) 606 | { 607 | // // Update toc entry 608 | // currentImage.block_size = 2352; //(98 * (24)) 609 | // currentImage.block_size_read = 2352; // 98*24 610 | // currentImage.tracks[track_num - 1].CTRL_ADR = 0x0; 611 | // currentImage.tracks[track_num - 1].id = track_num; 612 | // currentImage.tracks[track_num - 1].mode = CDDA; 613 | } 614 | else { 615 | valid = false; 616 | break; 617 | } 618 | // currentImage.nb_track++; 619 | } else { 620 | valid = false; 621 | break; 622 | } 623 | continue; 624 | } 625 | else if (strncmp(line_start, "INDEX", 5) == 0) 626 | { 627 | unsigned int indexnum, min, sec, frame; 628 | if (sscanf(line_end, " %u %u:%u:%u\r\n", &indexnum, &min, &sec, &frame) == EOF) { 629 | valid = false; 630 | break; 631 | } 632 | 633 | // if (indexnum == 1) 634 | // { 635 | // currentImage.tracks[track_num - 1].msf[0] = min; 636 | // currentImage.tracks[track_num - 1].msf[1] = sec + 2; 637 | // currentImage.tracks[track_num - 1].msf[2] = frame; 638 | // currentImage.tracks[track_num - 1].lba = min*60*75+sec*75+frame; 639 | // } 640 | } 641 | #ifdef USE_PRE_POST_GAP 642 | else if (strncmp(line_start, "PREGAP", 6) == 0) 643 | { 644 | if (sscanf(line_end, " %d:%d:%d\r\n", &min, &sec, &frame) == EOF) 645 | break; 646 | 647 | // pregap += MSF_TO_FAD(min, sec, frame); 648 | } 649 | else if (strncmp(line_start, "POSTGAP", 7) == 0) 650 | { 651 | if (sscanf(line_end, " %d:%d:%d\r\n", &min, &sec, &frame) == EOF) 652 | break; 653 | } 654 | #endif 655 | } 656 | } 657 | /* Close the file */ 658 | f_close(&myFile); 659 | break; 660 | } 661 | return valid; 662 | } 663 | 664 | static bool ValidateInfofromIso(FILINFO *fileInfo) { 665 | if (currentImage.dev_addr == 0xFF) return; 666 | FIL myFile; 667 | UINT i = strlen(fileInfo->fname); 668 | FRESULT fr; 669 | char *newPath = malloc(strlen(currentImage.curPath)+i+2); 670 | sprintf(&newPath[0], "%s\\%s", currentImage.curPath, fileInfo->fname); 671 | if (!isA3doImage(newPath)) { 672 | return false; 673 | } 674 | 675 | return true; 676 | } 677 | 678 | static bool LoadfromIso(char *filePath) { 679 | if (currentImage.dev_addr == 0xFF) return false; 680 | FIL myFile; 681 | FILINFO fileInfo; 682 | FRESULT fr; 683 | if (!isA3doImage(filePath)) { 684 | return false; 685 | } 686 | fr = f_stat(filePath, &fileInfo); 687 | if ((fileInfo.fsize % 2352)==0) { 688 | currentImage.block_size = 2352; 689 | currentImage.offset = 16; 690 | } else if ((fileInfo.fsize % 2048)==0) { 691 | currentImage.block_size = 2048; 692 | currentImage.offset = 0; 693 | } else { 694 | //Bad format 695 | LOG_SATA("File is %d bytes length\n", fileInfo.fsize); 696 | return false; 697 | } 698 | 699 | LOG_SATA("Load Game %s\n", filePath); 700 | 701 | if (curBinPath != NULL) free(curBinPath); 702 | curBinPath = filePath; 703 | 704 | currentImage.block_size_read = currentImage.block_size; 705 | 706 | currentImage.nb_block = fileInfo.fsize / currentImage.block_size; 707 | 708 | currentImage.first_track = 1; 709 | currentImage.last_track = 1; 710 | currentImage.nb_track = 1; 711 | currentImage.hasOnlyAudio = false; 712 | currentImage.format = 0x0; //MODE1 always 713 | 714 | currentImage.tracks[0].CTRL_ADR = 0x4; 715 | 716 | currentImage.tracks[0].msf[0] = 0; 717 | currentImage.tracks[0].msf[1] = 2; 718 | currentImage.tracks[0].msf[2] = 0; 719 | currentImage.tracks[0].lba = 0; 720 | currentImage.tracks[0].mode = MODE_1; 721 | currentImage.tracks[0].id = 1; 722 | 723 | int lba = currentImage.nb_block + 150; 724 | currentImage.msf[0] = lba/(60*75); 725 | lba %= 60*75; 726 | currentImage.msf[1] = lba / 75; 727 | currentImage.msf[2] = lba % 75; 728 | 729 | return true; 730 | } 731 | 732 | 733 | static bool extractBootImage(FILINFO *fileInfo, char* curPath, uint8_t dev_addr) { 734 | if (currentImage.dev_addr != 0xFF) return; 735 | FIL myFile; 736 | UINT i = strlen(fileInfo->fname); 737 | FRESULT fr; 738 | char *newPath = malloc(strlen(curPath)+i+2); 739 | sprintf(&newPath[0], "%s\\%s", curPath, fileInfo->fname); 740 | if (!isA3doImage(newPath)) { 741 | LOG_SATA("Is not a 3DO image %s\n", curPath); 742 | free(newPath); 743 | return false; 744 | } 745 | if (((fileInfo->fsize % 2352)!=0) && ((fileInfo->fsize % 2048)!=0)){ 746 | LOG_SATA("File is %d bytes length\n", fileInfo->fsize); 747 | free(newPath); 748 | return false; 749 | } 750 | if ((fileInfo->fsize % 2352)==0) { 751 | currentImage.block_size = 2352; 752 | currentImage.offset = 16; 753 | } else if ((fileInfo->fsize % 2048)==0) { 754 | currentImage.block_size = 2048; 755 | currentImage.offset = 0; 756 | } 757 | 758 | if (curBinPath != NULL) free(curBinPath); 759 | 760 | device_s *dev = getDevice(dev_addr); 761 | currentImage.dev_addr = dev->dev_addr; 762 | currentImage.lun = dev->lun; 763 | 764 | if (currentImage.curPath != NULL) free(currentImage.curPath); 765 | currentImage.curPath = curPath; 766 | 767 | curBinPath = newPath; 768 | 769 | currentImage.block_size_read = currentImage.block_size; 770 | 771 | currentImage.nb_block = fileInfo->fsize / currentImage.block_size; 772 | 773 | currentImage.first_track = 1; 774 | currentImage.last_track = 1; 775 | currentImage.nb_track = 1; 776 | currentImage.hasOnlyAudio = false; 777 | currentImage.format = 0x0; //MODE1 always 778 | 779 | currentImage.tracks[0].CTRL_ADR = 0x4; 780 | 781 | currentImage.tracks[0].msf[0] = 0; 782 | currentImage.tracks[0].msf[1] = 2; 783 | currentImage.tracks[0].msf[2] = 0; 784 | currentImage.tracks[0].lba = 0; 785 | currentImage.tracks[0].mode = MODE_1; 786 | currentImage.tracks[0].id = 1; 787 | 788 | int lba = currentImage.nb_block + 150; 789 | currentImage.msf[0] = lba/(60*75); 790 | lba %= 60*75; 791 | currentImage.msf[1] = lba / 75; 792 | currentImage.msf[2] = lba % 75; 793 | return true; 794 | } 795 | 796 | static bool validateFile(FILINFO* fileInfo) { 797 | if (f_path_contains(fileInfo->fname,"*.cue")){ 798 | return ValidateInfofromCue(fileInfo); 799 | } 800 | if (f_path_contains(fileInfo->fname,"*.iso")){ 801 | return ValidateInfofromIso(fileInfo); 802 | } 803 | return false; 804 | } 805 | 806 | static bool loadFile(char* filepath) { 807 | if (f_path_contains(filepath,"*.cue")){ 808 | return LoadfromCue(filepath); 809 | } 810 | if (f_path_contains(filepath,"*.iso")){ 811 | return LoadfromIso(filepath); 812 | } 813 | return false; 814 | } 815 | 816 | static dir_t* getNewDir(void) { 817 | dir_t * ret=(dir_t*)malloc(sizeof(dir_t)); 818 | return ret; 819 | } 820 | 821 | #define MAX_LEVEL 3 822 | int level = -1; 823 | static bool buildDir(dir_t *dirInfo, char *path) { 824 | FILINFO fileInfo; 825 | bool ended = false; 826 | bool hasGame = false; 827 | level++; 828 | LOG_SATA("Explore %s (%d)\n", path, level); 829 | FRESULT res = f_findfirst(&dirInfo->dir, &fileInfo, path, "*"); 830 | do { 831 | ended = (strlen(fileInfo.fname) == 0) || (level >= 2) || (res != FR_OK); 832 | if (!ended) { 833 | bool isDir = (fileInfo.fattrib & AM_DIR); 834 | if (isDir && !(fileInfo.fname[0] == '.' || fileInfo.fattrib & (AM_HID | AM_SYS))) { // skip hidden or system files 835 | FRESULT res; 836 | dir_t* new_dir = getNewDir(); 837 | UINT i = strlen(fileInfo.fname); 838 | char *newPath = malloc(strlen(path)+i+2); 839 | sprintf(&newPath[0], "%s\\%s", path, fileInfo.fname); 840 | res = f_opendir(&(new_dir->dir), newPath); 841 | hasGame |= buildDir(new_dir, newPath); 842 | 843 | f_closedir(&(new_dir->dir)); 844 | } else { 845 | hasGame |= f_path_contains(fileInfo.fname,"*.cue"); //Verifier le parsing et le cue 846 | // hasGame |= f_path_contains(fileInfo.fname,"*.bin"); //Verifier le parsing et le cue 847 | hasGame |= f_path_contains(fileInfo.fname,"*.iso"); //Verifier le parsing et le cue 848 | } 849 | res = f_findnext(&dirInfo->dir, &fileInfo); 850 | } 851 | } while(!ended); 852 | level--; 853 | return hasGame; 854 | } 855 | 856 | bool loadPlaylistEntry(uint8_t dev_addr) { 857 | bool ret = false; 858 | bool loaded = false; 859 | FRESULT res; 860 | FILINFO fileInfo; 861 | LOG_SATA("try to load (%x) %d %s\n", playlist.tocid[playlist.current_entry], playlist.current_entry, playlist.path[playlist.current_entry]); 862 | device_s *new_dev = getDevice(playlist.tocid[playlist.current_entry]>>24); 863 | if (getTocEntry(playlist.tocid[playlist.current_entry]) == 0x0) { 864 | //Entry detected as device 865 | LOG_SATA("Detected an entry\n"); 866 | device_s *dev = getDevice(dev_addr); 867 | memcpy(¤tImage, &new_dev->rawImage, sizeof(cd_s)); 868 | new_dev->state = MOUNTED; 869 | usb_cmd_on_going = false; 870 | set3doCDReady(new_dev->dev_addr, true); 871 | set3doDriveMounted(new_dev->dev_addr, true); 872 | loaded = true; 873 | ret = true; 874 | } else { 875 | LOG_SATA("Try to load\n"); 876 | currentImage.dev_addr = new_dev->dev_addr; 877 | currentImage.lun = new_dev->lun; 878 | if (loadFile(playlist.path[playlist.current_entry])) { 879 | LOG_SATA("Load entry %d\n",playlist.current_entry); 880 | loaded = true; 881 | if (f_open(&curBinFile, curBinPath, FA_READ) == FR_OK) { 882 | device_s *dev = getDevice(dev_addr); 883 | LOG_SATA("Game loaded\n"); 884 | last_pos = 0; 885 | dev->state = MOUNTED; 886 | usb_cmd_on_going = false; 887 | set3doCDReady(currentImage.dev_addr, true); 888 | set3doDriveMounted(currentImage.dev_addr, true); 889 | ret = true; 890 | } else { 891 | LOG_SATA("Can not open the Game!\n"); 892 | } 893 | } 894 | } 895 | if (loaded) { 896 | playlist.current_entry++; 897 | updatePlayListEntries(); 898 | } 899 | 900 | return ret; 901 | } 902 | 903 | bool loadBootIso(uint8_t dev_addr) { 904 | bool ret = false; 905 | FRESULT res; 906 | FILINFO fileInfo; 907 | LOG_SATA("Load boot.iso\n"); 908 | dir_t *curDir = getNewDir(); 909 | char *curPath = (char *) malloc(5); 910 | snprintf(curPath, 5, "%d:", dev_addr-1); 911 | LOG_SATA("Try to load on %s\n", curPath); 912 | device_s *dev = getDevice(dev_addr); 913 | res = f_findfirst(&curDir->dir, &fileInfo, curPath, "boot.iso"); 914 | if ((res != FR_OK) || (strlen(fileInfo.fname) == 0)) { 915 | //report error. Boot iso is not found 916 | LOG_SATA("Error on %s\n", curPath); 917 | } else { 918 | //load boot.iso 919 | if (extractBootImage(&fileInfo, curPath, dev_addr)) { 920 | if (currentImage.curDir != NULL) free(currentImage.curDir); 921 | currentImage.curDir = curDir; 922 | // memcpy(¤tImage, &allImage[selected_img].info, sizeof(cd_s)); 923 | if (f_open(&curBinFile, curBinPath, FA_READ) == FR_OK) { 924 | last_pos = 0; 925 | dev->state = MOUNTED; 926 | onBootIso = true; 927 | usb_cmd_on_going = false; 928 | LOG_SATA("Boot iso path %s\n", currentImage.curPath); 929 | set3doCDReady(currentImage.dev_addr, true); 930 | set3doDriveMounted(currentImage.dev_addr, true); 931 | ret = true; 932 | } else { 933 | LOG_SATA("Can not open the Game!\n"); 934 | if (currentImage.curDir != NULL) free(currentImage.curDir); 935 | if (currentImage.curPath != NULL) free(currentImage.curPath); 936 | currentImage.curDir = NULL; 937 | currentImage.curPath = NULL; 938 | currentImage.dev_addr = 0xFF; 939 | currentImage.lun = 0; 940 | } 941 | } 942 | else { 943 | currentImage.curDir = NULL; 944 | currentImage.curPath = NULL; 945 | currentImage.dev_addr = 0xFF; 946 | currentImage.lun = 0; 947 | LOG_SATA("Can not extract on %s\n", curPath); 948 | } 949 | } 950 | if (!ret) { 951 | free(curDir); 952 | free(curPath); 953 | } 954 | return ret; 955 | } 956 | 957 | static bool handleBootImage(uint8_t dev_addr) { 958 | device_s *dev = getDevice(currentImage.dev_addr); 959 | if ((currentImage.dev_addr != 0xFF) && (dev->type == MSC_TYPE) && (currentImage.dev_addr != dev_addr)) { 960 | LOG_SATA("Boot image is on %d\n", currentImage.dev_addr); 961 | return true; 962 | } 963 | LOG_SATA("Handle Boot image %d (%d)\n", onMountMode, playlist.nb_entries); 964 | if (playlist.nb_entries != 0) { 965 | LOG_SATA("Handle playlist\n"); 966 | return loadPlaylistEntry(dev_addr); 967 | } else { 968 | LOG_SATA("Handle boot.iso\n"); 969 | return loadBootIso(dev_addr); 970 | } 971 | } 972 | 973 | bool MSC_Inquiry(uint8_t dev_addr, uint8_t lun) { 974 | FRESULT result; 975 | LOG_SATA("MSC_Inquiry %d\n", dev_addr); 976 | if (tuh_msc_get_block_size(dev_addr, lun) == 0) { 977 | LOG_SATA("MSC block is 0\n"); 978 | return false; 979 | } 980 | device_s *dev = getDevice(dev_addr); 981 | char path[7]; 982 | snprintf(path, 7, "%d://", dev_addr-1); 983 | LOG_SATA("Try to mount on %s\n", path); 984 | result = f_mount(&dev->DiskFATState, path , 1); 985 | if (result!=FR_OK) { 986 | LOG_SATA("Can not mount\n"); 987 | dev->isFatFs = false; 988 | dev->useable = false; 989 | return false; 990 | } 991 | dev->isFatFs = true; 992 | dev->useable = true; 993 | LOG_SATA("MSC mounted here: %s\n", path); 994 | mediaInterrupt(); 995 | } 996 | 997 | int getTocLevel(void) { 998 | return current_toc_level; 999 | } 1000 | 1001 | int getTocIndex(void) { 1002 | return current_toc>>24; 1003 | } 1004 | 1005 | int getTocEntry(int index) { 1006 | return (index&0xFFFFFF); 1007 | } 1008 | 1009 | static bool isUp(int index) { 1010 | return (getTocEntry(index)==0xFFFFFF); 1011 | } 1012 | 1013 | void setTocLevel(int index) { 1014 | if (currentImage.dev_addr == 0xFF) return; 1015 | FRESULT res; 1016 | FILINFO fileInfo; 1017 | int curDirNb = 0; 1018 | LOG_SATA("current_toc %d (%d) vs %d (%d) current_toc_level %d\n", getTocEntry(current_toc), current_toc>>24, getTocEntry(index), index>>24, current_toc_level); 1019 | if (isUp(index)) { 1020 | LOG_SATA("Set Toc Level start %s level %d\n", currentImage.curPath, current_toc_level); 1021 | if ((current_toc_level == 1)&&(getDeviceCount()>1)) { 1022 | f_closedir(¤tImage.curDir->dir); 1023 | free(currentImage.curPath); 1024 | currentImage.curPath = NULL; 1025 | current_toc_level = 0; 1026 | // current_toc_index = 0xFF; 1027 | current_toc = 0x00000000; 1028 | } else { 1029 | char *lastDir = rindex(currentImage.curPath, '\\'); 1030 | if (lastDir != NULL) { 1031 | bool found = false; 1032 | char *newPath = malloc(lastDir - currentImage.curPath + 1); 1033 | memcpy(newPath, currentImage.curPath, lastDir - currentImage.curPath); 1034 | newPath[lastDir-currentImage.curPath] = 0; 1035 | f_closedir(¤tImage.curDir->dir); 1036 | res = f_opendir(¤tImage.curDir->dir, newPath); 1037 | current_toc_offset = 0; 1038 | free(currentImage.curPath); 1039 | currentImage.curPath = newPath; 1040 | LOG_SATA("Set Toc Level path %s\n", currentImage.curPath); 1041 | current_toc &= ~0xFFFFFF; 1042 | current_toc_level -= 1; 1043 | } 1044 | } 1045 | LOG_SATA("New current_toc_level %d\n", current_toc_level); 1046 | return; 1047 | } 1048 | if (current_toc != index) { 1049 | //need to change the current TOC level 1050 | //Get required Toc Entry 1051 | if (((getTocEntry(index)) == 0) && (current_toc_level == 0)){ 1052 | int idx = (index>>24)-1; 1053 | if (idx < 0) idx = 0; 1054 | currentImage.curDir = getNewDir(); 1055 | currentImage.curPath = (char*)malloc(20 * sizeof(char)); 1056 | // current_toc_index = index>>24; 1057 | snprintf(currentImage.curPath, 20, "%d://", idx); 1058 | res = f_opendir(¤tImage.curDir->dir, currentImage.curPath); 1059 | current_toc_offset = 0; 1060 | current_toc_level++; 1061 | LOG_SATA("Setup root path to %s\n", currentImage.curPath); 1062 | } else { 1063 | int i = 0; 1064 | LOG_SATA("Load path %s\n", currentImage.curPath); 1065 | f_closedir(¤tImage.curDir->dir); 1066 | f_opendir(¤tImage.curDir->dir, currentImage.curPath); 1067 | while(i < getTocEntry(index)) { 1068 | LOG_SATA("Look for entry %d\n", i); 1069 | if (getNextValidToc(&fileInfo)) { 1070 | i++; 1071 | current_toc_offset++; 1072 | } 1073 | if (fileInfo.fname[0] == 0) { 1074 | //Should raise en arror. Shall never happen 1075 | LOG_SATA("!!! WTF not found\n"); 1076 | LOG_SATA("New current_toc_level %d\n", current_toc_level); 1077 | return; //End of file list 1078 | } 1079 | } 1080 | LOG_SATA("Finish at entry %d\n", i); 1081 | if (fileInfo.fattrib & AM_DIR) { 1082 | int i = strlen(fileInfo.fname); 1083 | char *newPath = malloc(strlen(currentImage.curPath)+i+2); 1084 | sprintf(&newPath[0], "%s\\%s", currentImage.curPath, fileInfo.fname); 1085 | free(currentImage.curPath); 1086 | currentImage.curPath = newPath; 1087 | LOG_SATA("Set Toc Level path to dir %s\n", currentImage.curPath); 1088 | f_closedir(¤tImage.curDir->dir); 1089 | res = f_opendir(¤tImage.curDir->dir, currentImage.curPath); 1090 | current_toc_offset = 0; 1091 | current_toc_level++; 1092 | } else { 1093 | LOG_SATA("New current_toc_level %d\n", current_toc_level); 1094 | LOG_SATA("!!! WTF not a directory\n"); 1095 | } 1096 | } 1097 | current_toc = index; 1098 | } else { 1099 | if ((getTocLevel() == 0) && (getDeviceCount()<=1)) { 1100 | current_toc = (currentImage.dev_addr)<<24; 1101 | } 1102 | } 1103 | LOG_SATA("New current_toc_level %d\n", current_toc_level); 1104 | } 1105 | 1106 | static bool getNextValidToc(FILINFO *fileInfo) { 1107 | if (currentImage.dev_addr == 0xFF) return; 1108 | FRESULT res; 1109 | res = f_readdir(¤tImage.curDir->dir, fileInfo); /* Read a directory item */ 1110 | if (res != FR_OK) fileInfo->fname[0] = 0; /* Break on error or end of dir */ 1111 | // Ne bouger que si dir, iso ou cue, a voir 1112 | if (fileInfo->fname[0] == 0) return false; /* Break on error or end of dir */ 1113 | if ((fileInfo->fname[0] == '.') || (fileInfo->fattrib & (AM_HID | AM_SYS))) return false; 1114 | if (strlen(fileInfo->fname) >= TOC_NAME_LIMIT) return false; 1115 | if (!(fileInfo->fattrib & AM_DIR)) { 1116 | if (!validateFile(fileInfo)) return false; 1117 | } 1118 | LOG_SATA("File %s is ok\n", fileInfo->fname); 1119 | return true; 1120 | } 1121 | 1122 | bool seekTocTo(int index) { 1123 | if (currentImage.dev_addr == 0xFF) return; 1124 | FILINFO fileInfo; 1125 | int i = 0; 1126 | f_closedir(¤tImage.curDir->dir); 1127 | f_opendir(¤tImage.curDir->dir, currentImage.curPath); 1128 | current_toc_offset = 0; 1129 | while(i < index) { 1130 | if (getNextValidToc(&fileInfo)) { 1131 | i++; 1132 | current_toc_offset++; 1133 | } 1134 | if (fileInfo.fname[0] == 0) return false; //End of file list 1135 | } 1136 | return true; 1137 | } 1138 | 1139 | bool getReturnTocEntry(toc_entry* toc) { 1140 | if (toc == NULL) return false; 1141 | toc->flags = TOC_FLAG_DIR; 1142 | toc->toc_id = 0xFFFFFFFF; 1143 | toc->name_length = 3; 1144 | toc->name = malloc(toc->name_length); 1145 | snprintf(toc->name, toc->name_length, ".."); 1146 | toc->name[2] = 0; 1147 | return true; 1148 | } 1149 | 1150 | bool getNextTOCEntry(toc_entry* toc) { 1151 | FILINFO fileInfo; 1152 | if (toc == NULL) return false; 1153 | 1154 | while (!getNextValidToc(&fileInfo)) { 1155 | if (fileInfo.fname[0] == 0) return false; 1156 | } 1157 | current_toc_offset++; 1158 | 1159 | if (fileInfo.fattrib & AM_DIR) { /* It is a directory */ 1160 | toc->flags = TOC_FLAG_DIR; 1161 | } else { /* It is a file. */ 1162 | toc->flags = TOC_FLAG_FILE; 1163 | } 1164 | toc->toc_id = current_toc_offset; 1165 | toc->name_length = strlen(fileInfo.fname) + 1; 1166 | toc->name = malloc(toc->name_length); 1167 | snprintf(toc->name, toc->name_length, "%s", fileInfo.fname); 1168 | toc->name[toc->name_length-1] = 0; 1169 | return true; 1170 | } 1171 | 1172 | void requestOpenFile(char* name, uint16_t name_length, bool write) { 1173 | if (currentImage.dev_addr == 0xFF) return; 1174 | uint16_t length = name_length + strlen(currentImage.curPath) + 1; 1175 | if (curFilePath != NULL) free(curFilePath); 1176 | curFilePath = malloc(length); 1177 | curFileMode = write; 1178 | snprintf(&curFilePath[0], length, "%s\\%s", currentImage.curPath, name); 1179 | fileCmdRequired = OPEN; 1180 | } 1181 | 1182 | void requestWriteFile(uint8_t* buf, uint16_t length) { 1183 | curBuf = buf; 1184 | curBufLength = length; 1185 | fileCmdRequired = WRITE; 1186 | } 1187 | 1188 | void requestReadFile(uint8_t* buf, uint16_t length) { 1189 | curBuf = buf; 1190 | curBufLength = length; 1191 | fileCmdRequired = READ; 1192 | } 1193 | 1194 | void requestCloseFile() { 1195 | fileCmdRequired = CLOSE; 1196 | } 1197 | 1198 | static void check_open_file() { 1199 | usb_cmd_on_going = true; 1200 | usb_result = false; 1201 | usb_result = (f_open(&curDataFile, curFilePath, FA_WRITE| FA_READ |FA_OPEN_ALWAYS) == FR_OK); 1202 | usb_cmd_on_going = false; 1203 | } 1204 | 1205 | static void check_write_file() { 1206 | usb_cmd_on_going = true; 1207 | uint nb_write; 1208 | usb_result =(f_write(&curDataFile, curBuf, curBufLength, &nb_write) == FR_OK); 1209 | usb_result =(f_sync(&curDataFile) == FR_OK); 1210 | usb_cmd_on_going = false; 1211 | } 1212 | 1213 | static void check_read_file() { 1214 | usb_cmd_on_going = true; 1215 | uint nb_read; 1216 | FRESULT res = f_read(&curDataFile, curBuf, curBufLength, &nb_read); 1217 | usb_result = (res == FR_OK); 1218 | if (!usb_result) LOG_SATA("Issue while reading %d (%d) => %x\n", curBufLength, nb_read,res); 1219 | usb_cmd_on_going = false; 1220 | } 1221 | 1222 | 1223 | static void check_close_file() { 1224 | usb_cmd_on_going = true; 1225 | usb_result = (f_close(&curDataFile) == FR_OK); 1226 | usb_cmd_on_going = false; 1227 | } 1228 | 1229 | static void check_file(uint8_t dev_addr) { 1230 | switch(fileCmdRequired) { 1231 | case OPEN: 1232 | check_open_file(); 1233 | fileCmdRequired = DONE; 1234 | break; 1235 | case WRITE: 1236 | check_write_file(); 1237 | fileCmdRequired = DONE; 1238 | break; 1239 | case READ: 1240 | check_read_file(); 1241 | fileCmdRequired = DONE; 1242 | break; 1243 | case CLOSE: 1244 | check_close_file(); 1245 | fileCmdRequired = DONE; 1246 | break; 1247 | default: 1248 | break; 1249 | } 1250 | } 1251 | 1252 | //Need a umount callback 1253 | 1254 | #endif 1255 | -------------------------------------------------------------------------------- /src/interfaces/3DO.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pico/stdlib.h" 5 | #include "hardware/clocks.h" 6 | #include "hardware/gpio.h" 7 | #include "hardware/irq.h" 8 | #include "hardware/dma.h" 9 | #include "hardware/structs/bus_ctrl.h" 10 | #include "pico/multicore.h" 11 | 12 | #include "3DO.h" 13 | #include "MSC.h" 14 | #include "CDFormat.h" 15 | 16 | #define DATA_BUS_MASK (0xFF<>CDD0)&0xFF) 46 | 47 | extern cd_s currentImage; 48 | 49 | typedef enum{ 50 | SPIN_UP = 0x2, 51 | EJECT_DISC = 0x6, 52 | INJECT_DISC = 0x7, 53 | SET_MODE = 0x09, 54 | ABORT = 0x08, 55 | FLUSH = 0x0B, 56 | READ_DATA = 0x10, 57 | DATA_PATH_CHECK = 0x80, 58 | READ_ERROR = 0x82, 59 | READ_ID = 0x83, 60 | READ_CAPACITY = 0x85, 61 | READ_SUB_Q = 0x87, 62 | READ_DISC_INFO = 0x8B, 63 | READ_TOC = 0x8C, 64 | READ_SESSION = 0x8D, 65 | //Fixel added commands 66 | EXT_ID = 0x93, 67 | CHANGE_TOC = 0xC0, 68 | GET_TOC = 0xC1, 69 | GET_DESC = 0xC2, 70 | CLEAR_PLAYLIST = 0xC3, 71 | ADD_PLAYLIST = 0xC4, 72 | LAUNCH_PLAYLIST = 0xC5, 73 | 74 | GET_TOC_LIST = 0xD1, 75 | 76 | CREATE_FILE = 0xE0, 77 | OPEN_FILE = 0xE1, 78 | SEEK_FILE = 0xE2, 79 | READ_FILE_BYTE = 0xE3, 80 | WRITE_FILE_BYTE = 0xE4, 81 | CLOSE_FILE = 0xE5, 82 | WRITE_BUFFER_OFFSET = 0xE6, 83 | READ_BUFFER = 0xE7, 84 | 85 | UPDATE_ODE = 0xF0, 86 | }CD_request_t; 87 | 88 | /* 89 | case 0xc0: dev_ode_changetoc(); break; 90 | case 0xc1: dev_ode_gettoc(); break; 91 | case 0xc2: dev_ode_getdesc(); break; 92 | case 0xc3: dev_ode_clearpl(); break; 93 | case 0xc4: dev_ode_addpl(); break; 94 | case 0xc5: dev_ode_launchpl(); break; 95 | 96 | case 0xd1: dev_ode_gettoclist(); break; 97 | 98 | 99 | case 0xe0: dev_ode_createfile(); break; 100 | case 0xe1: dev_ode_openfile(); break; 101 | case 0xe2: dev_ode_seekfile(); break; 102 | case 0xe3: dev_ode_readfile(); break; 103 | case 0xe4: dev_ode_writefile(); break; 104 | case 0xe5: dev_ode_closefile(); break; 105 | case 0xe6: dev_ode_bufsend(); break; 106 | case 0xe7: dev_ode_bufrecv(); break; 107 | 108 | case 0xf0: dev_ode_startupdate(); break; 109 | */ 110 | 111 | typedef enum{ 112 | TRAY_IN = 0x80, 113 | DISC_PRESENT = 0x40, 114 | SPINNING = 0x20, 115 | CHECK_ERROR = 0x10, 116 | DOUBLE_SPEED = 0x02, 117 | DISC_RDY = 0x01 118 | }CD_status_t; 119 | 120 | typedef enum{ 121 | NO_ERROR = 0x0, 122 | SOFT_READ_RETRY = 0x1, 123 | SOFT_READ_CORRECTION = 0x2, 124 | NOT_READY = 0x3, 125 | NO_TOC = 0x4, 126 | HARD_READ = 0x5, 127 | SEEK_FAIL = 0x6, 128 | TRACKING_FAIL = 0x7, 129 | DRIVE_RAM_ERROR = 0x8, 130 | SELF_TEST_ERROR = 0x9, 131 | FOCUSING_FAIL = 0xA, 132 | SPINDLE_FAIL = 0xB, 133 | DATA_PATH_FAIL = 0xC, 134 | ILLEGAL_LBA = 0xD, 135 | ILLEGAL_CDB = 0xE, 136 | END_USER_TRACK = 0xF, 137 | ILLEGAL_MODE = 0x10, 138 | MEDIA_CHANGED = 0x11, 139 | POWER_OR_RESET_OCCURED = 0x12, 140 | DRIVE_ROM_FAIL = 0x13, 141 | ILLEGAL_CMD = 0x14, 142 | DISC_REMOVED = 0x15, 143 | HARDWARE_ERROR = 0x16, 144 | ILLEGAL_REQUEST = 0x17, 145 | }CD_error_t; 146 | 147 | typedef enum { 148 | CHAN_WRITE_STATUS = 0, 149 | CHAN_WRITE_DATA, 150 | CHAN_MAX 151 | } DMA_chan_t; 152 | 153 | 154 | dma_channel_config config[CHAN_MAX]; 155 | uint8_t sm[CHAN_MAX]; 156 | uint8_t sm_offset[CHAN_MAX]; 157 | int channel[CHAN_MAX]; 158 | 159 | int errorOnDisk = 0; 160 | 161 | 162 | uint sm_read = -1; 163 | uint instr_jmp_read; 164 | 165 | uint instr_out; 166 | uint instr_pull; 167 | uint instr_set; 168 | uint instr_jmp[CHAN_MAX]; 169 | uint instr_restart; 170 | 171 | uint nbWord = 0; 172 | 173 | static bool use_cdrom = false; 174 | 175 | static bool ledState = false; 176 | 177 | static bool canHandleReset = false; 178 | 179 | static int pitch = 0; 180 | 181 | static uint8_t errorCode = POWER_OR_RESET_OCCURED; 182 | static uint8_t status = TRAY_IN | CHECK_ERROR | DISC_RDY; 183 | 184 | void close_tray(bool close) { 185 | device_s *dev = NULL; 186 | bool has_usb = false; 187 | bool has_cd = false; 188 | for (int i = 0; itype == MSC_TYPE) { 191 | has_usb = true; 192 | } 193 | if (curdev->type == CD_TYPE) { 194 | has_cd = true; 195 | } 196 | } 197 | LOG_SATA("Ask to eject %d has_sub %d has_cd %d\n", close, has_usb, has_cd); 198 | //By default eject currentImage device 199 | if (currentImage.dev_addr != 0xFF) dev = getDevice(currentImage.dev_addr); 200 | //In case there is no currentImage, we might have an invalid CD 201 | if ((currentImage.dev_addr == 0xFF) && (has_cd)) { 202 | for (int i = 0; itype == CD_TYPE) { 205 | dev = curdev; 206 | break; 207 | } 208 | } 209 | } 210 | if (dev != NULL) { 211 | //If the currentImage device is a cd but we have usb key, do not eject it 212 | if ((dev->type == CD_TYPE) && (has_usb)) 213 | dev = NULL; 214 | } 215 | //But In case we are on Boot menu and there is a CD, eject the CD 216 | if (onBootIso & has_cd) { 217 | //on Boot menu, if there is a CDROM, try to eject it. 218 | for (int i = 0; itype == CD_TYPE) { 221 | dev = curdev; 222 | break; 223 | } 224 | } 225 | } 226 | if (dev != NULL) { 227 | LOG_SATA("request Eject on dev %d, type %s\n", dev->dev_addr, (dev->type==CD_TYPE)?"CD":"USB"); 228 | if (!USBDriveEject(dev->dev_addr, !close)) { 229 | LOG_SATA("Can not eject/inject\n"); 230 | return; 231 | } 232 | } 233 | // status &= ~TRAY_IN; 234 | if (!onBootIso) 235 | mediaInterrupt(); 236 | } 237 | 238 | void wait_out_of_reset() { 239 | while( !gpio_get(CDRST)) { 240 | gpio_put(CDMDCHG, 1); //Under reset 241 | } 242 | sleep_ms(500); 243 | gpio_put(CDMDCHG, 0); //Under reset 244 | sleep_ms(100); 245 | gpio_put(CDMDCHG, 1); //Under reset 246 | } 247 | 248 | void set3doCDReady(uint8_t dev_addr, bool on) { 249 | if (on && (currentImage.dev_addr == dev_addr)) { 250 | errorOnDisk = 0; 251 | switch(currentImage.format) { 252 | case 0x0: 253 | if (currentImage.hasOnlyAudio) 254 | LOG_SATA("Audio CD detected\n"); 255 | else 256 | LOG_SATA("Data CD detected\n"); 257 | //Need to check if compatible 3DO game 258 | break; 259 | case 0x20: 260 | LOG_SATA("Photo-CD detected\n"); 261 | break; 262 | case 0xFF: 263 | LOG_SATA("CD-i detected\n"); 264 | break; 265 | } 266 | status = TRAY_IN | DISC_RDY | DISC_PRESENT | SPINNING; 267 | errorCode = 0; 268 | status &= ~CHECK_ERROR; 269 | } else { 270 | if (on) LOG_SATA("Current Image is on dev addr %x but CD is %x\n", currentImage.dev_addr, dev_addr); 271 | } 272 | 273 | } 274 | 275 | void set3doDriveMounted(uint8_t dev_addr, bool on) { 276 | device_s *dev = getDevice(dev_addr); 277 | if ((currentImage.dev_addr == dev_addr) && (!on)) { 278 | LOG_SATA("set3doDriveMounted %d\n", on); 279 | if (currentImage.curDir != NULL) free(currentImage.curDir); 280 | if (currentImage.curPath != NULL) free(currentImage.curPath); 281 | currentImage.curDir = NULL; 282 | currentImage.curPath = NULL; 283 | currentImage.dev_addr = 0xFF; 284 | currentImage.lun = 0x0; 285 | } 286 | } 287 | 288 | void set3doDriveReady() { 289 | } 290 | 291 | void set3doDriveError() { 292 | LOG_SATA("Drive error\n"); 293 | errorOnDisk = 1; 294 | errorCode = SOFT_READ_RETRY; 295 | status |= CHECK_ERROR; 296 | status &= ~DISC_RDY; 297 | status &= ~SPINNING; 298 | USB_reset(); 299 | } 300 | 301 | bool is3doData() { 302 | return pio_sm_get_rx_fifo_level(pio0, sm_read) != 0; 303 | } 304 | 305 | uint32_t get3doData() { 306 | uint32_t val = 0x0; 307 | val = pio_sm_get_blocking(pio0, sm_read); 308 | return val; 309 | } 310 | 311 | void print_dma_ctrl(dma_channel_hw_t *channel) { 312 | uint32_t ctrl = channel->ctrl_trig; 313 | int rgsz = (ctrl & DMA_CH0_CTRL_TRIG_RING_SIZE_BITS) >> DMA_CH0_CTRL_TRIG_RING_SIZE_LSB; 314 | LOG_SATA("(%08x) ber %d rer %d wer %d busy %d trq %d cto %d rgsl %d rgsz %d inw %d inr %d sz %d hip %d en %d", 315 | (uint) ctrl, 316 | ctrl & DMA_CH0_CTRL_TRIG_AHB_ERROR_BITS ? 1 : 0, 317 | ctrl & DMA_CH0_CTRL_TRIG_READ_ERROR_BITS ? 1 : 0, 318 | ctrl & DMA_CH0_CTRL_TRIG_WRITE_ERROR_BITS ? 1 : 0, 319 | ctrl & DMA_CH0_CTRL_TRIG_BUSY_BITS ? 1 : 0, 320 | (int) ((ctrl & DMA_CH0_CTRL_TRIG_TREQ_SEL_BITS) >> DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB), 321 | (int) ((ctrl & DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) >> DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB), 322 | ctrl & DMA_CH0_CTRL_TRIG_RING_SEL_BITS ? 1 : 0, 323 | rgsz ? (1 << rgsz) : 0, 324 | ctrl & DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS ? 1 : 0, 325 | ctrl & DMA_CH0_CTRL_TRIG_INCR_READ_BITS ? 1 : 0, 326 | 1 << ((ctrl & DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS) >> DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB), 327 | ctrl & DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS ? 1 : 0, 328 | ctrl & DMA_CH0_CTRL_TRIG_EN_BITS ? 1 : 0); 329 | } 330 | 331 | void setDataDir(int value) { 332 | gpio_put(DIR_DATA, value); 333 | if (value == DATA_IN) { 334 | pio_sm_drain_tx_fifo(pio0, sm_read); 335 | } 336 | } 337 | 338 | 339 | void restartPio(uint8_t channel) { 340 | pio_sm_drain_tx_fifo(pio0, sm[channel]); 341 | pio_sm_restart(pio0, sm[channel]); 342 | pio_sm_exec(pio0, sm[channel], instr_jmp[channel]); 343 | pio_sm_set_enabled(pio0, sm[channel], true); 344 | } 345 | 346 | static void restartReadPio() { 347 | pio_sm_drain_tx_fifo(pio0, sm_read); 348 | pio_sm_restart(pio0, sm_read); 349 | pio_sm_exec(pio0, sm_read, instr_jmp_read); 350 | pio_sm_set_enabled(pio0, sm_read, true); 351 | } 352 | 353 | void startDMA(uint8_t access, uint8_t *buffer, uint32_t nbWord) { 354 | dma_channel_transfer_from_buffer_now(channel[access], buffer, nbWord); 355 | } 356 | 357 | void sendAnswer(uint8_t *buffer, uint32_t nbWord, uint8_t access) { 358 | restartPio(access); 359 | startDMA(access, buffer, nbWord); 360 | pio_sm_set_consecutive_pindirs(pio0, sm[access], CDD0, 8, true); 361 | setDataDir(DATA_OUT); //Output data 362 | gpio_put(CDSTEN + access, 0x0); 363 | 364 | dma_channel_wait_for_finish_blocking(access); 365 | while(!pio_sm_is_tx_fifo_empty(pio0, sm[access])); 366 | while (pio_sm_get_pc(pio0, sm[access]) != sm_offset[access]); 367 | gpio_put(CDSTEN + access, 0x1); 368 | setDataDir(DATA_IN); //input data 369 | pio_sm_set_consecutive_pindirs(pio0, sm[access], CDD0, 8, false); 370 | pio_sm_set_enabled(pio0, sm[access], false); 371 | } 372 | 373 | bool sendAnswerStatusMixed(uint8_t *buffer, uint32_t nbWord, uint8_t *buffer_status, uint8_t nbStatus, bool last, bool trace) { 374 | bool statusStarted = false; 375 | bool interrupted = false; 376 | absolute_time_t a,b,c,d,e, s = get_absolute_time(); 377 | bool lastCDEN = gpio_get(CDEN); 378 | if (trace) a= get_absolute_time(); 379 | restartPio(CHAN_WRITE_DATA); 380 | if (trace) b= get_absolute_time(); 381 | startDMA(CHAN_WRITE_DATA, buffer, nbWord); 382 | if (trace) c= get_absolute_time(); 383 | pio_sm_set_consecutive_pindirs(pio0, sm[CHAN_WRITE_DATA], CDD0, 8, true); 384 | if (trace) d= get_absolute_time(); 385 | setDataDir(DATA_OUT); //Output data 386 | gpio_put(CDDTEN, 0x0); 387 | if (trace) e= get_absolute_time(); 388 | absolute_time_t start = get_absolute_time(); 389 | bool canBeInterrupted = false; 390 | 391 | if (trace) 392 | LOG_SATA("a %lld, b %lld, c %lld, d %lld, e %lld\n", absolute_time_diff_us(s,a), absolute_time_diff_us(a,b), absolute_time_diff_us(b,c), absolute_time_diff_us(c,d), absolute_time_diff_us(d,e)); 393 | 394 | while (dma_channel_is_busy(CHAN_WRITE_DATA)) { 395 | if (gpio_get(CDEN) != lastCDEN) { 396 | lastCDEN = !lastCDEN; 397 | pio_sm_set_consecutive_pindirs(pio0, sm[CHAN_WRITE_DATA], CDD0, 8, !lastCDEN); 398 | } 399 | if((absolute_time_diff_us(start,get_absolute_time()) > 100) && (!statusStarted) && canBeInterrupted && last) { 400 | statusStarted = true; 401 | setDataDir(DATA_OUT); 402 | gpio_put(CDSTEN, 0x0); 403 | } 404 | 405 | if (!gpio_get(CDEN)) { 406 | start = get_absolute_time(); 407 | canBeInterrupted = true; 408 | } 409 | 410 | if (!gpio_get(CDHWR)) 411 | { 412 | pio_sm_set_enabled(pio0, sm[CHAN_WRITE_DATA], false); 413 | pio_sm_set_consecutive_pindirs(pio0, sm[CHAN_WRITE_DATA], CDD0, 8, false); 414 | gpio_put(CDDTEN, true); 415 | setDataDir(DATA_IN); //Input data 416 | return false; 417 | } 418 | 419 | if (gpio_get(CDEN) && statusStarted) { 420 | interrupted = true; 421 | pio_sm_set_enabled(pio0, sm[CHAN_WRITE_DATA], false); 422 | sendAnswer(buffer_status, nbStatus, CHAN_WRITE_STATUS); 423 | pio_sm_set_consecutive_pindirs(pio0, sm[CHAN_WRITE_DATA], CDD0, 8, true); 424 | pio_sm_set_enabled(pio0, sm[CHAN_WRITE_DATA], true); 425 | } 426 | } 427 | while(!pio_sm_is_tx_fifo_empty(pio0, sm[CHAN_WRITE_DATA])); 428 | while (pio_sm_get_pc(pio0, sm[CHAN_WRITE_DATA]) != sm_offset[CHAN_WRITE_DATA]); 429 | gpio_put(CDDTEN, 0x1); 430 | setDataDir(DATA_IN); //Input data 431 | if (!interrupted && last) sendAnswer(buffer_status, nbStatus, CHAN_WRITE_STATUS); 432 | else pio_sm_set_consecutive_pindirs(pio0, sm[CHAN_WRITE_DATA], CDD0, 8, false); 433 | pio_sm_set_enabled(pio0, sm[CHAN_WRITE_DATA], false); 434 | return true; 435 | } 436 | 437 | static uint8_t TOC[2048] = {0}; 438 | uint8_t FILE_BUFFER[2048] = {0}; 439 | 440 | static void handleTocChange(int index) { 441 | toc_entry toc; 442 | //switch to the right TOC level 443 | setTocLevel(index); 444 | } 445 | 446 | char* getPathForTOC(int entry) { 447 | if (getTocEntry(entry)==0x0) { 448 | device_s *dev = getDevice(entry>>24); 449 | if (!dev->useable) return NULL; 450 | char* result = malloc(7); 451 | snprintf(result, 7, "%d://", (entry>>24)-1); 452 | return result; 453 | } else { 454 | for (int i=0; i<2048;) { 455 | uint32_t flags = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 456 | if (flags != TOC_FLAG_INVALID) { 457 | uint32_t toc_id = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 458 | uint32_t name_length = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 459 | if (toc_id == entry) { 460 | if (flags != TOC_FLAG_FILE) return NULL; 461 | int pathLength = name_length + 1 + strlen(currentImage.curPath)+1; 462 | char* result = malloc(pathLength); 463 | snprintf(result, pathLength, "%s\\%s", currentImage.curPath, &TOC[i]); 464 | return result; 465 | } 466 | i += name_length; 467 | } else { 468 | return NULL; 469 | } 470 | } 471 | } 472 | return NULL; 473 | } 474 | 475 | void getTocFull(int index, int nb) { 476 | int toclen = 0; 477 | int id = 0; 478 | bool ended = false; 479 | memset(TOC,0xff,sizeof(TOC)); 480 | if ((getTocLevel() == 0) && (getDeviceCount()>1)) { 481 | int max = CFG_TUH_DEVICE_MAX; 482 | if (nbtype != UNKNOWN_TYPE) { 488 | toc_entry *te = malloc(sizeof(toc_entry)); 489 | memset(te, 0x0, sizeof(toc_entry)); 490 | char name[20]; 491 | if (dev->type == CD_TYPE) { 492 | snprintf(name, 20, "CD %d", nbCD); 493 | nbCD++; 494 | } 495 | if (dev->type == MSC_TYPE) { 496 | snprintf(name, 20, "USB %d", nbUsb); 497 | nbUsb++; 498 | } 499 | te->flags = (dev->isFatFs)?TOC_FLAG_DIR:TOC_FLAG_FILE; 500 | te->toc_id = dev->dev_addr<<24; 501 | te->name_length = strlen(name) + 1; 502 | te->name = malloc(te->name_length); 503 | snprintf(te->name, te->name_length, "%s", name); 504 | te->name[te->name_length-1] = 0; 505 | 506 | TOC[toclen++]=te->flags>>24; 507 | TOC[toclen++]=te->flags>>16; 508 | TOC[toclen++]=te->flags>>8; 509 | TOC[toclen++]=te->flags&0xff; 510 | TOC[toclen++]=te->toc_id>>24; 511 | TOC[toclen++]=te->toc_id>>16; 512 | TOC[toclen++]=te->toc_id>>8; 513 | TOC[toclen++]=te->toc_id&0xff; 514 | TOC[toclen++]=te->name_length>>24; 515 | TOC[toclen++]=te->name_length>>16; 516 | TOC[toclen++]=te->name_length>>8; 517 | TOC[toclen++]=te->name_length&0xff; 518 | for(uint32_t t=0;tname_length;t++) { 519 | TOC[toclen++]=te->name[t]; 520 | } 521 | if (te->name != NULL) free(te->name); 522 | free(te); 523 | } 524 | 525 | } 526 | } else { 527 | if (!seekTocTo(index)) { 528 | LOG_SATA("Index %d is out of files number\n", index); 529 | return; 530 | } 531 | while(!ended) { 532 | toc_entry *te = malloc(sizeof(toc_entry)); 533 | memset(te, 0x0, sizeof(toc_entry)); 534 | if ((index == 0) && (id == 0) && (getTocLevel() != 0)) { 535 | if (!getReturnTocEntry(te)) break; 536 | } else { 537 | if (!getNextTOCEntry(te)) break; 538 | } 539 | id++; 540 | if ((nb != -1) && (id >= (nb))) { 541 | LOG_SATA("Limit has been reached on Id %d\n", id, nb); 542 | ended = true; 543 | } else { 544 | LOG_SATA("Got %d files on %d\n", id, nb+index); 545 | } 546 | te->toc_id &= ~(0xFF<<24); 547 | te->toc_id |= getTocIndex()<<24; 548 | TOC[toclen++]=te->flags>>24; 549 | TOC[toclen++]=te->flags>>16; 550 | TOC[toclen++]=te->flags>>8; 551 | TOC[toclen++]=te->flags&0xff; 552 | TOC[toclen++]=te->toc_id>>24; 553 | TOC[toclen++]=te->toc_id>>16; 554 | TOC[toclen++]=te->toc_id>>8; 555 | TOC[toclen++]=te->toc_id&0xff; 556 | TOC[toclen++]=te->name_length>>24; 557 | TOC[toclen++]=te->name_length>>16; 558 | TOC[toclen++]=te->name_length>>8; 559 | TOC[toclen++]=te->name_length&0xff; 560 | for(uint32_t t=0;tname_length;t++) { 561 | TOC[toclen++]=te->name[t]; 562 | } 563 | if (te->name != NULL) free(te->name); 564 | free(te); 565 | if (toclen > (sizeof(TOC)-(128+13))) { 566 | LOG_SATA("Buffer is full\n"); 567 | ended = true; 568 | } 569 | } 570 | 571 | } 572 | 573 | } 574 | 575 | void getToc(int index, int offset, uint8_t* buffer) { 576 | if (offset == 0) { 577 | //init the TOC buffer 578 | getTocFull(index, -1); 579 | } 580 | memcpy(buffer, &TOC[offset], 16); 581 | 582 | } 583 | 584 | absolute_time_t lastPacket; 585 | void sendData(int startlba, int nb_block, bool trace) { 586 | 587 | uint8_t buffer[2500]; 588 | uint8_t status_buffer[2] = {READ_DATA, status}; 589 | int start = startlba; 590 | absolute_time_t a,b,c,d,e, s; 591 | int reste = 0; 592 | 593 | if (nb_block == 0) return; 594 | int id = 0; 595 | while (nb_block != 0) { 596 | s = get_absolute_time(); 597 | int current = id; 598 | int data_idx = 0; 599 | if (trace) a= get_absolute_time(); 600 | if (!(status & DISC_PRESENT)) { 601 | return; 602 | } 603 | 604 | readBlock(startlba, 1, currentImage.block_size_read, &buffer[0]); 605 | if (trace) b= get_absolute_time(); 606 | while(!block_is_ready() && !errorOnDisk && gpio_get(CDRST)); 607 | 608 | if (!gpio_get(CDRST)) return; 609 | if (isAudioBlock(startlba)) { 610 | int timeForASecond = (990 + pitch) * 1000 + reste; //Shall be 1s but cd drive is a bit slower than expected 611 | int correctedDelay = timeForASecond/75; 612 | reste = timeForASecond % 75; 613 | if (is_nil_time(lastPacket)) { 614 | lastPacket = delayed_by_us(get_absolute_time(),correctedDelay); 615 | } else { 616 | absolute_time_t currentPacket = get_absolute_time(); 617 | int64_t delay = absolute_time_diff_us(currentPacket, lastPacket); /*Right number shall be 1000000/75*/ 618 | if (delay>0) sleep_us(delay); 619 | else lastPacket = currentPacket; 620 | lastPacket = delayed_by_us(lastPacket,correctedDelay); 621 | } 622 | } 623 | if (trace) c = get_absolute_time(); 624 | nb_block--; 625 | startlba++; 626 | id = (id++)%2; 627 | if (trace) d= get_absolute_time(); 628 | if (!sendAnswerStatusMixed(&buffer[0], currentImage.block_size_read, status_buffer, 2, nb_block == 0, trace)) return; 629 | if (trace) e = get_absolute_time(); 630 | if (trace) 631 | LOG_SATA("send data a %lld, b %lld, c %lld, d %lld, e %lld\n", absolute_time_diff_us(s,a), absolute_time_diff_us(a,b), absolute_time_diff_us(b,c), absolute_time_diff_us(c,d), absolute_time_diff_us(d,e)); 632 | 633 | } 634 | } 635 | 636 | void sendRawData(int command, uint8_t *buffer, int length) { 637 | uint8_t status_buffer[2] = {command, status}; 638 | if (length == 0) return; 639 | if (!sendAnswerStatusMixed(buffer, length, status_buffer, 2, true, false)) return; 640 | } 641 | 642 | static bool hasMediaInterrupt = false; 643 | void mediaInterrupt(void) { 644 | hasMediaInterrupt = true; 645 | // canHandleReset = false; 646 | // status |= TRAY_IN; 647 | } 648 | void handleMediaInterrupt() { 649 | if (!hasMediaInterrupt) return; 650 | if ((status & DISC_PRESENT) && !canHandleReset) { 651 | gpio_put(LED, ledState); 652 | ledState = !ledState; 653 | return; 654 | } 655 | hasMediaInterrupt = false; 656 | // gpio_set_dir(CDRST, true); 657 | // gpio_put(CDRST, 0); 658 | // pio_sm_set_enabled(pio0, sm_read, false); 659 | // gpio_put(CDMDCHG, 1); //Under reset 660 | // sleep_ms(200); 661 | // gpio_put(CDRST, 1); 662 | // gpio_set_dir(CDRST, false); 663 | // sleep_ms(150); 664 | // gpio_put(CDMDCHG, 0); //Under reset 665 | // sleep_ms(10); 666 | gpio_put(CDMDCHG, 0); //Under reset 667 | status &= ~DISC_PRESENT & ~SPINNING; 668 | status |= CHECK_ERROR; 669 | errorCode = DISC_REMOVED; 670 | sleep_ms(10); 671 | while (!pio_sm_is_rx_fifo_empty(pio0, sm_read)) { 672 | pio_sm_get(pio0, sm_read); 673 | } 674 | LOG_SATA("Look for BootImage\n"); 675 | onBootIso = false; 676 | if (getPlaylistEntries() == 0) { 677 | currentImage.dev_addr = 0xFF; 678 | currentImage.lun = 0x0; 679 | } 680 | if (currentImage.dev_addr != 0xFF) { 681 | device_s *current_dev = getDevice(currentImage.dev_addr); 682 | if (current_dev->type == CD_TYPE) { 683 | currentImage.dev_addr = 0xFF; 684 | currentImage.lun = 0x0; 685 | } 686 | } 687 | for (int i=0; idev_addr == 0xFF) { 691 | LOG_SATA("%d is not a real device\n", i); 692 | continue; 693 | } 694 | if (dev->type == MSC_TYPE) { 695 | LOG_SATA("%d is a MSC\n", i); 696 | requestBootImage(); 697 | waitForLoad(); 698 | LOG_SATA("Loaded on %d\n", i); 699 | } 700 | if (dev->type == CD_TYPE) { 701 | LOG_SATA("%d is a CD (%d)\n", i, dev->state); 702 | wakeUpCDRom(dev->dev_addr, dev->lun); 703 | set3doCDReady(dev->dev_addr, dev->state == MOUNTED); 704 | set3doDriveMounted(dev->dev_addr, dev->state == MOUNTED); 705 | } 706 | 707 | } 708 | gpio_put(CDMDCHG, 1); //Under reset 709 | // pio_sm_set_enabled(pio0, sm_read, false); 710 | // errorCode |= POWER_OR_RESET_OCCURED; 711 | } 712 | 713 | void handleCommand(uint32_t data) { 714 | CD_request_t request = (CD_request_t) GET_BUS(data); 715 | bool isCmd = (data>>CDCMD)&0x1 == 0x0; 716 | uint32_t data_in[6]; 717 | uint8_t buffer[18]; 718 | uint8_t subBuffer[16]; 719 | uint index = 0; 720 | 721 | gpio_put(LED, ledState); 722 | ledState = !ledState; 723 | 724 | switch(request) { 725 | case READ_ID: 726 | for (int i=0; i<6; i++) { 727 | data_in[i] = get3doData(); 728 | } 729 | 730 | LOG_SATA("READ ID %x\n", status); 731 | if (errorOnDisk != 0) errorOnDisk++; 732 | buffer[index++] = READ_ID; 733 | buffer[index++] =0x00; //manufacture Id 734 | buffer[index++] =0x10; 735 | buffer[index++] =0x00; //manufacture number 736 | buffer[index++] =0x01; 737 | buffer[index++] =0x30; 738 | buffer[index++] =0x75; 739 | buffer[index++] =0x00; //revision number 740 | buffer[index++] =0x00; 741 | buffer[index++] =0x00; //flag 742 | buffer[index++] =0x00; 743 | buffer[index++] = status; 744 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 745 | break; 746 | case EJECT_DISC: 747 | for (int i=0; i<6; i++) { 748 | data_in[i] = get3doData(); 749 | } 750 | LOG_SATA("EJECT\n"); 751 | canHandleReset = true; 752 | close_tray(false); 753 | buffer[index++] = status; 754 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 755 | break; 756 | case INJECT_DISC: 757 | for (int i=0; i<6; i++) { 758 | data_in[i] = get3doData(); 759 | } 760 | LOG_SATA("INJECT\n"); 761 | close_tray(true); 762 | buffer[index++] = status; 763 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 764 | break; 765 | case READ_ERROR: 766 | for (int i=0; i<6; i++) { 767 | data_in[i] = get3doData(); 768 | } 769 | LOG_SATA("READ ERROR %x %x\n", errorCode, status); 770 | buffer[index++] = READ_ERROR; 771 | buffer[index++] = 0x00; 772 | buffer[index++] = 0x00; 773 | buffer[index++] = errorCode; //error code 774 | buffer[index++] = 0x00; 775 | buffer[index++] = 0x00; 776 | buffer[index++] = 0x00; 777 | buffer[index++] = 0x00; 778 | buffer[index++] = 0x00; 779 | status &= ~CHECK_ERROR; 780 | errorCode = NO_ERROR; 781 | buffer[index++] = status; 782 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 783 | break; 784 | case DATA_PATH_CHECK: 785 | for (int i=0; i<6; i++) { 786 | data_in[i] = get3doData(); 787 | } 788 | LOG_SATA("DATA_PATH_CHECK %d\n", (status & DISC_PRESENT)); 789 | buffer[index++] = DATA_PATH_CHECK; 790 | if (!(status & DISC_PRESENT)) { 791 | buffer[index++] = 0xA5; 792 | buffer[index++] = 0xA5; 793 | } else { 794 | buffer[index++] = 0xAA; //This means ok 795 | buffer[index++] = 0x55; //This means ok. Not the case when no disc 796 | } 797 | buffer[index++] = status; 798 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 799 | canHandleReset = true; 800 | break; 801 | case SPIN_UP: 802 | if (status & DISC_PRESENT) { 803 | for (int i=0; i<6; i++) { 804 | data_in[i] = get3doData(); 805 | } 806 | LOG_SATA("SPIN UP\n"); 807 | buffer[index++] = SPIN_UP; 808 | if (!(status & TRAY_IN)) { 809 | status |= CHECK_ERROR; 810 | errorCode |= ILLEGAL_CMD; 811 | } else { 812 | if (!(status & DISC_RDY)) { 813 | status |= CHECK_ERROR; 814 | errorCode = DISC_REMOVED; 815 | } else { 816 | status |= SPINNING; 817 | } 818 | } 819 | buffer[index++] = status; 820 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 821 | } 822 | break; 823 | case READ_DATA: 824 | if (status & DISC_PRESENT) { 825 | for (int i=0; i<6; i++) { 826 | data_in[i] = GET_BUS(get3doData()); 827 | } 828 | LOG_SATA("READ DATA MSF %d:%d:%d %x\n", data_in[0], data_in[1], data_in[2], status); 829 | if (data_in[3] == 0x00) { 830 | //MSF 831 | int lba = data_in[0]*60*75+data_in[1]*75+data_in[2] - 150; 832 | int nb_block = (data_in[4]<<8)|data_in[5]; 833 | sendData(lba, nb_block, false); 834 | } else { 835 | //LBA not supported yet 836 | LOG_SATA("LBA not supported yet\n"); 837 | } 838 | } 839 | break; 840 | case ABORT: 841 | for (int i=0; i<6; i++) { 842 | data_in[i] = get3doData(); 843 | } 844 | LOG_SATA("ABORT\n"); 845 | buffer[index++] = ABORT; 846 | buffer[index++] = status; 847 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 848 | break; 849 | case FLUSH: 850 | for (int i=0; i<6; i++) { 851 | data_in[i] = get3doData(); 852 | } 853 | LOG_SATA("FLUSH\n"); 854 | buffer[index++] = FLUSH; 855 | buffer[index++] = status; 856 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 857 | break; 858 | case READ_DISC_INFO: 859 | if (status & DISC_PRESENT) { 860 | for (int i=0; i<6; i++) { 861 | data_in[i] = get3doData(); 862 | } 863 | LOG_SATA("DISC_INFO\n"); 864 | buffer[index++] = READ_DISC_INFO; 865 | // LBA = (((M*60)+S)*75+F)-150 866 | if (status & DISC_PRESENT) { 867 | buffer[index++] = currentImage.format; 868 | buffer[index++] = currentImage.first_track; 869 | buffer[index++] = currentImage.last_track; 870 | buffer[index++] = currentImage.msf[0]; 871 | buffer[index++] = currentImage.msf[1]; 872 | buffer[index++] = currentImage.msf[2]; 873 | 874 | } else { 875 | errorCode = NOT_READY; 876 | buffer[index++] = 0x0; 877 | buffer[index++] = 0x0; 878 | buffer[index++] = 0x0; 879 | buffer[index++] = 0x0; 880 | buffer[index++] = 0x0; 881 | buffer[index++] = 0x0; 882 | } 883 | buffer[index++] = status; 884 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 885 | LOG_SATA("%d %x %d %d %d:%d:%d\n", (status & DISC_PRESENT), buffer[1], buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]); 886 | } 887 | break; 888 | case READ_TOC: 889 | if (status & DISC_PRESENT) { 890 | for (int i=0; i<6; i++) { 891 | data_in[i] = GET_BUS(get3doData()); 892 | } 893 | LOG_SATA("READ_TOC %x\n", data_in[1]); 894 | buffer[index++] = READ_TOC; 895 | buffer[index++] = 0x0; //NixByte? 896 | buffer[index++] = currentImage.tracks[data_in[1]-1].CTRL_ADR; //ADDR 897 | buffer[index++] = currentImage.tracks[data_in[1]-1].id; //ENT_NUMBER 898 | buffer[index++] = 0x0;//Format 899 | buffer[index++] = currentImage.tracks[data_in[1]-1].msf[0]; 900 | buffer[index++] = currentImage.tracks[data_in[1]-1].msf[1]; 901 | buffer[index++] = currentImage.tracks[data_in[1]-1].msf[2]; 902 | buffer[index++] = 0x0; 903 | buffer[index++] = status; 904 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 905 | LOG_SATA("%x %d %d:%d:%d\n", buffer[2], buffer[3],buffer[5],buffer[6],buffer[7]); 906 | } 907 | break; 908 | case READ_SESSION: 909 | if (status & DISC_PRESENT) { 910 | for (int i=0; i<6; i++) { 911 | data_in[i] = get3doData(); 912 | } 913 | LOG_SATA("READ_SESSION\n"); 914 | buffer[index++] = READ_SESSION; 915 | if (currentImage.multiSession) { 916 | //TBD with a multisession disc 917 | buffer[index++] = 0x80; 918 | buffer[index++] = currentImage.msf[0]; //might some other values like msf for multisession start 919 | buffer[index++] = currentImage.msf[1]; 920 | buffer[index++] = currentImage.msf[2]; 921 | buffer[index++] = 0x0; 922 | buffer[index++] = 0x0; 923 | } else { 924 | buffer[index++] = 0x0; 925 | buffer[index++] = 0x0; 926 | buffer[index++] = 0x0; 927 | buffer[index++] = 0x0; 928 | buffer[index++] = 0x0; 929 | buffer[index++] = 0x0; 930 | } 931 | buffer[index++] = status; 932 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 933 | LOG_SATA("%d:%d:%d\n", buffer[2], buffer[3],buffer[4]); 934 | } 935 | break; 936 | case READ_CAPACITY: 937 | if (status & DISC_PRESENT) { 938 | for (int i=0; i<6; i++) { 939 | data_in[i] = get3doData(); 940 | } 941 | LOG_SATA("READ_CAPACITY\n"); 942 | buffer[index++] = READ_CAPACITY; 943 | buffer[index++] = currentImage.msf[0]; 944 | buffer[index++] = currentImage.msf[1]; 945 | buffer[index++] = currentImage.msf[2]; 946 | buffer[index++] = 0x0; //0x8? 947 | buffer[index++] = 0x0; 948 | buffer[index++] = status; 949 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 950 | } 951 | break; 952 | case SET_MODE: 953 | for (int i=0; i<6; i++) { 954 | data_in[i] = GET_BUS(get3doData()); 955 | } 956 | LOG_SATA("SET_MODE %x %x %x %x %x %x\n", data_in[0], data_in[1], data_in[2], data_in[3], data_in[4], data_in[5]); 957 | /* 958 | not entirely full 959 | [18:04] 960 | cmd9 has many settings 961 | [18:04] 962 | [0] = 0x9 963 | [18:04] 964 | [1] = setting type 965 | [18:04] 966 | where : 967 | [18:04] 968 | 0 = density 969 | [18:04] 970 | 1 = error recovery 971 | [18:04] 972 | 2 = stop time 973 | [18:05] 974 | 3 = speed+pitch 975 | [18:05] 976 | 4 = chunk size 977 | [18:06] 978 | density : [2] = density code, [3][4] = block length [5] = flags 979 | [18:06] 980 | error recovery : [2] = type [3] = retry count 981 | [18:07] 982 | stop time : [2] = time in 100ms 983 | [18:07] 984 | speed/pitch: [2]=speed [3][4] = pitch 985 | [18:09] 986 | chunk size : [2] = chunk size (1-8) 987 | 988 | fixel — Aujourd’hui à 18:17 989 | on density : [5] flags : 990 | [18:18] 991 | 0x80 = 2353 bytes CDDA + error correction (modifié) 992 | [18:19] 993 | 0x40 = 2448 bytes CDDA+subcode 994 | [18:19] 995 | 0xc0 (0x80|0x40) = 2449 bytes : CDDA+subcode+error correction 996 | [18:19] 997 | 0x00 : 2048 998 | [18:21] 999 | what's your reply to 0x83? 1000 | */ 1001 | 1002 | if (data_in[0] == 0x3) { 1003 | if (data_in[1] & (0x80)) { 1004 | status |= DOUBLE_SPEED; 1005 | } else { 1006 | status &= ~DOUBLE_SPEED; 1007 | } 1008 | 1009 | if (data_in[2] & 0x4) { 1010 | //Pitch correction On 1011 | pitch = ((data_in[2]&0x3)<<8) | data_in[3]; 1012 | if (data_in[2]&0x2) pitch -= 1024; 1013 | } else { 1014 | pitch = 0; 1015 | } 1016 | } 1017 | if (data_in[0] == 0x0) { 1018 | currentImage.block_size_read = (data_in[2]<<8)|(data_in[3]); 1019 | if ((data_in[4] & 0xC0) == 0x80) { 1020 | currentImage.block_size_read = 2353; //CDDA + error correction 1021 | } 1022 | if ((data_in[4] & 0xC0) == 0x40) { 1023 | currentImage.block_size_read = 2448; //CDDA+subcode 1024 | } 1025 | if ((data_in[4] & 0xC0) == 0xC0) { 1026 | currentImage.block_size_read = 2449; //CDDA+subcode+error correction 1027 | } 1028 | LOG_SATA("Block size to %d\n",currentImage.block_size_read ); 1029 | } 1030 | buffer[index++] = SET_MODE; 1031 | buffer[index++] = status; 1032 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1033 | break; 1034 | case READ_SUB_Q: 1035 | if (status & DISC_PRESENT) { 1036 | for (int i=0; i<6; i++) { 1037 | data_in[i] = GET_BUS(get3doData()); 1038 | } 1039 | LOG_SATA("READ_SUB_Q\n"); 1040 | buffer[index++] = READ_SUB_Q; 1041 | readSubQChannel(&subBuffer[0]); 1042 | while(!block_is_ready()); 1043 | 1044 | buffer[index++] = subBuffer[5]; //Ctrl/adr 1045 | buffer[index++] = subBuffer[6]; //trk 1046 | buffer[index++] = subBuffer[7]; //idx 1047 | buffer[index++] = 0; 1048 | buffer[index++] = subBuffer[9]; //total M 1049 | buffer[index++] = subBuffer[10]; //total S 1050 | buffer[index++] = subBuffer[11]; //total F 1051 | buffer[index++] = subBuffer[13]; //current M 1052 | buffer[index++] = subBuffer[14]; //current S 1053 | buffer[index++] = subBuffer[15]; //current F 1054 | buffer[index++] = status; 1055 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1056 | } 1057 | break; 1058 | //FIXEL Extended commands implementation for ODE menu 1059 | case EXT_ID: 1060 | for (int i=0; i<6; i++) { 1061 | data_in[i] = GET_BUS(get3doData()); 1062 | } 1063 | LOG_SATA("EXT_ID\n"); 1064 | buffer[index++] = EXT_ID; 1065 | buffer[index++] = 0x1; //Where is located the boot.iso microsd=1, usbmsc=2, flash=4, sata=8 1066 | buffer[index++] = 'L'; 1067 | buffer[index++] = 'O'; 1068 | buffer[index++] = 'C'; 1069 | buffer[index++] = 'O'; 1070 | buffer[index++] = 'D'; 1071 | buffer[index++] = 'E'; 1072 | buffer[index++] = 1; //rev major 1073 | buffer[index++] = 1; //rev minor 1074 | buffer[index++] = 0; //rev patch 1075 | buffer[index++] = status; 1076 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1077 | break; 1078 | case CHANGE_TOC: 1079 | for (int i=0; i<6; i++) { 1080 | data_in[i] = GET_BUS(get3doData()); 1081 | } 1082 | buffer[index++] = CHANGE_TOC; 1083 | { 1084 | uint32_t entry = 0; 1085 | entry = ((data_in[0]&0xFF)<<24)|((data_in[1]&0xFF)<<16)|((data_in[2]&0xFF)<<8)|((data_in[3]&0xFF)<<0); 1086 | LOG_SATA("CHANGE_TOC %d on %d\n", entry&0xFFFFFF, entry>>24); 1087 | handleTocChange(entry); 1088 | } 1089 | buffer[index++] = status; 1090 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1091 | break; 1092 | case GET_TOC: 1093 | for (int i=0; i<6; i++) { 1094 | data_in[i] = GET_BUS(get3doData()); 1095 | } 1096 | buffer[index++] = GET_TOC; 1097 | { 1098 | uint32_t entry = 0; 1099 | uint16_t offset = 0; 1100 | entry = ((data_in[0]&0xFF)<<24)|((data_in[1]&0xFF)<<16)|((data_in[2]&0xFF)<<8)|((data_in[3]&0xFF)<<0); 1101 | offset = ((data_in[4]&0xFF)<<8)|((data_in[5]&0xFF)<<0); 1102 | LOG_SATA("GET_TOC %d %d\n", entry, offset); 1103 | getToc(entry, offset, &buffer[index]); 1104 | for (int i=0; i<16; i++) LOG_SATA("%x ", buffer[index+i]); 1105 | LOG_SATA("\n"); 1106 | index += 16; 1107 | } 1108 | buffer[index++] = status; 1109 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1110 | break; 1111 | case GET_DESC: 1112 | for (int i=0; i<6; i++) { 1113 | data_in[i] = GET_BUS(get3doData()); 1114 | } 1115 | LOG_SATA("GET_DESC\n"); 1116 | buffer[index++] = GET_DESC; 1117 | buffer[index++] = status; 1118 | break; 1119 | case CLEAR_PLAYLIST: 1120 | for (int i=0; i<6; i++) { 1121 | data_in[i] = GET_BUS(get3doData()); 1122 | } 1123 | LOG_SATA("CLEAR_PLAYLIST\n"); 1124 | buffer[index++] = CLEAR_PLAYLIST; 1125 | buffer[index++] = status; 1126 | clearPlaylist(); 1127 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1128 | break; 1129 | case ADD_PLAYLIST: 1130 | for (int i=0; i<6; i++) { 1131 | data_in[i] = GET_BUS(get3doData()); 1132 | } 1133 | buffer[index++] = ADD_PLAYLIST; 1134 | { 1135 | uint32_t entry = 0; 1136 | bool valid = false; 1137 | bool added = false; 1138 | entry = ((data_in[0]&0xFF)<<24)|((data_in[1]&0xFF)<<16)|((data_in[2]&0xFF)<<8)|((data_in[3]&0xFF)<<0); 1139 | LOG_SATA("ADD_PLAYLIST %d\n", entry); 1140 | addToPlaylist(entry, &valid, &added); 1141 | buffer[index++] = valid; 1142 | buffer[index++] = added; 1143 | } 1144 | buffer[index++] = status; 1145 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1146 | break; 1147 | case LAUNCH_PLAYLIST: 1148 | for (int i=0; i<6; i++) { 1149 | data_in[i] = GET_BUS(get3doData()); 1150 | } 1151 | LOG_SATA("LAUNCH_PLAYLIST\n"); 1152 | //Initiate an media change error 1153 | status |= CHECK_ERROR; 1154 | buffer[index++] = LAUNCH_PLAYLIST; 1155 | buffer[index++] = status; 1156 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1157 | mediaInterrupt(); 1158 | break; 1159 | case GET_TOC_LIST: 1160 | for (int i=0; i<6; i++) { 1161 | data_in[i] = GET_BUS(get3doData()); 1162 | } 1163 | buffer[index++] = GET_TOC_LIST; 1164 | { 1165 | uint32_t entry = 0; 1166 | uint16_t offset = 0; 1167 | entry = ((data_in[0]&0xFF)<<24)|((data_in[1]&0xFF)<<16)|((data_in[2]&0xFF)<<8)|((data_in[3]&0xFF)<<0); 1168 | offset = ((data_in[4]&0xFF)<<8)|((data_in[5]&0xFF)<<0); 1169 | LOG_SATA("GET_TOC_LIST %d %d\n", entry, offset); 1170 | getTocFull(entry, offset); 1171 | } 1172 | sendRawData(GET_TOC_LIST, &TOC[0], 2048); 1173 | LOG_SATA("TOC Buffer:\n"); 1174 | for (int i=0; i<2048;) { 1175 | uint32_t flags = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 1176 | if (flags != TOC_FLAG_INVALID) { 1177 | uint32_t toc_id = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 1178 | uint32_t name_length = (TOC[i++]<<24)|(TOC[i++]<<16)|(TOC[i++]<<8)|(TOC[i++]<<0); 1179 | LOG_SATA(".flags :0x%x, .toc_id: %d %d, .name_length: %d, .name: %s\n", flags, toc_id>>24, getTocEntry(toc_id), name_length, &TOC[i]); 1180 | i += name_length; 1181 | } else break; 1182 | } 1183 | LOG_SATA("\n"); 1184 | break; 1185 | //Not supported yet 1186 | case CREATE_FILE: 1187 | for (int i=0; i<6; i++) { 1188 | data_in[i] = GET_BUS(get3doData()); 1189 | } 1190 | LOG_SATA("CREATE_FILE\n"); 1191 | buffer[index++] = CREATE_FILE; 1192 | buffer[index++] = 0; //Always report a failure 1193 | buffer[index++] = status; 1194 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1195 | break; 1196 | case OPEN_FILE: 1197 | for (int i=0; i<6; i++) { 1198 | data_in[i] = GET_BUS(get3doData()); 1199 | } 1200 | { 1201 | bool write = (data_in[5]!=0); 1202 | bool success = false; 1203 | if ((data_in[0]&0xFF) != 0) { 1204 | uint32_t toc_id = ((data_in[1]&0xFF)<<24)|((data_in[2]&0xFF)<<16)|((data_in[3]&0xFF)<<8)|((data_in[4]&0xFF)<<0); 1205 | LOG_SATA("OPEN_FILE TOC_ID %x, W/R %d\n", toc_id, write); 1206 | } else { 1207 | uint16_t name_length = ((data_in[1]&0xFF)<<8)|((data_in[2]&0xFF)<<0); 1208 | LOG_SATA("OPEN_FILE NAME %d %s, W/R %d\n", name_length, &FILE_BUFFER[0], write); 1209 | requestOpenFile(&FILE_BUFFER[0], name_length, write); 1210 | while (!cmd_is_ready(&success)); 1211 | } 1212 | buffer[index++] = OPEN_FILE; 1213 | buffer[index++] = success; //Always report a failure 1214 | buffer[index++] = status; 1215 | } 1216 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1217 | break; 1218 | case SEEK_FILE: 1219 | for (int i=0; i<6; i++) { 1220 | data_in[i] = GET_BUS(get3doData()); 1221 | } 1222 | LOG_SATA("SEEK_FILE\n"); 1223 | buffer[index++] = SEEK_FILE; 1224 | buffer[index++] = status; 1225 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1226 | break; 1227 | case READ_FILE_BYTE: 1228 | for (int i=0; i<6; i++) { 1229 | data_in[i] = GET_BUS(get3doData()); 1230 | } 1231 | { 1232 | bool success = false; 1233 | uint16_t length = ((data_in[0]&0xFF)<<8)|((data_in[1]&0xFF)<<0); 1234 | LOG_SATA("READ_FILE_BYTE %x\n", length); 1235 | requestReadFile(&FILE_BUFFER[0], length); 1236 | while (!cmd_is_ready(&success)); 1237 | buffer[index++] = READ_FILE_BYTE; 1238 | buffer[index++] = success?data_in[0]:0; 1239 | buffer[index++] = success?data_in[1]:0; 1240 | } 1241 | buffer[index++] = status; 1242 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1243 | break; 1244 | case WRITE_FILE_BYTE: 1245 | for (int i=0; i<6; i++) { 1246 | data_in[i] = GET_BUS(get3doData()); 1247 | }{ 1248 | bool success = false; 1249 | uint16_t length = ((data_in[0]&0xFF)<<8)|((data_in[1]&0xFF)<<0); 1250 | LOG_SATA("WRITE_FILE_BYTE %x\n", length); 1251 | requestWriteFile(&FILE_BUFFER[0], length); 1252 | while (!cmd_is_ready(&success)); 1253 | buffer[index++] = WRITE_FILE_BYTE; 1254 | buffer[index++] = success?data_in[0]:0; 1255 | buffer[index++] = success?data_in[1]:0; 1256 | } 1257 | buffer[index++] = status; 1258 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1259 | break; 1260 | case CLOSE_FILE: 1261 | for (int i=0; i<6; i++) { 1262 | data_in[i] = GET_BUS(get3doData()); 1263 | } 1264 | LOG_SATA("CLOSE_FILE\n"); 1265 | requestCloseFile(); 1266 | while (!cmd_is_ready(NULL)); 1267 | buffer[index++] = CLOSE_FILE; 1268 | buffer[index++] = status; 1269 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1270 | break; 1271 | case WRITE_BUFFER_OFFSET: 1272 | for (int i=0; i<6; i++) { 1273 | data_in[i] = GET_BUS(get3doData()); 1274 | } 1275 | { 1276 | uint16_t offset = (((data_in[0]&0xFF)<<8)|((data_in[1]&0xFF)<<0))<<2; 1277 | LOG_SATA("WRITE_BUFFER_OFFSET 0x%x\n", offset); 1278 | for (int i=0; i<4; i++) { 1279 | FILE_BUFFER[offset+i] = data_in[2+i]; 1280 | } 1281 | } 1282 | buffer[index++] = WRITE_BUFFER_OFFSET; 1283 | buffer[index++] = status; 1284 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1285 | break; 1286 | case READ_BUFFER: 1287 | for (int i=0; i<6; i++) { 1288 | data_in[i] = GET_BUS(get3doData()); 1289 | } 1290 | LOG_SATA("READ_BUFFER\n"); 1291 | sendRawData(READ_BUFFER, &FILE_BUFFER[0], 2048); 1292 | break; 1293 | case UPDATE_ODE: 1294 | for (int i=0; i<6; i++) { 1295 | data_in[i] = GET_BUS(get3doData()); 1296 | } 1297 | LOG_SATA("UPDATE_ODE\n"); 1298 | buffer[index++] = UPDATE_ODE; 1299 | buffer[index++] = status; 1300 | sendAnswer(buffer, index, CHAN_WRITE_STATUS); 1301 | break; 1302 | default: LOG_SATA("unknown Cmd %x\n", request); 1303 | } 1304 | } 1305 | 1306 | void setupDMA(uint8_t access) { 1307 | channel[access] = dma_claim_unused_channel(true); 1308 | config[access] = dma_channel_get_default_config(channel[access]); 1309 | channel_config_set_transfer_data_size(&config[access], DMA_SIZE_8); 1310 | channel_config_set_read_increment(&config[access], true); 1311 | channel_config_set_write_increment(&config[access], false); 1312 | channel_config_set_irq_quiet(&config[access], true); 1313 | channel_config_set_dreq(&config[access], DREQ_PIO0_TX0 + access); 1314 | dma_channel_set_write_addr(channel[access], &pio0->txf[sm[access]], false); 1315 | dma_channel_set_config(channel[access], &config[access], false); 1316 | 1317 | bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS; 1318 | } 1319 | 1320 | void pio_program_init(int channel) { 1321 | sm[channel] = channel; 1322 | sm_offset[channel] = pio_add_program(pio0, &write_program); 1323 | write_program_init(pio0, sm[channel], sm_offset[channel]); 1324 | instr_jmp[channel] = pio_encode_jmp(sm_offset[channel]); 1325 | LOG_SATA("Prog %d offset %d\n", channel, sm_offset[channel]); 1326 | } 1327 | 1328 | static absolute_time_t s; 1329 | static bool debounceEject = false; 1330 | 1331 | void core1_entry() { 1332 | 1333 | uint32_t data_in; 1334 | bool reset_occured = true; 1335 | bool ejectState = gpio_get(EJECT); 1336 | 1337 | lastPacket = nil_time; 1338 | 1339 | instr_out = pio_encode_out(pio_null, 16); 1340 | instr_pull = pio_encode_pull(pio_null, 32); 1341 | instr_set = pio_encode_set(pio_pins, 0b11); 1342 | 1343 | for (int i = 0; i< CHAN_MAX; i++) { 1344 | pio_program_init(i); 1345 | setupDMA(i); 1346 | } 1347 | 1348 | LOG_SATA("Ready\n"); 1349 | while (1){ 1350 | 1351 | if (use_cdrom) { 1352 | gpio_put(CDRST_SNIFF, gpio_get(CDRST)); 1353 | gpio_put(CDEN_SNIFF, gpio_get(CDEN)); 1354 | } else { 1355 | if (!gpio_get(CDRST)) { 1356 | LOG_SATA("Got a reset Status!\n"); 1357 | reset_occured = true; 1358 | wait_out_of_reset(); 1359 | status |= CHECK_ERROR; 1360 | errorCode = POWER_OR_RESET_OCCURED; 1361 | restartReadPio(); 1362 | } 1363 | if (gpio_get(CDEN)) { 1364 | LOG_SATA("CD is not enabled\n"); 1365 | while(gpio_get(CDEN)); 1366 | LOG_SATA("CD is enabled now\n"); 1367 | } 1368 | 1369 | bool ejectCurrent = gpio_get(EJECT); 1370 | if ((ejectCurrent != ejectState)) { 1371 | if (!debounceEject) s = get_absolute_time(); 1372 | debounceEject = true; 1373 | if (absolute_time_diff_us(s, get_absolute_time()) > 25000) { 1374 | ejectState = ejectCurrent; 1375 | //Eject button pressed, toggle tray position 1376 | if (!ejectCurrent) { 1377 | close_tray((status & TRAY_IN) == 0); 1378 | } 1379 | debounceEject = false; 1380 | } 1381 | } else { 1382 | if (debounceEject && (absolute_time_diff_us(s, get_absolute_time()) > 25000)) debounceEject = false; 1383 | } 1384 | 1385 | reset_occured = false; 1386 | if (is3doData()) { 1387 | data_in = get3doData(); 1388 | handleCommand(data_in); 1389 | } 1390 | handleMediaInterrupt(); 1391 | } 1392 | } 1393 | } 1394 | 1395 | void _3DO_init() { 1396 | // use_cdrom = true; 1397 | uint offset = -1; 1398 | 1399 | gpio_init(CDRST); 1400 | gpio_set_dir(CDRST, false); 1401 | 1402 | gpio_init(EJECT); 1403 | gpio_set_dir(EJECT, false); 1404 | 1405 | gpio_init(CDWAIT); 1406 | gpio_put(CDWAIT, 1); //CDWAIT is always 1 1407 | gpio_set_dir(CDWAIT, (!use_cdrom)); 1408 | 1409 | gpio_init(CDEN); 1410 | gpio_set_dir(CDEN, false); 1411 | 1412 | gpio_init(CDMDCHG); 1413 | gpio_put(CDMDCHG, 1); 1414 | gpio_set_dir(CDMDCHG, (!use_cdrom)); 1415 | 1416 | 1417 | gpio_init(CDSTEN); 1418 | gpio_put(CDSTEN, 1); 1419 | gpio_set_dir(CDSTEN, (!use_cdrom)); 1420 | 1421 | gpio_init(CDDTEN); 1422 | gpio_put(CDDTEN, 1); 1423 | gpio_set_dir(CDDTEN, (!use_cdrom)); 1424 | 1425 | gpio_init(LED); 1426 | gpio_set_dir(LED, (!use_cdrom)); 1427 | 1428 | gpio_init(CDHRD); 1429 | gpio_set_dir(CDHRD, false); 1430 | 1431 | gpio_init(CDHWR); 1432 | gpio_set_dir(CDHWR, false); 1433 | 1434 | gpio_init(DIR_DATA); 1435 | gpio_put(DIR_DATA, DATA_IN); //Input data 1436 | gpio_set_dir(DIR_DATA, (!use_cdrom)); 1437 | 1438 | gpio_set_dir_masked(DATA_BUS_MASK, DATA_BUS_MASK); 1439 | gpio_init_mask(DATA_BUS_MASK); 1440 | 1441 | gpio_init(CDRST_SNIFF); 1442 | gpio_put(CDRST_SNIFF, 0); 1443 | gpio_set_dir(CDRST_SNIFF, (!use_cdrom)); 1444 | 1445 | gpio_init(CDEN_SNIFF); 1446 | gpio_put(CDEN_SNIFF, 1); 1447 | gpio_set_dir(CDEN_SNIFF, (!use_cdrom)); 1448 | 1449 | if (!use_cdrom) { 1450 | 1451 | sm_read = CHAN_MAX; 1452 | offset = pio_add_program(pio0, &read_program); 1453 | read_program_init(pio0, sm_read, offset); 1454 | instr_jmp_read = pio_encode_jmp(offset); 1455 | 1456 | 1457 | for (int i = 0; i<32; i++) { 1458 | gpio_set_drive_strength(i, GPIO_DRIVE_STRENGTH_12MA); 1459 | } 1460 | 1461 | pio_gpio_init(pio0, CDD0); 1462 | pio_gpio_init(pio0, CDD1); 1463 | pio_gpio_init(pio0, CDD2); 1464 | pio_gpio_init(pio0, CDD3); 1465 | pio_gpio_init(pio0, CDD4); 1466 | pio_gpio_init(pio0, CDD5); 1467 | pio_gpio_init(pio0, CDD6); 1468 | pio_gpio_init(pio0, CDD7); 1469 | } 1470 | 1471 | 1472 | LOG_SATA("wait for msg now\n"); 1473 | 1474 | 1475 | int clock = clock_get_hz(clk_sys); 1476 | LOG_SATA("Clock is %d\n", clock); 1477 | 1478 | multicore_launch_core1(core1_entry); 1479 | } 1480 | --------------------------------------------------------------------------------