;
; Program : MakeRes 1.1
; Date    : 10-May-1993
; Author  : G.Nikl
;
;   snail mail: Gunther Nikl
;               Hans-Beimler-Str 17
;               Parchim
;               O-2850
;
;        email: gnikl@informatik.uni-rostock.de

; MakeRes installs 'HackDisk' by Dan Babcock resident in ram
; This is done via KickMemPtr & KickMemList so it should work
; on all systems. Should be called as the first program in the
; STARTUP-SEQUENCE ( yes the STARTUP-SEQUENCE ) because of a
; reset we have to do to activate the new trackdisk.device !
; (The reset is only be done if the REBOOT keyword is specified)
;
; The program can be started from CLI or from the Workbench.
; You can select among eight switches as cli args or tooltypes.
; These are : (1) ?       - to get the argument template
;             (2) INSTALL - installs hackdisk in system
;             (3) TEST    - calculates a checksum to ensure the
;                           devices is still intact
;             (4) ENABLE  - hackdisk will be activated after reset
;             (5) DISABLE - hackdisk won't be activated after reset
;             (6) REMOVE  - removes hackdisk completly
;             (7) REBOOT  - forces a computer reboot
;             (8) QUIET   - suppress all messages
; NOTE: some switches are of cource mutual exclusive !!!
; MakeRes returns zero if all is ok. If an error occured the
; program returns 5 (WARN) - useful for scripts with the QUIET
; argument.
; The program has been tested on an a4000/030 with Kick 3.0 (39.106)
; and on an a500 with Kick 1.2 (33.180).
;
; I wrote this tiny program because i had nothing to install
; hackdisk.device in my system (Fred Fish deleted the support
; utility hackdisk was supplied with).
;
;   Disclaimer
;   ~~~~~~~~~~~
;   The author cannot be held liable for the suitability or accuracy of
;   this the program.  Any damage directly or indirectly caused by the
;   use or misuse of this the program is the sole responsibility of the
;   user her/him self.

; This program and the source are public domain

		include	dos_lib.i
		include	exec_lib.i

TDNestCount	equ	295
KickMemPtr	equ	546
KickTagPtr	equ	550
KickCheckSum	equ	554

ADDARG		macro
		dc.w	\1.str-ArgTab
\1		equ	ArgCount
ArgCount	set	\1+1
		endm

ADDSTR		macro
		dc.w	\1.str-StringTab
\1		equ	StrCount
StrCount	set	\1+1
		endm

bp		equr	a5

gb_SysBase	equ	   -0	; L		; destroys original A5 !!!!
gb_DosBase	equ	   -4	; L
gb_IconBase	equ	   -8	: L
gb_WbMsg	equ	  -12	; L
gb_StdOut	equ	  -16	; L
gb_ArgQuiet	equ	  -17	; B		; arg vector
gb_ArgBoot	equ	  -18	; B
gb_ArgRemove	equ	  -19	; B
gb_ArgDisable	equ	  -20	; B
gb_ArgEnable	equ	  -21	; B
gb_ArgTest	equ	  -22	; B
gb_ArgInst	equ	  -23	; B
gb_ArgHelp	equ	  -24	; B
gb_Reserved1	equ	  -26	; W
gb_ArgC		equ	  -28	; W
gb_ArgV		equ	  -60	; L*8
gb_PrintBuf	equ	 -188	: B*128
gb_SIZEOF	equ	 -188

MaxArg		equ	    8

start		link	bp,#gb_SIZEOF		; Platz fuer Vars schaffen
		moveq	#100,d7			; err: serious trouble
		move.l	d0,d2			; Argumentlaenge sichern
		move.l	a0,a2			; Argumentzeile sichern
		move.l	#(~gb_SIZEOF>>2),d1
		move.l	bp,a1
1$		clr.l	-(a1)			; Variablenbereich loeschen
		dbra	d1,1$
		move.l	4,a6
		move.l	a6,gb_SysBase(bp)	; ExecBase sichern
		move.l	276(a6),a4		; SysBase->ThisTask
		tst.l	172(a4)
		bne.s	fromCLI			; CLI-Start
