#include #include #include #include #include #include #include "opendevice.h" #include "qdinc.h" #define _16MBIT 0x200000 #define HIROM_BANK_SIZE_SHIFT 16 #define LOROM_BANK_SIZE_SHIFT 15 #define HIROM_BANK_COUNT_SHIFT 32 #define LOROM_BANK_COUNT_SHIFT 64 static const char * default_tempfile = "/tmp/quickdev"; void usage(void) { fprintf(stderr, "Usage: qdinc [option] \n\n\ Options:\n\ -i\tInitial ROM upload\n\ -s\tSkip ROM header\n\ -q\tBe quiet\n\ -h\tForce HiROM mode\n\n"); exit(1); } int main(int argc, char * argv[]) { char * filename = 0; int hirom = 0; int header = 0; int init = 0; int quiet = 0; int opt = 0; if (argc==1) usage(); while ((opt = getopt(argc,argv,"qish")) != -1){ switch (opt) { case 'i': init = 1; break; case 's': header = 1; break; case 'h': hirom = 1; break; case 'q': quiet = 1; break; default: usage(); } } if (optind >= argc) { usage(); } filename = argv[optind]; int j,j2; int ref_complete, upload_complete = 0; const char * tempfile_name = getenv("QDINC_FILE"); if(tempfile_name == 0) tempfile_name = default_tempfile; char * outfile = malloc(strlen(tempfile_name) + sizeof(".out")); char * ext = stpcpy(outfile, tempfile_name); strcpy(ext, ".out"); FILE * temp_file = fopen(outfile, "wb"); if(temp_file == 0) { fprintf(stderr, "Could not open file %s for writing\n", outfile); exit(1); } FILE * new_rom = fopen(filename, "rb"); if(new_rom == 0) { fprintf(stderr, "Could not open file %s\n", argv[3]); exit(1); } fseek(new_rom, 0, SEEK_END); unsigned int size = ftell(new_rom); if(header) { if(size < 512) size = 0; else size -= 512; fseek(new_rom, 512, SEEK_SET); } else rewind(new_rom); if(size > _16MBIT) { fprintf(stderr, "Input file is larger than supported by Quickdev16\n"); exit(1); } FILE * ref = 0; if(!init) ref = fopen(tempfile_name, "rb"); ref_complete = (ref == 0); usb_dev_handle *handle = NULL; const unsigned char rawVid[2] = { USB_CFG_VENDOR_ID }, rawPid[2] = { USB_CFG_DEVICE_ID}; char vendor[] = { USB_CFG_VENDOR_NAME, 0 }, product[] = { USB_CFG_DEVICE_NAME, 0}; int cnt, vid, pid; usb_init(); vid = rawVid[1] * 256 + rawVid[0]; pid = rawPid[1] * 256 + rawPid[0]; if (usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0) { fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid); exit(1); } cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_SET_LOADER, 0, 0, NULL, 0, 5000); cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_MODE_AVR, 0, 0, NULL, 0, 5000); usleep(50000); cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_BULK_UPLOAD_INIT, (hirom ? HIROM_BANK_SIZE_SHIFT : LOROM_BANK_SIZE_SHIFT) , (hirom ? HIROM_BANK_COUNT_SHIFT : LOROM_BANK_COUNT_SHIFT) /* << this is wrong, but only used for progress display */, NULL, 0, 5000); unsigned char diffblock[256]; unsigned int blocklen = 0; unsigned int reallen = 0; unsigned int position = 0; unsigned int last_position = (unsigned int)(-1); unsigned char lastchar = 0; unsigned int transmitted = 0; char progress[21]; memset(progress,' ',19); progress[20] = 0; j = 0; j2 = 0; while(!upload_complete) { int msg = 0; unsigned char updchar = fgetc(new_rom); unsigned char refchar=0; if(feof(new_rom)) { msg = 1; upload_complete = 1; } else fputc(updchar, temp_file); if(!ref_complete && !upload_complete) { refchar = fgetc(ref); if(feof(ref)) ref_complete= 1; } int match = (ref_complete || updchar != refchar); if(upload_complete) match = 0; if(match) { diffblock[blocklen] = updchar; blocklen++; reallen = blocklen; } else if(blocklen > 0) { diffblock[blocklen] = updchar; blocklen++; } position++; if((reallen > 0 && upload_complete) || ((!upload_complete) && (( (blocklen - reallen) >= QDINC_RANGE && !match) || blocklen == QDINC_SIZE)) ) { int consecutive = (last_position == position - blocklen); unsigned int begin = position - blocklen; cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, consecutive ? USB_BULK_UPLOAD_NEXT : USB_BULK_UPLOAD_ADDR, begin >> 16, begin & 0xFFFF, (char *) diffblock, reallen, 5000); last_position = position - blocklen + reallen; transmitted += reallen; blocklen = 0; reallen = 0; msg = 1; } if(!quiet && msg) { for(; j < (position - 1) * 20 / size; j++) progress[j] = '='; for(; j2 < transmitted * 20 / size; j2++) progress[j2] = '#'; printf("At 0x%06x/0x%06x %6.2f%% [%10s] Tx 0x%06x/0x%06x %6.2f%%\r", position - 1, size, (position - 1) * 100.0 / size, progress, transmitted, size, transmitted * 100.0 / size); fflush(stdout); } lastchar = updchar; } position--; printf("\n"); while(!ref_complete) { unsigned char refchar = fgetc(ref); if(feof(ref)) ref_complete = 1; else fputc(refchar, temp_file); } fclose(temp_file); fclose(new_rom); if (!init) fclose(ref); if(rename(outfile, tempfile_name)) { fprintf(stderr, "Could not replace tempfile %s\n", tempfile_name); exit(1); } cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_BULK_UPLOAD_END, 0, 0, NULL, 0, 5000); cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_SET_LOADER, 1, 1, NULL, 0, 5000); cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USB_MODE_SNES, 0, 0, NULL, 0, 5000); return 0; }