mirror of
https://github.com/raphnet/gc_n64_usb-v3
synced 2024-12-22 07:18:52 -05:00
Cleaned-up N64 Mempak read/write through adapter
This commit is contained in:
parent
4374cd879a
commit
76b5f386ff
@ -26,10 +26,10 @@ MEMPAKLIB_OBJS=mempak.o mempak_fs.o
|
|||||||
|
|
||||||
all: gcn64ctl mempak_ls mempak_format mempak_extract_note mempak_insert_note mempak_rm mempak_convert gcn64ctl_gui
|
all: gcn64ctl mempak_ls mempak_format mempak_extract_note mempak_insert_note mempak_rm mempak_convert gcn64ctl_gui
|
||||||
|
|
||||||
gcn64ctl_gui: gcn64ctl_gui.o gcn64ctl_gui_mpkedit.o gcn64.o gcn64lib.o hexdump.o ihex.o $(COMPAT_OBJS) $(MEMPAKLIB_OBJS)
|
gcn64ctl_gui: gcn64ctl_gui.o gcn64ctl_gui_mpkedit.o gcn64.o gcn64lib.o hexdump.o ihex.o mempak_gcn64usb.o $(COMPAT_OBJS) $(MEMPAKLIB_OBJS)
|
||||||
$(LD) $^ $(LDFLAGS) $(GTK_LDFLAGS) -o $@
|
$(LD) $^ $(LDFLAGS) $(GTK_LDFLAGS) -o $@
|
||||||
|
|
||||||
gcn64ctl: main.o gcn64.o mempak_old.o gcn64lib.o hexdump.o gc2n64_adapter.o ihex.o delay.o $(COMPAT_OBJS)
|
gcn64ctl: main.o gcn64.o gcn64lib.o hexdump.o gc2n64_adapter.o ihex.o delay.o mempak_gcn64usb.o $(COMPAT_OBJS) $(MEMPAKLIB_OBJS)
|
||||||
$(LD) $^ $(LDFLAGS) -o $@
|
$(LD) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
gcn64ctl_gui.o: gcn64ctl_gui.c gcn64ctl_gui.h
|
gcn64ctl_gui.o: gcn64ctl_gui.c gcn64ctl_gui.h
|
||||||
|
85
tool/main.c
85
tool/main.c
@ -29,7 +29,8 @@
|
|||||||
#include "gcn64.h"
|
#include "gcn64.h"
|
||||||
#include "gcn64lib.h"
|
#include "gcn64lib.h"
|
||||||
#include "gc2n64_adapter.h"
|
#include "gc2n64_adapter.h"
|
||||||
#include "mempak_old.h"
|
#include "mempak.h"
|
||||||
|
#include "mempak_gcn64usb.h"
|
||||||
#include "../requests.h"
|
#include "../requests.h"
|
||||||
#include "../gcn64_protocol.h"
|
#include "../gcn64_protocol.h"
|
||||||
|
|
||||||
@ -156,6 +157,16 @@ struct option longopts[] = {
|
|||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void mempak_read_progress_cb(int addr)
|
||||||
|
{
|
||||||
|
printf("\rReading address 0x%04x / 0x%04x ", addr, MEMPAK_MEM_SIZE); fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mempak_write_progress_cb(int addr)
|
||||||
|
{
|
||||||
|
printf("\rWriting address 0x%04x / 0x%04x ", addr, MEMPAK_MEM_SIZE); fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
static int listDevices(void)
|
static int listDevices(void)
|
||||||
{
|
{
|
||||||
int n_found = 0;
|
int n_found = 0;
|
||||||
@ -368,16 +379,82 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_N64_MEMPAK_DUMP:
|
case OPT_N64_MEMPAK_DUMP:
|
||||||
|
{
|
||||||
|
mempak_structure_t *pak;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
printf("Reading mempak...\n");
|
||||||
|
res = gcn64lib_mempak_download(hdl, 0, &pak, mempak_read_progress_cb);
|
||||||
|
printf("\n");
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
if (outfile) {
|
if (outfile) {
|
||||||
mempak_dumpToFile(hdl, outfile);
|
int file_format;
|
||||||
|
|
||||||
|
file_format = mempak_getFilenameFormat(outfile);
|
||||||
|
if (file_format == MPK_FORMAT_INVALID) {
|
||||||
|
fprintf(stderr, "Unknown file format (neither .MPK nor .N64). Not saving.\n");
|
||||||
} else {
|
} else {
|
||||||
mempak_dump(hdl);
|
if (0 == mempak_saveToFile(pak, outfile, file_format)) {
|
||||||
|
printf("Wrote file '%s' in %s format\n", outfile, mempak_format2string(file_format));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "error writing file\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // No outfile
|
||||||
|
mempak_hexdump(pak);
|
||||||
|
}
|
||||||
|
mempak_free(pak);
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "No mempak detected\n");
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
fprintf(stderr, "I/O error reading pak\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case -3:
|
||||||
|
fprintf(stderr, "Error\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_N64_MEMPAK_WRITE:
|
case OPT_N64_MEMPAK_WRITE:
|
||||||
|
{
|
||||||
|
mempak_structure_t *pak;
|
||||||
|
int res;
|
||||||
printf("Input file: %s\n", optarg);
|
printf("Input file: %s\n", optarg);
|
||||||
mempak_writeFromFile(hdl, optarg);
|
|
||||||
|
pak = mempak_loadFromFile(optarg);
|
||||||
|
if (!pak) {
|
||||||
|
fprintf(stderr, "Failed to load mempak\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Writing to mempak...\n");
|
||||||
|
res = gcn64lib_mempak_upload(hdl, 0, pak, mempak_write_progress_cb);
|
||||||
|
printf("\n");
|
||||||
|
if (res) {
|
||||||
|
switch(res)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
fprintf(stderr, "Error: No mempak detected.\n");
|
||||||
|
break;
|
||||||
|
case -2:
|
||||||
|
fprintf(stderr, "I/O error writing to pak.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Error uploading mempak\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Mempak uploaded\n");
|
||||||
|
}
|
||||||
|
mempak_free(pak);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_SI8BIT_SCAN:
|
case OPT_SI8BIT_SCAN:
|
||||||
|
239
tool/mempak_gcn64usb.c
Normal file
239
tool/mempak_gcn64usb.c
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "gcn64lib.h"
|
||||||
|
#include "gcn64.h"
|
||||||
|
#include "mempak.h"
|
||||||
|
#include "mempak_gcn64usb.h"
|
||||||
|
#include "../gcn64_protocol.h"
|
||||||
|
#include "../requests.h"
|
||||||
|
|
||||||
|
/* __calc_address_crc is from libdragon which is public domain. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate the 5 bit CRC on a mempak address
|
||||||
|
*
|
||||||
|
* This function, given an address intended for a mempak read or write, will
|
||||||
|
* calculate the CRC on the address, returning the corrected address | CRC.
|
||||||
|
*
|
||||||
|
* @param[in] address
|
||||||
|
* The mempak address to calculate CRC over
|
||||||
|
*
|
||||||
|
* @return The mempak address | CRC
|
||||||
|
*/
|
||||||
|
static uint16_t __calc_address_crc( uint16_t address )
|
||||||
|
{
|
||||||
|
/* CRC table */
|
||||||
|
uint16_t xor_table[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x1F, 0x0B, 0x16, 0x19, 0x07, 0x0E, 0x1C, 0x0D, 0x1A, 0x01 };
|
||||||
|
uint16_t crc = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Make sure we have a valid address */
|
||||||
|
address &= ~0x1F;
|
||||||
|
|
||||||
|
/* Go through each bit in the address, and if set, xor the right value into the output */
|
||||||
|
for( i = 15; i >= 5; i-- )
|
||||||
|
{
|
||||||
|
/* Is this bit set? */
|
||||||
|
if( ((address >> i) & 0x1) )
|
||||||
|
{
|
||||||
|
crc ^= xor_table[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just in case */
|
||||||
|
crc &= 0x1F;
|
||||||
|
|
||||||
|
/* Create a new address with the CRC appended */
|
||||||
|
return address | crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* __calc_data_crc is from libdragon which is public domain. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate the 8 bit CRC over a 32-byte block of data
|
||||||
|
*
|
||||||
|
* This function calculates the 8 bit CRC appropriate for checking a 32-byte
|
||||||
|
* block of data intended for or retrieved from a mempak.
|
||||||
|
*
|
||||||
|
* @param[in] data
|
||||||
|
* Pointer to 32 bytes of data to run the CRC over
|
||||||
|
*
|
||||||
|
* @return The calculated 8 bit CRC over the data
|
||||||
|
*/
|
||||||
|
static uint8_t __calc_data_crc( uint8_t *data )
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
int i,j;
|
||||||
|
|
||||||
|
for( i = 0; i <= 32; i++ )
|
||||||
|
{
|
||||||
|
for( j = 7; j >= 0; j-- )
|
||||||
|
{
|
||||||
|
int tmp = 0;
|
||||||
|
|
||||||
|
if( ret & 0x80 )
|
||||||
|
{
|
||||||
|
tmp = 0x85;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret <<= 1;
|
||||||
|
|
||||||
|
if( i < 32 )
|
||||||
|
{
|
||||||
|
if( data[i] & (0x01 << j) )
|
||||||
|
{
|
||||||
|
ret |= 0x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret ^= tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32])
|
||||||
|
{
|
||||||
|
unsigned char cmd[64];
|
||||||
|
//int cmdlen;
|
||||||
|
int n;
|
||||||
|
uint16_t addr_crc;
|
||||||
|
unsigned char crc;
|
||||||
|
|
||||||
|
addr_crc = __calc_address_crc(addr);
|
||||||
|
|
||||||
|
cmd[0] = N64_EXPANSION_READ;
|
||||||
|
cmd[1] = addr_crc>>8; // Address high byte
|
||||||
|
cmd[2] = addr_crc&0xff; // Address low byte
|
||||||
|
|
||||||
|
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
||||||
|
if (n != 33) {
|
||||||
|
printf("Hey! %d\n", n);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, cmd, 0x20);
|
||||||
|
|
||||||
|
crc = __calc_data_crc(dst);
|
||||||
|
if (crc != cmd[32]) {
|
||||||
|
fprintf(stderr, "Bad CRC reading address 0x%04x\n", addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_mempak_detect(gcn64_hdl_t hdl)
|
||||||
|
{
|
||||||
|
unsigned char buf[0x20];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
printf("Init 1\n");
|
||||||
|
memset(buf, 0xfe, 32);
|
||||||
|
res = gcn64lib_expansionWrite(hdl, 0x8000, buf);
|
||||||
|
if (res != 0xe1) {
|
||||||
|
printf("res: %d\n", res);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Init 2\n");
|
||||||
|
memset(buf, 0x80, 32);
|
||||||
|
res = gcn64lib_expansionWrite(hdl, 0x8000, buf);
|
||||||
|
if (res != 0xe1) {
|
||||||
|
printf("res: %d\n", res);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_mempak_writeBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char data[32])
|
||||||
|
{
|
||||||
|
return gcn64lib_expansionWrite(hdl, __calc_address_crc(addr), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Read a physical mempak
|
||||||
|
* \param hdl The Adapter handler
|
||||||
|
* \param channel The adapter channel (for multi-port adapters)
|
||||||
|
* \param pak Pointer to mempak_structure pointer to store the new mempak
|
||||||
|
* \param progressCb Callback to notify read progress (called after each block)
|
||||||
|
* \return 0: Success, -1: No mempak, -2: IO/error, -3: Other errors
|
||||||
|
*/
|
||||||
|
int gcn64lib_mempak_download(gcn64_hdl_t hdl, int channel, mempak_structure_t **mempak, void (*progressCb)(int cur_addr))
|
||||||
|
{
|
||||||
|
mempak_structure_t *pak;
|
||||||
|
unsigned short addr;
|
||||||
|
|
||||||
|
if (!mempak) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gcn64lib_mempak_detect(hdl)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pak = calloc(1, sizeof(mempak_structure_t));
|
||||||
|
if (!pak) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
pak->file_format = MPK_FORMAT_MPK;
|
||||||
|
|
||||||
|
for (addr = 0x0000; addr < MEMPAK_MEM_SIZE; addr+= 0x20)
|
||||||
|
{
|
||||||
|
if (gcn64lib_mempak_readBlock(hdl, addr, &pak->data[addr]) != 0x20) {
|
||||||
|
fprintf(stderr, "Error: Short read\n");
|
||||||
|
free(pak);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (progressCb) {
|
||||||
|
progressCb(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*mempak = pak;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gcn64lib_mempak_upload(gcn64_hdl_t hdl, int channel, mempak_structure_t *pak, void (*progressCb)(int cur_addr))
|
||||||
|
{
|
||||||
|
unsigned short addr;
|
||||||
|
unsigned char readback[0x20];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!pak) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if (gcn64lib_mempak_detect(hdl)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (addr = 0x0000; addr < MEMPAK_MEM_SIZE; addr+= 0x20)
|
||||||
|
{
|
||||||
|
res = gcn64lib_mempak_writeBlock(hdl, addr, &pak->data[addr]);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Write error\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x20 != gcn64lib_mempak_readBlock(hdl, addr, readback)) {
|
||||||
|
// TODO : Why not retry?
|
||||||
|
fprintf(stderr, "readback failed\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(readback, &pak->data[addr], 0x20)) {
|
||||||
|
fprintf(stderr, "Readback compare failed\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progressCb) {
|
||||||
|
progressCb(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
13
tool/mempak_gcn64usb.h
Normal file
13
tool/mempak_gcn64usb.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _mempak_gcn64usb_h__
|
||||||
|
#define _mempak_gcn64usb_h__
|
||||||
|
|
||||||
|
#include "mempak.h"
|
||||||
|
|
||||||
|
int gcn64lib_mempak_detect(gcn64_hdl_t hdl);
|
||||||
|
int gcn64lib_mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]);
|
||||||
|
int gcn64lib_mempak_writeBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char data[32]);
|
||||||
|
|
||||||
|
int gcn64lib_mempak_download(gcn64_hdl_t hdl, int channel, mempak_structure_t **mempak, void (*progressCb)(int cur_addr));
|
||||||
|
int gcn64lib_mempak_upload(gcn64_hdl_t hdl, int channel, mempak_structure_t *pak, void (*progressCb)(int cur_addr));
|
||||||
|
|
||||||
|
#endif // _mempak_gcn64usb_h__
|
@ -1,335 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "hexdump.h"
|
|
||||||
#include "gcn64.h"
|
|
||||||
#include "gcn64lib.h"
|
|
||||||
#include "mempak_old.h"
|
|
||||||
#include "../gcn64_protocol.h"
|
|
||||||
#include "../requests.h"
|
|
||||||
|
|
||||||
/* __calc_address_crc is from libdragon which is public domain. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculate the 5 bit CRC on a mempak address
|
|
||||||
*
|
|
||||||
* This function, given an address intended for a mempak read or write, will
|
|
||||||
* calculate the CRC on the address, returning the corrected address | CRC.
|
|
||||||
*
|
|
||||||
* @param[in] address
|
|
||||||
* The mempak address to calculate CRC over
|
|
||||||
*
|
|
||||||
* @return The mempak address | CRC
|
|
||||||
*/
|
|
||||||
static uint16_t __calc_address_crc( uint16_t address )
|
|
||||||
{
|
|
||||||
/* CRC table */
|
|
||||||
uint16_t xor_table[16] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x1F, 0x0B, 0x16, 0x19, 0x07, 0x0E, 0x1C, 0x0D, 0x1A, 0x01 };
|
|
||||||
uint16_t crc = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Make sure we have a valid address */
|
|
||||||
address &= ~0x1F;
|
|
||||||
|
|
||||||
/* Go through each bit in the address, and if set, xor the right value into the output */
|
|
||||||
for( i = 15; i >= 5; i-- )
|
|
||||||
{
|
|
||||||
/* Is this bit set? */
|
|
||||||
if( ((address >> i) & 0x1) )
|
|
||||||
{
|
|
||||||
crc ^= xor_table[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Just in case */
|
|
||||||
crc &= 0x1F;
|
|
||||||
|
|
||||||
/* Create a new address with the CRC appended */
|
|
||||||
return address | crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* __calc_data_crc is from libdragon which is public domain. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculate the 8 bit CRC over a 32-byte block of data
|
|
||||||
*
|
|
||||||
* This function calculates the 8 bit CRC appropriate for checking a 32-byte
|
|
||||||
* block of data intended for or retrieved from a mempak.
|
|
||||||
*
|
|
||||||
* @param[in] data
|
|
||||||
* Pointer to 32 bytes of data to run the CRC over
|
|
||||||
*
|
|
||||||
* @return The calculated 8 bit CRC over the data
|
|
||||||
*/
|
|
||||||
static uint8_t __calc_data_crc( uint8_t *data )
|
|
||||||
{
|
|
||||||
uint8_t ret = 0;
|
|
||||||
int i,j;
|
|
||||||
|
|
||||||
for( i = 0; i <= 32; i++ )
|
|
||||||
{
|
|
||||||
for( j = 7; j >= 0; j-- )
|
|
||||||
{
|
|
||||||
int tmp = 0;
|
|
||||||
|
|
||||||
if( ret & 0x80 )
|
|
||||||
{
|
|
||||||
tmp = 0x85;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret <<= 1;
|
|
||||||
|
|
||||||
if( i < 32 )
|
|
||||||
{
|
|
||||||
if( data[i] & (0x01 << j) )
|
|
||||||
{
|
|
||||||
ret |= 0x1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret ^= tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int mempak_writeBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char data[32])
|
|
||||||
{
|
|
||||||
unsigned char cmd[40];
|
|
||||||
int cmdlen;
|
|
||||||
int n;
|
|
||||||
uint16_t addr_crc;
|
|
||||||
|
|
||||||
addr_crc = __calc_address_crc(addr);
|
|
||||||
|
|
||||||
cmd[0] = N64_EXPANSION_WRITE;
|
|
||||||
cmd[1] = addr_crc>>8; // Address high byte
|
|
||||||
cmd[2] = addr_crc&0xff; // Address low byte
|
|
||||||
memcpy(cmd + 3, data, 0x20);
|
|
||||||
cmdlen = 3 + 0x20;
|
|
||||||
|
|
||||||
n = gcn64lib_rawSiCommand(hdl, 0, cmd, cmdlen, cmd, sizeof(cmd));
|
|
||||||
if (n != 1) {
|
|
||||||
printf("write block returned != 1 (%d)\n", n);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32])
|
|
||||||
{
|
|
||||||
unsigned char cmd[64];
|
|
||||||
//int cmdlen;
|
|
||||||
int n;
|
|
||||||
uint16_t addr_crc;
|
|
||||||
unsigned char crc;
|
|
||||||
|
|
||||||
addr_crc = __calc_address_crc(addr);
|
|
||||||
|
|
||||||
cmd[0] = N64_EXPANSION_READ;
|
|
||||||
cmd[1] = addr_crc>>8; // Address high byte
|
|
||||||
cmd[2] = addr_crc&0xff; // Address low byte
|
|
||||||
|
|
||||||
n = gcn64lib_rawSiCommand(hdl, 0, cmd, 3, cmd, sizeof(cmd));
|
|
||||||
if (n != 33) {
|
|
||||||
printf("Hey! %d\n", n);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(dst, cmd, 0x20);
|
|
||||||
|
|
||||||
crc = __calc_data_crc(dst);
|
|
||||||
if (crc != cmd[32]) {
|
|
||||||
fprintf(stderr, "Bad CRC reading address 0x%04x\n", addr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mempak_init(gcn64_hdl_t hdl)
|
|
||||||
{
|
|
||||||
unsigned char buf[0x20];
|
|
||||||
int res;
|
|
||||||
|
|
||||||
memset(buf, 0xfe, 32);
|
|
||||||
res = mempak_readBlock(hdl, 0x8001, buf);
|
|
||||||
|
|
||||||
if (res == 0xe1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DUMP_SIZE 0x8000
|
|
||||||
|
|
||||||
int mempak_writeAll(gcn64_hdl_t hdl, unsigned char srcbuf[0x8000])
|
|
||||||
{
|
|
||||||
unsigned short addr;
|
|
||||||
unsigned char readback[0x20];
|
|
||||||
int res;
|
|
||||||
|
|
||||||
for (addr = 0x0000; addr < DUMP_SIZE; addr+= 0x20)
|
|
||||||
{
|
|
||||||
printf("Writing address 0x%04x / 0x8000\r", addr); fflush(stdout);
|
|
||||||
res = mempak_writeBlock(hdl, addr, &srcbuf[addr]);
|
|
||||||
if (res < 0) {
|
|
||||||
fprintf(stderr, "Write error\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0x20 != mempak_readBlock(hdl, addr, readback)) {
|
|
||||||
// TODO : Why not retry?
|
|
||||||
fprintf(stderr, "readback failed\n");
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
printf("\nDone!\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int mempak_readAll(gcn64_hdl_t hdl, unsigned char dstbuf[0x8000])
|
|
||||||
{
|
|
||||||
unsigned short addr;
|
|
||||||
|
|
||||||
for (addr = 0x0000; addr < DUMP_SIZE; addr+= 0x20)
|
|
||||||
{
|
|
||||||
printf("Reading address 0x%04x / 0x8000\r", addr); fflush(stdout);
|
|
||||||
if (mempak_readBlock(hdl, addr, &dstbuf[addr]) != 0x20) {
|
|
||||||
fprintf(stderr, "Error: Short read\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\nDone!\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mempak_dump(gcn64_hdl_t hdl)
|
|
||||||
{
|
|
||||||
unsigned char cardbuf[0x8000];
|
|
||||||
int i,j;
|
|
||||||
|
|
||||||
printf("Init pak\n");
|
|
||||||
mempak_init(hdl);
|
|
||||||
|
|
||||||
printf("Reading card...\n");
|
|
||||||
i = mempak_readAll(hdl, cardbuf);
|
|
||||||
if (i<0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0; i<DUMP_SIZE; i+=0x20) {
|
|
||||||
printf("%04x: ", i);
|
|
||||||
for (j=0; j<0x20; j++) {
|
|
||||||
printf("%02x ", cardbuf[i+j]);
|
|
||||||
}
|
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
for (j=0; j<0x20; j++) {
|
|
||||||
printf("%c", isprint(cardbuf[i+j]) ? cardbuf[i+j] : '.' );
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NUM_COPIES 4
|
|
||||||
|
|
||||||
int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename)
|
|
||||||
{
|
|
||||||
unsigned char cardbuf[0x8000];
|
|
||||||
FILE *fptr;
|
|
||||||
int copies;
|
|
||||||
|
|
||||||
printf("Init pak\n");
|
|
||||||
// mempak_init(hdl);
|
|
||||||
printf("Reading card...\n");
|
|
||||||
mempak_readAll(hdl, cardbuf);
|
|
||||||
|
|
||||||
printf("Writing to file '%s'\n", out_filename);
|
|
||||||
fptr = fopen(out_filename, "w");
|
|
||||||
if (!fptr) {
|
|
||||||
perror("fopen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (copies = 0; copies < NUM_COPIES; copies++) {
|
|
||||||
if (1 != fwrite(cardbuf, sizeof(cardbuf), 1, fptr)) {
|
|
||||||
perror("fwrite");
|
|
||||||
fclose(fptr);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Done\n");
|
|
||||||
|
|
||||||
fclose(fptr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mempak_writeFromFile(gcn64_hdl_t hdl, const char *in_filename)
|
|
||||||
{
|
|
||||||
unsigned char cardbuf[0x8000];
|
|
||||||
FILE *fptr;
|
|
||||||
long file_size;
|
|
||||||
int i;
|
|
||||||
int num_images = -1;
|
|
||||||
long offset = 0;
|
|
||||||
|
|
||||||
fptr = fopen(in_filename, "rb");
|
|
||||||
if (!fptr) {
|
|
||||||
perror("fopen");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek(fptr, 0, SEEK_END);
|
|
||||||
file_size = ftell(fptr);
|
|
||||||
fseek(fptr, 0, SEEK_SET);
|
|
||||||
|
|
||||||
printf("File size: %ld bytes\n", file_size);
|
|
||||||
|
|
||||||
/* Raw binary images. Those can contain more than one card's data. For
|
|
||||||
* instance, Mupen64 seems to contain four saves. */
|
|
||||||
for (i=1; i<=4; i++) {
|
|
||||||
if (file_size == 0x8000*i) {
|
|
||||||
num_images = i;
|
|
||||||
printf("MPK file Contains %d image(s)\n", num_images);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_images < 0) {
|
|
||||||
char header[11];
|
|
||||||
char *magic = "123-456-STD";
|
|
||||||
/* If the size is not a fixed multiple, it could be a .N64 file */
|
|
||||||
fread(header, 11, 1, fptr);
|
|
||||||
if (0 == memcmp(header, magic, sizeof(header))) {
|
|
||||||
printf(".N64 file detected\n");
|
|
||||||
// TODO : Extract comments and other info. from the header
|
|
||||||
offset = 0x1040; // Thanks to N-Rage`s Dinput8 Plugin sources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek(fptr, offset, SEEK_SET);
|
|
||||||
fread(cardbuf, sizeof(cardbuf), 1, fptr);
|
|
||||||
fclose(fptr);
|
|
||||||
|
|
||||||
|
|
||||||
printf("Init pak\n");
|
|
||||||
mempak_init(hdl);
|
|
||||||
printf("Writing card...\n");
|
|
||||||
mempak_writeAll(hdl, cardbuf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
// TO BE REMOVED
|
|
||||||
|
|
||||||
int mempak_dump(gcn64_hdl_t hdl);
|
|
||||||
int mempak_readBlock(gcn64_hdl_t hdl, unsigned short addr, unsigned char dst[32]);
|
|
||||||
int mempak_dumpToFile(gcn64_hdl_t hdl, const char *out_filename);
|
|
||||||
int mempak_writeFromFile(gcn64_hdl_t hdl, const char *in_filename);
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user