Source file: /~heha/hs/dos/dosmisc.zip/SRC/CDPL.ASM

;CD-Player, der kein MSCDEX braucht! Nur den Hardwaredevicedriver!
	include	prolog.asm
	include	"sound.asm"
	mov	al,0		;Nummer des gewünschten CDROMs
	call	OpenCD		;ein paar Parameter einsammeln
	jc	errm
	mov	si,ofs MediaCKdo
	call	myIOCTL
	mov	di,81h
scancl:	mov	al,[di]
	inc	di
	call	Upcase
	cmp	al,' '
	jz	scancl
	cmp	al,'-'
	jz	scancl
	cmp	al,'/'
	jz	scancl
	cmp	al,'H'
	jz	help
	cmp	al,'?'
	jz	help
	cmp	al,'O'
	mov	si,ofs EjectKdo
	jz	Kdo
	cmp	al,'E'
	jz	Kdo
	cmp	al,'L'
	mov	si,ofs LockKdo
	jz	Kdo
	cmp	al,'U'
	mov	si,ofs UnlockKdo
	jz	Kdo
	cmp	al,'C'
	mov	si,ofs CloseKdo
	jz	Kdo
	cmp	al,'S'
	jz	KdoStop
	cmp	al,'P'
	jz	KdoPlay		;Ganze Disk abspielen
	cmp	al,'A'	;stAtus
	jz	KdoState
	cmp	al,'I'	;Kurzinfo
	jn	z,KdoInfo
	cmp	al,13
	jnz	scancl
exi:	call	CloseCD
	DOS	4c00h
errm:	mov	cx,3
	call	PRINTF
	DOS	4c01h
Help:	mov	cx,2
	call	PRINTF
	jr	exi

Kdo:	call	myIOCTL
	jr	scancl

KdoStop:
	mov	ax,850dh	;Länge und Kommando
	call	myCmd2CD
	mov	ax,850dh	;Länge und Kommando
	call	myCmd2CD
	jmp	scancl

KdoPlay:
	mov	si,ofs VolsizeKdo
	call	myIOCTL
	jnc	kpl1
	mov	al,18*7		;7 Sekunden warten (???)
	call	wait8
	mov	si,ofs MediaCKdo
	call	myIOCTL
	mov	si,ofs VolsizeKdo
	call	myIOCTL
	jnc	kpl1
	cmp	al,0fh		;Disk change?
	jz	KdoPlay
	call	axhx		;Fehlernummer zur Diagnose
	jmp	scancl
kpl1:	mov	ax,[wo LOW Volsize]
	mov	[wo LOW ReqHdr.sectors],ax
	mov	ax,[wo HIGH Volsize]
	mov	[wo HIGH ReqHdr.sectors],ax
	mov	ax,132*256+13+9	;Länge und Kommando
	call	myCmd2CD
scan01:	jmp	scancl

KdoState:
	call	DevStat
	jc	scan01
	mov	cx,0
	call	PRINTF
	mov	ax,[wo LOW status]
	call	axhx
	mov	cx,1
	call	PRINTF
	mov	dx,[wo LOW status]
	mov	cl,3
	shl	dx,cl
	mov	cx,13	;13 Wörter
loo:	shl	dx,1
	sbb	ax,ax	;0 oder -1
	push	ax
	loop	loo	;13mal
	mov	cx,5	;Superstring
	call	printf	;Nu schaufel mal!
	add	sp,13*2
	jr	scan01

KdoInfo:
	call	DevStat
	jc	scan01
	mov	dx,[wo LOW status]
	test	dh,8	;CD eingelegt?
	call	pushnz
	test	dl,2
	call	pushnz
	test	dl,1
	call	pushnz
	mov	cx,4	;String-No.
	call	PRINTF
	add	sp,6
	jr	scan01

pushnz:	pop	cx
	mov	ax,0
	jz	pu1
	inc	ax
pu1:	push	ax
	jmp	cx	;zurück

