 /*
  * UAE - The Un*x Amiga Emulator
  *
  * AutoConfig devices
  *
  * (c) 1995 Bernd Schmidt
  */

#include "shared.h"

#ifdef HAS_HARDFILE

#include "memory.h"
#include "custom.h"
#include "readcpu.h"
#include "newcpu.h"
#include "disk.h"
#include "xwin.h"
#include "autoconf.h"
#include "execlib.h"

static int opencount = 0;
static long hardfile_size = 0;
int numtracks = 512;

static uae_u32 hardfile_open(void)
{
    uaecptr tmp1 = m68k_areg(regs, 1); /* IOReq */

    /* Check unit number */
    if (m68k_dreg(regs, 0) == 0) {
	opencount++;
	put_word (m68k_areg(regs, 6)+32, get_word (m68k_areg(regs, 6)+32) + 1);
	put_long (tmp1+24, 0); /* io_Unit */
	put_byte (tmp1+31, 0); /* io_Error */
	put_byte (tmp1+8, 7); /* ln_type = NT_REPLYMSG */
	return 0;
    }

    put_long (tmp1+20, (uae_u32)-1);
    put_byte (tmp1+31, (uae_u8)-1);
    return (uae_u32)-1;
}

static uae_u32 hardfile_close(void)
{
    opencount--;
    put_word (m68k_areg(regs, 6)+32, get_word (m68k_areg(regs, 6)+32) - 1);

    return 0;
}

static uae_u32 hardfile_expunge(void)
{
    return 0; /* Simply ignore this one... */
}

static uae_u32 hardfile_beginio(void)
{
    uae_u32 tmp1, tmp2, dataptr, offset;
    uae_u32 retval = m68k_dreg(regs, 0);

    tmp1 = m68k_areg(regs, 1);
#define DEBUGME
#ifdef DEBUGME
    printf ("hardfile: tmp1 = %08lx\n", (unsigned long)tmp1);
    printf ("hardfile: cmd  = %d\n", (int)get_word(tmp1+28));
#endif
    
    put_byte (tmp1+8, NT_MESSAGE);
    put_byte (tmp1+31, 0); /* no error yet */
    tmp2 = get_word (tmp1+28); /* io_Command */
/*    put_byte (tmp1 + 30, get_byte (tmp1 + 30) & ~1);*/
    switch (tmp2) {
     case CMD_READ:
	dataptr = get_long (tmp1 + 40);
	if (dataptr & 1)
	    goto bad_command;
	offset = get_long (tmp1 + 44);
	if (offset & 511)
	    goto bad_command;
	tmp2 = get_long (tmp1 + 36); /* io_Length */
	if (tmp2 & 511)
	    goto bad_command;
	if (tmp2 + offset > (uae_u32)numtracks * 32 * 512)
	    goto bad_command;

	put_long (tmp1 + 32, tmp2); /* set io_Actual */
	emu_FileSeek (offset, SEEK_SET);
	while (tmp2) {
	    int i;
	    char buffer[512];
	    emu_FileRead (buffer, 512);
	    for (i = 0; i < 512; i++, dataptr++)
		put_byte(dataptr, buffer[i]);
	    tmp2 -= 512;
	}
	break;

     case CMD_WRITE:
     case 11: /* Format */
	dataptr = get_long (tmp1 + 40);
	if (dataptr & 1)
	    goto bad_command;
	offset = get_long (tmp1 + 44);
	if (offset & 511)
	    goto bad_command;
	tmp2 = get_long (tmp1 + 36); /* io_Length */
	if (tmp2 & 511)
	    goto bad_command;
	if (tmp2 + offset > (uae_u32)numtracks * 32 * 512)
	    goto bad_command;

	put_long (tmp1 + 32, tmp2); /* set io_Actual */
	emu_FileSeek (offset, SEEK_SET);
	while (tmp2) {
	    char buffer[512];
	    int i;
	    for (i=0; i < 512; i++, dataptr++)
		buffer[i] = get_byte(dataptr);
	    // JMH not supported : write (uaedevfd, buffer, 512);
	    tmp2 -= 512;
	}
	break;

	bad_command:
	break;

     case 18: /* GetDriveType */
	put_long (tmp1 + 32, 1); /* not exactly a 3.5" drive, but... */
	break;

     case 19: /* GetNumTracks */
	put_long (tmp1 + 32, numtracks);
	break;

	/* Some commands that just do nothing and return zero */
     case CMD_UPDATE:
     case CMD_CLEAR:
     case 9: /* Motor */
     case 10: /* Seek */
     case 12: /* Remove */
     case 13: /* ChangeNum */
     case 14: /* ChangeStatus */
     case 15: /* ProtStatus */
     case 20: /* AddChangeInt */
     case 21: /* RemChangeInt */
	put_long (tmp1+32, 0); /* io_Actual */
	retval = 0;
	break;

     default:
	/* Command not understood. */
	put_byte (tmp1+31, (uae_u8)-3); /* io_Error */
	retval = 0;
	break;
    }
#if 0
    if ((get_byte (tmp1+30) & 1) == 0) {
	/* Not IOF_QUICK -- need to ReplyMsg */
	m68k_areg(regs, 1) = tmp1;
	CallLib (get_long(4), -378);
    }
#endif
    return retval;
}

