ATAPI(IDE) CD
Информация к размышлению
Данный документ никоим
образом не является полным описанием стандартного ATAPI-CD. Здесь были собраны
только основные данные, необходимые для общего понимания принципов
функционирования. Предполагается знание (хотя бы в общих чертах) IDE-интерфейса
(стандарт ходил под именем ATA-R4C.*).
Для желающих быстро
заполучить исходники для управления CD-ROM могу порекомендовать драйвер
VIDE-CDD.SYS. Он проще всего поддается дизассемблированию и содержит достаточно
неплохой код. Кроме того, в исходных текстах драйвера CD для Linux содержится
много полезной информации, хотя ориентация на "юниксоидный" тип
запросов мешает использованию этих текстов для компиляции под MS-DOS.
Соглашения и используемые
сокращения.
При указании конкретных адресов подразумевается, что
CD является
мастером, адрес
контроллера - 170h. Если у Вас используются другие адреса,
вместо 17x необходимо подставить 1Fx,
1E8+x или 168+x.
Тик = 18.2 герца.
Данные длиной в слово или двойное слово в/из CD
идут в формате
co старшим первым байтом ( в отличие от
PC, где первый байт - младший).
AP - Atapi пакет, 12
байт передаваемых в CD-Rom. Содержат команду
и
основные данные для нее. ВНИМАНИЕ: возможно существуют устройства
c пакетом длиной в 16
байт. Однако, подавляющее большинство
драйверов не
анализируют и не поддерживают такой формат.
Для определения размера пакета
используется ATA-команда A1h.
AK - Atapi команда
M - минуты
S - секунды
F
- номер фрейма (1/75 секунды)
Часто используемые
биты региста cостояния (177h):
BSY - бит 80h
DRQ - бит 08h
CHK - бит 01h
I. Определение наличия CD в системе
Для проверки присутствия Atapi-CD
устройства необходимо:
1. На нужном шлейфе выбрать требуемое устройство (Master/Slave) в
регистре 176h.
2. Проверить
отсутствие BSY
3. Если занято - устройства
нет.
Далее можно дать
команду общего сброса (вывести код 8 в регистр 177h и подождать 1-3 тика), либо
попробовать обойтись без этого. Если CD находится в cостоянии нормального
ожидания команды, сброс давать не обязательно.
3. В порты 174h и 175h
записать нечто, отличающееся от 14EBh.
4. В порт 177h вывести
команду ECh и подождать пару тиков.
5. Проверить порт 174h
(д.б. = 14h) и порт 175h (д.б. = EBh).
При этом надо
учитывать, что в регистрах должна будет установлена ошибка (177h - 51h, 171h -
04h). Это нормально.
Если все условия
соблюдены, то можно считать, что на IDE-шлейфе присутствует Atapi устройство.
Для уточнения типа устройства можно воспользоваться уже Atapi-командами.
Данный алгоритм может
применяться только тогда, когда достоверно известно, что CD до этого не
выполнял команд. В противном случае бит BSY может быть установлен. Если
необходнимо, проверку регистра состояния можно смягчить, проверяя только
наличие самого ATA устройства записью в регистры.
II. Выполнение команд
Для выполнения AK
необходимо (работа без прерываний):
1. Выбрать
соответствующее устройство (Master/Slave) в порту 176h
2. Дождаться готовности (BSY и DRQ = 0). Драйверы ждут до 10-20 секунд.
Если готовности нет - можно попытаться сбросить привод.
3. Установить
желательный размер блока в регистрах 174h (мл.)
и 175h (ст. часть)
Если команда не возвращает данные, это можно
и не делать. Для
DMA-шных обменов в этот момент надо установить
и другие регистры.
4. В 177h записать команду A0h. В ответ на это устройство может
установить BSY на время подготовки к приему AP.
5. Дождаться требования данных (DRQ=1 и BSY=0). (обычно ждать не надо -
драйв выставляет требование сразу). При этом в регистре 172h два младших бита
должны иметь значение 01.
6. В режиме словной
пересылки записать в порт 170h 6 слов AP.
7. Дождаться готовности (BSY=0). (В зависимости от типа команды и
других обстоятельств, драйв может выполнять команду за время от тысячных долей
секунды до десятков секунд (Если, например, плохо читается сектор диска).
8. Проверить бит DRQ и
если он установлен, то считать из регистров
174h и 175h длину
передаваемого блока.
9. Если длина =0 или бит DRQh в 177h не установлен - п. 11, иначе
произвести обмен данными через порт 170h. При этом два младших бита регистра
172h могут принимать значение 00 (при передаче данных в CD) или 02 (при приеме
данных из CD).
10.Если команда не
закончила обмен (бит BSY=1), то повторить с п 7.
11.После завершения
команды два младших бита регистра 172 обычно принимают значение 03, что
означает готовность драйва к выдаче статуса завершения команды. При этом можно
проанализировать результат завершения команды (регистры 177h и 171h). При
ошибках можно использовать ATAPI-функцию 03h для получения более детальной
информации.
III. Типы команд
По режимам обмена
команды можно разделить на три группы:
а) Управления
Как правило, все
данные находятся в AP. В некоторых командах применяется дополнительно пересылаемый
блок данных.
Результат можно
определить по регистрам ошибок (171h и 177h) или с помощью дополнительной
команды получения состояния.
б) Передачи данных
Адресные данные и
параметры передачи находятся в AP
Поскольку пишущие CD
не рассматриваются (мне они не известны), то блок данных, передаваемых в CD,
отсутствует.
Если в команде
подразумевается передача данных из CD и
нет ошибок, CD драйв
выдает в ответ на команду блок (блоки) данных.
в) Получения
информации
Все данные о запросе
находятся в AP. В ответ на команду СD выдает блок данных.
IV. ATA команды
У CD есть несколько
вспомогательных команд, которые исполняются так же, как и команды обычного
IDE-винчестера. При этом назначение регистров совпадает с назначением по ATA.
Вот основные команды:
A0h - Команда передачи AP.
A1h - Идентификация привода. Аналог команды ECh для IDE-винчестера, но
формат выходного блока другой (описан в приложении C).
ECh - Воспринимается как ошибка, но в регистрах 174h и 175h
устанавливается сигнатура 14EBh - признак Atapi устройства.
08h - Програмный сброс.
Выполняет процедуру начальной инициализации.
Также, могут выполняться
некоторые команды управления сохранением энергии, установки возможностей и пр.
Во многих приводах они воспринимаются как правильные команды, но реально не
исполняются или исполняются частично.
V. Команды в ATAPI-пакетах
Первый байт в AP является
кодом команды. Это единственный байт, который анализируется всегда. Остальные
11 байт содержат информацию, зависящую от конкретной команды.
----------------------------------------------------------------------
Команда 00h - пустышка, проверяет готовность
Пакет:
db 0
db 11*dup(0)
; *
Ничего не делает, может
применяться для проверки смены диска
ПРИМЕЧАНИЯ:
1) Первая команда после смены диска будет отвергнута с кодом ошибки
"смена носителя".
2) Здесь и далее:
данные помеченые "*", как правило, не анализируются
CD, но для совместимости должны быть
установлены в 0.
Команда Пакет: |
01h - Установить
головку на начало диска db 01h db 12*dup(0) ; * Команда управляющая
(практически не используется). |
------- Команда Пакет: |
-------------------------------------------------------------- 03h - читать состояние
привода db 03h db 3*dup(0) ; * db Len ; длина выходного блока db 7*dup(0) ; * На выходе таблица из 12h
байт, в которой самыми интересными являются байты 2, 0С и 0D - это три байта
кода ошибки последней операции. |
------- Команда Пакет: |
------------------------------------------------------------------ 012h - читать строку
параметров изготовителя драйва db 12h db 0h,0h ; иногда здесь устанавливаются некие
параметры db 0h ; * db Len ; длина выходной строки db 7*dup(0) ; * Драйв выдает некую
строку изготовителя (в формате изготовителя) Зависит от типа
CD-Rom. Иногда применяется в драйверах для проверки соответствия драйвера и
устройства. Структура выходного
блока: 0 db 1Fh - тип
устройства (CD = 5) E0h - для CD =0 1 db 7Fh - = 0 (для
совм. со SCSI-1) 80h - поддерживаются сменные носители 2 db 0 - версии
ISO, ECMA и ANSI. 3 db 0 - для
совместимости со SCSI-2 4 db ? - длина
оставшегося блока 5 db
2 dup(?) - резервные 7 db 0 - для
совместимости со SCSI-2 8 db 8 dup(?) - строка изготовителя (там бывает 'ATAPI') 10h db 10h
dup(?) - название продукции 20h db 4
dup(?) - ревизия Текстовые поля образуют
одну строку, разделенную пробелами. |
------- Команда Пакет: |
------------------------------------------------------------------- 01Bh - управление треем и
прочее db 1Bh db 3*dup(0) ; * db Func ; подфункция db 7*dup(0) ; * Команда управляющая. Подфункции: 0 - войти в режим Sleep 1 - остановить проигрывание/чтение 2 - выдвинуть трей 3 - закрыть трей |
------- Команда Пакет: |
------------------------------------------------------------------- 01Eh - блокировка трея db 1Eh db 3*dup(?) ; * db Func ; подфункция db 7*dup(?) ; * Команда управляющая. Младший бит Func= 0
- разблокировать трей = 1 - заблокировать трей |
------- Команда Пакет: |
------------------------------------------------------------------- 025h - получить размер
вставленного диска в секторах. db 25h db 11*dup(0) ; * Команда информационная. Пользователю в ответ
передается блок из 8 байт: dd Sectors ; число секторов на текущем диске dd SectSize ; размер сектора (как правило, не
зависит ; от диска и равен 930h) |
Команда Пакет: |
02Bh - Seek db 2Bh db 2*dup(0) ; * db M,S,F ; куда позиционироваться db 6*dup(0) ; * Команда управляющая. |
Команда Пакет: |
042h - смешанная
информация (чтение субканала) db 42h db ScMsf ; 0/2 - тип выдачи адресов (номер сектора или MSF) db FullInfo; вариант запроса
(полный/краткий - бит 40h) db Func ; подфункция (только для полного запроса) db 3*dup(0); * dw Length ; Длина таблицы db 3*dup(0); * Команда
информационная, выдает блок следующей информации: 00h dw состояние проигрывания аудио: 00h - неизвестно или
не поддерживается 11h - Играет аудио 12h - Аудио стоит 13h - Аудио
остановилось на конце 14h - Открыта дверь
или ошибка запуска 15h - Прочее 02h dw длина последующих данных (0 - нет) 04h и далее присутствует при наличии бита 40h в FullInfo
и зависят от Func Func не равен 2 или
3 04h db 01h
(формат данных субканала = 1) 05h db Ctrl/Addr 06h db TrackNumber 07h db Point or Index 08h db 0 09h db 3*dup(?) - MSF/SECTOR на диске 0Ch db 0 0Dh db 3*dup(?) - MSF/SECTOR на дорожке --Подфункция 2--
(Получить UPC код) 04h db 02h
(формат данных субканала = 2) 05h db 3h*dup(?) 08h db 80h - флажок наличия UPC (если нет, то UPC отсутствует) 09h db
0Ch*dup(?) - здесь хранится UPC код (6 цифр в BCD коде) 15h db 3*dup(?)
- Положение чего-то на диске в формате MSF --Подфункция 3--
(получить ISRC код) 04h db 03h
(формат данных субканала = 2) 05h db Ctrl/Addr 06h db TrackNumber - не всегда используется. 07h db ? 08h db 80h - флажок присутствия (аналогично
функции 02h) 09h db
далее запись ISRC |
------- Команда Пакет: |
--------------------------------------------------------------------- 043h - информация о
дорожках (READ TOC) db 43h db ScMsf ; 0/2 - тип выдачи адресов (номер сектора или MSF) db 4*dup(0); * db BegTrk ; начальная дорожка (от 1, 0 заменяется на 1) dw Length ; Длина таблицы db Func ; варианты выдачи информации (0/40h/80h) db 2*dup(0); * Команда информационная, выдает таблицу дорожек. Максимальная длина
таблицы 8*64h+4 байт или 64h (100.) дорожек. Func = 00h
; получить обычную таблицу дорожек = 40h ; получить таблицу сессий = 80h ; получить обычную таблицу в расширенном
формате Общий формат таблицы
: dw Len ; длина последующих полей в байтах db BegTrk ; первая дорожка db EndTrk ; последняя дорожка d? <track_Def> ; описание дорожек Описание дорожек м.б.
трех форматов: |
1) 5 байт на дорожку (внутренний формат, наружу из CD не выдается):
db Ctrl/Addr ; тип дорожки и флаги
db Index ;
индекс дорожки (номер)
db*3 Start ;
адрес начала дорожки
2) 8 байт на дорожку (Func=0h/40h): db ?
db Ctrl/Addr ; тип дорожки и флаги
db TrackNumber ; номер дорожки
db ?
db*4 Start ;
адрес начала дорожки
3) 11 байт на дорожку (Func = 80h): db Res1
db Ctrl/Addr ; тип дорожки
db Res2
db Index ; индекс дорожки
db Res3
db Res4
db Res5
db*4 Start ; адрес начала дорожки
Ctrl/Addr - тип дорожки(то-же, что и в MSCDEX, но
переставлены тетрады):
Ctrl
(младшая тетрада, отдельные биты):
01 - есть pre-emphasis
02 - разрешено
копирование
04 - дорожка данных
08 - 4 канала (а не 2)
Addr (старшая тетрада,
коды):
0 - нет субканала
1 - в субканале
закодирована позиция
2 - в субканале
закодирован UPC
3 - в субканале
закодирован ISRC
прочее - зарезервировано
Самые распространенные
коды:
14h - ROM
10h - audio
Index - кодируется в
BCD и для обычной дорожки находится в интервале
01-99. Коды A0 и выше
имеют специальное значение, они не соответстуют физическим дорожкам на диске, а
носят служебный характер - информируют о числе дорожек, начале диска, конце
диска и т.п.
Start - в зависимости от
запроса, может быть либо номером сектора, либо адресом сектора в формате MSF.
Команда Пакет: |
044h db db db db db dw db |
информация 44h SL ; ; 0 ; M,S,F ; 0 ; Len ; 3*dup(0); |
о реальных метках
положения (Read HEADER) бит 2 - что
записывать в выходной буфер (исходный номер сектора
или считанный) * Номер сектора * длина выдаваемой
информации * |
Команда информационная,
выдает следующую таблицу из 8 байт:
db SectorType ; тип формата сектора (data mode)
db 4*dup(0)
db M,S,F ; адрес сектора
Пакет выдается только в том
случае, если CD смог считать заданный сектор и определить его тип.
Команда Пакет: |
045h - проигрывать
audio в терминах блоков (длина - слово) db 45h db 0 ; * dd StartBlock ; блок начала проигрывания (-1 - с тек.
положения) db ? dw Length ; число блоков db 3*dup(?) ; * Команда управляющая. |
Команда Пакет: |
047h - проигрывать
audio в стиле MSF db 47h db 2*dup(?) ; * db M,S,F ; начало отрезка (FF:FF:FF - текущая
позиция) db M,S,F ; конец отрезка db 3*dup(?) ; * Команда управляющая. |
Команда Пакет : |
04Bh - Start/stop
audio db 4Bh db 7*dup(0) ; * db Func db 3*dup(0) ; * Команда управляющая. Младший бит Func= 0
- остановить = 1 - запустить |
Команда Пакет: |
04Eh - остановить
проигрывание db 4eh db 11*dup(?) ; * Команда управляющая. |
Команда Пакет: |
055h -
установить параметры db 55h db ? ; бит 1 - сохранять в NVRAM (?) db Page ; требуемая страница параметров db 4 dup (?) dw Length ; длина таблицы db 3*dup(0); * Команда управляющая, коды
и формат страниц описан в команде 5Ah. |
------- Команда Пакет: |
-------------------------------------------------------------------- 05Ah - получить параметры db 5Ah db ? db Page
- определяет требуемые параметры, состоит из двух битовых полей: 3Fh - номер
требуемой страницы параметров: 01h - параметры исправления
ошибок 0Dh
- общие параметры 0Eh
- аудио-управление 2Ah - параметры
устройства (только читается) 3Fh - все странички C0 - биты типа
требуемой страницы: 00
- текущие значения 01 - измененные
значения 10 - значения по
умолчанию 11 - сохраненные значения db 4 dup (?) dw Length ; длина таблицы db 3*dup(0); * Команда
информационная, выдает cоответствующую страничку параметров. Общий заголовок: 00h dw Длина всего блока (без первого слова) 02h db Состояние привода 03h db 5 dup(?); Заголовок каждой
страницы: 08h db
Номер страницы из запроса 09h db
Длина страницы Страница 01 -
исправление ошибок 0Ah db
Параметр исправления ошибок 0Bh db
Счетчик повторов чтения Страница 0D - общие
параметры 0Ah db
? 0Bh db
Множитель таймера неактивности 0Ch dw
Число S единиц в M единице для формата MSF (60) 0Eh dw
Число F единиц в S единице для формата MSF (75) Страница 0E - аудио
параметры 0Ah db
? параметр не исп., но
изменяется 0Bh db
2 dup(?) 0Dh db
? =0 LBA всегда равен номеру
сектора, старший бит
указывает правильность следующего поля 0Eh dw 0 Число логических блоков в секунду для
проигрывания. (как-правило не используется) 10h db
мл. тетрада - биты выходного порта канала 0 11h db
громкость канала 0 12h db
мл. тетрада - биты выходного порта канала 1 13h db
громкость канала 1 14h db
мл. тетрада - биты выходного порта канала 2 15h db
громкость канала 2 16h db
мл. тетрада - биты выходного порта канала 3 17h db
громкость канала 3 Страница 2Ah -
параметры устройства (только чтение) ; биты
присутствия/отсутствия функций 0Ch db
01h - проигрывание аудио 02h - композитный
аудио/видео поток 04h - Digital out to
port 1 08h - Digital out to
port 2 10h - чтение
секторов Mode 2 Form 1 20h -
-----//-------- Mode 2 Form 2 40h - Чтение
многосессионных дисков 80h - ? 0Dh db
01h - Чтение RedBook через команду Read-CD 02h - Чтение
RedBook "with accurate
stream" 04h - Чтение
субканала 08h - Поддержка
деинтерливинга данных субканала 10h - Поддержка
"C2 error pointers" 20h - Поддержка
чтения ISRC 40h - Поддержка
чтения UPC 80h - ? 0Eh 01h - блокировка носителя 02h - чтение статуса
блокировки 04h - Disk prevent
jumper present 08h - команда
выброса носителя 10h - ? E0h - Тип
загрузчика: 0 - Caddy 1 - Tray 2 - Pop-Up 3 - Reserved 4 - Ченджер с
индивидуально меняемыми дисками 5 - Картридж 6 - Reserved 7 - Reserved 0Fh db
01h - Раздельная регулировка каналов 02h - Раздельный
комутатор каналов 04h - Информация о
наличии диска 08h - 10h - 20h - 40h - 80h - 10h dw
Максимальная скорость обмена в килобайтах 13h db
Число градаций регулировки
громкости 14h dw
Размер буфера в килобайтах 16h dw
Текущая скорость обмена ;---------иногда может
отсутствовать------------- 18h db
? 19h db
01h - Digital out по фронту/спаду сигнала BCKF 02h - LRCK
индицирует левый/правый канал 04h - данные в
формате LSB/MSB 08h 10h \ BCKs:
0 - 32 20h | 1 - 16 40h / 2 - 24 3 - 24 (I^2S) 80h - ? Длина каждой из
стрниц может быть разной. Здесь описаны только те поля, которые более-менее
стандартны. Если запрашиваются все странички (код 3Fh), то в выходном блоке
будет присутствовать один общий заголовок и последовательно расположенные
странички со своими заголовками. |
------- Команда Пакет: |
--------------------------------------------------------------------- 0A5h - проигрывать audio
в терминах блоков db A5h db 0 ; * dd StartBlock ; блок начала проигрывания (-1 - с тек.
положения) dd Length ; число блоков db 2*dup(?) ; * Команда управляющая. |
Команда Пакет: |
0B9h - читать данные db B9h ; db Fmt ; может быть = 00h годится любой формат ; 08h обычный CD-диск (Желтая
книга) ; 10h\ разновидности ; 14h/ Green XA db 0 ; * db M,S,F; начало чтения db M,S,F; конец чтения db Flg ; флаги читаемого куска сектора: ; 01h три ; 02h неиспользуемых (?) ; 04h бита ; 08h EDC/Zero/ECC ; 10h основное тело сектора (data) ; 20h описатель адреса сектора (head) ; 40h данные субканала (sub) ; 80h начальные синхробайты (sync) ; передаются только
те части секторов, для которых ; установлены биты.
Передаваемые части сектора должны идти ; подряд, без
пропусков. db 0 ; всегда д.б. =0, иначе ошибка (?) db 0 ; * Команда передачи
данные. Если начало=конец,
производится позиционирование на указанную позицию и тест читабельности. В
этом случае данные не передаются. |
------- |
------------------------------------------------------------------ |
Пакет:
db BEh ;
db Fmt ;
dd Sec ; начало чтения (исп. только 24 бита)
db 0 ; *
dw ScNum; Число секторов
db Flg ; флаги читаемого куска сектора (как в B9h)
db 0 ; всегда д.б. =0, иначе ошибка (?)
db 0 ; *
Команда полностью
аналогична команде B9, за исключением задания адресов области чтения в терминах
секторов.
==============================================================================
Приложение A
Коды ошибок ATAPI
устройства
(взяты из драйвера CD в
Linux'е)
Первый байт |
|
00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0ah 0bh 0ch 0dh 0eh 0fh |
No sense data Recovered error Not ready Medium error Hardware error Illegal request Unit attention Data protect
(reserved) (reserved) (reserved) Aborted command
(reserved) (reserved) Miscompare (reserved) |
Второй и третий байты
0000h No additional sense information
0011h Audio play operation in progress
0012h Audio play operation paused
0013h Audio play operation
successfully completed
0014h Audio play operation stopped due
to error
0015h No current audio status to
return
0200h No seek complete
0400h Logical unit not ready - cause
not reportable
0401h Logical unit not ready - in
progress (sic) of becoming ready
0402h Logical unit not ready -
initializing command required
0403h Logical unit not ready - manual
intervention required
0600h No reference position found
0900h Track following error
0901h Tracking servo failure
0902h Focus servo failure
0903h Spindle servo failure
1100h Unrecovered read error
1106h CIRC unrecovered error
1500h Random positioning error
1501h Mechanical positioning error
1502h Positioning error detected by
read of medium
1700h Recovered data with no error
correction applied
1701h Recovered data with retries
1702h Recovered data with positive
head offset
1703h Recovered data with negative
head offset
1704h Recovered data with retries
and/or CIRC applied
1705h Recovered data using previous
sector ID
1800h Recovered data with error
correction applied
1801h Recovered data with error
correction and retries applied
1802h Recovered data - the data was
auto-reallocated
1803h Recovered data with CIRC
1804h Recovered data with L-EC
1805h Recovered data - recommend
reassignment
1806h Recovered data - recommend
rewrite
1a00h Parameter list length error
2000h Invalid command operation code
2100h Logical block address out of
range
2400h Invalid field in command packet
2600h Invalid field in parameter list
2601h Parameter not supported
2602h Parameter value invalid
2603h Threshold parameters not
supported
2800h Not ready to ready transition,
medium may have changed
2900h Power on, reset or bus device
reset occurred
2a00h Parameters changed
2a01h Mode parameters changed
3000h Incompatible medium installed
3001h Cannot read medium - unknown
format
3002h Cannot read medium -
incompatible format
3700h Rounded parameter
3900h Saving parameters not supported
3a00h Medium not present
3f00h ATAPI CD-ROM drive operating
conditions have changed
3f01h Microcode has been changed
3f02h Changed operating definition
3f03h Inquiry data has changed
4000h Diagnostic failure on component
(ASCQ)
4400h Internal ATAPI CD-ROM drive
failure
4e00h Overlapped commands attempted
5300h Media load or eject failed
5302h Medium removal prevented
5700h Unable to recover table of
contents
5a00h Operator request or state change
input (unspecified)
5a01h Operator medium removal request
5b00h Threshold condition met
5c00h Status change
6300h End of user area encountered on
this track
6400h Illegal mode for this track
bf00h Loss of streaming
-------------------------------------------------------------------------
Приложение B
Некоторые форматы секторов
Аудио диск (красная
книга): |
audio_sample_bytes 2352 |
||||||
Данные (желтая, mode 1): |
sync 12 |
head 4 |
data 2048 |
EDC 4 |
zero 8 |
ECC 276 |
|
Данные (желтая, mode2): |
sync 12 |
head 4 |
data 2336 |
||||
XA данные (зеленая, mode2 form1): |
sync 12 |
head 4 |
sub 8 |
data 2048 |
EDC 4 |
ECC 276 |
|
XA данные (зеленая, mode2 form2): |
sync 12 |
head 4 |
sub 8 |
data 2324 |
EDC 4 |
||
-------------------------------------------------------------------------
Приложение C
Блок, передаваемый по
ATA-команде A1
Смещение
00h db битовое поле:
03h - Длина
пакета: 00 - 12 байт
01 - 16 байт
прочее - Reserved
1Ch - ?
60h - CMD DRQ
Type: 00 - Микропроцессор
01 - Interrupt
02 - Accelerated
03 - Reserved
80h - Съемное
01h db 1Fh - Тип устройства: 05 -
CD-ROM
(остальные типы можно
посмотреть
в описании SCSI)
;--тут пропуск---
14h dw*0Ah Серийный номер
28h dw*3 Что-то от производителя
2Eh dw*4 Версия прошивки
36h dw*14h Название модели
5Eh dw Что-то от производителя
60h dw 0
62h db ????? (0)
63h db 01h - поддержка DMA
02h - поддержка
LBA
04h - устройство
может запрещать использование IORDY
08h - поддержка
IORDY
20h - поддержка
перекрывающихся операций
40h - поддержка
Proxy Interrupt
80h - поддержка
Interleave DMA
66h db PIO time (ns)
67h db PIO mode
69h db S/W DMA mode
6Ah db 1 - Поля 6Сh-73h
используются
2 - Advanced PIO Support
(поля 80h-8Dh используются)
; поля 6Ch - 78h взяты
из Interrupt List'а. В большинстве CD не используются
6Ch dw ??? logical cylinders in current translation mode
6Eh dw ??? logical heads in current translation mode
70h dw ??? logical sectors per track in current translation
mode
72h dw*2 ??? current capacity in sectors
76h dw ??? multiple-sector count for read/write multiple
command
78h dw*2 ??? total
number of user-addressable sectors (LBA mode)
;параметры DMA
7Ch db S/W DMA modes: 1 - 0; 2 -
0,1; 4 -0,1,2; Прочее - нет DMA
7Dh db Текущий режим S/W DMA: 1 -
0, 2 - 1, 4 - 2, прочее - не DMA
7Eh db M/W DMA modes (как в S/W
DMA)
7Fh db Текущий режим M/W DMA
80h db Advanced PIO modes: 4 - PIO 5
2 - PIO 4
1 - PIO 3
82h dw Минимальное время передачи в M/W DMA
84h dw Рекомендуемое ---//----//---
86h dw
Минимальное время передачи в
PIO без F/C
88h dw
-----//------//-------//----//---
с F/C (IORDY)
8Ah dw*2
зарезервировано для будущих
PIO-режимов
; эти два поля
используются для определениея параметров
; перекрывающегося
обмена
8Eh dw типичное время отпускания
шины после команды (ms)
90h dw ----//-----//-----//-----//----//---
обслуживания (ms)
;
92h dw
Какой-то номер версии
96h dw*38h
0
100h dw*20h
Что-то от производителя
140h dw*60h
0
|
Приложение D
Назначение регистров интерфейса |
170h |
Регистр данных. Через
этот регистр CD обменивается с внешним миром данными. Ввод/вывод только
словами. |
171h |
Чтение - регистр
ошибок: 01h - Ошибочная
длина 02h - Обнаружен
конец носителя 04h - Команда
отвергнута (бит совпадает по смыслу с ATA) 08h - Обнаружена
смена носителя F0h - Младшие 4 бита
первого байта кодов ошибки Запись - регистр
доп. возможностей (опциональный): 01h - включение
обмена по DMA 02h - включение
перекрывающихся операций FDh - зарезервировано |
172h 173h |
Регистр уточнения
причины прерывания: 01h - Тип передачи: 0 - передача данных, 1 - передача AP 02h -
направление передачи: 0 - в CD, 1 - из CD 04h - индицирует
освобождение шины ATA. (как правило = 0) F8h -
Зарезервировано Сочетания битов 1 и
2 имеют следующий смысл: 0 - Ввод блока
данных (в CD) 1 - Ввод
Atapi-пакета 2 - Вывод блока
данных (из CD) 3
- Выдача состояния завершения команды Зарезервирован |
174h 175h |
\Регистры длины
пересылки. При записи устанавливается /желательный размер
блока пересылки в байтах. При чтении возвращается объем,
подготовленный для передачи из CD или требуемый для передачи в CD в следующем
цикле обмена. |
176h |
Регистр выбора
устройства 0Fh -
Зарезервированы (SAM LUN) 10h - Мастер (0)/
Слэйв (1) 20h - 1 40h -
Зарезервировано (0) 80h - 1 |
177h |
Регистр команды
(запись) / состояния (чтение) Биты регистра
состояния: 01h - Ошибка
выполнения команды 02h - Не
используется 04h - Обнаружена
скорректированная ошибка чтения (в большинстве
устройств постоянно сброшен) 08h - Устройство
требует обмена данными 10h - Устройство запросило прерывание для обслуживания (во многих
приводах установлен постоянно) 20h - Усторойство
готово к DMA-обмену или индикация ошибок
(зависит от режима и зачастую не используется) 40h - Устройство
закончило выполнение команды (этот бит лучше не
использовать) 80h - Устройство занято. |
376h |
Регистр управления
устройством (мне кажется, он есть не на всех устройствах) По записи: 01h - 0 02h - Запрет
прерываний от устройства 04h - Програмный
сброс 08h - 1 F0h - зарезервировано |
Примечание: При выполнении
обычных ATA (не ATAPI) команд назначение регистров совпадает с их назначением
по ATA.
-----------------------------------------------------------------------
Приложение E
/*****************************************************************/ /* Пример
использования ATAPI-CD команд для проигрывания дисков */ /* без использования драйвера
*/
/* Приложение к
документации по ATAPI-CD
*/
/* Компилятор: BC 3.1,
large model */
/* Это _крайне_ сырая
версия. Т.к. большинство приводов расчитаны*/
/* на работу по
прерываниям, существуют определенные проблемы при*/
/* работе без них.
Информация о проблемах, возникших с различными*/
/* приводами будет очень ценна для создания версии, */
/* работоспособной на
как можно большем количестве устройств.
*/
/*****************************************************************/
#include
<stdio.h>
#include
<stdlib.h>
#include <dos.h>
#include <conio.h>
typedef unsigned
char byte;
typedef unsigned
int word;
typedef unsigned long
dword;
/* описатель
IDE-устройства */
typedef struct
int port; /* базовый порт */
char irq; /* номер IRQ 1-15, если
отсутствует - 0 */
char ms; /* 1 - мастер, 0 - слэйв */
ATAPos;
/* Если используются
другие прерывания
таблицу надо модифицировать */
static ATAPos Atp[]=
0x1F0,14,1,
0x1F0,14,0,
0x170,15,1,
0x170,15,0,
0x1E0,10,1,
0x1E0,10,0,
0x168,11,1,
0x168,11,0,
0,0,0;
/* то, что последний
раз считалось из 1x7 */
static byte Last1X7=0;
/*static ATAPos
*GetDescr(int drvnum)return(Atp+drvnum);*/
void
StoreLBAToMSF(long lba, void *msf)
byte *msfb=msf;
lba+=150;
*msfb++=lba/(60L*75L);
lba%=(60L*75l);
*msfb++=lba/75L;
*msfb++=lba%75L;
word GetMSBWord(word cd)return(
(cd >> 8)|
(cd << 8));
dword
GetMSBDword(dword cd)return(
((cd >> 24)&0x000000FFL)|
((cd >> 8)&0x0000FF00L)|
((cd << 8)&0x00FF0000L)|
((cd <<
24)&0xFF000000L));
/* ждать установки бит
*/
int WtBitMask(int
port, int and, int wt, int sec)
long counter;
for(counter=sec*1000L;counter>0;counter--)
int i;
i=inportb(port);
if((port&7)==7) Last1X7=i;
if((i&and)==wt) return(0);
delay(1);
return(1);
/* произвести сброс */
int ResetDrive(int
port)
int i;
outportb(port+7,8); /* программный сброс */
outportb(port+0x206,0xe);
/* аппаратный сброс */
delay(10);
outportb(port+0x206,8);
delay(10);
for(i=0;i<200;i++)
if((inportb(port+7)&0x88)==0)return(0);
else delay(10);
return(1);
/* найти не более
<maxdetect> ATAPI-cd и
записать их описатели
в таблицу DrvTbl*/
int FindAtapiCD(int
maxdetect, int *DrvTbl)
int devnum;
int totaldev=0;
for(devnum=0;(Atp[devnum].port!=0)&&(totaldev<=maxdetect);devnum++)
register int
port=Atp[devnum].port;
int i;
/* адрес устройства */
outportb(port+6,Atp[devnum].ms?0xA0:0xB0);
delay(1);
if(inportb(port+7)==0xFF)continue;
if(inportb(port+7)&0x80)
/*
м.б. оживится ? */
if(ResetDrive(port))continue;
outportb(port+4,0);
outportb(port+5,0);
outportb(port+7,0xEC);
for(i=0;i<20;i++)
delay(1);
if((inportb(port+4)==0x14)&&
(inportb(port+5)==0xEB))
word devcode;
/* есть ATAPI-устройство, анализируем
подробнее */
delay(1);
outportb(port+7,0xA1);
for(i=0;i<100;i++)
if(inport(port+7)&0x80)delay(1);
else
goto okcont;
goto cont;
okcont:
delay(10);
devcode=inport(port);
for(i=0;i<255;i++)inport(port);
/* это CD ? */
if((devcode&0x1F00)!=0x500)break;
/* У него 12 бит в AP ? */
if(devcode&1)break;
*DrvTbl++=devnum;
totaldev++;
break;
cont:;
return(totaldev);
/* запретить
прерывания - дабы умные cd-драйвера не мешались */
int DsbIrq(int devnum)
int
inum=Atp[devnum].irq;
int oldst;
if(inum==0)return(0);
if(inum>=8)
oldst=inportb(0xA1);
outportb(0xA1,oldst|(1<<(inum-8)));
return(!(oldst&(1<<(inum-8))));
oldst=inportb(0x21);
outportb(0x21,oldst|(1<<(inum)));
return(!(oldst&(1<<(inum))));
/* разрешить
прерывание от cd - при завершении работы */
void EndIrq(int
devnum)
int
inum=Atp[devnum].irq;
if(inum==0)return;
if(inum>=8)
outportb(0xA1,
inportb(0xA1)&(~(1<<(inum-8))));
else
outportb(0x21,
inportb(0x21)&(~(1<<inum)));
/* Выполнить ATAPI-команду:
drive - устройство
dir - 1 - чтение, 0 - запись данных в CDD
AP -
буфер с ATAPI-пакетом
buffer - буфер с данными (NULL, если
не нужен)
bufflen- длина выводимых данных или
макс. размер вводимых
на выходе:
-1 -
была ошибка
прочее - размер пересланного блока (в
байтах)
*/
static word
PrefIOBlock=0x8000; /* размер блока
пересылки в словах */
static byte DontResetFlg=0; /* не сбрасывать при
неготовности */
int ExecATAPICMD(int drive,
int dir, word *AP, word *buffer, word bufflen)
int port;
int i;
int readed=0;
int size;
port=Atp[drive].port;
/* выберем активное устройство */
outportb(port+6,Atp[drive].ms?0xA0:0xB0);
rerd:
Last1X7=inportb(port+7);
if(Last1X7&0x88) /* не очень
готов - попробуем исправить положение */
if(DontResetFlg)return(-1);
ResetDrive(port);
/*
ждем завершения команды сброса */
if(WtBitMask(port+7,0x80,0x0,10))return(-1); /* не готов */
goto
rerd;
/* установим размер блока */
register
word pl;
if(PrefIOBlock>bufflen)pl=bufflen;
else pl=PrefIOBlock;
outportb(port+4,pl);
outportb(port+5,pl>>8);
/* запретим всякие хитрые обмены
*/
outportb(port+1,0);
/* все готово к работе - приступим к передаче пакета */
outportb(port+7,0xA0);
/* ждем готовности не более 3х
секунд (можно и меньше) */
if(WtBitMask(port+7,0x89,8,3))return(-1);
/* выведем пакетик */
disable();
for(i=0;i<6;i++)
outport(port,*AP++);
enable();
/* точка входа цикла приема блоков
*/
GetNextBlk:
/* здесь ждем до 30 секунд */
WtBitMask(port+7,0x80,0x00,30);
/* пакет воспринят, а запрос
выполнен -
получим
размер и направление передачи */
size=inportb(port+4) |
(inportb(port+5)<<8);
Last1X7=inportb(port+7);
if(Last1X7&1)return(-1); /* ошибка выполнения команды */
if(Last1X7&8) /* нужно что-то
пересылать */
if(inportb(port+2)&2)
/*из
CD */
if(dir==1 &&
buffer != NULL )
/* прочтем
предлагаемое */
while(size>0)
int
i=inport(port);
size-=2;
if(bufflen<1)break;
*buffer++=i;
readed+=2;
bufflen-=2;
/* пропустим
ненужный остаток */
while((size-=2)>0)inport(port);
else
/*
в CD */
if(dir==0 && buffer!=NULL )
while(bufflen>0
&& size > 0)
if(bufflen<1)break;
outport(port,*buffer++);
bufflen-=2;
readed+=2;
size-=2;
/* добросим остаток нулями */
while((size-=2)>0)outport(port,0);
goto
GetNextBlk;
/* пересылать больше не нужно -
команда завершена */
Last1X7=inportb(port+7); if(Last1X7&1)
/*
были ошибки */ return(-1);
return(readed);
/***************************************************************/ /*
это тестовый проигрыватель CD */ /* для упрощения интерфейса проигрывает только
первые 10 треков*/
/***************************************************************/
/* примитивная спрашивалка
строки */
char *AskStr(char
*quest)
static char str[80];
rtt:
printf(quest);
fflush(stdin);
if(fgets(str,79,stdin)==NULL)exit(1);
return(str);
typedef struct
word Params1;
word scsi1;
byte len;
word dummy2;
byte Scsi2;
char Manuf[8];
char Prod[0x16];
char Rev[4];
Inf12Blk;
typedef struct
word bkllen;
byte state;
byte undef[9];
byte flags1,
flags2, flags3, flags4;
word maxspeed;
byte undef2;
byte audiosteps;
word bufsize;
word curspeed;
word dummy[10];
Cmd5AInfo;
typedef struct
word st1;
byte err0;
byte dummy1[9];
byte err1;
byte err2;
byte dummy2[4];
Inf3Blk;
typedef struct
byte res1;
byte CA;
byte number;
byte res2;
byte Start[4];
OneTrk0;
typedef struct
word Len;
byte BegTrk;
byte EndTrk;
OneTrk0 Trk[11];
TOC10;
Cmd5AInfo Buf5A2A;
Inf12Blk Info12Buf;
Inf3Blk Info3Buf;
TOC10 TrkBuf;
/* ATAPI-пакеты для
разных запросов */
word
ClosePkt[6]=0x1B,0,3,0,0,0;
word
EjectPkt[6]=0x1B,0,2,0,0,0;
word
Info5A2A[6]=0x5A,0xAA,0,0,0x1C,0;
word
Info12[6]=0x12,0,sizeof(Inf12Blk),0,0,0;
word
LockPkt[6]=0x1E,0,1,0,0,0;
word
UnlockPkt[6]=0x1E,0,0,0,0,0;
word
Info3[6]=0x3,0,sizeof(Inf3Blk),0,0,0;
word
RdToc[6]=0x243,0,0,1,sizeof(TOC10),0;
word
PlaySt[6]=0x47,0,0,-1,255,0;
word
ReadSc[6]=0xBE,0,0,0,0,0;
word
ReadScM[6]=0xB9,0x0,0x0,0x0,0x0,0;
/* Буфер для чтения
секторов */
#define MaxSect 16U
byte Buffer[2352U*MaxSect];
void main(void)
int devtbl[8];
int workdrv;
int maxdrv;
int i;
maxdrv=FindAtapiCD(8,devtbl);
printf("Detected
%d ATAPI CD-ROM drive(s):\n",maxdrv); if(maxdrv<1)return;
int i;
for(i=0;i<maxdrv;i++)
printf("%1.1d: %3.3Xh:%c (irq
%d)\n",i+1,
Atp[devtbl[i]].port,
Atp[devtbl[i]].ms?'M':'S',
Atp[devtbl[i]].irq);
if(maxdrv>1)
do
workdrv=atoi(AskStr("Select
work drive>")); while((workdrv<1)||(workdrv>maxdrv));
workdrv=devtbl[workdrv-1];
else AskStr("Press Enter to
continue....");
workdrv=devtbl[0];
/* рабочий диск выбран
*/
DsbIrq(workdrv);
redrawscr:
clrscr();
gotoxy(1,15);
cprintf(
" 0-9 - Start play at track X E
- Eject disk\n\r"
" R - Rescan track list C
- Close tray\n\r"
" I - Some drive info M - Manufacturer Info\n\r"
" L - Lock tray U - unlock tray\n\r"
" X - Error type W - write CD to disk\n\r"
" Z - Redraw screen\n\r"
" Esc -
quit");
gotoxy(1,22);
cprintf(" Select >");
rein:
gotoxy(10,22);
while(kbhit())getch();
i=getch();
gotoxy(1,23);clreol();
switch(i)
/* треки - запуск на проигрывание */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':i-='0';
cprintf("Start playing....");
PlaySt[1]=TrkBuf.Trk[i].Start[1]<<8;
PlaySt[2]=TrkBuf.Trk[i].Start[2]|(TrkBuf.Trk[i].Start[3]<<0x8);
PlaySt[3]=TrkBuf.Trk[i+1].Start[1]|(TrkBuf.Trk[i+1].Start[2]<<0x8);
PlaySt[4]=TrkBuf.Trk[i+1].Start[3]<<8;
if(ExecATAPICMD(workdrv,0,PlaySt,NULL,0)!=-1)cprintf("Ok");
else printf("Fail");
break;
/* выбросить трей */
case 'E':
case 'e':
cprintf("Eject
disk....");
if(ExecATAPICMD(workdrv,0,EjectPkt,NULL,0)!=-1)cprintf("Ok");
else printf("Fail");
break;
/* втянуть диск */
case 'C':
case 'c':
cprintf("Close
tray....");
if(ExecATAPICMD(workdrv,0,ClosePkt,NULL,0)!=-1)cprintf("Ok");
else printf("Fail");
break;
/* смешанная информация
(команда 5A/2A) */
case 'I':
case 'i':
if(ExecATAPICMD(workdrv,1,Info5A2A,(void*)&Buf5A2A,sizeof(Buf5A2A))>0)
cprintf("MaxSpd: %d, CurSpd:
%d, Buff: %d Kb",
GetMSBWord(Buf5A2A.maxspeed),
GetMSBWord(Buf5A2A.curspeed),
GetMSBWord(Buf5A2A.bufsize));
else cprintf("Fail");
break;
/* информация от
производителя */
case 'M':
case 'm':
if(ExecATAPICMD(workdrv,1,Info12,(void*)&Info12Buf,sizeof(Info12Buf))>0)
cprintf("Manuf: [%8.8s],
Prod: [%16.16s], Rev: [%4.4s]",
Info12Buf.Manuf,
Info12Buf.Prod,
Info12Buf.Rev);
else cprintf("Fail");
break;
/* блокировка трея */
case 'l':
case 'L':cprintf("Lock
tray....");
if(ExecATAPICMD(workdrv,0,LockPkt,NULL,0)!=-1)cprintf("Ok");
else printf("Fail");
break;
/* разблокировка трея */
case 'u':
case
'U':cprintf("Unlock tray....");
if(ExecATAPICMD(workdrv,0,UnlockPkt,NULL,0)!=-1)cprintf("Ok");
else printf("Fail");
break;
/* расширенная информация
об ошибках */
case 'X':
case 'x':
if(ExecATAPICMD(workdrv,1,Info3,(void*)&Info3Buf,sizeof(Info3Buf))>0)
cprintf("Err0: %3.3Xh, Err1:
%3.3Xh, Err2: %3.3Xh",
Info3Buf.err0,
Info3Buf.err1,
Info3Buf.err2);
else cprintf("Fail");
break;
/* перечитать список
дорожек */
case 'R':
case 'r':
if(ExecATAPICMD(workdrv,1,RdToc,(void*)&TrkBuf,sizeof(TrkBuf))>0)
gotoxy(1,1);
cprintf("Num Ctrl/Addr
TrNum Start");
for(i=0;i<10;i++)
cprintf("\n\r");
clreol();
if(i<TrkBuf.EndTrk)
cprintf("%2.2d %3.3Xh %2.2X %2.2d:%2.2d:%2.2d",
i,
TrkBuf.Trk[i].CA,
TrkBuf.Trk[i].number,
TrkBuf.Trk[i].Start[1],
TrkBuf.Trk[i].Start[2],
TrkBuf.Trk[i].Start[3]);
else cprintf("Fail");
break;
/* чтение секторов на диск
(от начала и пока не остановят) */
case 'w':
case 'W':FILE *img;
word len;
long CurSector=0;
while(kbhit())getch();
img=fopen("CDImage.bin","wb");
if(img==NULL)cprintf("Can't
open save file !");
cprintf("Copying sectors.
Press any key to abort [");
do
cprintf("/");
StoreLBAToMSF(CurSector,((byte*)ReadScM)+3);
StoreLBAToMSF(CurSector+MaxSect,((byte*)ReadScM)+6);
((byte*)ReadScM)[9]=0x10;
len=ExecATAPICMD(workdrv,1,ReadScM,(void*)Buffer,sizeof(Buffer));
if(len==0xFFFF)
cprintf("]CD read fail");goto ecpy;;
if(len==0)
cprintf("]CD return zero bytes");goto ecpy;
cprintf("%u\\",len);
if(fwrite(Buffer,len,1,img)!=1)
cprintf("]Error
write to disk");
goto ecpy;
CurSector+=MaxSect;
while(!kbhit());
while(kbhit())getch();
cprintf("]Copy
stopped");
ecpy:
cprintf("(%ld)",CurSector);
fclose(img);
break;
case 'z':
case 'Z':goto redrawscr;
/* выход из програмы */
case 0x1b:goto finch;
case 0: goto rein;
goto rein;
finch:
clrscr();
#########################################################################
PS/ Изначально этот документ составлялся исключительно для внутреннего
использования по причине невозможности найти фирменное описание стандарта на
ATAPI-CD.
Поскольку вся
информация бралась из дизассемблированных драйверов, исходных текстов Linux'а,
отдизассемблированной прошивки ACER665, a также из описания SCSI-пакетов и
стандарта на ATAPI, то вполне возможны определенные расхождения со стандартом
(в существовании которого я не уверен). Несмотря на это, мне кажется, что даже
такое описание представляет определенную ценность.
В данное описание не
попала команда специального чтения данных (028h/0A8h) - у меня нет четких
данных о ее работе, а также несколько других, которые не используются в
драйверах и поддерживаются не всеми приводами. Это касается команд потрекового
проигрывания Audio-CD, команд смены диска в многодисковых приводах и т.п.
У меня осталась еще
кое-какая информация, например, тексты CD-драйверов, прошивок и т.п., которые
были сочтены несущественными или излишне громоздкими. Если необходимо, можно
вставить в этот документ выдержки из драйверов.
Для любитетлей
"подробных описаний" могу порекомендовать стандарт
SCSI-2 (X3T9.2).Там
есть большое количество интересной информации, но солидный объем (более 20 тыс.
строк или около 1.7 Mb), некоторые отличия SCSI от ATAPI и
"замусоренность" лишними деталями усложняют получение нужных сведений.
При необходимости
более детального ознакомления с процессом обмена (обмен по DMA, перекрывающиеся
команды и т.п.) можно прочитать стандарт на ATAPI устройства (X3T10). Однако,
описание конкретных CD команд там отсутствует (есть ссылка на SCSI).
Ревизии:
10.08.1996 - собраны и как-то систематизированы
отрывочные данные
19.09.1996 - первый раз отдан на растерзание.
20.12.1996 - добавлено кое-что из ATAPI и сказевого
описания.
14.02.1997 - уточнены термины, добавлено описание
некоторых битов, регистров и команд.
01.03.1997 - еще одно мелкое исправление терминов.
23.03.1997 - подправлено описание битов, добавлена
тестовая программа,
убрано "hex-по
умолчанию",
убраны ошибочные
сведения о бите 10h в 177h и другие
ошибки в алгоритме
выполнения команды.
29.03.1997 - В команде 4B на хвосте пакета был один лишний байт.
Предложения, замечания,
ругань и т.п.
просьба направлять по
адресу 2:5030/163.44
Константин Норватов
(Konstantin Norvatoff, KonNor)
Также, можно
попробовать найти меня по адресу: konnor@small.spb.su