fromWB		lea	92(a4),a0
		jsr	_LVOWaitPort(a6)
		lea	92(a4),a0
		jsr	_LVOGetMsg(a6)
		move.l	d0,gb_WbMsg(bp)		; WB-Message
		move.l	d0,a2
		bsr.s	OpenDOS
		beq.s	exit2			; kein DOS
		move.l	a2,a1
		lea	gb_ArgV(bp),a2
		moveq	#0,d2
		bsr.s	ParseWB
		move.w	d2,gb_ArgC(bp)		; Argumentzahl sichern
		bsr	main
		move.l	d0,d7
exit2		jsr	_LVOForbid(a6)
		move.l	gb_WbMsg(bp),a1
		jsr	_LVOReplyMsg(a6)	; WB-Message beantworten
		bra.s	exit			; zum Hauptprogramm

fromCLI		clr.b	-1(a2,d2.w)		; Zeile terminieren
		bsr.s	OpenDOS
		beq.s	exit			; kein DOS
		move.l	a2,a1
		lea	gb_ArgV(bp),a2
		moveq	#0,d2
		bsr	ParseCLI		; Argument-Vektor aufbauen
		move.w	d2,gb_ArgC(bp)		; Argumentzahl sichern
		bsr	main			; Hauptprogramm
		move.l	d0,d7
exit		bsr.s	CloseDOS
		move.l	d7,d0			; ReturnCode setzen
		unlk	bp			; Stack aufraeumen
		rts

OpenDOS		lea	DosName(pc),a1		; dos.library
		moveq	#33,d0
		jsr	_LVOOpenLibrary(a6)	; DOS oeffen
		move.l	d0,gb_DosBase(bp)	; sichern -> Flags stellen
		rts

DosName		dc.b	'dos.library',0
		even

CloseDOS	move.l	gb_DosBase(bp),d0	; DOS geoeffnet ?
		beq.s	1$			; nein
		move.l	d0,a1
		jsr	_LVOCloseLibrary(a6)	; DOS schliessen
1$		rts

*****************************************************************************

; a1 - wbmsg
; d2 - argc
; a2 - argv

_LVOGetDiskObject	equ	-78
_LVOFreeDiskObject	equ	-90

ParseWB		move.l	a4,-(sp)
		move.l	36(a1),a3
		lea	IconName(pc),a1
		moveq	#33,d0
		jsr	_LVOOpenLibrary(a6)
		move.l	d0,gb_IconBase(bp)
		beq.s	1$			; no icon library ?!
		move.l	(a3),d1
		move.l	gb_DosBase(bp),a6
		jsr	_LVOCurrentDir(a6)	; set wa_Lock
		move.l	4(a3),a0
		move.l	gb_IconBase(bp),a6
		jsr	_LVOGetDiskObject(a6)	; get wa_Name
		move.l	d0,a4
		move.l	a4,d0
		beq.s	2$
		lea	gb_PrintBuf(bp),a1
		move.l	54(a4),a3		; do_ToolTypes
		bra.s	4$
6$		cmp.w	#MaxArg,d2
		bcc.s	4$
		move.l	a1,(a2)+		; store arpptr
		addq.w	#1,d2			; increment argc
		move.l	d0,a0
5$		move.b	(a0)+,(a1)+		; copy value
		bne.s	5$
4$		move.l	(a3)+,d0
		bne.s	6$
3$		move.l	a4,a0
		jsr	_LVOFreeDiskObject(a6)
2$		move.l	a6,a1
		move.l	gb_SysBase(bp),a6
		jsr	_LVOCloseLibrary(a6)	; close icon lib
1$		move.l	(sp)+,a4
		rts

IconName	dc.b	'icon.library',0
		even

*****************************************************************************

; a1 - pointer into command line
; d2 - argc
; a2 - argv

ParseCLI	bsr.s	GetNext			; search argument
		bmi.s	doquote			; quotation sign
		beq.s	dosemi			; commentary stops all
		bcs.s	ParseCLI		; separation sign
		lea	-1(a1),a0		; argument start
		bsr.s	BumpArgV		; argc+1 & ptr to argv
build_2		bsr.s	GetNext			; search separation sign
		beq.s	dosemi			; commentary stops all
		bcc.s	build_2			; no separation sign
		clr.b	-1(a1)			; mark end
		bra.s	ParseCLI		; continue search

