home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 13
/
AACD13.ISO
/
AACD
/
Utilities
/
ACDPlay
/
src
/
V1.6
/
asmlib
/
CD-ROM.s
< prev
next >
Wrap
Text File
|
1997-10-18
|
60KB
|
1,429 lines
*
* CD-ROM.s V0.17 by mak passend zu ACDPlay.c V1.49 beta
*
* ACHTUNG! Alle Funktionen hier (und auch C) gehen davon aus daß alle Register
* erhalten bleiben. Darum müssen alle Register die irgendwie verändert
* werden gesichert werden. Auch d0, wenn kein Wert zurückgegeben wird.
*
*///Autor Version Datum Veränderungen
* ------- --------- -------- ------------------------------------------
* mak 0.01 04.01.97 - Ersterstellung CDOpenDeviceA(), CDCloseDeviceA()
* 0.02 07.01.97 - CDUpdateA() dazu
* 08.01.97 - CDDoSCSIA() erstellt
* 14.01.97 - CDPauseA() dazu
* 0.03 15.01.97 - CDUpdateA() überarbeitet und CDx-Struktur erweitert
* - ReadTOCA() angefangen
* 0.04 19.01.97 - CDEjectA() erstellt
* - CDUpdateA() testet jetzt auf Fehler
* 20.01.97 - Errortest in CDDoSCSIA() eingebaut
* 0.05 21.01.97 - CDPlayA() erstellt
* 0.06 23.01.97 - CDStopA() erstellt
* 24.01.97 - CDTestUnitA() hinzugefügt
* 0.07 27.01.97 - CDJumpA() endlich fertig
* 28.01.97 - CDJumpA() kennt jetzt 4 Arbeitsmodi
* - CDReadTOCA() beendet
* 30.01.97 - Funktion CDReadTOC() überarbeitet: leadout jetzt in Entry[0] und Entry[lasttrack+1]
* - TOC wird abhängig vom AudioStatus in CDUpdateA() neu eingelesen
* - CDOpenDeviceA() liest TOC nun auch ein
* - DoSCSIA setzt Conditioncodes
* 0.08 31.01.97 - MODE SENSE angefangen (Volume) usw.
* 01.02.97 - CDxRequest Struktur überholt
* - CDUpdateA() überarbeitet: setzt jetzt Positionen ggf. auf 0
* 0.09 07.02.97 - CDReadTOCA() sucht jetzt 1. AudioTrack heraus und errechnet die DiskID
* 08.02.97 - Argument singletrack aus CDPlayA() entfernt
* - CDNextA() und CDPrevA() erstellt
* 0.10 26.02.97 - FirstTrack usw. und TocEntry[0] wird gelöscht wenn keine Disk eingelegt
* 27.02.97 - LUN wird jetzt bei Fehler auch angezeigt
* - cdx_TrackLength hinzu
* 0.11 02.03.97 - Sensecodes in CDxRequest eingebaut
* - Bugfix (falscher Returncode) in CDUpdateA()
* 05.03.97 - cdx_SimpleStatus zwecks Kompatibilität zur cdplayLib dazu
* 0.12 08.03.97 - TrackNum in CDTOC Struktur eingefügt und kleine Änderungen in CDUpdateA()
* 11.03.97 - cdx_LUN und CDChangeDeviceA() dazu
* - CDEjectA() setzt jetzt JUSTCLOSED-Flag
* 0.13 23.03.97 - Datenrichtung von TestUnitCmd ist nicht mehr SCSIF_READ
* 25.03.97 - CDPlayA() funktioniert nun endlich mit NEC-Laufwerken
* - CDFastModeA() dazu
* - Eject jetzt mit Immediate-Bit
* 28.03.97 - CDSetVolumeA() ist endlich da :-)
* 0.14 29.03.97 - Lautstärkefunktion in CDVolumeA() umbenannt und cdx_Volume hinzu
* - cdx_SimpleStatus in cdx_Active umbenannt
* 0.15 15.06.97 - DoATAPI() eingebaut und kleine Veränderungen am ATAPI-Kram
* 0.16 09.07.97 - ATAPI-CDUpdateA() erweitert
* - "Diskwechselbug" in CDUpdateA entfernt der Enforcerhits provuzierte
* 13.07.97 - cd.device wird 2 mal geöffnet
* - Routinen etwas Geschwindigkeitsoptimiert
* 14.07.97 - ReadTOCA() arbeitet nun auch mit cd.device
* 15.07.97 - CDUpdateA(), CDStopA(), CDPlayA() und CDPauseA() fertig cd.deviciert
* 16.07.97 - CDJumpA() endlich auch ATAPI kompatibel
* - cdx_VendorID hinzugefügt
* 0.17 28.07.97 - CDLockA() setzt SPECIALF_LOCKED-Flag
* 29.07.97 - CDID sollte jetzt auch mit NEC-500 Laufwerken generiert werden können
* 30.07.97 - CDVolumeA(), CDNextA() und CDPrevA() jetzt ATAPI kompatibel
*///
;/// Includes
include 'exec/memory.i'
include 'devices/scsidisk.i'
include 'devices/cd.i'
include "CD-ROM.i"
;///
*////*---------------- CDOpenDeviceA() ----------------------------<c>-*/
*/
* struct CDxRequest *CDOpenDeviceA(register __a0 char *devicename, register __d0 ULONG unitnumber, register __d1 ULONG lun);
*
* Öffnet das übergebene SCSI-Device und gibt einen Zeiger auf eine
* ausgefüllte CDx-Struktur zurück. Konnte das Device nicht geöffnet werden,
* wird der Fehler angezeigt und die Funktion gibt NULL zurück.
* Achtung: Der Devicename wird nicht kopiert, und muß für CDChangeDeviceA()
* unbedingt erhalten bleiben!
*
CNOP 0,2
xdef _CDOpenDeviceA
_CDOpenDeviceA: movem.l d1-d7/a0-a6,-(sp)
move.l 4.w,a6 ; a6 = SysBase
move.l a0,a4 ; a4 = devicename
move.l d0,d2 ; d2 = unitnumber
move.l d1,d3 ; d3 = lun
moveq #0,d4
lea CDDevice(pc),a1 ; 'cd.device' öffnen?
.NextChar move.b (a0)+,d0
cmp.b (a1)+,d0
bne .GetCDxStruct ; nein: CDx holen usw.
tst.b d0
bne .NextChar
moveq #SPECIALF_ATAPI,d4
.GetCDxStruct move.l #cdx_SIZEOF+CDxTOC_SIZEOF+AUDIOPAGE_SIZEOF+15,d0 ; Speicher für CDxRequest, cdx_TOCData
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1 ; und cdx_ValidAudioPage
bsr _GetVecA
tst.l d0
beq .EXIT
move.l d0,a0
moveq #15,d5 ; Diese Ausrichtung der CDx-Struktur
add.l d5,d0 ; erhöht die Zugriffsgeschwindigkeit
not.l d5 ; auf 030+ Systemen, da nur ein Buszyklus
and.l d5,d0 ; für ein Langwortzugriff notwendig wird
move.l d0,a3 ; a3 = CDxRequest
move.l a0,cdx_MemStart(a3)
addi.l #cdx_SIZEOF,d0
move.l d0,cdx_TOCData(a3) ; alle Adressen eintragen
addi.l #CDxTOC_SIZEOF,d0
move.l d0,cdx_ValidAudioPage(a3)
.InitCDxStruct or.b d4,cdx_Flags(a3)
move.b d2,cdx_Unit(a3)
move.b d3,cdx_LUN(a3)
move.l a6,cdx_SysBase(a3)
move.l a4,cdx_DeviceName(a3)
btst.b #SPECIALB_ATAPI,cdx_Flags(a3)
beq .GetBufMem
move.l #CDTOC_SIZE*100+CDINFO_SIZE+QCODE_SIZE,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
bsr _GetVecA
move.l d0,cdx_SCSIDataStart(a3)
beq FreeCDxStruct
move.l d0,cdx_SCSIData(a3)
addi.l #CDTOC_SIZE*100,d0
move.l d0,cdx_Info(a3)
addi.l #CDINFO_SIZE,d0
move.l d0,cdx_QCode(a3)
bra .CreateIOPort
.GetBufMem move.l #DATA_LEN+SENSE_LEN+15,d0 ; 2 Puffer-Blöcke
move.l #MEMF_PUBLIC|MEMF_24BITDMA|MEMF_CLEAR,d1
bsr _GetVecA
move.l d0,cdx_SCSIDataStart(a3) ; auch dies hier soll die Geschwindigkeit
beq FreeCDxStruct
addi.l #15,d0 ; auf 030+ CPUs mit DMA-Kontrollern
and.l d5,d0 ; "greatly improven"
move.l d0,cdx_SCSIData(a3) ; Data-Block
addi.l #DATA_LEN,d0 ; Sense-Block errechnen
move.l d0,cdx_SCSISense(a3)
.CreateIOPort jsr _LVOCreateMsgPort(a6)
move.l d0,cdx_IOPort(a3)
bne .CreateIOReq
lea _ls,a0 ; auf den Stack schieben
move.l 4*MSG_NO_MSGPORT(a0),-(a7)
move.l 4*MSG_ERROR_TITLE(a0),-(a7)
bsr _ShowMsgA ; Error anzeigen
lea 8(a7),a7 ; Stack wieder runtersetzen
bra FreeBufMem
.CreateIOReq movea.l d0,a0
moveq #IOSTD_SIZE,d0
jsr _LVOCreateIORequest(a6)
move.l d0,cdx_IORequest(a3)
beq DeleteIOPort
move.l d0,a2 ; a2 = cdx_IORequest
.OpenDevice move.l d3,d0
mulu.w #10,d0
add.l d2,d0 ; d0 = unit + lun*10
moveq #0,d1 ; Flags
move.l a4,a0 ; devicename
move.l a2,a1 ; io_request
jsr _LVOOpenDevice(a6)
tst.l d0
beq .GetCmdStruct
move.l d3,-(a7) ; Argumente für ShowMsgA
move.l d2,-(a7)
move.l a4,-(a7)
lea _ls,a0 ; auf den Stack schieben
move.l 4*MSG_NO_SCSIDEVICE(a0),-(a7)
move.l 4*MSG_ERROR_TITLE(a0),-(a7)
bsr _ShowMsgA ; Error anzeigen
lea 20(a7),a7 ; Stack wieder runtersetzen
bra DeleteIOReq
.GetCmdStruct move.l #scsi_SIZEOF,d0
move.l #MEMF_PUBLIC|MEMF_CLEAR,d1 ; RAM für die SCSICmd-Struktur
bsr _GetVecA
move.l d0,cdx_Cmd(a3)
beq CloseDevice
btst.b #SPECIALB_ATAPI,cdx_Flags(a3)
beq .GoOn
.Create2ndPort jsr _LVOCreateMsgPort(a6)
move.l d0,cdx_CDPlayIOPort(a3)
bne .Create2ndIOReq
lea _ls,a0 ; auf den Stack schieben
move.l 4*MSG_NO_MSGPORT(a0),-(a7)
move.l 4*MSG_ERROR_TITLE(a0),-(a7)
bsr _ShowMsgA ; Error anzeigen
lea 8(a7),a7 ; Stack wieder runtersetzen
bra CloseCmdStruct
.Create2ndIOReq movea.l d0,a0
moveq #IOSTD_SIZE,d0
jsr _LVOCreateIORequest(a6)
move.l d0,cdx_CDPlayIORequest(a3)
beq Delete2ndPort
move.l d0,a2 ; a2 = cdx_IORequest
.Open2ndDevice move.l d3,d0
mulu.w #10,d0
add.l d2,d0 ; d0 = unit + lun*10
moveq #0,d1 ; Flags
move.l a4,a0 ; devicename
move.l a2,a1 ; io_request
jsr _LVOOpenDevice(a6)
tst.l d0
beq .GoOn
move.l d3,-(a7) ; Argumente für ShowMsgA
move.l d2,-(a7)
move.l a4,-(a7)
lea _ls,a0 ; auf den Stack schieben
move.l 4*MSG_NO_SCSIDEVICE(a0),-(a7)
move.l 4*MSG_ERROR_TITLE(a0),-(a7)
bsr _ShowMsgA ; Error anzeigen
lea 20(a7),a7 ; Stack wieder runtersetzen
bra Delete2ndIOReq
.GoOn move.l a3,a0
bsr _CDInitDeviceA ; CDx Rest ausfüllen
move.l a3,d0 ; Return CDxRequest
.EXIT movem.l (sp)+,d1-d7/a0-a6
rts
CDDevice: dc.b 'cd.device',0
*///
*////*---------------- CDInitDeviceA() ----------------------------<c>-*/
*/
* LONG CDInitDeviceA(register __a0 struct CDxRequest);
*
*
CNOP 0,2
xdef _CDInitDeviceA
_CDInitDeviceA: movem.l d1-d7/a0-a6,-(sp)
move.l a0,a3 ; a3 = cdx
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
beq .Start
move.b #5,cdx_DeviceType(a0)
bra .FillCDx
.Start move.l cdx_IORequest(a0),a1
move.w #HD_SCSICMD,IO_COMMAND(a1) ; IOStdRequest füllen
move.l cdx_Cmd(a0),IO_DATA(a1)
move.l #scsi_SIZEOF,IO_LENGTH(a1)
.DoInquiry moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDInquiry,a1
bsr CDDoSCSIA ; Inquiry schicken
bne .EXIT
move.l cdx_SCSIData(a3),a2
move.b (a2),d0
andi.l #%00011111,d0 ; nur Bits 0-4
move.b d0,cdx_DeviceType(a3) ; Peripheral Device Type
adda.l #8,a2 ; a2 = CDROM-VendorID
lea cdx_VendorID(a3),a0
move.l (a2),(a0)+ ; VendorID erstmal kopieren
move.l 4(a2),(a0)
lea Vendors(pc),a1 ; a1 = Vendor-Tabelle
.NextVendor tst.b (a1) ; keine weiteren IDs
beq .VendorUnknown ; in Tabelle
move.l a2,a0 ; a0 = CDROM-VendorID
.CmpLoop move.b (a1)+,d0 ; VendorID zuende?
beq .VendorKnown ; ja: beide identisch!
cmp.b (a0)+,d0 ; ansonsten weitervergleichen
beq .CmpLoop
moveq #1,d0
.SkipRest tst.b (a1)+ ; Rest der Tabelle
bne .SkipRest ; überspringen
dbra d0,.SkipRest
bra .NextVendor
.VendorUnknown lea UnknownVendor(pc),a0
move.l a0,cdx_Vendor(a3)
move.l (a2),(a0)+
move.l 4(a2),(a0)
bra .Check
.VendorKnown move.l a1,cdx_Vendor(a3)
.Check lea SpecialDevices(pc),a1 ; ist das benutzte LW in der
.NextDevice tst.b (a1) ; Liste der Geräte mit besonderen
beq .CopyRest ; Eigenschaften (Flags)?
move.l a2,a0
.CmpNextChar move.b (a1)+,d0
beq .FoundIt
cmp.b (a0)+,d0
beq .CmpNextChar
.SkipRest2 tst.b (a1)+
bne .SkipRest2
addq.l #1,a1
bra .NextDevice
.FoundIt move.b (a1),d0
or.b d0,cdx_Flags(a3) ; cdx_Flag dazusetzen (SPECIALF_)
.CopyRest adda.l #8,a2 ; nächte Bytes der Inquirydaten
lea cdx_Product(a3),a0 ; Product Identification
moveq #3,d0 ; 16 Bytes (4 Langworte)
.l1 move.l (a2)+,(a0)+ ; kopieren
dbra d0,.l1
lea cdx_Revision(a3),a0 ; Product Revision Level
move.l (a2)+,(a0) ; nur 4 Bytes groß
lea cdx_Specific(a3),a0 ; Vendor Specific
moveq #4,d0 ; 20 Bytes (4 Langworte)
.l2 move.l (a2)+,(a0)+ ; kopieren
dbra d0,.l2
.GetValidAPage move.l a3,a0
lea CMDModeSense(pc),a1 ; veränderbare Felder der AudioPage herausbekommen
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA ; Kommando ausführen
bne .FillCDx
move.l cdx_SCSIData(a3),a1
tst.b (a1) ; Mode Data Length = 0
beq .FillCDx
addq.l #3,a1 ; ans Ende des Mode Parameter Header springen
move.b (a1),d0 ; Block Descriptor Length
.sl addq.l #1,a1 ; Block Descriptor(s) überspringen
dbra d0,.sl
moveq #0,d0
move.b (a1)+,d0
andi.b #%00111111,d0 ; Page Code ohne Bit 6-7
cmp.b #$e,d0 ; wirklich Audio Control Page?
bne .FillCDx
addq.l #1,a1
moveq #AUDIOPAGE_SIZEOF-1,d0
move.l cdx_ValidAudioPage(a3),a0
.cl move.b (a1)+,(a0)+ ; Changeable Values der AudioPage kopieren
dbra d0,.cl
.FillCDx move.b #AUDIO_STAT_NO_DISK,cdx_AudioStatus(a3)
move.b #AUDIO_STAT_NO_DISK,cdx_Active(a3)
move.l a3,a0
bsr _CDUpdateA ; Rest der CDx-Struktur füllen
bsr _CDReadTOCA ; TOC einlesen
moveq #GET_VOLUME,d0
bsr _CDVolumeA
.EXIT movem.l (sp)+,d1-d7/a0-a6
rts
CMDInquiry: dc.b $12, 0, 0, 0, 96, 0
CMDModeSense: dc.b $1a, 8, $4e, 0, 254, 0
*///
*////*---------------- CDChangeDeviceA() --------------------------<c>-*/
*/
* BOOL CDChangeDeviceA(register __a0 struct CDxRequest, register __d0 ULONG unitnumber, register __d1 ULONG lun);
*
* Versucht das per CDOpenDeviceA() geöffnete Device unter einer anderen Unit
* oder LUN neu zu öffnen und schließt gegebenenfalls das alte. Konnte das
* neue Device geöffnet werden, oder sind Unit/LUN mit dem alten Device
* identisch, wird TRUE zurückgegeben, andernfalls FALSE.
*
CNOP 0,2
xdef _CDChangeDeviceA
_CDChangeDeviceA: movem.l d1-d3/a0-a3/a6,-(sp)
moveq #TRUE,d7 ; return-vorgabe
cmp.b cdx_Unit(a0),d0 ; Unit und LUN gleich?
bne .Begin
cmp.b cdx_LUN(a0),d1
beq .EXIT
.Begin move.l a0,a3 ; a3=cdx
moveq #FALSE,d7 ; return-vorgabe
btst.b #SPECIALB_ATAPI,cdx_Flags(a3) ; mit cd.device klappt das nicht
bne .EXIT
move.l d0,d2 ; d2 = unitnumber
move.l d1,d3 ; d3 = lun
.CreateNewReq move.l cdx_SysBase(a3),a6
movea.l cdx_IOPort(a3),a0
moveq #IOSTD_SIZE,d0
jsr _LVOCreateIORequest(a6) ; neuen IORequest für
tst.l d0 ; 'neues' Device...
beq .EXIT
move.l d0,a2 ; a2 = neuer IORequest
.OpenNewDevice move.l d3,d0
mulu.w #10,d0
add.l d2,d0 ; unit + lun*10
moveq #0,d1 ; Flags
move.l cdx_DeviceName(a3),a0 ; devicename
move.l a2,a1 ; neuer io_request
jsr _LVOOpenDevice(a6)
tst.l d0
beq .Ok ; 0 => erfolgreich
move.l a2,a0
jsr _LVODeleteIORequest(a6)
bra .EXIT
.Ok move.l cdx_IORequest(a3),a1 ; 'altes' Device schließen
jsr _LVOCloseDevice(a6)
move.l cdx_IORequest(a3),a0 ; alten IORequest löschen
jsr _LVODeleteIORequest(a6)
move.l a2,cdx_IORequest(a3) ; neuen IORequest eintragen
move.b d2,cdx_Unit(a3)
move.b d3,cdx_LUN(a3)
move.l a3,a0
bsr _CDInitDeviceA ; CDx neu ausfüllen/initialisieren
moveq #TRUE,d7
.EXIT move.l d7,d0
movem.l (sp)+,d1-d3/a0-a3/a6
rts
*///
*////*---------------- CDCloseDeviceA() ---------------------------<c>-*/
*
* BOOL CDCloseDeviceA(register __a0 struct CDxRequest);
*
* Schließt ein SCSI-Device, das mit CDOpenDeviceA() geöffnet wurde. Das
* Ergebnis ist dabei immer NULL.
*
CNOP 0,2
xdef _CDCloseDeviceA
_CDCloseDeviceA: movem.l d1-d7/a0-a6,-(sp)
move.l a0,a3 ; a3 = MyCDxReq
move.l cdx_SysBase(a3),a6
btst.b #SPECIALB_ATAPI,cdx_Flags(a3)
beq CloseCmdStruct
bsr _CDStopA ; muß leider sein, da kein laufender
; IORequest gefreed werden kann
Close2ndDevice move.l cdx_CDPlayIORequest(a3),a1
jsr _LVOCloseDevice(a6)
Delete2ndIOReq move.l cdx_CDPlayIORequest(a3),a0
jsr _LVODeleteIORequest(a6)
Delete2ndPort move.l cdx_CDPlayIOPort(a3),a0
jsr _LVODeleteMsgPort(a6)
CloseCmdStruct move.l cdx_Cmd(a3),a1
jsr _LVOFreeVec(a6)
CloseDevice move.l cdx_IORequest(a3),a1
jsr _LVOCloseDevice(a6)
DeleteIOReq move.l cdx_IORequest(a3),a0
jsr _LVODeleteIORequest(a6)
DeleteIOPort move.l cdx_IOPort(a3),a0
jsr _LVODeleteMsgPort(a6)
FreeBufMem move.l cdx_SCSIDataStart(a3),a1
jsr _LVOFreeVec(a6)
FreeCDxStruct move.l cdx_MemStart(a3),a1
jsr _LVOFreeVec(a6)
.EXIT moveq #NULL,d0
movem.l (sp)+,d1-d7/a0-a6
rts
*///
*////*---------------- CDDoSCSIA() --------------------------------<c>-*/
*
* LONG CDDoSCSIA(register __a0 struct CDxRequest *cdx, a1 APTR Command, d0 cmdlen. d1 flags);
*
* Führt das übergebene SCSI Direktkommando aus und gibt im Fehlerfall einen
* Wert zurück, der sich aus dem Sense Key (Bit 16-31), dem Additional Sense
* Code (Bit 8-15) und dem Additional Sense Code Qualifier (Bit 0-7)
* zusammensetzt. Ist keine CD eingelegt werden alle CD-abhängigen Daten auf
* 0 gesetzt. Die Conditioncodes werden in Abhängigkeit von d0 gesetzt.
*
CNOP 0,2
CDDoSCSIA: movem.l d1/a0-a2/a6,-(sp)
move.l cdx_SysBase(a0),a6 ; SysBase...
move.l cdx_Cmd(a0),a2 ; a2=SCSICmd
move.l cdx_SCSIData(a0),(a2)+ ; scsi_Data;
move.l #DATA_LEN,(a2)+ ; scsi_Length;
clr.l (a2)+ ; scsi_Actual;
move.l a1,(a2)+ ; scsi_Command;
move.w d0,(a2)+ ; scsi_CmdLength;
clr.w (a2)+ ; scsi_CmdActual;
move.b d1,(a2)+ ; scsi_Flags;
clr.b (a2)+ ; scsi_Status;
move.l cdx_SCSISense(a0),(a2)+ ; scsi_SenseData;
move.w #SENSE_LEN,(a2)+ ; scsi_SenseLength;
clr.w (a2) ; scsi_SenseActual;
move.l a0,a2 ; CDxRequest retten
move.l cdx_IORequest(a0),a1
jsr _LVODoIO(a6) ; Kommando schicken und warten
moveq #0,d0 ; Return = 0
move.l cdx_Cmd(a2),a1 ; a1=SCSICmd
tst.w scsi_SenseActual(a1) ; Sense Daten da?
beq .EXIT
move.l scsi_SenseData(a1),a1 ; a1=SenseData
move.b (a1),d1 ; Error Code ($70 oder $71)
andi.b #%01111111,d1 ; Valid-Bit auslassen
cmp.b #$70,d1 ; Current Error ($70) ?
bne .EXIT
move.b 2(a1),d0 ; d0=Sense Key
andi.b #%00001111,d0 ; nur 4 Bits
tst.b d0 ; NO SENSE ($0) ?
beq .EXIT
move.b d0,cdx_SenseKey(a2) ; in cdx schreiben (für ARexx)
swap.w d0 ; Returnwert berechnen
cmp.b #6,7(a1) ; ASC und ASCQ vorhanden?
blt .EXIT
move.w 12(a1),d0 ; ASC und ASCQ zu Returnwert
move.w d0,cdx_AddSenseCode(a2) ; in cdx schreiben
.EXIT movem.l (sp)+,d1/a0-a2/a6
tst.l d0 ; Conditioncodes setzen
rts
*///
*////*---------------- DoATAPI() ----------------------------------<n>-*/
*
* LONG DoATAPI(register __a0 struct IORequest *ioreq);
*
* Ergebnis ist io_Error.
*
CNOP 0,2
DoATAPI: movem.l d1/a0-a1/a6,-(sp)
move.l 4.w,a6
move.l a0,a1
jsr _LVODoIO(a6)
.EXIT movem.l (sp)+,d1/a0-a1/a6
tst.l d0
rts
*///
*////*---------------- CDUpdateA() --------------------------------<c>-*/
*
* LONG CDUpdateA(register __a0 struct CDxRequest *cdx);
*
* Aktualisiert den Track, Index, Adresssen und Audiostatus der übergebenen
* CDx-Struktur. Tritt ein Fehler auf, liefert die Funktion einen Wert in
* dem in CDDoSCSIA beschriebenem Format zurück. Wurde seit dem letztem
* Update eine CD eingelegt, wird der TOC neu eingelesen. Entspricht der
* aktuelle Audiostatus AUDIO_STAT_NO_DISK, AUDIO_STAT_NOT_VALID oder
* AUDIO_STAT_NONE, werden die Positionsfelder der CDx-Struktur auf 0 gesetzt.
*
CNOP 0,2
xdef _CDUpdateA
_CDUpdateA: movem.l d1-d3/a0-a2,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #10,d0 ; 10 Byte Kommando
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDReadSubCh(pc),a1
bsr CDDoSCSIA ; Kommando ausführen
beq .DiscChanged ; alles korrekt
cmp.l #$023A00,d0 ; NO MEDIA PRESENT ?
bne .EXIT ; unerwarteter Fehler
.NoCD move.b #AUDIO_STAT_NO_DISK,cdx_AudioStatus(a0)
move.b #AUDIO_STAT_NO_DISK,cdx_Active(a0)
move.l cdx_TOCData(a0),a1 ; keine CD eingelegt: alles
moveq #3,d1 ; CD spezifische löschen
.loop clr.l (a1)+ ; FirstTrack/LastTrack/FirstAudioTrack/reserved3/FirstAudioAddress
dbra d1,.loop ; und Entry[0] löschen
.Stopped clr.w (a0)+ ; cdx_CurrentTrack/CurrentIndex
moveq #4,d1
.loop2 clr.l (a0)+ ; cdx_CurrentAbsAddr/CurrentRelAddr/RelRemainBlocks/AbsRemainBlocks/TrackLength
dbra d1,.loop2
bra .EXIT
.SetSimpleStat move.b #AUDIO_STAT_STOPPED,cdx_Active(a0)
bra .Stopped
.DiscChanged cmp.b #AUDIO_STAT_NO_DISK,cdx_AudioStatus(a0) ; neue Disk eingelegt?
bne .UpdateCDx
bsr _CDReadTOCA ; ja: Table Of Contents neu einlesen
moveq #10,d0 ; Subchannel muß nochmal gelesen werden, da die SCSI-Daten
bsr CDDoSCSIA ; mit dem TOC überschrieben sind
bne .EXIT
.UpdateCDx move.l cdx_SCSIData(a0),a1
addq.l #1,a1
move.b (a1)+,d0 ; Audio Status lesen
move.b d0,cdx_AudioStatus(a0) ; und setzen
move.b d0,cdx_Active(a0)
beq .SetSimpleStat ; AUDIO_STAT_NOT_VALID (=0)
cmp.b #AUDIO_STAT_COMPLETED,d0
bcc .SetSimpleStat ; d0 >= AUDIO_STAT_COMPLETED (STOPPED/NONE)
; übrig bleibt PLAY und PAUSE: Positionen lesen
tst.w (a1) ; subchannel data length = 0 ?
beq .EXIT
addq.l #4,a1
move.l cdx_TOCData(a0),a2 ; TOC-Struktur sichern
move.b (a1),d0 ; d0=CurrentTrack
move.w (a1)+,(a0)+ ; cdx_CurrentTrack+CurrentIndex
move.l (a1)+,d2 ; d2=cdx_CurrentAbsAddr
move.l d2,(a0)+
move.l (a1),(a0)+ ; cdx_CurrentRelAddr
.calcrest addq.l #Entry,a2
move.l Address(a2),d1 ; Startaddresse der lead-out area
ext.w d0
mulu.w #CDTOCEntry_SIZEOF,d0
adda.l d0,a2
move.l Address(a2),d0 ; d0=Entry[CurTrack].Address
addq.l #CDTOCEntry_SIZEOF,a2 ; nachfolgender Track
move.l Address(a2),d3 ; d3=Entry[CurTrack+1].Address
move.l d3,a1
sub.l d0,d3 ; d3 = d3-d0
move.l a1,d0
sub.l d2,d0
move.l d0,(a0)+ ; cdx_RelRemainBlocks
sub.l d2,d1
move.l d1,(a0)+ ; cdx_AbsRemainBlocks
move.l d3,(a0) ; cdx_TrackLength
moveq #0,d0 ; alles okay: RETURN_OK
.EXIT movem.l (sp)+,d1-d3/a0-a2
rts
.ATAPI bsr _CDTestUnitA
tst.l d0
bne .NoCD
move.l a0,a2 ; a2 = cdx
cmp.b #AUDIO_STAT_NO_DISK,cdx_AudioStatus(a2) ; neue Disk eingelegt?
bne .goon
bsr _CDReadTOCA ; ja: Table Of Contents neu einlesen
.goon move.l cdx_IORequest(a2),a0 ; a0 = IORequest
move.w #CD_INFO,IO_COMMAND(a0)
move.l cdx_Info(a2),a1 ; a1 = CDInfo
move.l a1,IO_DATA(a0)
move.l #CDINFO_SIZE,IO_LENGTH(a0)
bsr DoATAPI
bne .EXIT ; Fehler?
.ok btst.w #CDSTSB_PLAYING,CDINFO_Status(a1)
beq .stp
move.b #AUDIO_STAT_PLAYING,cdx_AudioStatus(a2)
move.b #AUDIO_STAT_PLAYING,cdx_Active(a2)
move.w #CD_QCODELSN,IO_COMMAND(a0)
move.l cdx_QCode(a2),a1 ; a1 = QCode
move.l a1,IO_DATA(a0)
clr.l IO_LENGTH(a0)
bsr DoATAPI ; Wenn die CD gestoppt ist, gibt CDQCODELSN
bne .stp ; einen Fehlercode zurück und die Werte
; müssen von Hand auf 0 gesetzt werden
move.l cdx_TOCData(a2),a0
move.w QCODE_Track(a1),(a2)+ ; cdx_CurrentTrack+CurrentIndex
move.l QCODE_DiskPosition(a1),d2
move.l d2,(a2)+ ; d2=cdx_CurrentAbsAddr
move.l QCODE_TrackPosition(a1),(a2)+ ; cdx_CurrentRelAddr
move.b QCODE_Track(a1),d0 ; d0=CurrentTrack
exg.l a0,a2 ; a2=TOCData, a0=*cdx_RelRemainBlocks
bra .calcrest
.stp move.b #AUDIO_STAT_STOPPED,cdx_AudioStatus(a2)
move.b #AUDIO_STAT_STOPPED,cdx_Active(a2)
clr.w (a2)+
clr.l (a2)+
clr.l (a2)+
moveq #0,d0
bra .EXIT
CMDReadSubCh: dc.b $42, 0, $40, 1, 0, 0, 0, 0, 16, 0
*///
*////*---------------- CDReadTOCA() -------------------------------<c>-*/
*
* LONG CDReadTOCA(register __a0 struct CDxRequest *cdx);
*
CNOP 0,2
xdef _CDReadTOCA
_CDReadTOCA: movem.l d1-d3/a0-a3/a6,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #10,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDReadTOC(pc),a1
bsr CDDoSCSIA
bne .EXIT
move.l cdx_SCSIData(a0),a1
move.w (a1)+,d0 ; TOC Data Length
beq .EXIT
move.l cdx_SysBase(a0),a6 ; für später...
move.l cdx_TOCData(a0),a0 ; da soll alles hin
move.w (a1),(a0)+ ; First und Last Track
move.b (a1)+,d1 ; FirstTrack
moveq #0,d3
move.b (a1)+,d3 ; LastTrack
sub.b d1,d3
addq.b #1,d3 ; d3=Track Anzahl
move.l a0,a3 ; für später
clr.w (a0)+ ; wird nachher gefüllt...
clr.l (a0)+ ; (TrackNum/FirstAudioTrack/FirstAudioAddress)
move.l a0,a2 ; Track 0 gibt's nicht, da kommt
clr.l (a0)+ ; nacher die logical block
clr.l (a0)+ ; address der lead-out area rein
clr.l 16(a0) ; Entry für Track 3 sicherheitshalber löschen
clr.l 20(a0) ; (für ID Berechnung :-)
lsr.l #3,d0 ; durch 8 (pro Entry 8 bytes)
; die 2 bytes für F. und L. Track fallen raus
subq.l #1,d0 ; dbra endet bei -1
bmi .Good ; jetzt schon -1?
moveq #-1,d2 ; noch keinen AudioTrack gefunden...
.loop move.l (a1)+,d1
move.l d1,(a0)+ ; ersten 4 bytes (8 bytes / Entry) kopieren
tst.b d2 ; schon AudioTrack gefunden?
beq .loopend
btst.l #18,d1 ; AudioTrack?
bne .loopend
move.b d3,(a3)+ ; TrackNum
lsr.w #8,d1
move.b d1,(a3)+ ; FirstAudioTrack
move.l (a1),-4(a2) ; FirstAudioAddress
moveq #0,d2
.loopend move.l (a1)+,(a0)+ ; letzten 4 Bytes kopieren
dbra d0,.loop
.LeadOut subq.l #8,a1 ; letzten Entry nochmal holen
cmp.b #$AA,2(a1) ; wirklich lead out area? (Tracknr. $AA)
beq .IsLeadOut
cmp.b #$A2,2(a1) ; für NEC-500 u.ä. Laufwerke (Tracknr. $A2)
bne .Good
.IsLeadOut move.l (a1)+,(a2)+ ; ja: nochmal nach Entry[0] kopieren
move.l (a1),(a2)
.CalcID lea IDFormat(pc),a0
move.l (a2),-(a7) ; Entry[0].Address
move.l 24(a2),-(a7) ; Entry[3].Address
move.l d3,-(a7) ; LastTrack-FirstTrack+1
move.l a7,a1
lea CDID-(Entry+4)(a2),a3
lea PutChProc(pc),a2
jsr _LVORawDoFmt(a6) ; ID formatieren
lea 12(a7),a7
.Good moveq #0,d0
.EXIT movem.l (sp)+,d1-d3/a0-a3/a6
rts
.ATAPI move.l a0,a2 ; a2 = CDx
move.l cdx_IORequest(a2),a0 ; a0 = IORequest
move.w #CD_TOCLSN,IO_COMMAND(a0)
move.l cdx_SCSIData(a2),IO_DATA(a0)
move.l #100,IO_LENGTH(a0)
clr.l IO_OFFSET(a0)
bsr DoATAPI
beq .Ok
move.l #$00090000,d0 ; Vendor specific Error
bra .EXIT
.Ok move.l cdx_SysBase(a2),a6
move.l cdx_SCSIData(a2),a1
move.l cdx_TOCData(a2),a0
move.w (a1),(a0)+ ; First- und LastTrack
moveq #0,d1
move.b (a1)+,d1 ; FirstTrack
moveq #0,d3
move.b (a1)+,d3 ; LastTrack
sub.b d1,d3
addq.b #1,d3 ; d3=Track Anzahl
move.b d3,(a0)+
move.l a0,a3 ; für später
clr.b (a0)+ ; FirstAudioTrack
clr.l (a0)+ ; FirstAudioAddress
clr.w (a0)+ ; Entry[0].reserved1/CtlAdr
move.w #$AA00,(a0)+ ; Entry[0].Track/reserved2
move.l a0,a2
move.l (a1)+,(a0)+ ; Entry[0].Address (LeadOut)
move.l d3,d0
subq.l #1,d0
moveq #-1,d2 ; noch keinen AudioTrack gefunden
.aloop move.b (a1)+,d1 ; CtlAdr
move.w d1,(a0)+ ; Entry->reserved1/CtlAdr
tst.b d2 ; ersten Audiotrack schon gefunden?
beq .aloopend ; ja -->
btst #2,d1 ; ist Track ein Audiotrack?
bne .aloopend ; nein -->
move.b (a1),(a3)+ ; FirstAudioTrack
move.l 1(a1),(a3) ; FirstAudioAddress
moveq #0,d2 ; ersten Audiotrack gefunden
.aloopend move.b (a1)+,(a0)+ ; Entry->Track
clr.b (a0)+ ; Entry->reserved2
move.l (a1)+,(a0)+ ; Entry->Address
dbra d0,.aloop
clr.w (a0)+ ; Entry[TrackNum+1].reserved1/CtlAdr
move.w #$AA00,(a0)+ ; Entry[TrackNum+1].Track/reserved2
move.l (a2),(a0) ; Entry[TrackNum+1].Address (LeadOut)
bra .CalcID
CMDReadTOC: dc.b $43, 0, 0, 0, 0, 0, 0, $3, $24, 0
IDFormat: dc.b '%02ld%06lx%06lx',0
*///
*////*---------------- CDTestUnitA() ------------------------------<c>-*/
*
* LONG CDTestUnitA(register __a0 struct CDxRequest *cdx);
*
* Testet die logical unit ob sie bereit ist. Wenn sie das ist, wird GOOD (0)
* zurückgegeben, ansonsten ein Returncode im in CDDoSCSIA beschriebenem
* Format.
*
CNOP 0,2
xdef _CDTestUnitA
_CDTestUnitA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #6,d0 ; 6 Byte Kommando
moveq #SCSIF_AUTOSENSE,d1 ; REQUEST SENSE ausführen lassen
lea CMDReadSubCh(pc),a1
bsr CDDoSCSIA ; Kommando ausführen
.EXIT movem.l (sp)+,d1/a0-a1
rts
.ATAPI move.l cdx_IORequest(a0),a0
move.w #CD_CHANGESTATE,IO_COMMAND(a0)
bsr DoATAPI
beq .Ok
move.l #$00090000,d0 ; Vendor specific Error
bra .EXIT
.Ok move.l IO_ACTUAL(a0),d0 ; gültige CD eingelegt?
beq .EXIT ; ja: return(0)
move.l #$0023A00,d0 ; MEDIUM NOT PRESENT
bra .EXIT
CMDTestUnitReady: dc.b $0, 0, 0, 0, 0, 0
*///
*////*---------------- CDEjectA() ---------------------------------<c>-*/
*
* LONG CDEjectA(register __a0 struct CDxRequest *cdx, register __d0 BOOL really);
*
* TRUE öffnet die Schublade, FALSE schließt sie. Im Fehlerfall (Schublade
* schon offen/geschlossen) wird ein Fehlercode zurückgegeben. Außerdem
* wird das Flag JUSTCLOSED gesetzt, wenn die Schublade geschlossen werden
* soll, sonst wird es gelöscht.
*
CNOP 0,2
xdef _CDEjectA
_CDEjectA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
lea CMDStartStopUnit(pc),a1
.eject moveq #2,d1
and.b #~SPECIALF_JUSTCLOSED,cdx_Flags(a0)
tst.l d0
bne .goon
.load moveq #3,d1
or.b #SPECIALF_JUSTCLOSED,cdx_Flags(a0)
.goon move.b d1,4(a1)
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1/a0-a1
rts
.ATAPI and.b #~SPECIALF_JUSTCLOSED,cdx_Flags(a0)
moveq #1,d1
tst.l d0
bne .goon2
or.b #SPECIALF_JUSTCLOSED,cdx_Flags(a0)
moveq #0,d1
.goon2 move.l cdx_IORequest(a0),a0
lea IO_ACTUAL(a0),a1
clr.l (a1)+ ; IO_ACTUAL
move.l d1,(a1)+ ; IO_LENGTH
clr.l (a1)+ ; IO_DATA
clr.l (a1) ; IO_OFFSET
move.w #CD_EJECT,IO_COMMAND(a0)
bsr DoATAPI
move.l IO_ACTUAL(a0),d0
bra .EXIT
CMDStartStopUnit: dc.b $1B, 1, 0, 0, 2, 0
*///
*////*---------------- CDLockA() ----------------------------------<c>-*/
*
* LONG CDLockA(register __a0 struct CDxRequest *cdx, register __d0 BOOL really);
*
* TRUE verbietet das Öffnen der Schublade am Gerät. In diesem Falle wird
* das Flag SPECIALF_LOCKED gesetzt.
*
CNOP 0,2
xdef _CDLockA
_CDLockA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .EXIT
lea CMDPreventAllow(pc),a1
.prevent moveq #1,d1
or.b #SPECIALF_LOCKED,cdx_Flags(a0)
tst.l d0
bne .goon
.allow moveq #0,d1
and.b #~SPECIALF_LOCKED,cdx_Flags(a0)
.goon move.b d1,4(a1)
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1/a0-a1
rts
CMDPreventAllow: dc.b $1e, 0, 0, 0, 0, 0
*///
*////*---------------- CDPlayA() ----------------------------------<c>-*/
*
* LONG CDPlayA(register __a0 struct CDxRequest *cdx, register __d0 UBYTE starttrack, register __d1 UBYTE startindex);
*
CNOP 0,2
xdef _CDPlayA
_CDPlayA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .Playerjump
lea CMDPlayTI(pc),a1
move.b #99,8(a1)
btst.b #SPECIALB_NEC,cdx_Flags(a0) ; NEC Laufwerk vorhanden?
beq .PlayNormal ; Flag ist nicht gesetzt
clr.b 8(a1) ; NEC braucht End-Index 0
.PlayNormal move.b d0,4(a1) ; Track
move.b d1,5(a1) ; Index
moveq #10,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA
bra .EXIT
.Playerjump move.l cdx_TOCData(a0),a1
cmp.b FirstTrack(a1),d0 ; Liegt Track im
bcs .error ; gültigen Bereich
cmp.b LastTrack(a1),d0
bhi .error
addq.l #Entry,a1
ext.w d0
mulu.w #CDTOCEntry_SIZEOF,d0
adda.l d0,a1
move.l Address(a1),d0 ; d0=Entry[Track].Address
moveq #JUMPMODE_PLAY_ABS,d1
bsr _CDJumpA ; Audio Play 12
bra .EXIT
.error move.l #$052400,d0 ; "ILLEGAL REQUEST: INVALID FIELD IN CDB" setzen
.EXIT movem.l (sp)+,d1/a0-a1
rts
CMDPlayTI: dc.b $48, 0, 0, 0, 0, 0, 0, 99, 99, 0
*///
*////*---------------- CDPauseA() ---------------------------------<c>-*/
*
* LONG CDPauseA(register __a0 struct CDxRequest *cdx, register __d0 BOOL really);
*
* TRUE läßt das Laufwerk anhalten, während FALSE den Pause-Modus wieder
* aufhebt.
*
CNOP 0,2
xdef _CDPauseA
_CDPauseA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
lea CMDPauseResume(pc),a1
.pause moveq #0,d1
tst.l d0
bne .goon
.resume moveq #1,d1
.goon move.b d1,8(a1)
moveq #10,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1/a0-a1
rts
.ATAPI moveq #1,d1
tst.l d0
bne .start
moveq #0,d1
.start move.l cdx_IORequest(a0),a0
move.w #CD_PAUSE,IO_COMMAND(a0)
clr.l IO_DATA(a0)
move.l d1,IO_LENGTH(a0)
clr.l IO_OFFSET(a0)
bsr DoATAPI
bra .EXIT
CMDPauseResume: dc.b $4b, 0, 0, 0, 0, 0, 0, 0, 0, 0
*///
*////*---------------- CDStopA() ----------------------------------<c>-*/
*
* LONG CDStopA(register __a0 struct CDxRequest *cdx);
*
CNOP 0,2
xdef _CDStopA
_CDStopA: movem.l d1/a0-a2/a6,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDStartStopUnit2(pc),a1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1/a0-a2/a6
rts
.ATAPI move.l cdx_SysBase(a0),a6
move.l cdx_CDPlayIORequest(a0),a2
move.l a2,a1
jsr _LVOCheckIO(a6)
tst.l d0
bne .ok
move.l a2,a0
jsr _LVOAbortIO(a6)
move.l a2,a1
jsr _LVOWaitIO(a6)
.ok moveq #0,d0
bra .EXIT
CMDStartStopUnit2: dc.b $1B, 0, 0, 0, 0, 0
*///
*////*---------------- CDPrevA() ----------------------------------<c>-*/
*
* LONG CDPrevA(register __a0 struct CDxRequest *cdx);
*
CNOP 0,2
xdef _CDPrevA
_CDPrevA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #10,d0 ; 10 Byte Kommando
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDReadSubCh(pc),a1
bsr CDDoSCSIA ; Kommando ausführen
bne .EXIT
move.l cdx_SCSIData(a0),a1
move.b 6(a1),d0 ; Current Track
.Start subq.b #1,d0
moveq #1,d1 ; Index
bsr _CDPlayA
.EXIT movem.l (sp)+,d1/a0-a1
rts
.ATAPI bsr _CDUpdateA
move.b cdx_CurrentTrack(a0),d0
bra .Start
*///
*////*---------------- CDNextA() ----------------------------------<c>-*/
*
* LONG CDNextA(register __a0 struct CDxRequest *cdx);
*
CNOP 0,2
xdef _CDNextA
_CDNextA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
moveq #10,d0 ; 10 Byte Kommando
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDReadSubCh(pc),a1
bsr CDDoSCSIA ; Kommando ausführen
bne .EXIT
move.l cdx_SCSIData(a0),a1
move.b 6(a1),d0 ; Current Track
.Start addq.b #1,d0
moveq #1,d1 ; Index
bsr _CDPlayA
.EXIT movem.l (sp)+,d1/a0-a1
rts
.ATAPI bsr _CDUpdateA
move.b cdx_CurrentTrack(a0),d0
bra .Start
*///
*////*---------------- CDJumpA() ----------------------------------<c>-*/
*
* LONG CDJumpA(register __a0 struct CDxRequest *cdx, register __d0 LONG address, register __d1 BYTE jumpmode);
*
CNOP 0,2
xdef _CDJumpA
_CDJumpA: movem.l d1-d3/a0-a2/a6,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
move.b d1,d3 ; d3 = JumpMode
btst.b #0,d3 ; relativ?
beq .absolute
.relative move.l d0,d2 ; offset retten
moveq #10,d0 ; 10 Byte Kommando
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
lea CMDReadSubCh(pc),a1
bsr CDDoSCSIA ; Kommando ausführen
bne .EXIT
move.l cdx_SCSIData(a0),a1
move.l 8(a1),d0 ; d0=current logical block addr.
add.l d2,d0 ; neue Adresse berechnen
.absolute btst.b #1,d3 ; play?
beq .seek
.play lea CMDPlay12(pc),a1 ; Play(12) Command
moveq #12,d1
bra .start
.seek lea CMDSeek10(pc),a1 ; Seek(10) Command
moveq #10,d1
.start move.l d0,2(a1)
move.l d1,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1-d3/a0-a2/a6
rts
.ATAPI move.l d0,d2 ; d2 = address
move.l d1,d3 ; d3 = Jumpmode
move.l a0,a2 ; a2 = cdx
move.l cdx_SysBase(a2),a6
move.l cdx_CDPlayIORequest(a2),a1
jsr _LVOCheckIO(a6)
tst.l d0 ; läuft noch der Play IORequest
bne .goon
bsr _CDStopA ; ja: abbrechen
.goon btst.b #0,d3 ; relativ?
beq .aabsolute
move.l cdx_IORequest(a2),a0
move.w #CD_QCODELSN,IO_COMMAND(a0)
move.l cdx_QCode(a2),a1 ; a1 = QCode
move.l a1,IO_DATA(a0)
clr.l IO_LENGTH(a0)
bsr DoATAPI ; aktuelle Position bestimmen
bne .aabsolute
move.l QCODE_DiskPosition(a1),d0
add.l d0,d2 ; neue Adresse berechnen
.aabsolute btst.b #1,d3 ; play?
beq .aseek
.aplay move.l cdx_CDPlayIORequest(a2),a1
move.w #CD_PLAYLSN,IO_COMMAND(a1)
clr.l IO_DATA(a1)
move.l cdx_TOCData(a2),a0
move.l Entry+Address(a0),d0 ; Adresse der LeadOut-Area (Ende)
sub.l d2,d0 ; Länge=Ende-Start
move.l d0,IO_LENGTH(a1)
move.l d2,IO_OFFSET(a1)
jsr _LVOSendIO(a6)
move.b #AUDIO_STAT_PLAYING,cdx_Active(a2)
move.b #AUDIO_STAT_PLAYING,cdx_AudioStatus(a2)
moveq #0,d0
bra .EXIT
.aseek move.l cdx_IORequest(a2),a0
move.w #CD_SEEK,IO_COMMAND(a0)
move.l d2,IO_OFFSET(a0)
bsr DoATAPI
bra .EXIT
CMDPlay12: dc.b $A5, 0, 0,0,0,0, 0,$4,$20,$00, 0, 0
CMDSeek10: dc.b $2B, 0, 0,0,0,0, 0, 0, 0, 0
*///
*////*---------------- CDFastModeA() ------------------------------< >-*/
*
* LONG CDFastModeA(register __a0 struct CDxRequest *cdx, register __d0 UBYTE mode, register __d1 UBYTE vendor);
*
CNOP 0,2
xdef _CDFastModeA
_CDFastModeA: movem.l d1/a0-a1,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .EXIT
tst.b d0
bne .FAST
moveq #0,d0
moveq #JUMPMODE_PLAY_REL,d1
bsr _CDJumpA
bra .EXIT
.FAST tst.b d1
bne .SONY
lea CMDStartFP(pc),a1
move.b #$3,1(a1)
cmp.b #FASTMODE_FORWARD,d0
bne .goon
move.b #$2,1(a1)
.goon moveq #10,d0
moveq #SCSIF_AUTOSENSE,d1
bsr CDDoSCSIA
bra .EXIT
.SONY lea CMDSonyStartFP(pc),a1
move.b #$11,1(a1)
cmp.b #FASTMODE_FORWARD,d0
bne .goon2
move.b #$1,1(a1)
.goon2 moveq #12,d0
moveq #SCSIF_AUTOSENSE,d1
bsr CDDoSCSIA
.EXIT movem.l (sp)+,d1/a0-a1
rts
CMDStartFP: dc.b $CA, 2, 0, 0, 0, 0, 0, 0, 0, $C0
CMDSonyStartFP: dc.b $DC, 1, 0,0,2,0, 0,0,0,0, 0, $40
*///
*////*---------------- CDVolumeA() --------------------------------<c>-*/
*
* LONG CDVolumeA(register __a0 struct CDxRequest *cdx, register __d0 UBYTE mode);
*
CNOP 0,2
xdef _CDVolumeA
_CDVolumeA: movem.l d1-d3/a0-a3,-(sp)
btst.b #SPECIALB_ATAPI,cdx_Flags(a0)
bne .ATAPI
move.b d0,d2 ; SET/GET-Flag sichern
lea CMDModeSense2(pc),a1
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_READ,d1
bsr CDDoSCSIA ; aktuelle Audio Page auslesen
bne .EXIT ; erfolgreich?
move.l cdx_SCSIData(a0),a1
tst.b (a1) ; Mode Data Length = 0
beq .EXIT ; ja: Ende
addq.l #3,a1
move.b (a1),d0 ; Block Descriptor Length
.sl addq.l #1,a1 ; Block Descriptor(s) überspringen
dbra d0,.sl
moveq #0,d0
move.b (a1)+,d0
andi.b #%00111111,d0 ; Page Code ohne Bit 6-7
cmp.b #$e,d0 ; wirklich Audio Control Page? (Eh)
bne .EXIT
addq.l #1,a1
lea cdx_Volume0(a0),a2
tst.b d2 ; Lautstärke lesen oder setzen?
bne .SetVolume
.GetVolume move.b 7(a1),(a2)+ ; Lautstärke in CDx eintragen
move.b 9(a1),(a2)+
move.b 11(a1),(a2)+
move.b 13(a1),(a2)
moveq #0,d0 ; alles glatt verlaufen
bra .EXIT
.SetVolume move.b (a2)+,7(a1) ; CDx-Werte in Audio Page eintragen
move.b (a2)+,9(a1)
move.b (a2)+,11(a1)
move.b (a2)+,13(a1)
moveq #AUDIOPAGE_SIZEOF-1,d0
lea AudioPage(pc),a2
move.l cdx_ValidAudioPage(a0),a3
.cl move.b (a1)+,(a2) ; Page durch "Changeable Fields
move.b (a3)+,d1 ; Maske" kopieren
and.b d1,(a2)+
dbra d0,.cl
move.l cdx_SCSIData(a0),a1
lea Header(pc),a2
moveq #6+AUDIOPAGE_SIZEOF,d0
.huil move.b (a2)+,(a1)+ ; fertige Page (plus Header) in SCSI-Datenpuffer kopieren
dbra d0,.huil
lea CMDModeSelect(pc),a1
moveq #6,d0
moveq #SCSIF_AUTOSENSE|SCSIF_WRITE,d1
bsr CDDoSCSIA ; Mode Select: Audiopage setzen
.EXIT movem.l (sp)+,d1-d3/a0-a3
rts
.ATAPI moveq #-1,d1 ; Lautstärke nur auslesen
tst.l d0
beq .GET ; SET/GET?
.SET moveq #0,d1
move.b cdx_Volume0(a0),d1
mulu.w #$7fff,d1 ; volle Lautstärke = 0x7fff
divu.w #255,d1 ; Verhältnisgleichung...
ext.l d1
.GET move.l a0,a1 ; a1 = cdx
move.l cdx_IORequest(a1),a0 ; a0 = IORequest
move.w #CD_ATTENUATE,IO_COMMAND(a0)
clr.l IO_DATA(a0) ; NULL
clr.l IO_LENGTH(a0) ; Änderung sofort vornehmen
move.l d1,IO_OFFSET(a0)
bsr DoATAPI
move.l IO_ACTUAL(a0),d1 ; aktuelle Lautstärke
mulu.w #255,d1 ; umrechnen
divu.w #$7fff,d1
move.b d1,cdx_Volume0(a1) ; und eintragen
move.b d1,cdx_Volume1(a1)
bra .EXIT
CMDModeSense2: dc.b $1a, 8, $e, 0, 254, 0
CMDModeSelect: dc.b $15, 16, 0, 0, 20, 0
*///
;/// Sonstiges
Header: dc.b 0, 0, 0, 0 ; Mode Data Length, Medium Type, Device-Specific Parameter, Block Descriptor Length
dc.b $e, $e ; Page Code (0Eh), Parameter Length (0Eh)
AudioPage: dcb.b AUDIOPAGE_SIZEOF
UnknownVendor: dcb.b 9
Vendors:
dc.b "APPLE" ,0, "Apple Computer, Inc.",0
dc.b "CONNER" ,0, "Conner Peripherals",0
dc.b "DENON" ,0, "Denon/Nippon Columbia",0
dc.b "FUJI" ,0, "Fuji Electric Co., Ltd. (Japan)",0
dc.b "FUJITSU" ,0, "Fujitsu",0
dc.b "JVC" ,0, "JVC Information Products Co.",0
dc.b "MATSHITA" ,0, "Matsushita",0
dc.b "MAXTOR" ,0, "Maxtor Corp.",0
dc.b "MELA" ,0, "Mitsubishi Electronics America",0
dc.b "MELCO" ,0, "Mitsubishi Electric (Japan)",0
dc.b "MICROP" ,0, "Micropolis",0
dc.b "NEC" ,0, "NEC",0
dc.b "OSI" ,0, "Optical Storage International",0
dc.b "QUANTUM" ,0, "Quantum Corp.",0
dc.b "SANYO" ,0, "SANYO Electric Co., Ltd.",0
dc.b "SEAGATE" ,0, "Seagate",0
dc.b "SONY" ,0, "Sony Corporation Japan",0
dc.b "TEAC" ,0, "TEAC Japan",0
dc.b "TOSHIBA" ,0, "Toshiba Japan",0
dc.b "WDIGTL" ,0, "Western Digital",0
dc.b 0
SpecialDevices:
dc.b 'NEC ' , 0, SPECIALF_NEC
dc.b 0
;///