Ch 20 光碟機 (1)

光碟機在 1990 年代中期就已經成為電腦的標準配備,但是卻很少有人提及有關光碟的程式製作,我想原因不外兩個,文件取得不易及過於複雜,小木偶參考松崗公司所出版林祚儀編著的 『CD-ROM、聲霸卡、資訊安全等函數庫設計』一書及第三波第 142、143 期趙文志所寫的『DOS 下的 CD-AUDIO 播音程式』一文以及中山美麗之島精華區光碟驅動原始說明文件等文獻,發現幾乎以 C 語言撰寫這些程式,故小木偶想以這一章以及下一章等兩章的篇幅簡單介紹如何以組合語言播放音樂光碟及控制光碟機。

在 MS DOS 的環境堙A要使用光碟必須在 CONFIG.SYS 檔案中加入光碟的驅動程式,這個驅動程式通常是由廠商提供,故名稱不太相同,您必須看看廠商的使用說明書,不過因為光碟機已經相當普遍了,所以各廠商的驅動程式幾乎都能相通,小木偶在 CONFIG.SYS 堛漪O:

DEVICE=C:\AOATAPI.SYS /D:IDECD00 /P:170,15

除了在 CONFIG.SYS 堶n有驅動程式外,在 AUTOEXEC.BAT 還要有 Microsoft 所提供的程式辨認:

C:\DOS\MSCDEX /D:IDECD00 /L:M

要注意的是,這兩個程式的參數『/D:』後面接的文字必須相同,『/L:』後面接的是光碟機的編號,如果成功,那在 DOS 底下的光碟機標號就是『M:』(就好像軟碟機是 A: 一樣)。

在組合語言中使用光碟,要呼叫 INT 2FH 中斷。INT 2FH 也是屬於 DOS 服務程式,但它是由驅動程式所提供的,像網路、光碟機。因為 INT 2FH 提供許多種設備的服務程式,因此使用上較為複雜,底下僅就光碟機的部份說明。

AX=1500H/INT 2FH 光碟安裝檢查

當要使用光碟機時,第一步就是要檢查光碟機是否存在,常用的檢查方式就是用 INT 2FH 中斷。如同 INT 21H 一樣, INT 2FH 中斷也把不同的功能放入 AH 暫存器中,如有更細分的『子』功能就放入 AL 中。在此檢查光碟機用

mov     ax,1500h
mov     bx,0000
int     2fh

返回時,如果有安裝好光碟機則 BX 會存有光碟機數 (不管您的光碟機是 IDE 界面或 SCSI 界面,此處 BX 是光碟機總數),而 CX 會存有第一台光碟機的編號,如果第一台光碟機是 A: 則 CX 為零;如果第一台光碟機是 B: 則 CX 為一,依此類推。如果您沒裝光碟機,則 BX 等於零。

CMD=0C/0/5 AX=1510H/INT 2FH 將光碟機托盤打開或關上

先說把光碟機的托盤打開。要把光碟機的托盤打開,必須先設定一個稱為 device driver request header (驅動裝置請求表頭) 的結構體。這個結構體的欄位如下:

位址 長度 意義
00BYTE 結構體長度,以位元組為單位
01BYTE subunit,設為 0 即可
02BYTE 命令碼,參考此處
03WORD 由 INT 2FH 返回時的狀態,參考此處
05DWORD 保留,均設為 0
09DWORD 保留,均設為 0

這個 device driver request header 會隨著呼叫功能而有所小幅度變動,但是上面這 13 個位元組所代表的意義是不會變動的。

開啟光碟托盤,相當於電腦主機板對光碟機輸出控制命令,也可以看成將控制命令的資料傳送給光碟機。參考註一得知命令碼為 0CH,意思是 IOCTL OUTPUT。好了,當光碟機收到這個 device driver request header 之後,由命令碼,0CH,知道要接收由主機板來指令了,而這些指令是什麼呢?原來這個 device driver request header 還有下半部,這下半部常會隨功能不同,而有所變動。開啟光碟機托盤下半部格式如下:

