/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *  Portions Copyright (C) 1994 Rafael W. Luebbert
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define START
#include <ixemul.h>
#include "version.h"

/* size of C_PRIVATE was generated by create_header.c */
/* include the generated header */
#include "ix_internals.h"


	.text

   | The first executable location.  This should return an error
   | in case someone tried to run you as a program (instead of
   | loading you as a library).
	.globl	Start		| we use this to force inclusion of start.s
Start:
   movel   #-1,d0
   rts

|-----------------------------------------------------------------------
| A romtag structure.  Both "exec" and "ramlib" look for
| this structure to discover magic constants about you
| (such as where to start running you from...).
|-----------------------------------------------------------------------

initDDescrip:
               |STRUCTURE RT,0
     .word    RTC_MATCHWORD      | UWORD RT_MATCHWORD
     .long    initDDescrip       | APTR  RT_MATCHTAG
     .long    EndCode            | APTR  RT_ENDSKIP
     .byte    RTF_AUTOINIT       | UBYTE RT_FLAGS
     .byte    IX_VERSION         | UBYTE RT_VERSION
     .byte    NT_LIBRARY         | UBYTE RT_TYPE
     .byte    IX_PRIORITY        | BYTE  RT_PRI
     .long    ixName        	 | APTR  RT_NAME
     .long    idString           | APTR  RT_IDSTRING
     .long    Init               | APTR  RT_INIT
| this is just fool proof, and this library will never make it to ROM
| anyway, so resident tags are not that important ;-)
EndCode:


   | this is the name that the library will have
ixName:    .asciz IX_NAME

   | this is an identifier tag to help in supporting the library
   | format is 'name version.revision (dd.mm.yy)',<cr>,<lf>,<null>'
   | without any leading zeros in dd.mm.yy
idString:
	.ascii IX_IDSTRING
	.byte 13
	.byte 10
	.byte 0

   | force word alignment
   .even


   | The romtag specified that we were "RTF_AUTOINIT".  This means
   | that the RT_INIT structure member points to one of these
   | tables below.  If the AUTOINIT bit was not set then RT_INIT
   | would point to a routine to run.

Init:
   .long   IXBASE_SIZEOF	| size of library base data space
   .long   funcTable		| pointer to function initializers
   .long   dataTable            | pointer to data initializers
   .long   initRoutine	        | routine to run


funcTable:

   |------ standard system routines
   .long   Open
   .long   Close
   .long   Expunge
   .long   Null

   |------ my libraries definitions

#define ___must_recompile220 ___must_recompile
#define ___must_recompile221 ___must_recompile
#define ___must_recompile222 ___must_recompile
#define ___must_recompile223 ___must_recompile
#define ___must_recompile224 ___must_recompile
#define ___must_recompile226 ___must_recompile
#define ___must_recompile229 ___must_recompile
#define ___must_recompile235 ___must_recompile
#define ___must_recompile237 ___must_recompile
#define ___must_recompile239 ___must_recompile
#define ___must_recompile240 ___must_recompile
#define ___must_recompile241 ___must_recompile
#define ___must_recompile242 ___must_recompile
#define ___must_recompile243 ___must_recompile
#define ___must_recompile244 ___must_recompile
#define ___must_recompile253 ___must_recompile
#define ___must_recompile254 ___must_recompile
#define ___must_recompile255 ___must_recompile
#define ___must_recompile256 ___must_recompile
#define ___must_recompile259 ___must_recompile
#define ___must_recompile262 ___must_recompile
#define ___must_recompile267 ___must_recompile
#define ___must_recompile273 ___must_recompile
#define ___must_recompile274 ___must_recompile
#define ___must_recompile275 ___must_recompile
#define ___must_recompile277 ___must_recompile
#define ___must_recompile386 ___must_recompile
#define ___must_recompile387 ___must_recompile
#define ___must_recompile388 ___must_recompile
#define ___must_recompile389 ___must_recompile
#define ___must_recompile390 ___must_recompile
#define ___must_recompile447 ___must_recompile
#define ___must_recompile448 ___must_recompile
#define ___must_recompile449 ___must_recompile
#define ___must_recompile450 ___must_recompile
#define ___must_recompile502 ___must_recompile
#define ___must_recompile503 ___must_recompile
#define ___must_recompile504 ___must_recompile
#define ___must_recompile505 ___must_recompile
#define ___must_recompile506 ___must_recompile
#define ___must_recompile507 ___must_recompile
#define ___must_recompile520 ___must_recompile
#define ___must_recompile521 ___must_recompile
#define ___must_recompile523 ___must_recompile
#define ___must_recompile524 ___must_recompile
#define ___must_recompile525 ___must_recompile
#define ___must_recompile526 ___must_recompile
#define ___must_recompile527 ___must_recompile
#define ___must_recompile528 ___must_recompile
#define ___must_recompile529 ___must_recompile
#define ___must_recompile530 ___must_recompile

#ifdef TRACE_LIBRARY
#define SYSTEM_CALL(func, vec) .long trace_/**/func
#else
#define SYSTEM_CALL(func, vec) .long _/**/func
#endif
#include <sys/syscall.def>
#undef SYSTEM_CALL

   |------ function table end marker
   .long   -1