struc tReqHdr
len	db	?		;User-schreibbar
subno	db	?		;!!System-Eintrag!!
cmd	db	?		;User-schreibbar
stat	dw	?		;!!nur zum Rücklesen!!
res	db	8 dup (?)	;!!System-reserviert!!
;ab hier zum Manipulieren durch den Anwender
mode	db	?		;meist: Adressiermodus
pointer	dd	?		;meist ein Zeiger
sectors	dd	?		;meist irgendwelche Sektoren
volume	dd	?		;ein Volume??
ILS	db	?		;Interleave Skip (Maximallänge)
reserve	db	?		;für besseres Alignment
ends

	alignv	2
DevStrt	dd	?
DevIntr	dd	?
ReqHdr	tReqHdr	<>

StatKdo	db	5,3,6
Status	dd	?

VolsizeKdo db	5,3,8
Volsize	dd	?

MediaCKdo db	2,3,9
MediaC	db	?

EjectKdo db	1,12,0
LockKdo	db	2,12,1,1
UnlockKdo db	2,12,1,0
CloseKdo db	1,12,5

printf:	mov	bx,1		;Standardausgabe für 99% der Fälle
proc fprintf	;cx=String-Nummer in String-Ressource
	cld			;durchweg
	push	ax bx cx dx si bx
	mov	bx,sp
	add	bx,14		;wenn NEAR
	call	iprintf
	pop	si dx cx bx ax
	ret
endp fprintf

proc iprintf	;Innere PRINTF-Routine für Rekursionen
		;bx=Stackzeiger (Parameterliste)
		;cx=Stringnummer (auf Stack?)
		;auf Stack: const Handle

@hand	equ	<wo bp+4>
	entr	20		;20 Bytes lokale Variablen
@flag	equ	<by bp-1>
@fill	equ	<by bp-2>
@case	equ	<wo bp-4>
@zahl	equ	<wo bp-6>
@buff	equ	<bp-20>		;14 Bytes Zahlenpuffer o.ä.
	 mov	[@flag],0	;rücksetzen
	 mov	si,[StrC]	;Adresse der Kollekion holen (globaler Pointer)
	 jcxz	@@o2
@@l3:	 lodsb			;String mit Nummer suchen
	 or	al,al
	 jnz	@@l3
	 loop	@@l3
@@o2:	 mov	ah,'%'		;Extra-Terminator
	 call	strout		;liefert al=0, wenn ok beendet.
	 jc	@@e		;bei Fehler
	 or	al,al
	 jnz	@@2		;wenn '%'
@@e:	leav
	ret	2		;Ende mit Allende

@@casz:	;CASE-Anweisung
	mov	al,[@flag]
	test	al,80h		;Case-Mode aktiv?
	jnz	@@c1
	mov	dx,[ss:bx]	;niemals LONG
	inc	bx
	inc	bx
	mov	[@case],dx
	or	al,80h
@@c1:	or	al,40h		;HIDE setzen
	mov	dx,[@zahl]	;die vorher eingelesene
	cmp	[@case],dx
@@el:	jnz	@@c2		;wenn ungleich (bzw. Bit gesetzt)
	and	al,not 40h	;HIDE löschen
	or	al,20h		;ELSE totlegen
@@c2:	mov	[@flag],al
	jmp	@@o2		;weiter im Text

@@else:	;ELSE-Zweig
	mov	al,[@flag]	;kein Test auf vorangegangenes Case!
	or	al,40h		;HIDE setzen
	test	al,20h		;ELSE erlaubt?
	jr	@@el		;...!!!

@@endc:	;Ende der Case-Anweisung
	mov	al,0
	jr	@@c2		;Flags nullsetzen

@@nums:	 mov	ax,[ss:bx]	;vom Stack!
	 inc	bx
	 inc	bx
@@num1:	 mov	[@zahl],ax
	 jr	@@2a
@@lng:	 or	[@flag],2
	 jr	@@2a
@@nul:	 mov	[@fill],'0'
	 jr	@@2a
@@min:	 or	[@flag],1	;Minus-Bit setzen
	 jr	@@2a
@@2:	;%-Jokerzeichen
	 and	[@flag],not 0fh ;Joker-Lokal-Flags löschen
	 mov	[@fill],' '	;Standardfüllzeichen
	 mov	[@zahl],0	;Standardzahl