doquote		move.l	a1,a0			; argument start
		bsr.s	BumpArgV		; argc+1 & ptr to argv
quote_2		bsr.s	GetNext			; search quotation sign
		bpl.s	quote_2			; no quotation sign
		clr.b	-1(a1)			; mark end
quote_3		bsr.s	GetNext			; search sepaartion sign
		beq.s	dosemi			; commentary stops all
		bcc.s	quote_3			; no separation sign
		bra.s	ParseCLI		; continue search

dosemi		clr.b	-(a1)			; delete semicolon
		bra.s	ParseCLI		; go on

BumpArgV	cmp.w	#MaxArg,d2			; max argc reached ?
		bcc.s	1$
		move.l	a0,(a2)+		; store argptr
		addq.w	#1,d2			; increment argc
1$		rts

GetNext		move.b	(a1)+,d0		; test character
		beq.s	BuildRdy
		moveq	#-3,d1			; N=1,Z=0,C=0 -> quotation
		cmp.b	#'"',d0
		beq.s	1$
		moveq	#-2,d1			; N=0,Z=1,C=1 -> semicolon
		cmp.b	#';',d0
		beq.s	1$
		moveq	#-1,d1			; N=0,Z=0,C=1 -> separation
		cmp.b	#'=',d0
		beq.s	1$
		cmp.b	#' ',d0
		beq.s	1$
		cmp.b	#9,d0
		beq.s	1$
		moveq	#0,d1			; N=0,Z=0,C=0 -> others
1$		addq.l	#2,d1			; set flags ( see above )
		rts

BuildRdy	addq.l	#4,sp			; set right return address
		rts

*****************************************************************************

main		movem.l	d2-d4/a2/a3/a6,-(sp)
		bsr	CheckArgs		; check args
		tst.b	gb_ArgQuiet(bp)
		bne.s	m_quiet			; no output
		move.l	gb_DosBase(bp),a6
		lea	CliWin(pc),a1
		tst.l	gb_WbMsg(bp)
		beq.s	m_stdout
		lea	WbWin(pc),a1
m_stdout	move.l	a1,d1
		move.l	#1005,d2
		jsr	_LVOOpen(a6)		; open window
		move.l	d0,gb_StdOut(bp)
m_quiet		moveq	#PrgName,d0
		bsr	PrintStr
		moveq	#Usage,d0
		tst.w	gb_ArgC(bp)
		beq.s	m_error			; no args
		tst.b	gb_ArgHelp(bp)
		bne.s	m_error			; help requested

		moveq	#IllegalArgs,d0
		tst.b	gb_ArgDisable(bp)
		beq.s	m_check
		tst.b	gb_ArgRemove(bp)
		beq.s	m_check
		clr.b	gb_ArgDisable(bp)	; disable && remove ->remove
m_check		tst.b	gb_ArgInst(bp)
		bne.s	1$
		tst.b	gb_ArgEnable(bp)
		beq.s	m_install
1$		tst.b	gb_ArgDisable(bp)
		bne.s	m_error			; wrong args
		tst.b	gb_ArgRemove(bp)
		bne.s	m_error			; wrong args

m_install	moveq	#0,d4			; ReturnCode = All Ok
		tst.b	gb_ArgInst(bp)
		beq.s	m_test
		bsr	MakeRes
		beq.s	m_exit2
		tst.b	gb_ArgBoot(bp)
		beq.s	m_error
		bne.s	m_exit2			; install && boot
m_test		tst.b	gb_ArgTest(bp)
		beq.s	m_enable
		bsr	ResTest
		bne.s	m_error
m_enable	tst.b	gb_ArgEnable(bp)
		beq.s	m_disable
		bsr	ResEnable
		bne.s	m_error
m_disable	moveq	#0,d0
		tst.b	gb_ArgDisable(bp)
		bne.s	m_remove
		moveq	#1,d0
		tst.b	gb_ArgRemove(bp)
		beq.s	m_reboot
m_remove	bsr	ResRemove
		bne.s	m_error
m_reboot	tst.b	gb_ArgBoot(bp)
		beq.s	m_exit2
		bsr	ResReBoot