位址 長度 意義
0DBYTE 以前稱媒體描述子 (media descriptor),但已改稱位址
模式 (address mode),此處設為 0 即可
0EDWORD 傳送位址,區段位址及偏移位址
12WORD 呼叫時,為傳送位元組數
返回時,為實際傳送位元組數

在 device driver request header 結構體的 0EH 開始的兩字組所指的位址處有要光碟機執行的命令資料,而要傳送的資料可以有許多種,參考註三表格得知為 0 就是使光碟機托盤開啟,而且只有一個位元組,所以使 device driver request header 的第 12H 開始的字組為 1,表示命令長度只有一個位元組。此外還得找一塊記憶體,其長度為 1 個位元組,且該記憶體數值為 0 (事實上 IOCTL OUTPUT 有許多命令資料,請參考註三)。最後計算 device driver request header 總長度為 13H,放入此結構體的第零個位元組。

把 device driver request header 都設好之後,再來使 ES:BX 指向 device driver request header 結構體,要開啟托盤的光碟機編號放在 CX 堙A0 表示 A:,1 表示 B:,2 表示 C:。再把 AX 設定為 1510H 表示將功能請求傳送給裝置,最後呼叫 INT 2FH 中斷。下面程式組譯後,轉換成 *.COM 檔,可以把光碟機的托盤打開,

ddrh    struc           ;位址---意-----義-------
len     db      ?       ; 00 device driver request header 長度
subunit db      ?       ; 01 subunit,0
command db      ?       ; 02 命令碼
status  dw      ?       ; 03 返回狀態
revers1 dd      ?       ; 05 保留,0
revers2 dd      ?       ; 09 保留,0
media   db      ?       ; 0D 媒體描述子,0
trn_off dw      ?       ; 0E 傳送資料位址,偏移位址
trn_seg dw      ?       ;    區段位址
len_tr  dw      ?       ; 12 傳送資料長度
ddrh    ends
;***************************************
code    segment
        assume  cs:code,ds:code
        org     100h
;---------------------------------------
start:  jmp     begin
eject   ddrh    <13h,0,0ch,?,0,0,0,offset cd_ejt,?,1>
cd_ejt  db      0       ;開啟光碟托盤的命令碼
cd_rom  dw      ?       ;光碟機編號
begin:  mov     ax,1500h
        sub     bx,bx
        int     2fh
        mov     cd_rom,cx
        mov     ax,cs
        mov     eject.trn_seg,ax
        mov     ax,1510h
        mov     cx,cd_rom
        mov     bx,offset eject
        int     2fh
        int     20h
;---------------------------------------
code    ends
;***************************************
        end     start

要使光碟機托盤關上,device driver request header 所填入的數值相似,只有傳送的命令不同,關上托盤的命令長度也是一個位元組,但該命令資料為 5。(註三)

CMD=0C/01 AX=1510H/INT 2FH 將光碟機托盤鎖上或開鎖

光碟機托盤鎖上的意思是使光碟機面板的 EJECT 按鍵失效,也就是按下這個按鈕光碟機仍打不開,開鎖就是解除這個功能。要使光碟機鎖上也是要用 device driver request header,命令碼也是 0CH,但是傳送的命令資料是 01,01 兩個位元組;而開鎖則是傳送命令資料 01,00 兩個位元組,見註三,命令資料編號 1 的部份。

device driver request header 的第 12H 位元組開始的一個字組是命令資料長度,必須設為 02;而第 0EH 位元組開始的兩個字組分別指向傳送命令資料位址;第 02H 開始的一個位元組是命令碼 0CH。將這些設好之後,CX 設定光碟機編號,AX 設為 1510H,ES:BX 指向 device driver request header,再呼叫 INT 2FH 即可。下面程式可以把光碟機鎖上:

ddrh    struc           ;位址---意-----義-------
len     db      ?       ; 00 device driver request header 長度
subunit db      ?       ; 01 subunit,0
command db      ?       ; 02 命令碼
status  dw      ?       ; 03 返回狀態
revers1 dd      ?       ; 05 保留,0
revers2 dd      ?       ; 09 保留,0
media   db      ?       ; 0D 媒體描述子,0
trn_off dw      ?       ; 0E 傳送資料位址,偏移位址
trn_seg dw      ?       ;    區段位址
len_tr  dw      ?       ; 12 傳送資料長度
ddrh    ends
;***************************************
code    segment
        assume  cs:code,ds:code
        org     100h
;---------------------------------------
start:  jmp     begin
lock_rq ddrh    <13h,0,0ch,?,0,0,0,offset cd_lock,?,2>
cd_lock db      1,1    ;鎖上光碟托盤的命令資料
cd_rom  dw      ?      ;光碟機編號
begin:  mov     ax,1500h
        sub     bx,bx
        int     2fh
        mov     cd_rom,cx
        mov     ax,cs
        mov     lock_rq.trn_seg,ax
        mov     ax,1510h
        mov     cx,cd_rom
        mov     bx,offset lock_rq
        int     2fh
        int     20h
;---------------------------------------
code    ends
;***************************************
        end     start

註一: device driver 的命令碼
命令碼 說     明
十六進位 十進位
000 INIT
011 MEDIA CHECK (block devices)
022BUILD BPB (block devices)
033IOCTL INPUT
044INPUT
055NONDESTRUCTIVE INPUT, NO WAIT (character devices)
066INPUT STATUS (character devices)
077INPUT FLUSH (character devices)
088OUTPUT
099OUTPUT WITH VERIFY
0A10OUTPUT STATUS (character devices)
0B11OUTPUT FLUSH (character devices)
0C12IOCTL OUTPUT
0D13(DOS 3.0+) DEVICE OPEN
0E14(DOS 3.0+) DEVICE CLOSE
0F15(DOS 3.0+) REMOVABLE MEDIA (block devices)
1016(DOS 3.0+) OUTPUT UNTIL BUSY (character devices)
1117(European MS-DOS 4.0) STOP OUTPUT (console screen drivers only)
1218(European MS-DOS 4.0) RESTART OUTPUT (console screen drivers only)
1319(DOS 3.2+) GENERIC IOCTL
1420(DOS 4.0, KKCFUNC) DEVICE RESTORE (character device)
1521(European MS-DOS 4.0) RESET UNCERTAIN MEDIA FLAG
1622(DOS 4.0) unknown???
1723(DOS 3.2+) GET LOGICAL DEVICE
1824(DOS 3.2+) SET LOGICAL DEVICE
1925(DOS 5.0+) CHECK GENERIC IOCTL SUPPORT
80128(CD-ROM,DRFAT32) READ LONG
81129(CD-ROM) reserved
82130(CD-ROM,DRFAT32) READ LONG PREFETCH
83131(CD-ROM,DRFAT32) SEEK
84132(CD-ROM) PLAY AUDIO
85133(CD-ROM) STOP AUDIO
86134(CD-ROM,DRFAT32) WRITE LONG
87135(CD-ROM,DRFAT32) WRITE LONG VERIFY
88136(CD-ROM) RESUME AUDIO

註二
:device driver request header 返回時,狀態說明:
位元 說  明
0F 如果錯誤,此位元設為一,否則為零
0E-0B 保留,均為零
0A 某些呼叫驅動程式後,由 DOS 設定
09 忙碌時設為一
08 呼叫完成
如果位元 0F 為一時,07-00 位元為錯誤碼
07 未知的媒體
06 尋找錯誤
05 錯誤的功能請求
04 CRC 錯誤
03 未知命令
02 尚未準備好
01 未知 unit
00 寫入保護錯誤

註三
:命令資料的標號及說明:
命令資料編號 命令資料長度 說  明
01 開啟光碟機托盤
12 鎖上或開鎖光碟機托盤
21 重置光碟機
39 音頻控制
4? ?
51 關上光碟機托盤

回到首頁到第十九章到第二十一章