@@2a:	 lodsb			;nächstas Zeichen
	 cmp	al,'-'
	 jz	@@min
	 cmp	al,'0'
	 jz	@@nul
	 cmp	al,'l'
	 jz	@@lng
	 cmp	al,'z'		;num. Parameter auf Stack
	 jz	@@nums
	 cmp	al,'C'
	 jz	@@casz
	 cmp	al,'e'
	 jz	@@else
	 cmp	al,'E'
	 jz	@@endc
	 test	[@flag],40h	;hidden?
	 jnz	@@3
	 cmp	al,'Z'		;Keine anderen Parameter auswerten!
	 jz	@@wech
	 cmp	al,'s'
	 jz	@@str
	 cmp	al,'S'
	 jz	@@nest
	 cmp	al,'c'
	 jz	@@char
	 cmp	al,'i'
;	 jz	@@int
	 cmp	al,'u'
;	 jz	@@unsi
	 cmp	al,'x'
;	 jz	@@hex
	 cmp	al,'X'
;	 jz	@@hex
@@3:	 dec	si
	 push	bx
	  mov	bl,10
	  call	inw2
	 pop	bx
	 jnc	@@num1		;die Zahl eintragen
	 jmp	@@o2		;sonst Ausgabe fortsetzen (z.B. %%->%)

@@str:	;normaler String NEAR, ls=String FAR
	 push	ds si
	  mov	si,[ss:bx]
	  test	[@flag],2	;Long?
	  jz	@@str1		;Nein.
	  mov	ds,[ss:bx+2]	;ja.
@@str1:	;DS:SI=Stringadresse
	  call	fstrout
	 pop	si ds
	 jc	@@e1		;Bei Fehler sofort raus!

@@wech:	 ;hau wech den Parameter
	 inc	bx
	 inc	bx
	 test	[@flag],2	;Long Parameter?
	 jz	@@w1
	 inc	bx
	 inc	bx
@@w1:	 jmp	@@o2		;zurück zur Hauptschleife

@@char:	;1 Zeichen ausgeben
	 mov	al,[ss:bx]
	 mov	ah,0
	 push	ds si
	  LD	ds,ss
	  lea	si,[@buff]
	  mov	[si],ax
	  call	fstrout		;Dieses eine Zeichen als String betrachten
	 pop	si ds
	 jc	@@e1
	 jr	@@wech		;Parameter abräumen

@@nest:	;Nested String (Verschachtelt)
	mov	cx,[@Zahl]
	push	si
	push	[@hand]
	call	iprintf		;Fertig!!
	pop	si
	jnc	@@w1		;von vorn. (KEINE REKURSIONEN BITTE!!)
@@e1:	jmp	@@e


 proc mchars	;Gib [@zahl] Zeichen [@fill] aus!
	push	ds si
	 LD	ds,ss
	 lea	dx,[@fill]	;DS:SI=SS:BP+??
	 mov	cx,1		;je 1 Zeichen
@@l:	 call	DOSwrite	;schreiben
	 jc	@@e		;Fehler!
	 dec	[@zahl]
	 jnz	@@l
@@e:	pop	si ds
	ret
 endp mchars

 proc fstrout	;Formatierte Stringausgabe
		;PE: DS:SI=String
		;    [@zahl]=Anzahl der Zeichen mindestens
		;    [@fill]=Füllzeichen
		;   0[@flag]=Linksbündige Ausgabe
		;PA: CY=1: DOS-Fehler, AX=Fehlernummer
	  xor	ah,ah
	  push	si
	   call	strlen		;Länge kalkulieren (nur bis 0 oder lf)
	  pop	si
	  sub	[@zahl],cx
	  jbe	strout0
	  test	[@flag],1	;Minus=linksbündig?
	  jz	@@right
	  or	al,al		;0 als Abbruch?
	  jnz	strout0
	  call	strout0
	  jc	@@e
	  call	mchars
@@e:	 ret
@@right:  call	mchars		;Füllzeichen ausgeben
	  jc	@@e
	;ret absichtlich vergessen!
 endp fstrout