m_error		bsr	PrintStr		; error message
		moveq	#5,d4			; ReturnCode = WARN
m_exit2		move.l	gb_DosBase(bp),a6
		tst.l	gb_WbMsg(bp)
		beq.s	1$
		moveq	#Return,d0
		bsr	PrintStr
		move.l	gb_StdOut(bp),d1
		beq.s	m_exit
		lea	gb_PrintBuf(bp),a2
		move.l	a2,d2
		moveq	#1,d3
		jsr	_LVORead(a6)		; wait for key
1$		move.l	gb_StdOut(bp),d1
		beq.s	m_exit
		jsr	_LVOClose(a6)		; close our wb window
m_exit		move.l	d4,d0
		movem.l	(sp)+,d2-d4/a2/a3/a6
		rts

CliWin		dc.b	'*',0
WbWin		dc.b	'RAW:90/23/280/54/MsgWin',0
		even

*****************************************************************************

CheckArgs	moveq	#7,d3			; eight arguments
4$		lea	ArgTab(pc),a3
		move.w	d3,d0
		add.w	d0,d0
		adda.w	0(a3,d0.w),a3
		lea	gb_ArgV(bp),a2
		move.w	gb_ArgC(bp),d2
		bra.s	2$
3$		moveq	#$5f,d0
		and.b	(a0)+,d0
		moveq	#$5f,d1
		and.b	(a1)+,d1
		cmp.b	d0,d1
		bne.s	2$			; not same chars
		tst.b	d0
		bne.s	3$			; not the last char
		st	gb_ArgHelp(bp,d3.w)	; flag argument
		bra.s	1$
2$		move.l	(a2)+,a0
		move.l	a3,a1
		dbra	d2,3$
1$		dbra	d3,4$
		rts

ArgCount	set	0

ArgTab		ADDARG	Help
		ADDARG	Install
		ADDARG	Test
		ADDARG	Enable
		ADDARG	Disable
		ADDARG	Remove
		ADDARG	ReBoot
		ADDARG	Quiet

Help.str	dc.b	'?',0			; cli & wb parameter
Install.str	dc.b	'INSTALL',0
Test.str	dc.b	'TEST',0
Enable.str	dc.b	'ENABLE',0
Disable.str	dc.b	'DISABLE',0
Remove.str	dc.b	'REMOVE',0
ReBoot.str	dc.b	'REBOOT',0
Quiet.str	dc.b	'QUIET',0
		even

*****************************************************************************

ResTest		bsr	FindRes
		bne.s	1$			; oops, not installed
		moveq	#0,d0
		move.l	28(a0),d1
		move.l	24(a0),a1
2$		add.l	(a1)+,d0		; calc checksum
		subq.l	#4,d1
		bne.s	2$
		not.l	d0
		moveq	#IsCorrupt,d1
		sub.l	32(a0),d0
		bne.s	1$			; checksum error
		moveq	#IsCorrect,d0
		bsr	PrintStr		; message
		moveq	#0,d1
1$		move.l	d1,d0			; set flags
		rts

ResEnable	bsr	FindRes
		bne.s	1$			; oops, not installed
		addq.b	#1,TDNestCount(a6)	; Forbid()
		lea	36(a0),a0
		move.l	KickTagPtr(a6),d1
		beq.s	3$			; nothing installed
4$		cmp.l	a0,d1
		beq.s	2$			; already enabled !
		move.l	d1,a1
		move.l	4(a1),d1
		bclr	#31,d1
		bne.s	4$			; more entries
		move.l	KickTagPtr(a6),4(a0)
		bset	#7,4(a0)
3$		move.l	a0,KickTagPtr(a6)
		jsr	_LVOSumKickData(a6)	; enable it
		move.l	d0,KickCheckSum(a6)
2$		jsr	_LVOPermit(a6)		; enable multitasking
		moveq	#Enabled,d0
		bsr	PrintStr		; message
		moveq	#0,d1
1$		move.l	d1,d0			; set flags
		rts

ResRemove	move.l	d0,d3
		bsr	FindRes			; oops, not installed
		bne	1$
		addq.b	#1,TDNestCount(a6)	; Forbid()
		move.l	a0,a2
		lea	36(a0),a0
		lea	KickTagPtr-4(a6),a1
		move.l	4(a1),d1
		beq.s	30$			; nothing installed
