|
Данный документ никоим образом не является полным описанием стандартного 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 - информация о реальных метках положения (Read HEADER)
Пакет: db 44h db SL ; бит 2 - что записывать в выходной буфер ; (исходный номер сектора или считанный) db 0 ; * db M,S,F ; Номер сектора db 0 ; * dw Len ; длина выдаваемой информации db 3*dup(0); *
Команда информационная, выдает следующую таблицу из 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 ; *
Команда передачи данные. Если начало=конец, производится позиционирование на указанную позицию и тест читабельности. В этом случае данные не передаются.
-------------------------------------------------------------------------- Команда 0BEh - читать данные в терминах секторов Пакет: 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│No sense data │ │01h│Recovered error │ │02h│Not ready │ │03h│Medium error │ │04h│Hardware error │ │05h│Illegal request │ │06h│Unit attention │ │07h│Data protect │ │08h│(reserved) │ │09h│(reserved) │ │0ah│(reserved) │ │0bh│Aborted command │ │0ch│(reserved) │ │0dh│(reserved) │ │0eh│Miscompare │ │0fh│(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 │ head │ data │ EDC │ zero │ ECC │ │ │ 12 │ 4 │ 2048 │ 4 │ 8 │ 276 │ ├───────────────────────────────┼──────┼──────┼──────┴─────┴──────┴─────┤ │ Данные (желтая, mode2): │ sync │ head │ data │ │ │ 12 │ 4 │ 2336 │ ├───────────────────────────────┼──────┼──────┼──────┬──────┬─────┬─────┤ │ XA данные (зеленая, │ sync │ head │ sub │ data │ EDC │ ECC │ │ mode2 form1): │ 12 │ 4 │ 8 │ 2048 │ 4 │ 276 │ ├───────────────────────────────┼──────┼──────┼──────┼──────┴─────┼─────┤ │ XA данные (зеленая, │ sync │ head │ sub │ data │ EDC │ │ mode2 form2): │ 12 │ 4 │ 8 │ 2324 │ 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 - Регистр уточнения причины прерывания: 01h - Тип передачи: 0 - передача данных, 1 - передача AP 02h - направление передачи: 0 - в CD, 1 - из CD 04h - индицирует освобождение шины ATA. (как правило = 0) F8h - Зарезервировано Сочетания битов 1 и 2 имеют следующий смысл: 0 - Ввод блока данных (в CD) 1 - Ввод Atapi-пакета 2 - Вывод блока данных (из CD) 3 - Выдача состояния завершения команды
173h - Зарезервирован
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 на хвосте пакета был один лишний байт.
Автор статьи Константин Норватов (Konstantin Norvatoff, KonNor): konnor@small.spb.su
|
|