/* @(#)btcflash.c 1.18 17/07/15 2004-2017 J. Schilling */ #ifndef lint static const char _sccsid[] = "@(#)btcflash.c 1.18 17/07/15 2004-2017 J. Schilling"; #endif /*--------------------------------------------------------------------------*/ /* * Firmware flash utility for BTC DRW1008 DVD+/-RW recorder * Version 2004/04/29 * By David Huang * This work is dedicated to the public domain * * This utility may also work with other BTC DVD recorders, such as * the DRW1004 and DRW1108, but they have not been tested. * * USE AT YOUR OWN RISK! * btcflash is provided AS IS, with NO WARRANTY, either expressed or implied. * * Firmware files may be obtained by running BTC's Windows flash * utility, then searching in the WINDOWS\TEMP or WINNT\TEMP directory * for a *.HEX file. It will probably be in a subdirectory named * PAC*.tmp.DIR, and the HEX file will be named Vnnnn.HEX, where nnnn * is the firmware version number. You'll also find IDEFLASH.EXE or * BTCFLASH.EXE in the same directory. * * This utility will also accept firmware files in ".BIN" format. */ #ifdef DO_INCLUDE #include #include #include #include #endif #define FLASHSIZE 0x100000 /* BTC flash is 1MB */ EXPORT unsigned char *loadfirmware __PR((const char *)); LOCAL int getbyte __PR((char **)); LOCAL unsigned short calcsum __PR((unsigned char *)); LOCAL int btcmain __PR((SCSI *scgp, const char *fwfile)); EXPORT unsigned char * loadfirmware(firmware) const char * firmware; { FILE *f; char line[80]; char *p; unsigned char *fwbuf; int bank; int length; int offset; int type; int hexsum; int i; int b; fwbuf = malloc(FLASHSIZE); if (!fwbuf) { fprintf(stderr, _("Could not allocate memory for firmware\n")); return (NULL); } f = fopen(firmware, "r"); if (!f) { fprintf(stderr, _("%s: Unable to open: "), firmware); perror(NULL); free(fwbuf); return (NULL); } /* * Get length of file. If it's exactly FLASHSIZE, assume it's a * .bin file. Otherwise, try to read it as a .hex file. */ fseek(f, 0, SEEK_END); if (ftell(f) == FLASHSIZE) { rewind(f); if (fread(fwbuf, 1, FLASHSIZE, f) != FLASHSIZE) { fprintf(stderr, _("%s: Short read\n"), firmware); fclose(f); free(fwbuf); return (NULL); } fclose(f); return (fwbuf); } rewind(f); memset(fwbuf, 0xff, FLASHSIZE); bank = 0; while (fgets(line, sizeof (line), f)) { if (line[0] != ':') continue; p = line + 1; length = getbyte(&p); offset = getbyte(&p) << 8 | getbyte(&p); type = getbyte(&p); if (length < 0 || offset < 0 || type < 0 || (type != 0 && length != 0)) { errmsgno(EX_BAD, _("Malformed line: %.79s\n"), line); fclose(f); free(fwbuf); return (NULL); } else if (length == 0) { if (strncmp(line, ":00000155AA", 11) == 0) { if (++bank >= 16) { errmsgno(EX_BAD, _("Firmware file larger than 1MB\n")); fclose(f); free(fwbuf); return (NULL); } continue; } else if (strncmp(line, ":00000001FF", 11) == 0) { break; } else { errmsgno(EX_BAD, _("Malformed line: %.79s\n"), line); fclose(f); free(fwbuf); return (NULL); } } hexsum = (length + (offset >> 8) + (offset & 0xff)) & 0xff; for (i = 0; i < length; i++, offset++) { b = getbyte(&p); hexsum = (hexsum + b) & 0xff; if (b < 0) { errmsgno(EX_BAD, _("Short line: %.79s\n"), line); fclose(f); free(fwbuf); return (NULL); } fwbuf[(bank << 16) | offset] = (char)b; } hexsum = (0x100 - hexsum) & 0xff; if (hexsum != getbyte(&p)) { errmsgno(EX_BAD, _("Checksum mismatch: %.79s\n"), line); fclose(f); free(fwbuf); return (NULL); } } fclose(f); if (bank != 15) { errmsgno(EX_BAD, _("Firmware file too small\n")); free(fwbuf); return (NULL); } return (fwbuf); } LOCAL int getbyte(pp) char **pp; { int h; int l; h = **pp; if (h >= '0' && h <= '9') h -= '0'; else if (h >= 'A' && h <= 'F') h -= 'A' - 10; else if (h >= 'a' && h <= 'f') h -= 'a' - 10; else return (-1); l = *(*pp+1); if (l >= '0' && l <= '9') l -= '0'; else if (l >= 'A' && l <= 'F') l -= 'A' - 10; else if (l >= 'a' && l <= 'f') l -= 'a' - 10; else return (-1); *pp += 2; return ((h << 4) | l); } LOCAL unsigned short calcsum(fwbuf) unsigned char *fwbuf; { unsigned int flashsum; unsigned int i; for (flashsum = 0, i = 0; i < FLASHSIZE; i++) flashsum += fwbuf[i]; return ((flashsum & 0xffff)); } LOCAL int btcmain(scgp, fwfile) SCSI *scgp; const char *fwfile; { char confirm[5]; unsigned char *fwbuf; unsigned char inq[128]; unsigned char csbuf[32]; unsigned short checksum; unsigned int offset; printf(_("BTC DVD+/-RW firmware flash utility release %s %s\n"), "1.18", "17/07/15"); printf(_("USE AT YOUR OWN RISK!\n\n")); if (!(fwbuf = loadfirmware(fwfile))) return (1); checksum = calcsum(fwbuf); printf(_("Loaded firmware from %s\nFirmware checksum is %04X\n"), fwfile, checksum); if (inquiry(scgp, (char *)inq, 36) < 0) return (1); printf(_("Drive is currently: [%.8s][%.16s][%.4s]\n"), inq+8, inq+16, inq+32); printf(_("Firmware appears to be: [%.8s][%.16s][%.4s]\n\n"), fwbuf+0x40bc, fwbuf+0x40c4, fwbuf+0x40d4); if (strncmp((char *)inq + 8, (char *)fwbuf + 0x40bc, 24) != 0) printf( "**********************************************************\n"); printf( _("WARNING! THIS FIRMWARE DOES NOT SEEM TO BE FOR THIS DRIVE!\n")); printf( "**********************************************************\n"); printf(_("Type \"YES\" to proceed with flash: ")); fflush(stdout); fgets(confirm, sizeof (confirm), stdin); if (strcmp(confirm, "YES\n") != 0) { printf(_("\nFlash canceled.\n")); return (0); } printf(_("\nUploading firmware...\n")); /* Upload firmware */ for (offset = 0; offset < FLASHSIZE; offset += 0x1000) { if (write_buffer(scgp, (char *)fwbuf + offset, 0x1000, 6 /* Download Microcode with Offsets */, 0 /* Buffer ID 0 */, offset + 0x20) < 0) { errmsgno(EX_BAD, _("Cannot write microcode\n")); return (1); } } /* Upload checksum */ memset(csbuf, 0, 32); csbuf[30] = (checksum >> 8); csbuf[31] = (checksum & 0xff); if (write_buffer(scgp, (char *)csbuf, 0x20, 6 /* Download Microcode with Offsets */, 0 /* Buffer ID 0 */, 0) /* Offset 0 */ < 0) { errmsgno(EX_BAD, _("Cannot write microcode checksum\n")); return (1); } printf(_("Flashing drive...\n")); /* Firmware uploaded; now flash it! */ if (write_buffer(scgp, NULL, 0, 7 /* Download Microcode with Offsets and Save */, 0 /* Buffer ID 0 */, 0) /* Offset 0 */ < 0) { errmsgno(EX_BAD, _("Cannot save microcode\n")); return (1); } sleep(50); /* Let drive sit for a while before bothering it */ scgp->silent++; wait_unit_ready(scgp, 300); scgp->silent--; if (inquiry(scgp, (char *)inq, 36) < 0) return (1); printf(_("Drive is now: [%.8s][%.16s][%.4s]\n\n"), inq+8, inq+16, inq+32); printf(_("Please reboot before using the drive.\n")); return (0); }