50$		cmp.l	a0,d1
		beq.s	40$			; found it
		move.l	d1,a1
		move.l	4(a1),d1
		bclr	#31,d1
		bne.s	50$			; more entries
		bra.s	30$			; not installed
40$		move.l	4(a0),d1
		clr.l	4(a0)			; clear successor
		cmp.l	KickTagPtr(a6),a0
		bne.s	30$			; we are not in ExecBase
		bclr	#31,d1			; clear msb for ExecBase
30$		move.l	d1,4(a1)
		tst.l	d3
		beq.s	3$			; diasble only
		lea	KickMemPtr(a6),a0
		bra.s	5$
6$		move.l	d0,a0
5$		move.l	(a0),d0
		cmp.l	a2,d0
		bne.s	6$
		move.l	(a2),(a0)		; new successor
3$		jsr	_LVOSumKickData(a6)
		move.l	d0,KickCheckSum(a6)	; new checksum
		jsr	_LVOPermit(a6)		; enable multitasking
		moveq	#Disabled,d0
		tst.l	d3
		beq.s	2$
		moveq	#Removed,d0
2$		bsr	PrintStr		; message
		moveq	#0,d1
1$		move.l	d1,d0			; set flags
		rts

FindRes		moveq	#IsRes,d1
		move.l	gb_SysBase(bp),a6	; find our memlist
		lea	KickMemPtr(a6),a0
		bra.s	3$
4$		move.l	d0,a0
		cmp.w	#2,14(a0)
		bne.s	3$
		move.l	24(a0),a1
		lea	CmpName(pc),a2
		cmpm.l	(a2)+,(a1)+
		bne.s	3$
		cmpm.l	(a2)+,(a1)+
		beq.s	1$			; found
3$		move.l	(a0),d0
		bne.s	4$
		moveq	#IsNotRes,d1		; error
1$		rts

*****************************************************************************

MakeRes		bsr.s	FindRes			; resident
		beq	MakeQuit
		lea	NewDevice(pc),a1	; install it
		move.l	a1,d1
		move.l	gb_DosBase(bp),a6
		jsr	_LVOLoadSeg(a6)
		moveq	#LoadErr,d1
		move.l	d0,a3
		move.l	a3,d0
		beq	MakeQuit		; device not loaded
		adda.l	a3,a3
		adda.l	a3,a3
		move.l	-(a3),d3		; hunk size
		move.l	CmpName(pc),0(a3)	; set our magic
		move.l	CmpName+4(pc),4(a3)	; check mark
		moveq	#56,d0
		moveq	#1,d1
		swap	d1
		move.l	gb_SysBase(bp),a6
		jsr	_LVOAllocMem(a6)
		moveq	#MemErr,d1
		move.l	d0,a2
		move.l	a2,d0
		beq	MakeQuit		; no memory !
		lea	14(a2),a0
		moveq	#2,d2
		move.w	d2,(a0)+		; number of entries in MemList
		move.l	a2,(a0)+		; address of MemList
		moveq	#56,d2
		move.l	d2,(a0)+		; size of MemList
		move.l	a3,(a0)+		; address of Device
		move.l	d3,(a0)+		; size of Devices
		moveq	#0,d1
		move.l	a3,a1
4$		add.l	(a1)+,d1		; calculate a checksum
		subq.l	#4,d3
		bne.s	4$
		not.l	d1
		move.l	d1,(a0)+		; our checksum
		addq.l	#8,a3			; store correct address
		move.l	a3,(a0)			; of device
		addq.b	#1,295(a6)		; Forbid()
		move.l	KickTagPtr(a6),4(a0)	; save old KickTag
		beq.s	3$			; nothing installed
		bset	#7,4(a0)		; mark as next entry
3$		move.l	a0,KickTagPtr(a6)	; store new KickTag
		move.l	KickMemPtr(a6),d0
		beq.s	2$			; no old KickMem
		move.l	d0,(a2)			; old ptr our successor
		move.l	d0,a0
		move.l	a2,4(a0)		; predecessor