strout0: mov	ah,0
 proc strout ;Stringausgabe
	;PE: DS:SI: Stringzeiger
	;    AH: Extra-Terminator ('%' oder 0)
	;PA: AL=0: Normaler Terminator
	;    CY=1: Fehler beim Schreiben, dann AX=DOS-Fehlernummer
	;    SI zeigt HINTER den Terminator!
	;VR: AX SI
	;Bem.: Diese Funktion wandelt 0ah in 0dh-0ah

	push	cx dx

@@o:	 mov	dx,si		;Anfangsadresse
	 call	strlen		;SI ist danach hinter dem Endezeichen
	 push	ax		;Abbruchzeichen merken
	  call	DOSwrite
	  jc	@@e		;zum Fehler-Ende
	 pop	ax
	 cmp	al,0ah
	 clc
	 jnz	@@e
	;DOS-Newline
	ifdef olines		;Wenn Zeilenzähler definiert
	 inc	[olines]	;Zeilennummer erhöhen
	endif	;!!Probleme mit DS!! Woher denn nehmen??
	 mov	cl,[by nl$]	;im Datensegment wie auch StrC (Resourcezeiger)
	 mov	dx,ofs nl$+1	;PASCAL-String des Zeilentrenners (kann ja auch 0 sein!)
	 xor	ch,ch		;<=255 Zeichen
	 push	ax		;AH retten
	  call	DOSwrite
	  jc	@@er		;und weiter gehts! (wenn kein DOSenfehler)
	 pop	ax
	 jr	@@o

@@er:	 pop	cx
@@e:	pop	dx cx
	ret

  proc DOSwrite	;Schreiben auf BX, wenn BX=0 (stdin) dann in Speicher!
	test	[@flag],40h	;Hidden? (Unterdrückte Case-Zweige)
	jnz	@@x
	push	bx
	 mov	bx,[@hand]	;Handle vom Stack besorgen
	;PE: Handle, CX=Länge, Quelladresse DS:DX, ggf. Zieladresse ES:DI
	;PA: CY=1: Fehler, dann AX=Fehlernummer (DOS)
ifdef UseMemW
	 or	bx,bx
	 jz	@@mem
endif
	 DOS	40h		;Schreiben! (gleich ganzen Block)
	 jc	@@e		;DOS-Fehler
	 cmp	ax,cx
	 mov	ax,1		;Disk full-Fehler (da "unbek. FktNr" Quatsch)
ifdef UseMemW
	 jr	@@e
@@mem:
	 push	si cx
	  mov	si,dx
	  rep	movsb		;Speicherschreiben
	 pop	cx si
endif
@@e:	pop	bx
@@x:	ret
  endp DOSwrite

 endp strout

 proc strlen	;PE: DS:SI=String
		;PA: CX=Länge, SI zeigt HINTER den Terminator
	mov	cx,-1
@@l:	lodsb
	inc	cx
	or	al,al
	jz	@@e
	cmp	al,0ah
	jz	@@e
	cmp	al,ah
	jnz	@@l
@@e:	ret
 endp strlen
endp iprintf


StrC	dw	ofs exampl$
nl$:	dps	13,10
exampl$:

    dz	'Status: '	;0 ..%X',10
    dz	10		;1
 db	'Mini-CD-Ansteuerung (haftmann#software): TESTVERSION, benötigt KEIN MSCDEX',10
 db	'Parameter:	- h oder ?	Diese Hilfe',10
 db	'		- o oder e	CD-Fach öffnen',10
 db	'		- c		CD-Fach schließen',10
 db	'		- l		Fach verriegeln',10
 db	'		- u		Verriegelung aufheben',10
 db	'		- p		Ganze CD abspielen',10
 db	'		- s		Abspiel stoppen',10
 db	'		- a		Komplett-Statusanzeige',10
 db	'		- i		Kurzinfo',10
 db	'z.B. CDPL clp = CD einfahren, verriegeln und komplett abspielen',10
 db	'oder CDPL suo = (das Gegenteil), CDPL uocococococl = Leute ärgern',10
    dz			;2
 db	'Kein Hardwaretreiber für CD-Laufwerk %u gefunden',10
    dz			;3
 db	'%11S, %12S, %13S.',10
    dz			;4
    db	'%11S',10
    db	'%6S%12S',10
    db	'%10S%0Cnur %7S%e%7S und raw%E',10
    db	'%0C%8S%9S%e%9S und Schreiben%E',10
    db	'%0C%8SDaten%eDaten, Audio und Video%E',10
    db	'%0CKein Interleave%eISO-9660-konform%E',10
    db	'%Z'
    db	'%0C%eKein %EKommando-Prefetching',10
    db	'%0C%eKeine %EAudio-Kanal-Manipulation',10
    db	'HSG%0C-%e und Red Book %EAdressierung',10
    db	'%Z'
    db	'%13S',10
    db	'%10S%0C%ekeine %ER-W-Sub-Kanäle',10,10
    dz			;5
    dz	'Tür '		;6
    dz	'cooked'	;7
    dz	'Nur '		;8
    dz	'Lesen'		;9
    dz	'unterstützt '	;10
    dz	'%6S%0Cgeschloss%eoff%Een'	;11
    dz	'%0C%eun%Everriegelt'		;12
    dz	'CD %0C%enicht %Eeingelegt'	;13

	_UPCASE
	_AXHX
	_WAIT8
	_INW2


