#define DLMI_MAGIC_TOKEN 0xBF8DA5ED
#define DLMI_MAGIC_STRING "Grizzly"
#define DLMI_LIBRARY_VERSION 0x00020000
#define DLMI_MAJOR(x) ((x>>16)&0xffff)
#define DLMI_MINOR(x) (x&0xffff)
#define DLMI_MAJOR_VERSION DLMI_MAJOR(DLMI_LIBRARY_VERSION)
#define DLMI_MINOR_VERSION DLMI_MINOR(DLMI_LIBRARY_VERSION)
#define DLMI_MAKE_VERSION(x,y) (((x & 0xffff) << 16) | (y & 0xffff))

#define DLMI_CARD(a,b,c,d) ((d<<24) | (c<<16) | (b<<8) | (a))

#define DLMI_SLOT_NONE	0
#define DLMI_SLOT_ONE	1
#define DLMI_SLOT_TWO	2

#define FIXUP(x,y) (*((u32*)&(y)) += ((u32)(x)))
#define DRIVER_FIXUP(x,y) FIXUP((x), (x)->(y))

#define DLMI_FEATURE_MEDIA	0x00000001
#define DLMI_FEATURE_BOOT	0x00000002	// Firmware Bootable
#define DLMI_FEATURE_UPDATE	0x00000004	// Firmware Flashable
#define DLMI_FEATURE_RAMRW	0x00000010	// RAM Read-Write
#define DLMI_FEATURE_RAMRO	0x00000020	// RAM Read-Only
#define DLMI_FEATURE_FLASHRW	0x00000100	// Userflash Read-Write
#define DLMI_FEATURE_FLASHRO	0x00000200	// Userflash Read-Only
#define DLMI_FEATURE_SRAM	0x00001000	// SRAM
#define DLMI_FEATURE_RUMBLE	0x00010000
#define DLMI_FEATURE_MOTION	0x00100000
#define DLMI_FEATURE_SERIAL	0x01000000

#define DLMI_FIX_ALL	1
#define DLMI_FIX_GLUE	2
#define DLMI_FIX_GOT	4
#define DLMI_FIX_BSS	8

typedef struct DLMI_MODE_s {
	u32 Features;
	u32 RAMBase;
	u32 RAMSize;
	u32 RAMPages;
	u32 FlashBase;
	u32 FlashSize;
	u32 FlashPages;
	u32 SRAMBase;
	u32 SRAMSize;
	u32 SRAMPages;
} DLMI_MODE_t;

typedef struct DLMI_DRIVER_s {
	char DriverName[24];

	u32 LibraryVersion;
	u32 DriverVersion;

	u8 FixSections;
	u8 Slot;

	u8 CardCount;
	u8 ModeCount;

	u32 *CardList;
	DLMI_MODE_t *ModeList;

	u32 (*Init)(void);

	u32 (*SetMode)(u8 index);

	u32 (*RAM_Page)(u8 index);

	u32 (*Flash_Page)(u8 index);
	u32 (*Flash_Write)(u32 Offset, u16* Source, u32 Size);

	u32 (*SRAM_Page)(u8 index);

	void (*Rumble)(void);
	u32 (*Motion)(u32 *x, u32 *y, u32 *z, u32 *g);

	void (*Serial_Write)(u8 Data);
	u8 (*Serial_Read)(void);
	void (*Serial_Speed)(u32 speed);
} DLMI_DRIVER_t;

typedef struct DLMI_HEADER_s {
	u32 MagicToken;
	char MagicString[8];

	u32 _text_start;
	u32 _data_end;
	u32 _glue_start;
	u32 _glue_end;
	u32 _got_start;
	u32 _got_end;
	u32 _bss_start;
	u32 _bss_end;
	
	DLMI_DRIVER_t *driver;
} DLMI_HEADER_t;

#define DLMI_Rumble(dlmi) 				dlmi->driver->Rumble()
#define DLMI_SetMode(dlmi, index) 			dlmi->driver->SetMode(index)
#define DLMI_RAM_Page(dlmi, index) 			dlmi->driver->RAM_Page(index)
#define DLMI_Flash_Page(dlmi, index) 			dlmi->driver->Flash_Page(index)
#define DLMI_Flash_Write(dlmi, offset, source, size) 	dlmi->driver->Flash_Page(offset, source, size)
#define DLMI_SRAM_Page(dlmi, index) 			dlmi->driver->SRAM_Page(index)
#define DLMI_Motion(dlmi, x, y, z, g) 			dlmi->driver->Motion(x,y,z,g)
#define DLMI_Serial_Write(dlmi, data) 			dlmi->driver->Serial_Write(data)
#define DLMI_Serial_Read(dlmi) 				dlmi->driver->Serial_Read()
#define DLMI_Serial_Speed(dlmi) 			dlmi->driver->Serial_Speed()

DLMI_HEADER_t *DLMI_Load(char *filename);