#ifdef TRACE_LIBRARY
#define SYSTEM_CALL(func, vec) \
trace_/**/func: ;						\
	pea _/**/func;						\
	pea vec; 						\
	jsr _trace_entry;					\
	lea sp@(8),sp;						\
	tstl d0;						\
	beq  1f;		/* jump directly there */	\
	/* in that case, trace_entry already provided the result */	\
	movel sp@(-4),d0;					\
	rts;							\
1:	jmp _/**/func;
#include <sys/syscall.def>
#undef SYSTEM_CALL
#endif



   | The data table initializes static data structures.
   | The format is specified in exec/InitStruct routines
   | manual pages.  The INITBYTE/INITWORD/INITLONG routines
   | are in the file "exec/initializers.i".  The first argument
   | is the offset from the library base for this byte/word/long.
   | The second argument is the value to put in that cell.
   | The table is null terminated
   | NOTE - LN_TYPE below is a correction - old example had LH_TYPE

dataTable:
	INITBYTE (LN_TYPE, 		NT_LIBRARY)
	INITLONG (LN_NAME, 		ixName)
	INITBYTE (IXBASE_FLAGS, 	0x6) |LIBF_CHANGED_SUMUSED
	INITWORD (IXBASE_VERSION, 	IX_VERSION)
	INITWORD (IXBASE_REVISION, 	IX_REVISION)
	INITLONG (IXBASE_IDSTRING, 	idString)
	.long   0


#ifdef DEBUG
twoint:
	.asciz "$%lx, $%lx\n"
#endif

   | This routine gets called after the library has been allocated.
   | The library pointer is in D0.  The segment list is in A0.
   | If it returns non-zero then the library will be linked into
   | the library list.
initRoutine:

   |------ get the library pointer into a convenient A register
   movel   a5,sp@-
   movel   d0,a5

   |------ save a pointer to our loaded code
   movel   a0,a5@(IXBASE_SEGLIST)

   |------ do the higher-level initialization in C
   |------ the ix_init_glue() function checks if the hardware is supported
   |------ (using 68000 instructions only) and if so will call ix_init()
   |------ for the main initialization.
   pea	   a5@
   jsr	   _ix_init_glue
   addqw   #4,sp

   movel   sp@+,a5
   rts

|----------------------------------------------------------------------
|
| here begins the system interface commands.  When the user calls
| OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
| into a call to the following routines (Open/Close/Expunge).  Exec
| has already put our library pointer in A6 for us.  Exec has turned
| off task switching while in these routines (via Forbid/Permit), so
| we should not take too long in them.
|
|----------------------------------------------------------------------


   | Open returns the library pointer in d0 if the open
   | was successful.  If the open failed then null is returned.
   | It might fail if we allocated memory on each open, or
   | if only open application could have the library open
   | at a time...

Open:      | ( libptr:a6, version:d0 )


   |------ mark us as having another opener
   addqw   #1,a6@(IXBASE_OPENCNT)

   |------ prevent delayed expunges
   | !!!!!!
   | commo - example code uses private flags field (IXBASE_MYFLAGS), WHY????
   | !!!!!!
   bclr    #LIBB_DELEXP,a6@(IXBASE_FLAGS)

   |------ do other things in C
   pea	   a6@
   jsr	   _ix_open
   addqw   #4,sp
   |--- ix_open() should return the library base, if all ok

   rts

   | There are two different things that might be returned from
   | the Close routine.  If the library is no longer open and
   | there is a delayed expunge then Close should return the
   | segment list (as given to Init).  Otherwise close should
   | return NULL.

Close:      | ( libptr:a6 )

   |------ do any cleanups needed in C
   pea	   a6@
   jsr	   _ix_close
   addqw   #4,sp

   |------ mark us as having one fewer openers
   subqw   #1,a6@(IXBASE_OPENCNT)

   |------ see if there is anyone left with us open
   bne     Null

   |------ see if we have a delayed expunge pending
   btst    #LIBB_DELEXP,a6@(IXBASE_FLAGS)	| SEE ABOVE!
   bne     Expunge

   | reserved entry

Null:
   moveq   #0,d0
   rts

   | There are two different things that might be returned from
   | the Expunge routine.  If the library is no longer open
   | then Expunge should return the segment list (as given to
   | Init).  Otherwise Expunge should set the delayed expunge
   | flag and return NULL.
   |
   | One other important note: because Expunge is called from
   | the memory allocator, it may NEVER Wait() or otherwise
   | take long time to complete.

Expunge:   | ( libptr: a6 )
   moveml  a2/a5/a6,sp@-
   movel   a6,a5

   |------ assume we can't expunge
   subal   a2,a2
   bset    #LIBB_DELEXP,a5@(IXBASE_FLAGS)	| SEE ABOVE !!

   |------ see if anyone has us open
   tstw    a5@(IXBASE_OPENCNT)
   bne     L21

   |------ go ahead and get rid of us.  Store our seglist in a2
   movel   a5@(IXBASE_SEGLIST),a2
   movel   4:w,a6

   |------ unlink from library list
   movel   a5,a1
   jsr	   a6@(_LVORemove)

   |
   | device specific closings here...
   |
   pea	   a5@
   jsr	   _ix_expunge
   addqw   #4,sp

   |------ free our memory
   movel   a5,a1
   moveq   #0,d0
   movew   a5@(IXBASE_NEGSIZE),d0
   subl    d0,a1
   addw    a5@(IXBASE_POSSIZE),d0
   jsr	   a6@(_LVOFreeMem)

L21:       |------ set up our return value
   movel   a2,d0

   moveml  sp@+,a2/a5/a6
   rts