2$		move.l	a2,KickMemPtr(a6)	; store new KickMem
		jsr	_LVOSumKickData(a6)
		move.l	d0,KickCheckSum(a6)	; store new CheckSum
		jsr	_LVOPermit(a6)
		moveq	#Installed,d0
		bsr	PrintStr		; success
		moveq	#0,d1
		tst.b	gb_ArgBoot(bp)
		beq.s	MakeQuit		; no reboot ...

ResReBoot	moveq	#25,d1
		move.l	gb_DosBase(bp),a6
		jsr	_LVODelay(a6)		; wait half a second
		move.l	gb_SysBase(bp),a6
		cmp.w	#36,20(a6)		; Kick 2.0+ installed ?
		blt.s	1$
		jmp	-726(a6)		; ColdReboot() Kick 2.0+
1$		lea     $01000004,a4		; reboot manually
		suba.l  -$18(a4),a4
		movea.l (a4),a4
		subq.l  #2,a4
		lea     ResetCode(pc),a5
		jsr     _LVOSupervisor(a6)
		cnop    0,4
ResetCode	reset				; go away ...
		jmp    (a4)

MakeQuit	move.l	d1,d0			; set flags
		rts

		cnop	0,4
CmpName		dc.b	'HackDisk',0
NewDevice	dc.b	'devs:hackdisk.device',0
		even

*****************************************************************************

; d0 - string number

PrintStr	tst.b	gb_ArgQuiet(bp)		; messages allowed ?
		bne	PrintStrEnd
		movem.l	d2/d3/a2/a3/a6,-(sp)	; save regs
		move.l	d0,d2
		lea	StringTab(pc),a0	; start of string table
		add.w	d2,d2
		add.w	0(a0,d2.w),a0		; add offset
		pea	CmpName(pc)
		move.l	sp,a1			; pointer to argument
		lea	sc_put(pc),a2		; buffer function
		lea	gb_PrintBuf(bp),a3	; output buffer
		move.l	gb_SysBase(bp),a6
		jsr	_LVORawDoFmt(a6)	; do the format
		addq.l	#4,sp			; adjust stack
		move.l	gb_StdOut(bp),d1
		beq.s	3$			; no stdout
		lea	gb_PrintBuf(bp),a0
		move.l	a0,d2			; output buffer
		moveq	#-1,d3
2$		tst.b	(a0)+
		dbeq	d3,2$
		not.l	d3			; output lenght
		move.l	gb_DosBase(bp),a6
		jsr	_LVOWrite(a6)
3$		movem.l	(sp)+,d2/d3/a2/a3/a6	; restore regs
PrintStrEnd	rts

sc_put		move.b	d0,(a3)+		; store char in buffer
		rts

*****************************************************************************

StrCount	set	0

StringTab	ADDSTR	PrgName
		ADDSTR	Usage
		ADDSTR	IllegalArgs
		ADDSTR	Installed
		ADDSTR	IsRes
		ADDSTR	IsNotRes
		ADDSTR	IsCorrect
		ADDSTR	IsCorrupt
		ADDSTR	Enabled
		ADDSTR	Disabled
		ADDSTR	Removed
		ADDSTR	LoadErr
		ADDSTR	MemErr
		ADDSTR	Return

PrgName.str	dc.b	'MakeRes 1.1 © 1992/93 by G.Nikl',10,0
Usage.str	dc.b	'INSTALL/S,TEST/S,ENABLE/S,DISABLE/S,'
		dc.b	'REMOVE/S,REBOOT/S,QUIET/S',10,0
IllegalArgs.str	dc.b	'illegal argument combination !',10,0
Installed.str	dc.b	'%s succesfully installed !',10,0
IsRes.str	dc.b	'%s already installed !',10,0
IsNotRes.str	dc.b	'%s not installed !',10,0
IsCorrect.str	dc.b	'%s checksum ok !',10,0
IsCorrupt.str	dc.b	'%s corrupt !',10,0
Enabled.str	dc.b	'%s enabled !',10,0
Disabled.str	dc.b	'%s disabled !',10,0
Removed.str	dc.b	'%s removed !',10,0
LoadErr.str	dc.b	'couldn''t load %s !',10,0
MemErr.str	dc.b	'not enough memory !',10,0
Return.str	dc.b	10,'Any key to quit !',0

		end
