├── README ├── README.md ├── gopt.c ├── gopt.h ├── loader64.c ├── loader64.h ├── make.sh └── xcode └── loader64.xcodeproj ├── project.pbxproj ├── project.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── jfriend.xcuserdatad │ └── UserInterfaceState.xcuserstate └── xcuserdata └── jfriend.xcuserdatad └── xcschemes └── xcschememanagement.plist /README: -------------------------------------------------------------------------------- 1 | loader64 - Everdrive64 USB-tool v0.1 2 | by saturnu 3 | 4 | 5 | OS64 compatible USB upload tool 6 | please run as root 7 | 8 | 9 | required libs: 10 | libftdi 0.20 11 | http://www.intra2net.com/en/developer/libftdi/ 12 | 13 | 14 | compilation: 15 | chmod +x make.sh 16 | ./make.sh 17 | 18 | 19 | - examples - 20 | 21 | upload rom: 22 | sudo ./loader64 -vwf OS64.v64 23 | 24 | boot rom: 25 | sudo ./loader64 -vp 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # loader64 2 | loader64 - Everdrive64 USB-tool v0.1 3 | 4 | OS64 compatible USB upload tool 5 | 6 | by saturnu 7 | 8 | originally from http://krikzz.com/forum/index.php?topic=1407.msg14076 9 | 10 | forked by @jsdf to add macOS compatibility 11 | 12 | ## macOS instructions 13 | 14 | ### building from source 15 | 16 | install required libraries from homebrew: 17 | 18 | ```bash 19 | brew install libftdi libusb 20 | ``` 21 | 22 | - in XCode, open [xcode/loader64.xcodeproj](xcode/loader64.xcodeproj) 23 | 24 | - by default, building will install loader64 to `/usr/local/bin`. If you want to change this, in the loader64 target's build phases tab, change the 'copy files' command output path to where you want the loader64 binary installed 25 | 26 | - click 'run' to build and install loader64 binary 27 | 28 | ### usage 29 | 30 | uploading and booting a rom: 31 | 32 | ```bash 33 | # upload rom 34 | ./loader64 -v --write --file somerom.n64 35 | 36 | # boot rom that was uploaded 37 | ./loader64 -v --pifboot 38 | ``` 39 | 40 | 41 | ## linux instructions 42 | please run as root 43 | 44 | install `libftdi` from your package manager of choice (including headers). eg for ubuntu: 45 | 46 | ```bash 47 | sudo apt-get install libftdi1 libftdi1-dev 48 | ``` 49 | 50 | ```bash 51 | ./make.sh 52 | ``` 53 | 54 | - examples - 55 | 56 | upload rom: 57 | 58 | ```bash 59 | sudo ./loader64 -vwf somerom.v64 60 | ``` 61 | 62 | boot rom: 63 | ```bash 64 | sudo ./loader64 -vp 65 | ``` 66 | -------------------------------------------------------------------------------- /gopt.c: -------------------------------------------------------------------------------- 1 | /* gopt.c version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ 2 | /* 3 | I, Tom Vajzovic, am the author of this software and its documentation and 4 | permanently abandon all copyright and other intellectual property rights in 5 | them, including the right to be identified as the author. 6 | 7 | I am fairly certain that this software does what the documentation says it 8 | does, but I cannot guarantee that it does, or that it does what you think it 9 | should, and I cannot guarantee that it will not have undesirable side effects. 10 | 11 | You are free to use, modify and distribute this software as you please, but 12 | you do so at your own risk. If you remove or hide this warning then you are 13 | responsible for any problems encountered by people that you make the software 14 | available to. 15 | 16 | Before modifying or distributing this software I ask that you would please 17 | read http://www.purposeful.co.uk/tfl/ 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "gopt.h" 24 | 25 | #ifdef USE_SYSEXITS 26 | #include 27 | #else 28 | #define EX_OSERR EXIT_FAILURE 29 | #define EX_USAGE EXIT_FAILURE 30 | #endif 31 | 32 | struct opt_spec_s { 33 | int key; 34 | int flags; 35 | const char *shorts; 36 | const char* const *longs; 37 | }; 38 | typedef struct opt_spec_s opt_spec_t; 39 | 40 | struct opt_s { 41 | int key; 42 | const char *arg; 43 | }; 44 | typedef struct opt_s opt_t; 45 | 46 | void *gopt_sort( int *argc, const char **argv, const void *opt_specs ){ 47 | void *opts; 48 | {{{ 49 | const char* const *arg_p= argv + 1; 50 | size_t opt_count= 1; 51 | for( ; *arg_p; ++arg_p ) 52 | if( '-' == (*arg_p)[0] && (*arg_p)[1] ) 53 | if( '-' == (*arg_p)[1] ) 54 | if( (*arg_p)[2] ) 55 | ++opt_count; 56 | else 57 | break; 58 | else { 59 | const opt_spec_t *opt_spec_p= opt_specs; 60 | for( ; opt_spec_p-> key; ++opt_spec_p ) 61 | if( strchr( opt_spec_p-> shorts, (*arg_p)[1] )){ 62 | opt_count+= opt_spec_p-> flags & GOPT_ARG ? 1 : strlen( (*arg_p) + 1 ); 63 | break; 64 | } 65 | } 66 | opts= malloc( opt_count * sizeof(opt_t) ); 67 | }}} 68 | { 69 | const char **arg_p= argv + 1; 70 | const char **next_operand= arg_p; 71 | opt_t *next_option= opts; 72 | 73 | if( ! opts ){ 74 | perror( argv[0] ); 75 | exit( EX_OSERR ); 76 | } 77 | for( ; *arg_p; ++arg_p ) 78 | if( '-' == (*arg_p)[0] && (*arg_p)[1] ) 79 | if( '-' == (*arg_p)[1] ) 80 | if( (*arg_p)[2] ) 81 | {{{ 82 | const opt_spec_t *opt_spec_p= opt_specs; 83 | const char* const *longs= opt_spec_p-> longs; 84 | next_option-> key= 0; 85 | while( *longs ){ 86 | const char *option_cp= (*arg_p) + 2; 87 | const char *name_cp= *longs; 88 | while( *option_cp && *option_cp == *name_cp ){ 89 | ++option_cp; 90 | ++name_cp; 91 | } 92 | if( '=' == *option_cp || !*option_cp ){ 93 | if( *name_cp ){ 94 | if( next_option-> key ){ 95 | fprintf( stderr, "%s: --%.*s: abbreviated option is ambiguous\n", argv[0], (int)( option_cp -( (*arg_p) + 2 )), (*arg_p) + 2 ); 96 | free( opts ); 97 | exit( EX_USAGE ); 98 | } 99 | next_option-> key= opt_spec_p-> key; 100 | } 101 | else { 102 | next_option-> key= opt_spec_p-> key; 103 | goto found_long; 104 | } 105 | } 106 | if( !*++longs ){ 107 | ++opt_spec_p; 108 | if( opt_spec_p-> key ) 109 | longs= opt_spec_p-> longs; 110 | } 111 | } 112 | if( ! next_option-> key ){ 113 | fprintf( stderr, "%s: --%.*s: unknown option\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); 114 | free( opts ); 115 | exit( EX_USAGE ); 116 | } 117 | for( opt_spec_p= opt_specs; opt_spec_p-> key != next_option-> key; ++opt_spec_p ); 118 | found_long: 119 | 120 | if( !( opt_spec_p-> flags & GOPT_REPEAT )){ 121 | const opt_t *opt_p= opts; 122 | for( ; opt_p != next_option; ++opt_p ) 123 | if( opt_p-> key == opt_spec_p-> key ){ 124 | fprintf( stderr, "%s: --%.*s: option may not be repeated (in any long or short form)\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); 125 | free( opts ); 126 | exit( EX_USAGE ); 127 | } 128 | } 129 | if( opt_spec_p-> flags & GOPT_ARG ){ 130 | next_option-> arg= strchr( (*arg_p) + 2, '=' ) + 1; 131 | if( (char*)0 + 1 == next_option-> arg ){ 132 | ++arg_p; 133 | if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ 134 | fprintf( stderr, "%s: --%s: option requires an option argument\n", argv[0], (*(arg_p-1)) + 2 ); 135 | free( opts ); 136 | exit( EX_USAGE ); 137 | } 138 | next_option-> arg= *arg_p; 139 | } 140 | } 141 | else { 142 | if( strchr( (*arg_p) + 2, '=' )){ 143 | fprintf( stderr, "%s: --%.*s: option may not take an option argument\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); 144 | free( opts ); 145 | exit( EX_USAGE ); 146 | } 147 | next_option-> arg= NULL; 148 | } 149 | ++next_option; 150 | }}} 151 | else { 152 | for( ++arg_p; *arg_p; ++arg_p ) 153 | *next_operand++= *arg_p; 154 | break; 155 | } 156 | else 157 | {{{ 158 | const char *short_opt= (*arg_p) + 1; 159 | for( ;*short_opt; ++short_opt ){ 160 | const opt_spec_t *opt_spec_p= opt_specs; 161 | 162 | for( ; opt_spec_p-> key; ++opt_spec_p ) 163 | if( strchr( opt_spec_p-> shorts, *short_opt )){ 164 | if( !( opt_spec_p-> flags & GOPT_REPEAT )){ 165 | const opt_t *opt_p= opts; 166 | for( ; opt_p != next_option; ++opt_p ) 167 | if( opt_p-> key == opt_spec_p-> key ){ 168 | fprintf( stderr, "%s: -%c: option may not be repeated (in any long or short form)\n", argv[0], *short_opt ); 169 | free( opts ); 170 | exit( EX_USAGE ); 171 | } 172 | } 173 | next_option-> key= opt_spec_p-> key; 174 | 175 | if( opt_spec_p-> flags & GOPT_ARG ){ 176 | if( short_opt[1] ) 177 | next_option-> arg= short_opt + 1; 178 | 179 | else { 180 | ++arg_p; 181 | if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ 182 | fprintf( stderr, "%s: -%c: option requires an option argument\n", argv[0], *short_opt ); 183 | free( opts ); 184 | exit( EX_USAGE ); 185 | } 186 | next_option-> arg= *arg_p; 187 | } 188 | ++next_option; 189 | goto break_2; 190 | } 191 | next_option-> arg= NULL; 192 | ++next_option; 193 | goto continue_2; 194 | } 195 | fprintf( stderr, "%s: -%c: unknown option\n", argv[0], *short_opt ); 196 | free( opts ); 197 | exit( EX_USAGE ); 198 | continue_2: 0; 199 | } 200 | break_2: 0; 201 | }}} 202 | else 203 | *next_operand++= *arg_p; 204 | 205 | next_option-> key= 0; 206 | *next_operand= NULL; 207 | *argc= next_operand - argv; 208 | } 209 | return opts; 210 | } 211 | 212 | size_t gopt( const void *vptr_opts, int key ){ 213 | const opt_t *opts= vptr_opts; 214 | size_t count= 0; 215 | for( ; opts-> key; ++opts ) 216 | count+= opts-> key == key; 217 | 218 | return count; 219 | } 220 | 221 | size_t gopt_arg( const void *vptr_opts, int key, const char **arg ){ 222 | const opt_t *opts= vptr_opts; 223 | size_t count= 0; 224 | 225 | for( ; opts-> key; ++opts ) 226 | if( opts-> key == key ){ 227 | if( ! count ) 228 | *arg= opts-> arg; 229 | ++count; 230 | } 231 | return count; 232 | } 233 | 234 | const char *gopt_arg_i( const void *vptr_opts, int key, size_t i ){ 235 | const opt_t *opts= vptr_opts; 236 | 237 | for( ; opts-> key; ++opts ) 238 | if( opts-> key == key ){ 239 | if( ! i ) 240 | return opts-> arg; 241 | --i; 242 | } 243 | return NULL; 244 | } 245 | 246 | size_t gopt_args( const void *vptr_opts, int key, const char **args, size_t args_len ){ 247 | const char **args_stop= args + args_len; 248 | const char **args_ptr= args; 249 | const opt_t *opts= vptr_opts; 250 | 251 | for( ; opts-> key; ++opts ) 252 | if( opts-> key == key ){ 253 | if( args_stop == args_ptr ) 254 | return args_len + gopt( opts, key ); 255 | 256 | *args_ptr++= opts-> arg; 257 | } 258 | if( args_stop != args_ptr ) 259 | *args_ptr= NULL; 260 | return args_ptr - args; 261 | } 262 | 263 | void gopt_free( void *vptr_opts ){ 264 | free( vptr_opts ); 265 | } 266 | -------------------------------------------------------------------------------- /gopt.h: -------------------------------------------------------------------------------- 1 | /* gopt.h version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ 2 | /* 3 | I, Tom Vajzovic, am the author of this software and its documentation and 4 | permanently abandon all copyright and other intellectual property rights in 5 | them, including the right to be identified as the author. 6 | 7 | I am fairly certain that this software does what the documentation says it 8 | does, but I cannot guarantee that it does, or that it does what you think it 9 | should, and I cannot guarantee that it will not have undesirable side effects. 10 | 11 | You are free to use, modify and distribute this software as you please, but 12 | you do so at your own risk. If you remove or hide this warning then you are 13 | responsible for any problems encountered by people that you make the software 14 | available to. 15 | 16 | Before modifying or distributing this software I ask that you would please 17 | read http://www.purposeful.co.uk/tfl/ 18 | */ 19 | 20 | #ifndef GOPT_H_INCLUDED 21 | #define GOPT_H_INCLUDED 22 | 23 | #define GOPT_ONCE 0 24 | #define GOPT_REPEAT 1 25 | #define GOPT_NOARG 0 26 | #define GOPT_ARG 2 27 | 28 | #define gopt_start(...) (const void*)( const struct { int k; int f; const char *s; const char*const*l; }[]){ __VA_ARGS__, {0}} 29 | #define gopt_option(k,f,s,l) { k, f, s, l } 30 | #define gopt_shorts( ... ) (const char*)(const char[]){ __VA_ARGS__, 0 } 31 | #define gopt_longs( ... ) (const char**)(const char*[]){ __VA_ARGS__, NULL } 32 | 33 | 34 | void *gopt_sort( int *argc, const char **argv, const void *opt_specs ); 35 | /* returns a pointer for use in the following calls 36 | * prints to stderr and call exit() on error 37 | */ 38 | size_t gopt( const void *opts, int key ); 39 | /* returns the number of times the option was specified 40 | * which will be 0 or 1 unless GOPT_REPEAT was used 41 | */ 42 | size_t gopt_arg( const void *opts, int key, const char **arg ); 43 | /* returns the number of times the option was specified 44 | * writes a pointer to the option argument from the first (or only) occurance to *arg 45 | */ 46 | const char *gopt_arg_i( const void *opts, int key, size_t i ); 47 | /* returns a pointer to the ith (starting at zero) occurance 48 | * of the option, or NULL if it was not specified that many times 49 | */ 50 | size_t gopt_args( const void *opts, int key, const char **args, size_t args_len ); 51 | /* returns the number of times the option was specified 52 | * writes pointers to the option arguments in the order of occurance to args[]. 53 | * writes at most args_len pointers 54 | * if the return value is less than args_len, also writes a null pointer 55 | */ 56 | void gopt_free( void *opts ); 57 | /* releases memory allocated in the corresponding call to gopt_sort() 58 | * opts can no longer be used 59 | */ 60 | #endif /* GOPT_H_INCLUDED */ 61 | -------------------------------------------------------------------------------- /loader64.c: -------------------------------------------------------------------------------- 1 | /* loader64.c 2 | libftdi Everdrive 64 USB-tool 3 | by saturnu 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "gopt.h" 13 | #include "loader64.h" 14 | 15 | int main( int argc, const char **argv ) 16 | { 17 | 18 | //usb buffer 19 | char send_buff[512]; 20 | char recv_buff[512]; 21 | 22 | int arg_fail=1; 23 | 24 | //rom filename 25 | const char *filename; 26 | 27 | //verbosity level 0-2 28 | int verbosity; 29 | int i,print_help; 30 | 31 | void *options= gopt_sort( & argc, argv, gopt_start( 32 | gopt_option( 'h', 0, gopt_shorts( 'h' ), gopt_longs( "help" )), 33 | gopt_option( 'z', 0, gopt_shorts( 'z' ), gopt_longs( "version" )), 34 | gopt_option( 'v', GOPT_REPEAT, gopt_shorts( 'v' ), gopt_longs( "verbose" )), 35 | gopt_option( 'r', 0, gopt_shorts( 'r' ), gopt_longs( "read" )), 36 | gopt_option( 'w', 0, gopt_shorts( 'w' ), gopt_longs( "write" )), 37 | gopt_option( 'p', 0, gopt_shorts( 'p' ), gopt_longs( "pifboot" )), 38 | gopt_option( 'f', GOPT_ARG, gopt_shorts( 'f' ), gopt_longs( "file" )))); 39 | 40 | 41 | 42 | if( gopt( options, 'h' ) ){ 43 | fprintf( stdout, "Syntax: sudo ./loader64 [options] ...\n\n"); 44 | fprintf( stdout, "loader64 - Everdrive64 USB-tool\n" ); 45 | fprintf( stdout, "by saturnu \n\n" ); 46 | fprintf( stdout, " -h, --help\t\tdisplay this help and exit\n" ); 47 | fprintf( stdout, " -v, --verbose\t\tverbose\n" ); 48 | fprintf( stdout, " -f, --file=rom.z64\trom in z64 format\n" ); 49 | //TODO: 50 | //fprintf( stdout, " -r, --read\t\tread from sdram\n" ); 51 | fprintf( stdout, " -w, --write\t\twrite to sdram\n" ); 52 | fprintf( stdout, " -p, --pifboot\t\tsimulate pifboot CIC-6102\n" ); 53 | fprintf( stdout, " -z, --version\t\tversion\n" ); 54 | 55 | exit( EXIT_SUCCESS ); 56 | } 57 | 58 | 59 | //show info without options 60 | print_help=1; 61 | 62 | if( gopt( options, 'p' ) || gopt( options, 'w' ) || gopt( options, 'r') || gopt( options, 'z') || gopt( options, 'h') || gopt( options, 'v') ){ 63 | 64 | print_help = 0; 65 | if( gopt( options, 'p' ) || gopt( options, 'w' ) ) 66 | arg_fail = 0; 67 | } 68 | 69 | 70 | if( gopt( options, 'w' ) && gopt( options, 'r' )){ 71 | 72 | fprintf( stdout, "error: could not read and write at the same time\n" ); 73 | exit( EXIT_SUCCESS ); 74 | } 75 | 76 | if( gopt( options, 'w' ) && gopt( options, 'p' )){ 77 | 78 | fprintf( stdout, "error: use pifboot separately\n" ); 79 | exit( EXIT_SUCCESS ); 80 | } 81 | 82 | 83 | if( gopt( options, 'z' ) ){ 84 | 85 | fprintf( stdout, "loader64 version v%d.%d\n", MAJOR_VERSION, MINOR_VERSION ); 86 | exit( EXIT_SUCCESS ); 87 | } 88 | 89 | 90 | verbosity = gopt( options, 'v' ); 91 | 92 | 93 | if( verbosity > 1 ) 94 | fprintf( stderr, "being really verbose\n" ); 95 | 96 | else if( verbosity ) 97 | fprintf( stderr, "being verbose\n" ); 98 | 99 | 100 | //options are ok - init ftdi 101 | if(!arg_fail){ 102 | 103 | int ret; 104 | struct ftdi_context *ftdi; 105 | if ((ftdi = ftdi_new()) == 0) 106 | { 107 | fprintf(stderr, "ftdi_new failed\n"); 108 | return EXIT_FAILURE; 109 | } 110 | 111 | if ((ret = ftdi_usb_open(ftdi, USB_VENDOR, USB_DEVICE)) < 0) 112 | { 113 | fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(ftdi)); 114 | ftdi_free(ftdi); 115 | return EXIT_FAILURE; 116 | }else{ 117 | //read/write timeout e.g. 500ms 118 | ftdi->usb_read_timeout = USB_READ_TIMEOUT; 119 | ftdi->usb_write_timeout = USB_WRITE_TIMEOUT; 120 | } 121 | 122 | if (ftdi->type == TYPE_R) 123 | { 124 | unsigned int chipid; 125 | if(verbosity >= 1){ 126 | printf("ftdi_read_chipid: %d\n", ftdi_read_chipid(ftdi, &chipid)); 127 | printf("FTDI chipid: %X\n", chipid); 128 | } 129 | } 130 | 131 | 132 | //init usb transfer buffer 133 | memset(send_buff, 0, 512); 134 | memset(recv_buff, 0, 512); 135 | 136 | send_buff[0]='C'; 137 | send_buff[1]='M'; 138 | send_buff[2]='D'; 139 | send_buff[3]='T'; //test 140 | 141 | int ret_s = ftdi_write_data(ftdi, send_buff, 512); 142 | 143 | if(verbosity >= 1) 144 | printf("send: %i bytes\n",ret_s); 145 | 146 | int ret_r = ftdi_read_data(ftdi, recv_buff, 512); 147 | 148 | if(verbosity >= 1) 149 | printf("recv: %i bytes\n",ret_r); 150 | 151 | if(recv_buff[3]=='k'){ 152 | printf("init test: ok\n"); 153 | } 154 | else{ 155 | printf("init test: faild - ED64 not running?\n"); 156 | ftdi_free(ftdi); 157 | exit( EXIT_SUCCESS ); 158 | } 159 | 160 | 161 | memset(send_buff, 0, 512); 162 | memset(recv_buff, 0, 512); 163 | ret_s = 0; 164 | ret_r = 0; 165 | 166 | //pifboot 167 | if( gopt( options, 'p' ) ){ 168 | send_buff[0]='C'; 169 | send_buff[1]='M'; 170 | send_buff[2]='D'; 171 | send_buff[3]='S'; //pif boot 172 | 173 | ret_s = ftdi_write_data(ftdi, send_buff, 512); 174 | 175 | if(verbosity >= 1) 176 | printf("send: %i bytes\n",ret_s); 177 | printf("pif simulation instructed...\n"); 178 | 179 | }else //write 180 | if( gopt( options, 'w' ) ){ 181 | 182 | 183 | if( gopt_arg( options, 'f', & filename ) && strcmp( filename, "-" ) ){ 184 | 185 | FILE *fp; 186 | fp=fopen(filename, "rb"); 187 | int fsize; 188 | 189 | struct stat st; 190 | stat(filename, &st); 191 | fsize = st.st_size; 192 | 193 | if(verbosity >= 1) 194 | printf("test_size: %d\n",fsize); 195 | 196 | 197 | int length = (int) fsize; 198 | 199 | if(verbosity >= 1) 200 | printf("length: %d\n",length); 201 | 202 | if (((length / 0x10000) * 0x10000) != fsize) { 203 | length = (int) (((fsize / 0x10000) * 0x10000) + 0x10000); 204 | } 205 | 206 | 207 | if(verbosity >= 2) 208 | printf("length_buffer: %d\n",length); 209 | 210 | //FILE_CHUNK default 0x8000 211 | char buffer[FILE_CHUNK]; 212 | memset(buffer, 0, FILE_CHUNK); 213 | 214 | if(verbosity >= 2) 215 | printf("buffer created\n"); 216 | 217 | 218 | //tiny rom fill-mode 219 | if (length < 0x200000){ 220 | 221 | if(verbosity >= 1) 222 | printf("needs filling\n"); 223 | 224 | send_buff[0]='C'; 225 | send_buff[1]='M'; 226 | send_buff[2]='D'; 227 | send_buff[3]='F'; //fill 228 | 229 | ret_s = ftdi_write_data(ftdi, send_buff, 512); 230 | 231 | if(verbosity >= 1) 232 | printf("send: %i bytes\n",ret_s); 233 | 234 | sleep(1); 235 | int ret_r = ftdi_read_data(ftdi, recv_buff, 512); 236 | 237 | if(verbosity >= 1) 238 | printf("recv: %i bytes\n",ret_r); 239 | 240 | if(recv_buff[3]=='k'){ 241 | printf("fill test: ok\n"); 242 | memset(send_buff, 0, 512); 243 | memset(recv_buff, 0, 512); 244 | ret_s = 0; 245 | ret_r = 0; 246 | 247 | }else{ 248 | printf("fill test: error\n"); 249 | ftdi_free(ftdi); 250 | exit( EXIT_SUCCESS ); 251 | } 252 | } 253 | 254 | 255 | send_buff[0]='C'; 256 | send_buff[1]='M'; 257 | send_buff[2]='D'; 258 | send_buff[3]='W'; //write 259 | send_buff[4]=0; //offset 260 | send_buff[5]=0; //offset 261 | send_buff[6] = (char) ((( length) / 0x200) >> 8); //length 262 | send_buff[7] = (char) (length / 0x200); //length 263 | 264 | ret_s = ftdi_write_data(ftdi, send_buff, 512); 265 | 266 | if(verbosity >= 1) 267 | printf("send write cmd: %i bytes\n",ret_s); 268 | 269 | //now write in 0x8000 chunks -> 32768 270 | 271 | printf("sending...\n"); 272 | int s; 273 | for(s = 0;s < length; s += 0x8000){ 274 | 275 | if (s == 0x2000000) //step 1024 276 | { 277 | memset(send_buff, 0, 512); 278 | memset(recv_buff, 0, 512); 279 | ret_s = 0; 280 | ret_r = 0; 281 | 282 | send_buff[0]='C'; 283 | send_buff[1]='M'; 284 | send_buff[2]='D'; 285 | send_buff[3]='W'; //write 286 | send_buff[4]=0x40; //32mb offset 287 | send_buff[5]=0; //offset 288 | send_buff[6] = (char) (( ( length - 0x2000000) / 0x200) >> 8); //length 289 | send_buff[7] = (char) (( length - 0x2000000) / 0x200); //length 290 | 291 | ret_s = ftdi_write_data(ftdi, send_buff, 512); 292 | 293 | if(verbosity >= 1) 294 | printf("send offset cmd: %i bytes\n",ret_s); 295 | } 296 | 297 | //read parts to memory 298 | int fret = fread(buffer, sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp); 299 | 300 | ret_s = ftdi_write_data(ftdi, buffer, 0x8000); 301 | 302 | if ((s % 0x80000) == 0) 303 | { 304 | if(verbosity >= 1 && s!=0) 305 | printf("part sent: %i\n",s); 306 | } 307 | } 308 | 309 | printf("upload done...\n", argv[0]); 310 | 311 | } 312 | 313 | 314 | }else //TODO: read 315 | if( gopt( options, 'r' ) ){ 316 | send_buff[0]='C'; 317 | send_buff[1]='M'; 318 | send_buff[2]='D'; 319 | send_buff[3]='R'; //read 320 | } 321 | 322 | 323 | 324 | if ((ret = ftdi_usb_close(ftdi)) < 0) 325 | { 326 | fprintf(stderr, "unable to close ftdi device: %d (%s)\n", ret, ftdi_get_error_string(ftdi)); 327 | ftdi_free(ftdi); 328 | return EXIT_FAILURE; 329 | } 330 | 331 | 332 | ftdi_free(ftdi); 333 | 334 | 335 | } 336 | 337 | if(print_help){ 338 | 339 | printf("%s: missing operand\n", argv[0]); 340 | printf("Try '%s --help' for more information.\n", argv[0]); 341 | } 342 | 343 | 344 | gopt_free( options ); 345 | return EXIT_SUCCESS; 346 | } 347 | 348 | -------------------------------------------------------------------------------- /loader64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * loader64.h 3 | */ 4 | 5 | #define FILE_CHUNK 0x8000 6 | #define USB_VENDOR 0x0403 7 | #define USB_DEVICE 0x6001 8 | #define USB_READ_TIMEOUT 500 9 | #define USB_WRITE_TIMEOUT 500 10 | #define MAJOR_VERSION 0 11 | #define MINOR_VERSION 1 12 | 13 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | gcc loader64.c gopt.c -o loader64 -lusb-1.0 -lftdi1 -------------------------------------------------------------------------------- /xcode/loader64.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 739987E5239C536700EC20E6 /* gopt.c in Sources */ = {isa = PBXBuildFile; fileRef = 739987E2239C536700EC20E6 /* gopt.c */; }; 11 | 739987E6239C536700EC20E6 /* loader64.c in Sources */ = {isa = PBXBuildFile; fileRef = 739987E4239C536700EC20E6 /* loader64.c */; }; 12 | 739987EB239C540700EC20E6 /* libusb-1.0.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 739987EA239C540700EC20E6 /* libusb-1.0.a */; }; 13 | 739987ED239C541200EC20E6 /* libftdi1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 739987EC239C541200EC20E6 /* libftdi1.a */; }; 14 | 739987F0239C6B5400EC20E6 /* loader64 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 739987D7239C534A00EC20E6 /* loader64 */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | 739987D5239C534A00EC20E6 /* CopyFiles */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 12; 21 | dstPath = /usr/local/bin; 22 | dstSubfolderSpec = 0; 23 | files = ( 24 | 739987F0239C6B5400EC20E6 /* loader64 in CopyFiles */, 25 | ); 26 | runOnlyForDeploymentPostprocessing = 0; 27 | }; 28 | /* End PBXCopyFilesBuildPhase section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 739987D7239C534A00EC20E6 /* loader64 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = loader64; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 739987E1239C536700EC20E6 /* loader64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = loader64.h; path = ../../loader64.h; sourceTree = ""; }; 33 | 739987E2239C536700EC20E6 /* gopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gopt.c; path = ../../gopt.c; sourceTree = ""; }; 34 | 739987E3239C536700EC20E6 /* gopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gopt.h; path = ../../gopt.h; sourceTree = ""; }; 35 | 739987E4239C536700EC20E6 /* loader64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = loader64.c; path = ../../loader64.c; sourceTree = ""; }; 36 | 739987E8239C53F300EC20E6 /* libftdi1.2.4.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libftdi1.2.4.0.dylib; path = ../../../../../usr/local/Cellar/libftdi/1.4_1/lib/libftdi1.2.4.0.dylib; sourceTree = ""; }; 37 | 739987EA239C540700EC20E6 /* libusb-1.0.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libusb-1.0.a"; path = "../../../../../usr/local/Cellar/libusb/1.0.23/lib/libusb-1.0.a"; sourceTree = ""; }; 38 | 739987EC239C541200EC20E6 /* libftdi1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libftdi1.a; path = ../../../../../usr/local/Cellar/libftdi/1.4_1/lib/libftdi1.a; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 739987D4239C534A00EC20E6 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 739987ED239C541200EC20E6 /* libftdi1.a in Frameworks */, 47 | 739987EB239C540700EC20E6 /* libusb-1.0.a in Frameworks */, 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 739987CE239C534A00EC20E6 = { 55 | isa = PBXGroup; 56 | children = ( 57 | 739987D9239C534A00EC20E6 /* loader64 */, 58 | 739987D8239C534A00EC20E6 /* Products */, 59 | 739987E7239C53F300EC20E6 /* Frameworks */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 739987D8239C534A00EC20E6 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 739987D7239C534A00EC20E6 /* loader64 */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 739987D9239C534A00EC20E6 /* loader64 */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 739987E2239C536700EC20E6 /* gopt.c */, 75 | 739987E3239C536700EC20E6 /* gopt.h */, 76 | 739987E4239C536700EC20E6 /* loader64.c */, 77 | 739987E1239C536700EC20E6 /* loader64.h */, 78 | ); 79 | path = loader64; 80 | sourceTree = ""; 81 | }; 82 | 739987E7239C53F300EC20E6 /* Frameworks */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 739987EC239C541200EC20E6 /* libftdi1.a */, 86 | 739987EA239C540700EC20E6 /* libusb-1.0.a */, 87 | 739987E8239C53F300EC20E6 /* libftdi1.2.4.0.dylib */, 88 | ); 89 | name = Frameworks; 90 | sourceTree = ""; 91 | }; 92 | /* End PBXGroup section */ 93 | 94 | /* Begin PBXNativeTarget section */ 95 | 739987D6239C534A00EC20E6 /* loader64 */ = { 96 | isa = PBXNativeTarget; 97 | buildConfigurationList = 739987DE239C534A00EC20E6 /* Build configuration list for PBXNativeTarget "loader64" */; 98 | buildPhases = ( 99 | 739987D3239C534A00EC20E6 /* Sources */, 100 | 739987D4239C534A00EC20E6 /* Frameworks */, 101 | 739987D5239C534A00EC20E6 /* CopyFiles */, 102 | ); 103 | buildRules = ( 104 | ); 105 | dependencies = ( 106 | ); 107 | name = loader64; 108 | productName = loader64; 109 | productReference = 739987D7239C534A00EC20E6 /* loader64 */; 110 | productType = "com.apple.product-type.tool"; 111 | }; 112 | /* End PBXNativeTarget section */ 113 | 114 | /* Begin PBXProject section */ 115 | 739987CF239C534A00EC20E6 /* Project object */ = { 116 | isa = PBXProject; 117 | attributes = { 118 | LastUpgradeCheck = 1100; 119 | ORGANIZATIONNAME = jsdf; 120 | TargetAttributes = { 121 | 739987D6239C534A00EC20E6 = { 122 | CreatedOnToolsVersion = 11.0; 123 | }; 124 | }; 125 | }; 126 | buildConfigurationList = 739987D2239C534A00EC20E6 /* Build configuration list for PBXProject "loader64" */; 127 | compatibilityVersion = "Xcode 9.3"; 128 | developmentRegion = en; 129 | hasScannedForEncodings = 0; 130 | knownRegions = ( 131 | en, 132 | Base, 133 | ); 134 | mainGroup = 739987CE239C534A00EC20E6; 135 | productRefGroup = 739987D8239C534A00EC20E6 /* Products */; 136 | projectDirPath = ""; 137 | projectRoot = ""; 138 | targets = ( 139 | 739987D6239C534A00EC20E6 /* loader64 */, 140 | ); 141 | }; 142 | /* End PBXProject section */ 143 | 144 | /* Begin PBXSourcesBuildPhase section */ 145 | 739987D3239C534A00EC20E6 /* Sources */ = { 146 | isa = PBXSourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 739987E6239C536700EC20E6 /* loader64.c in Sources */, 150 | 739987E5239C536700EC20E6 /* gopt.c in Sources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXSourcesBuildPhase section */ 155 | 156 | /* Begin XCBuildConfiguration section */ 157 | 739987DC239C534A00EC20E6 /* Debug */ = { 158 | isa = XCBuildConfiguration; 159 | buildSettings = { 160 | ALWAYS_SEARCH_USER_PATHS = NO; 161 | CLANG_ANALYZER_NONNULL = YES; 162 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 163 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 164 | CLANG_CXX_LIBRARY = "libc++"; 165 | CLANG_ENABLE_MODULES = YES; 166 | CLANG_ENABLE_OBJC_ARC = YES; 167 | CLANG_ENABLE_OBJC_WEAK = YES; 168 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 169 | CLANG_WARN_BOOL_CONVERSION = YES; 170 | CLANG_WARN_COMMA = YES; 171 | CLANG_WARN_CONSTANT_CONVERSION = YES; 172 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 173 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 174 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 175 | CLANG_WARN_EMPTY_BODY = YES; 176 | CLANG_WARN_ENUM_CONVERSION = YES; 177 | CLANG_WARN_INFINITE_RECURSION = YES; 178 | CLANG_WARN_INT_CONVERSION = YES; 179 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 180 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 181 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 182 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 183 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 184 | CLANG_WARN_STRICT_PROTOTYPES = YES; 185 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 186 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 187 | CLANG_WARN_UNREACHABLE_CODE = YES; 188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 189 | COPY_PHASE_STRIP = NO; 190 | DEBUG_INFORMATION_FORMAT = dwarf; 191 | ENABLE_STRICT_OBJC_MSGSEND = YES; 192 | ENABLE_TESTABILITY = YES; 193 | GCC_C_LANGUAGE_STANDARD = gnu11; 194 | GCC_DYNAMIC_NO_PIC = NO; 195 | GCC_NO_COMMON_BLOCKS = YES; 196 | GCC_OPTIMIZATION_LEVEL = 0; 197 | GCC_PREPROCESSOR_DEFINITIONS = ( 198 | "DEBUG=1", 199 | "$(inherited)", 200 | ); 201 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 202 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 203 | GCC_WARN_UNDECLARED_SELECTOR = YES; 204 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 205 | GCC_WARN_UNUSED_FUNCTION = YES; 206 | GCC_WARN_UNUSED_VARIABLE = YES; 207 | MACOSX_DEPLOYMENT_TARGET = 10.14; 208 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 209 | MTL_FAST_MATH = YES; 210 | ONLY_ACTIVE_ARCH = YES; 211 | SDKROOT = macosx; 212 | }; 213 | name = Debug; 214 | }; 215 | 739987DD239C534A00EC20E6 /* Release */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | ALWAYS_SEARCH_USER_PATHS = NO; 219 | CLANG_ANALYZER_NONNULL = YES; 220 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 221 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 222 | CLANG_CXX_LIBRARY = "libc++"; 223 | CLANG_ENABLE_MODULES = YES; 224 | CLANG_ENABLE_OBJC_ARC = YES; 225 | CLANG_ENABLE_OBJC_WEAK = YES; 226 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 227 | CLANG_WARN_BOOL_CONVERSION = YES; 228 | CLANG_WARN_COMMA = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 232 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 233 | CLANG_WARN_EMPTY_BODY = YES; 234 | CLANG_WARN_ENUM_CONVERSION = YES; 235 | CLANG_WARN_INFINITE_RECURSION = YES; 236 | CLANG_WARN_INT_CONVERSION = YES; 237 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 238 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 239 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 242 | CLANG_WARN_STRICT_PROTOTYPES = YES; 243 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 244 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 245 | CLANG_WARN_UNREACHABLE_CODE = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | COPY_PHASE_STRIP = NO; 248 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 249 | ENABLE_NS_ASSERTIONS = NO; 250 | ENABLE_STRICT_OBJC_MSGSEND = YES; 251 | GCC_C_LANGUAGE_STANDARD = gnu11; 252 | GCC_NO_COMMON_BLOCKS = YES; 253 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 254 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 255 | GCC_WARN_UNDECLARED_SELECTOR = YES; 256 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 257 | GCC_WARN_UNUSED_FUNCTION = YES; 258 | GCC_WARN_UNUSED_VARIABLE = YES; 259 | MACOSX_DEPLOYMENT_TARGET = 10.14; 260 | MTL_ENABLE_DEBUG_INFO = NO; 261 | MTL_FAST_MATH = YES; 262 | SDKROOT = macosx; 263 | }; 264 | name = Release; 265 | }; 266 | 739987DF239C534A00EC20E6 /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | CODE_SIGN_STYLE = Automatic; 270 | HEADER_SEARCH_PATHS = /usr/local/include; 271 | LIBRARY_SEARCH_PATHS = ( 272 | "$(inherited)", 273 | /usr/local/lib, 274 | ); 275 | PRODUCT_NAME = "$(TARGET_NAME)"; 276 | }; 277 | name = Debug; 278 | }; 279 | 739987E0239C534A00EC20E6 /* Release */ = { 280 | isa = XCBuildConfiguration; 281 | buildSettings = { 282 | CODE_SIGN_STYLE = Automatic; 283 | HEADER_SEARCH_PATHS = /usr/local/include; 284 | LIBRARY_SEARCH_PATHS = ( 285 | "$(inherited)", 286 | /usr/local/lib, 287 | ); 288 | PRODUCT_NAME = "$(TARGET_NAME)"; 289 | }; 290 | name = Release; 291 | }; 292 | /* End XCBuildConfiguration section */ 293 | 294 | /* Begin XCConfigurationList section */ 295 | 739987D2239C534A00EC20E6 /* Build configuration list for PBXProject "loader64" */ = { 296 | isa = XCConfigurationList; 297 | buildConfigurations = ( 298 | 739987DC239C534A00EC20E6 /* Debug */, 299 | 739987DD239C534A00EC20E6 /* Release */, 300 | ); 301 | defaultConfigurationIsVisible = 0; 302 | defaultConfigurationName = Release; 303 | }; 304 | 739987DE239C534A00EC20E6 /* Build configuration list for PBXNativeTarget "loader64" */ = { 305 | isa = XCConfigurationList; 306 | buildConfigurations = ( 307 | 739987DF239C534A00EC20E6 /* Debug */, 308 | 739987E0239C534A00EC20E6 /* Release */, 309 | ); 310 | defaultConfigurationIsVisible = 0; 311 | defaultConfigurationName = Release; 312 | }; 313 | /* End XCConfigurationList section */ 314 | }; 315 | rootObject = 739987CF239C534A00EC20E6 /* Project object */; 316 | } 317 | -------------------------------------------------------------------------------- /xcode/loader64.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /xcode/loader64.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /xcode/loader64.xcodeproj/project.xcworkspace/xcuserdata/jfriend.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsdf/loader64/060de76b8c8efd9f7b255aafdbe9cb8e1de30c29/xcode/loader64.xcodeproj/project.xcworkspace/xcuserdata/jfriend.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /xcode/loader64.xcodeproj/xcuserdata/jfriend.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | loader64.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------