static uae_u32 hardfile_abortio(void)
{
    return (uae_u32)-3;
}


void hardfile_install(void)
{
    uae_u32 functable, datatable, inittable;
    uae_u32 initcode, openfunc, closefunc, expungefunc;
    uae_u32 beginiofunc, abortiofunc;

    emu_printf("looking hdd");
    hardfile_size = emu_FileSize(currprefs.hf0);
    //if (hardfile_size == 0) return;
    emu_FileOpen(currprefs.hf0);

    emu_printi(hardfile_size);
    

    ROM_hardfile_resname = ds("hardfile.device");
    ROM_hardfile_resid = ds("UAE hardfile.device 0.2");

    numtracks = hardfile_size / 16384;

    /* initcode */
#if 0
    initcode = here();
    calltrap(deftrap(hardfile_init)); dw(RTS);
#else
    initcode = filesys_initcode;
#endif
    /* Open */
    openfunc = here();
    calltrap(deftrap(hardfile_open)); dw(RTS);

    /* Close */
    closefunc = here();
    calltrap(deftrap(hardfile_close)); dw(RTS);

    /* Expunge */
    expungefunc = here();
    calltrap(deftrap(hardfile_expunge)); dw(RTS);

    /* BeginIO */
    beginiofunc = here();
    calltrap(deftrap(hardfile_beginio));
    dw (0x48E7); dw (0x8002); /* movem.l d0/a6,-(a7) */
    dw (0x0829); dw (0); dw (30); /* btst #0,30(a1) */
    dw (0x6608); /* bne.b +8 */
    dw (0x2C78); dw (0x0004); /* move.l 4,a6 */
    dw (0x4EAE); dw (-378); /* jsr ReplyMsg(a6) */
    dw (0x4CDF); dw (0x4001); /* movem.l (a7)+,d0/a6 */
    dw(RTS);

    /* AbortIO */
    abortiofunc = here();
    calltrap(deftrap(hardfile_abortio)); dw(RTS);

    /* FuncTable */
    functable = here();
    dl(openfunc); /* Open */
    dl(closefunc); /* Close */
    dl(expungefunc); /* Expunge */
    dl(EXPANSION_nullfunc); /* Null */
    dl(beginiofunc); /* BeginIO */
    dl(abortiofunc); /* AbortIO */
    dl(0xFFFFFFFFul); /* end of table */

    /* DataTable */
    datatable = here();
    dw(0xE000); /* INITuae_s8 */
    dw(0x0008); /* LN_TYPE */
    dw(0x0300); /* NT_DEVICE */
    dw(0xC000); /* INITuae_s32 */
    dw(0x000A); /* LN_NAME */
    dl(ROM_hardfile_resname);
    dw(0xE000); /* INITuae_s8 */
    dw(0x000E); /* LIB_FLAGS */
    dw(0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
    dw(0xD000); /* INITuae_s16 */
    dw(0x0014); /* LIB_VERSION */
    dw(0x0004); /* 0.4 */
    dw(0xD000);
    dw(0x0016); /* LIB_REVISION */
    dw(0x0000);
    dw(0xC000);
    dw(0x0018); /* LIB_IDSTRING */
    dl(ROM_hardfile_resid);
    dw(0x0000); /* end of table */

    ROM_hardfile_init = here();
    dl(0x00000100); /* ??? */
    dl(functable);
    dl(datatable);
    dl(initcode);

    if (hardfile_size > 0) {
	   uaecptr initfunc;
	   add_filesys_unit(NULL, "hardfile", 1);
     emu_printf("HDD installed");
    }
}



#endif