;CD-Unit, erfordert Variablen im Datensegment namens ReqHdr, DevStrt, DevIntr
DevStat:	;Get Device Status (dword)
	mov	si,ofs StatKdo

myIOCTL:lodsw
IOCTLIO:	;IOCTL Input/Output
		;PE: si: Tabelle, DS im Datensegment, al=Bytes im Puffer
		;ah=3 für Input, 12 (dez) für Output
	SDS	[ReqHdr.pointer],si
	mov	[by LOW wo LOW ReqHdr.sectors],al ;Länge
	mov	al,13+13	;AH ist bereits das Kommando
	jr	myCmd2CD

CloseCD:	;PE:-
	mov	ax,14*256+13

proc myCmd2CD	;PE: AL=Länge, AH=Kommando
		;oder AX= MEIN Kommandoword
		;PA: AX=Return-Code
		;Löscht nach Ausführung alle Folgefelder; müssen
		;beim nächsten Mal nicht initialisiert werden!
	push	es bx
	 mov	bx,ofs ReqHdr
	 mov	[bx+tReqHdr.len],al
	 mov	[bx+tReqHdr.cmd],ah
	 LD	es,ds
	 push	cx dx		;sicherheitshalber!!
	  call	[DevStrt]
	  call	[DevIntr]
	 pop	dx cx
	 mov	bx,ofs ReqHdr.stat
	 mov	ax,[bx]
	 push	cx
	  mov	cx,size tReqHdr-3 ;!!Tja, wie berechnet man eine Länge?
@@l:	  mov	[by bx],0	;Requestheader löschen
	  inc	bx
	  loop	@@l
	pop	cx bx es
	cmp	ah,80h
	cmc			;CY aus Bit15 ziehen
	ret
	endp

proc OpenCD	;PE: AL=Nummer; patcht in ReqHdr den Eintrag "sub"
		;PA: CY=1: Kein CD-ROM Nummer AL gefunden!
	push	es bx
	 DOS	52h		;gültig ab DOS 3.1!!!
	 add	bx,22h		;NUL Device Header
@@l:	 les	bx,[es:bx]	;nächster Devicedriver
	 cmp	bx,0ffffh
	 jnc	@@e		;Ende der Kette! (noch CY=0)
	 cmp	[wo es:bx+10],'SM'
	 jnz	@@l
	 cmp	[wo es:bx+12],'DC'
	 jnz	@@l
	 mov	ah,[by es:bx+15h];Anzahl Devices im Treiber
	 sub	al,ah
	 jnc	@@l		;noch nicht genug
	 add	al,ah		;CY immer 1
	 mov	[ReqHdr.subno],al;Nummer speichern
	 mov	[wo HIGH DevStrt],es
	 mov	[wo HIGH DevIntr],es
	 mov	ax,[es:bx+6]
	 mov	[wo LOW DevStrt],ax
	 mov	ax,[es:bx+8]
	 mov	[wo LOW DevIntr],ax
	 mov	ax,0d0dh
	 call	myCmd2CD	;CD öffnen
	 stc
@@e:	 cmc
	pop	bx es
	ret
	endp

	endc
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded