ВЛАДИМИР МЕШКОВ
Запись дисков CD-R/RW в Linux
Часть 1
В данной статье рассматриваются примеры использования мультимедийных команд стандарта SCSI (SCSI Multimedia Commands–4, MMC-4) для записи на лазерные диски CD-R/RW различной информации – музыкальных треков и данных.
В первой части статьи рассматриваются вопросы организации хранения данных на компакт-диске, порядок использования SCSI Generic-драйвера для доступа к устройству чтения/записи компакт-дисков, определения параметров конфигурации устройства и управления режимами работы устройства
Работоспособность всех примеров программ была проверена для ОС Linux, ядро 2.4.27. Модель привода для чтения и записи компакт-дисков – TEAC CD-W524E Rev 1.0E. Привод подключен как Secondary Master, в ядре включены поддержка SCSI Generic-драйвера и режим SCSI-эмуляции для ATAPI-устройств (SCSI host adapter emulation for IDE ATAPI devices).
Физический формат данных на компакт-диске
Данные, записанные на компакт-диск, представляют собой последовательность малых кадров, small frame.
1 synchronization
pattern
(24 + 3 bits)
|
1 byte
of Sub-channel data
(14 + 3 bits)
|
12 bytes
of main
channel data
(12 x (14 + 3) bits)
|
4 bytes
of CIRC code
(4 x (14 + 3) bits)
|
12 bytes
of main
channel data
(12 x (14 + 3) bits)
|
4 bytes
of CIRC code
(4 x (14 + 3) bits)
|
588 bits
|
Рисунок 1. Формат малого кадра
Малый кадр содержит:
- 3 байта кода синхронизации;
- 1 байт данных субканала;
- 24 байта данных основного канала (две группы по 12 байт);
- 8 байт помехоустойчивого корректирующего кода CIRC, Cross Interleaved Read-Solomon Code (две группы по 4 байта).
Общая длина данных малого кадра составляет 36 байт.
При записи на компакт-диск данные субканала, основного канала и CIRC кодируются 14-разрядными EFM-кодом (Eight to Fourteen Modulation). Дополнительно к каждому полю добавляются три связывающих бита. Итоговый размер малого кадра, записанного на компакт-диск, равен 588 бит (рис.1). 98 последовательно расположенных малых кадров образуют кадр (Frame), или сектор, минимально адресуемую единицу данных на компакт-диске. Один кадр содержит 24 x 98 = 2352 байт данных основного канала и 98 байт субканала. Эти 98 байт в свою очередь делятся на 2 байта синхронизации и 96 байт данных. Каждый байт данных субканала размечен на битовые позиции, и, таким образом, субканал делится еще на 8 субканалов.
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
P
|
Q
|
R
|
S
|
T
|
U
|
V
|
W
|
Рисунок 2. Формат байта данных субканала
В одном кадре для каждого из этих субканалов содержится по 96 бит (12 байт) информации.
Из всех имеющихся в наличии субканалов основную информационную нагрузку несет Q-субканал. В нем содержится адресная информация кадра, информация о логической структуре компакт-диска, идентификационная информация диска или музыкального трека. Рассмотрим формат данных Q-субканала. Q-субканал содержит:
- 2 бита синхронизации (S0, S1);
- 4 бита поля управления (Control Field);
- 4 бита идентификатора режима данных Q-субканала (ADR);
- 72 бита (9 байт) данных (DATA-Q);
- 16 контрольной суммы полей управления, режима данных и поля данных (CRC).
Поле Control Field определяет тип информации, которая находится в основном канале кадра. Это поле может принимать следующие значения:
- 00x0b – 2 аудиоканала без предыскажения;
- 00x1b – 2 аудиоканала, предыскажения 50/15 мкс;
- 10x0b – 4 аудиоканала без предыскажений;
- 10x1b – 4 аудиоканала, предыскажения 50/15 мкс;
- 01x0b – трек данных, непрерывный режим записи (Disk-at-once, DAO);
- 01x1b – трек данных, инкрементный режим записи (Track-at-once (TAO), Session-at-once (SAO));
- 11xxb – зарезервировано.
Поле режима данных Q-субканала ADR определяет формат данных Q-субканала. Подробное описание форматов данных Q-субканала находится в спецификации SCSI MMC-4 ([1]), п. 4.2.4.4 «Q Sub-channel».
Блок данных основного канала предназначен для хранения информации – аудио или данных. У компакт-дисков, используемых для хранения аудио-информации, все 2352 байт блока основного канала заняты аудиоданными. Для хранения данных используется 6 основных форматов блока основного канала. Наиболее широкое применение получили три формата:
- режим данных 1, Yellow Book Mode 1;
- форма 1 режима данных 2, CD-ROM XA Mode 2 Form 1;
- форма 2 режима данных 2, CD-ROM XA Mode 2 Form 2.
Блок основного канала, содержащий данные, начинается с поля синхронизации Data Block Sync Pattern длиной 12 байт (рис. 3). За полем синхронизации находится заголовок блока Header данных длиной 4 байт. Заголовок блока содержит координаты блока данных в формате MSF (Minute/Second/Frame) и байт формата записи данных Data Mode. Значение формата блока содержат биты 0-1 байта Data Mode.
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
0x00
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0xFF
|
0x00
|
Рисунок 3. Структура поля синхронизации Data Block Sync Pattern
Формат данных Mode 1 представлен в таблице 1, форматы данных Mode 2 Form 1 и Mode 2 Form 2 – в таблицах 2 и 3.
Таблица 1. Mode 1 data format
Byte Offset
|
Field Length
|
Content
|
0
|
12
|
Data Block Sync pattern, поле синхронизации
|
12
|
3
|
Block MSF address (BCD), адрес блока в формате MSF
|
15
|
1
|
Data mode = 01, режим данных
|
16
|
2048
|
User data, данные пользователя
|
2064
|
4
|
CRC (P = (X16+X15+X2+X1)*(X16+X2+X+1)) Bytes 0 - 2063
|
2068
|
8
|
Zero fill
|
2046
|
172
|
P parity symbols
|
2248
|
104
|
Q parity symbols
|
Таблица 2. Mode 2 Form 1 data format
Byte Offset
|
Field Length
|
Content
|
0
|
12
|
Data Block Sync pattern, поле синхронизации
|
12
|
3
|
Block MSF address (BCD), адрес блока в формате MSF
|
15
|
1
|
Data mode = 2, режим данных
|
16
|
4
|
Sub-header, first copy, подзаголовок (первая копия)
|
20
|
4
|
Sub-header, second copy, подзаголовок (вторая копия)
|
24
|
2048
|
User data, данные пользователя
|
2072
|
4
|
CRC (P = (X16+X15+X2+X1)*(X16+X2+X+1)) Bytes 16 - 2071
|
2076
|
172
|
P parity symbols
|
2248
|
104
|
Q parity symbols
|
Таблица 3. Mode 2 Form 2 data format
Byte Offset
|
Field Length
|
Content
|
0
|
12
|
Data Block Sync pattern, поле синхронизации
|
12
|
3
|
Block MSF address (BCD), адрес блока в формате MSF
|
15
|
1
|
Data mode = 2, режим данных
|
16
|
4
|
Sub-header, first copy, подзаголовок (первая копия)
|
20
|
4
|
Sub-header, second copy, подзаголовок (вторая копия)
|
24
|
2324
|
User data, данные пользователя
|
2348
|
4
|
Optional CRC Bytes 16 - 2347
|
Пространство CD-ROM делится на три области (рис. 4):
- Lead-In Area, входная область диска.
- User Data Area, область данных пользователя, или область программ.
- Lead-Out Area, выходная область диска.
Lead-in Area
|
User Data Area
|
Lead-out Area
|
Рисунок 4. Общая структура CD-ROM
Lead-In-область предназначена для хранения информации об организации данных на компакт-диске. Q-субканал Lead-In-области содержит таблицу содержания диска, Table Of Contents (TOC). В TOC хранится информация о сессиях и стартовых адресах треков. Пример чтения и описания формата Q-субканала Lead-In-области (TOC) приведен в [5].
В User Data Area находятся треки с данными пользователя. Минимальное число треков, которое может быть записано на компакт-диск, равно 1. Максимальное число треков на диске равно 99. Треки нумеруются начиная с единицы.
Совокупность всех трех областей – Lead-In, User Data, Lead-Out – называется сессией. Любой CD-ROM, содержащий информацию, имеет минимум одну сессию. Максимальное число сессий зависит от используемого типа компакт-диска. Нумерация сессий начинается с единицы.
Lead-In
|
User Data
|
Lead-Out
|
|
Session 1
|
Session 2
|
….
|
Session X-1
|
|
|
|
|
Lead-In
|
User Data
|
Lead-Out
|
|
|
|
|
|
Logical Track
N
|
Logical Track
N+1
|
…
|
Logical Track
N+K-1
|
|
|
K Logical Tracks
|
|
Рисунок 5. Общая структура многосессионного компакт-диска
Lead-In-область первой сессии является Lead-In-областью всего диска. Lead-Out-область последней сессии является Lead-Out-областью диска. В User Data-области любой сессии находятся треки с данными.
Диски CD-R и CD-RW содержат две дополнительные области перед первой Lead-In-областью компакт-диска – Power Calibration Area (PCA) и Program Memory Area (PMA).
Рисунок 6. Структура CD-R и CD-RW диска
The Power Calibration Area, PCA – область калибровки мощности пишущего лазера. Область присутствует только на CD-R и CD-RW дисках. В свою очередь, PCA делится на две области – тестовую область (test area) и область счетчика (count area).
Тестовая область содержит 100 калибровочных участков. Область счетчика используется для учета количества использованных калибровочных участков. Для калибровки мощности пишущего лазера используется последовательность команд READ DISK INFORMATION/SEND OPC INFORMATION (см. [1]).
The Program Memory Area, PMA – область памяти программ. Область присутствует только на CD-R и CD-RW дисках и предназначена для учета использования User Data-области носителя. Q-субканал области PMA используется в качестве временной TOC при записи треков в инкрементном режиме – Track-at-once (TAO), Session-at-once (SAO). При записи диска в режиме Disk-at-once (DAO) данные в PMA не записываются.
SCSI Generic-драйвер. Общие сведения
SCSI Generic-драйвер (далее sg-драйвер) входит в состав ядра Linux и позволяет приложению пользователя посылать SCSI-команды устройству при условии, что устройство эти команды понимает. Доступ к sg-драйверу выполняется через специальные файлы устройства, которые находятся в каталоге /dev. Список некоторых файлов можно получить при помощи команды:
# ls -l /dev/sg[01]
crw------- 1 root root 21, 0 Apr 13 /dev/sg0
crw------- 1 root root 21, 1 Apr 13 /dev/sg1
|
Каждый файл соответствует одному подключенному SCSI-устройству.
Обращение к SCSI-устройству через sg-драйвер выполняется при помощи системного вызова ioctl следующим образом:
ioctl(sg_fd, SG_IO, struct sg_io_hdr *)
Первый параметр sg_fd – это дескриптор файла sg-устройства /dev/sg*, открытого при помощи системного вызова open( ). Третий параметр – структура следующего типа:
typedef struct sg_io_hdr
{
int interface_id; /*"S" for SCSI generic (required) */
int dxfer_direction; /* data transfer direction */
unsigned char cmd_len; /* SCSI command length ( <= 16 bytes) */
unsigned char mx_sb_len; /* max length to write to sbp */
unsigned short iovec_count; /* 0 implies no scatter gather */
unsigned int dxfer_len; /* byte count of data transfer */
void * dxferp; /* points to data transfer memory or scatter gather list */
unsigned char * cmdp; /* points to command to perform */
unsigned char * sbp; /* points to sense_buffer memory */
unsigned int timeout; /* MAX_UINT->no timeout (unit: millisec) */
unsigned int flags; /* 0 -> default, see SG_FLAG... */
int pack_id; /* unused internally (normally) */
void * usr_ptr; /* unused internally */
unsigned char status; /* scsi status */
unsigned char masked_status; /* shifted, masked scsi status */
unsigned char msg_status; /* messaging level data (optional) */
unsigned char sb_len_wr; /* byte count actually written to sbp */
unsigned short host_status; /* errors from host adapter */
unsigned short driver_status; /* errors from software driver */
int resid; /* dxfer_len - actual_transferred */
unsigned int duration; /* time taken by cmd (unit: millisec) */
unsigned int info; /* auxiliary information */
} sg_io_hdr_t; /* 64 bytes long (on i386) */
Данная структура определена в файле . Назначение основных полей структуры:
- interface_id – это поле должно содержать литеру «S»;
- dxfer_direction – направление передачи данных. Поле может принимать следующие значения (см. ):
- #define SG_DXFER_NONE (-1) – нет обмена данными;
- #define SG_DXFER_TO_DEV (-2) – передача данных устройству;
- #define SG_DXFER_FROM_DEV (-3) – прием данных от устройства.
- cmdp – указатель на командный пакет, посылаемый устройству;
- cmd_len – размер командного пакета. Если для ATAPI-устройств размер командного пакета фиксирован и равен 12 байт, то для SCSI-устройств размер пакета может принимать значения 6, 10, 12 и 16 байт;
- sbp – указатель на буфер SENSE DATA (данные о состоянии устройства после выполнения команды, [1, 5]);
- mx_sb_len – максимальный размер буфера SENSE DATA;
- sb_len_wr – реальный размер данных, сохраненных в буфере SENSE DATA;
- dxferp – указатель на буфер для данных, принимаемых от устройства или передаваемых устройству;
- dxfer_len – размер передаваемых/принимаемых данных;
- iovec_count – если это поле равно 0, то буфер для данных представляет собой простой линейный массив байт, и поле dxferp – указатель на этот массив. В противном случае dxferp указывает на массив структур типа:
typedef struct sg_iovec {
void * iov_base; /* starting address */
size_t iov_len; /* length in bytes */
} sg_iovec_t,
а поле iovec_count – число структур в этом массиве.
Подробная информация о sg-драйвере приведена в SCSI-Generic-HOWTO [4].
Рассмотрим порядок использования sg-драйвера на примере чтения PMA (Program Memory Area) CD-R/RW диска. Для чтения PMA устройству необходимо послать команду READ TOC/PMA/ATIP. Формат этой команды описан в [1], пример использования был рассмотрен в [5]. Для чтения PMA поле Format должно содержать значение 0011b. В ответ на команду READ TOC/PMA/ATIP устройство вернет блок данных следующего формата:
READ TOC/PMA/ATIP response data (Format = 0011b)
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
(MSB)
|
PMA Data Length
|
1
|
|
(LSB)
|
2
|
Reserved
|
3
|
Reserved
|
|
0
|
Reserved
|
1
|
ADR
|
CONTROL
|
2
|
TNO
|
3
|
POINT
|
4
|
Min
|
5
|
Sec
|
6
|
Frame
|
7
|
Zero
|
8
|
PMIN
|
9
|
PSEC
|
10
|
PFRAME
|
Рисунок 7. Формат данных PMA, Format Field = 0011b
Поле PMA Data Length содержит размер данных PMA, при этом длина самого поля (2 байта) не учитывается. Назначение каждого байта дескриптора PMA определяется значением поля ADR:
Таблица 4
ADR
|
Поле
|
Значение поля
|
|
1
|
TNO
|
0
|
|
POINT
|
Номер трека в BCD-коде
|
|
MIN,SEC,FRAME
|
Координаты конца трека
|
|
PMIN,PSEC,PFRAME
|
Координаты начала трека
|
|
2
|
TNO
|
0
|
|
POINT
|
0
|
|
MIN,SEC,FRAME
|
Идентификатор диска (6 цифр в BCD-коде)
|
|
PMIN
|
0
|
|
PSEC
|
Формат сессии:
00 - CDDA, CD-ROM,
10 - CD-I, 20 - CD-ROM-XA
|
|
|
PFRAME
|
0
|
|
Заголовочные файлы:
#include
#include
#include
#include
#include
#include
#include
#define SG_DEV "/dev/sg0" // имя файла устройства
// Макрос для пересчета координат сектора из MSF формата в LBA
#define MSF2LBA(Min, Sec, Frame) (((Min * 60 + Sec) * 75 + Frame) - 150)
int sg_fd; // файловый дескриптор
Следующая структура описывает формат данных PMA, представленный на рис. 7:
typedef struct {
__u8 rez; // reserved
__u8 ctrl :4; // Control
__u8 adr :4; // ADR
__u8 tno; // TNO (always 0)
__u8 point; // POINT
__u8 min; // AMIN
__u8 sec; // ASEC
__u8 frame; // AFRAME
__u8 zero; // 0
__u8 pmin; // PMIN
__u8 psec; // PSEC
__u8 pframe; // PFRAME
} __attribute__ ((packed)) pma_t;
Обмен данными с sg-драйвером выполняет функция send_cmd(). Параметры функции:
- cmd – указатель на командный пакет;
- cmdlen – длина командного пакета;
- direction – направление передачи данных;
- data – указатель на блок памяти для данных, передаваемых устройству или принимаемых от устройства. Если обмен данными не предусмотрен, этот параметр содержит значение NULL;
- datalen – размер блока данных, на который указывает data. Если data == NULL, то datalen == 0
- timeout – значения time-out.
int send_cmd(__u8 *cmd, __u8 cmdlen, unsigned int direction, __u8 *data, __u32 datalen, unsigned int timeout)
{
int k = 0;
sg_io_hdr_t io_hdr;
/* В sense_buffer будет сохранена информация о состоянии устройства после выполнения команды */
__u8 sense_buffer[32];
/* Формируем запрос к sg-драйверу – заполняем поля структуры sg_io_hdr_t необходимыми значениями */
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = "S";
io_hdr.cmd_len = cmdlen; // длина команды
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = direction; // направление передачи данных
io_hdr.dxfer_len = datalen; // размер данных
io_hdr.dxferp = data; // указатель на блок данных
io_hdr.cmdp = cmd; // указатель на командный пакет
io_hdr.sbp = sense_buffer;
io_hdr.timeout = timeout;
/* Посылаем устройству команду */
if(ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
perror("SG_IO ioctl");
return -1;
}
/* Отобразим содержимое sense_buffer, если при выполнении команды произошла ошибка. Это позволит установить причину ошибки */
if((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
if (io_hdr.sb_len_wr > 0) {
printf("Sense data: ");
for (k = 0; k < io_hdr.sb_len_wr; ++k) {
if ((k > 0) && (0 == (k % 10))) printf(" ");
printf("0x%02x ", sense_buffer[k]);
}
printf(" ");
}
if(io_hdr.masked_status)
printf("SCSI status=0x%x ", io_hdr.status);
if(io_hdr.host_status)
printf("Host_status=0x%x ", io_hdr.host_status);
if(io_hdr.driver_status)
printf("Driver_status=0x%x ", io_hdr.driver_status);
return -1;
}
return 0;
}
Проверку готовности устройства к приему команды выполняет функция test_unit_ready():
int test_unit_ready()
{
__u8 testCmdBlk[6];
/* Prepare TEST UNIT command */
memset(testCmdBlk, 0, 6);
if(send_cmd(testCmdBlk, 6, SG_DXFER_NONE, NULL, 0, 20000) < 0) {
printf("Unit not ready ");
return -1;
}
return 0;
}
Чтение PMA выполняет функция read_pma():
int read_pma()
{
int i, k;
__u8 read_pma_cmd[10];
__u8 *pma_data_buff; // здесь будут сохранены результаты чтения PMA
__u16 buff_size = 0xFFFF; // размер блока памяти для хранения считываемых данных
__u16 pma_data_length = 0; // реальная длина записей PMA
__u32 lba;
int pma_entries = 0; // число записей PMA
pma_t *pma;
/* Проверяем готовность устройства к приему команды */
if(test_unit_ready() < 0) exit(-1);
pma_data_buff = (__u8 *)malloc(buff_size);
memset(pma_data_buff, 0, buff_size);
/* Формируем командный пакет */
memset(read_pma_cmd, 0, 10);
read_pma_cmd[0] = 0x43; // код команды READ_TOC/PMA/ATIP
read_pma_cmd[2] = 3; // поле Format Field = 011b, читаем PMA
read_pma_cmd[7] = 0xFF;
read_pma_cmd[8] = 0xFF;
/* Посылаем устройству команду */
if(send_cmd(read_pma_cmd, 10, SG_DXFER_FROM_DEV, pma_data_buff, buff_size, 20000) < 0) return -1;
/* Считываем длину записей PMA. Размер поля PMA Data Length (2 байта) не учитывается */
memcpy(&pma_data_length, pma_data_buff, 2);
pma_data_length = __swab16(pma_data_length);
printf("PMA data length - %d ", pma_data_length);
/* Определяем число записей PMA */
pma_entries = (pma_data_length - 2)/11;
printf("PMA entries - %d ", pma_entries);
/* Размер данных PMA точно известен и равен pma_data_length. Выделяем блок памяти для данных PMA и копируем их туда
* из pma_data_buff. После этого можно освободить блок памяти, на который указывает pma_data_buff
*/
pma = (pma_t *)malloc(pma_data_length);
memset((void *)pma, 0, pma_data_length);
memcpy((void *)pma, pma_data_buff + 4, pma_data_length);
free(pma_data_buff);
/* Отображаем данные PMA */
printf("Entry ADR CTRL Point Zero Min Sec Frame PMin Psec PFrame LBA ");
for(i = 0; i < pma_entries; i++) {
printf("%d ", i);
printf("%X ", (pma + i)->adr);
printf("%X ", (pma + i)->ctrl);
printf("%X ", (pma + i)->point);
printf("%d ", (pma + i)->zero);
printf("%d ", (pma + i)->min);
printf("%d ", (pma + i)->sec);
printf("%d ", (pma + i)->frame);
printf("%d ", (pma + i)->pmin);
printf("%d ", (pma + i)->psec);
printf("%d ", (pma + i)->pframe);
lba = MSF2LBA((pma + i)->pmin, (pma + i)->psec, (pma + i)->pframe);
if((pma + i)->adr != 1) printf("--- ");
else printf("%u ", lba);
}
free(pma);
return 0;
}
Вызов функции read_pma() для чтения данных PMA выполняется из главной функции:
Открываем файл устройства. Обратите внимание на режим открытия – чтение/запись. Если устройство открыто в режиме «Только чтение» (O_RDONLY), то оно воспринимает команды (см. [4]):
- INQUIRY
- TEST UNIT READY
- REQUEST SENSE
- READ CAPACITY
- READ BUFFER
- READ(6) (10) and (12)
- MODE SENSE(6) and (10)
int main()
{
if((sg_fd = open(SG_DEV, O_RDWR)) < 0) {
perror("open");
return -1;
}
/* Считываем PMA */
if(read_pma() < 0) printf("Cannot read PMA ");
close(sg_fd);
return 0;
}
Полный текст данной программы находится в файле SG/read_pma.c.
Устанавливаем в устройство диск CD-RW, на котором записано 3 аудиотрека, и запускаем программу на выполнение. Результаты работы программы:
PMA data length - 46
PMA entries - 4
Entry ADR CTRL Point Zero Min Sec Frame PMin Psec PFrame LBA
0 2 0 0 0 54 88 82 0 0 0 ---
1 1 0 1 0 5 3 16 0 2 0 0
2 1 0 2 0 8 28 58 5 5 16 22741
3 1 0 3 0 12 30 21 8 30 58 38158
|
Для анализа полученных результатов воспользуемся таблицей 4.
Запись
|
Значение
|
0
|
Поля MIN/SEC/FRAME содержат идентификатор диска в BCD-коде. Поле PSEC содержит формат сессии.
В нашем примере это значение равно 0 – CD-DA, аудиодиск.
|
1-3
|
Поле POINT содержит номер трека, поля PMIN/PSEC/PFRAME содержат координаты начала трека, MIN/SEC/FRAME – координаты конца трека. Хорошо видно, что пауза между треками составляет
2 секунды.
|
Свойства, профили и страницы режимов устройства
Свойства и профили устройства
Прежде чем послать устройству какую-либо команду, надо убедиться в том, что устройство способно эту команду выполнить. Для этого необходимо установить, какие именно команды поддерживает устройство. Набор команд, поддерживаемых устройством, называется свойством (Features).
Одно устройство может поддерживать несколько свойств. Базовый набор свойств устройства называется профилем (Profile). Перечень всех существующих свойств и профилей приведен в спецификации SCSI MMC-4, п. 5 «Features and Profiles for Multi-Media Device».
GET CONFIGURATION response data format
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0-7
|
Feature Header
|
8-n
|
|
Рисунок 8. Формат блока данных, возвращаемого по команде GET CONFIGURATION
Feature Header
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
(MSB)
Data Length
(LSB)
|
1
|
2
|
3
|
4
|
Reserved
|
5
|
Reserved
|
6
|
(MSB)
|
Current Profile
(LSB)
|
|
|
|
|
|
|
|
|
|
|
Рисунок 9. Формат заголовка свойства
Поле Data Length содержит размер считанных данных, следующих за эти полем, в поле Current Profile находится значение текущего профиля устройства. Если свойство не поддерживается устройством, то команда GET CONFIGU-RATION вернет только заголовок свойства, и поле Data Length будет содержать значение 4 (2 поля Reserved по одному байту каждое + 2 байта поля Current Profile).
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
(MSB)
|
Feature Code
(LSB)
|
1
|
2
|
Reserved
|
Version
|
Persistent
|
Current
|
3
|
Additional Length
|
4-n
|
Feature Dependent Data
|
Рисунок 10. Общий формат дескриптора свойства
Назначение полей дескриптора свойства:
- Feature Code – код свойства. Каждое свойство имеет свой уникальный код. Список всех кодов приведен в спецификации [1], п. 5.3 «Feature Definitions».
- Persistent – если этот бит установлен в 0, то данное свойство может менять текущий статус. Если бит равен 1, то свойство всегда активно.
- Current – если бит установлен в 1, то данное свойство активно, т.е. устройство поддерживает набор команд, определенный этим свойством.
- Feature Dependent Data – данные, специфичные для указанного свойства.
Назначение полей командного пакета:
- RT – определяет тип данных, возвращаемых устройством. Поле может принимать следующие значения:
- 00b – устройство возвращает заголовок свойства и дескрипторы всех свойств, поддерживаемых устройством, даже если свойство не является активным.
- 01b – устройство возвращает заголовок свойства и дескрипторы активных свойств устройства (у которых бит Current установлен в единицу).
- 10b – устройство возвращает заголовок и дескриптор свойства, номер которого задан в поле Starting Feature Number. Если запрашиваемое свойство не поддерживается устройством, возвращается только заголовок свойства Feature Header (рис. 9).
- 11b – зарезервировано.
- Allocation Length – размер памяти, выделенной для данных.
GET CONFIGURATION CDB
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
OPERATION CODE (46h)
|
1
|
Reserved
|
RT
|
2
|
(MSB)
|
Starting Feature Number
(LSB)
|
3
|
4
|
Reserved
|
5
|
Reserved
|
6
|
Reserved
|
7
|
(MSB)
|
Allocation Length
(LSB)
|
8
|
9
|
Control
|
Рисунок 11. Формат команды GET CONFIGURATION
Рассмотрим пример. Необходимо выяснить, может ли устройство выполнить запись треков на компакт-диск в режиме TAO. Для этого надо установить, обладает ли устройство свойством «СD Track at Once». Код этого свойства равен 0x002D (см. [1]).
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
(MSB)
|
Feature Code = 002Dh
(LSB)
|
1
|
2
|
Reserved
|
Version = 2h
|
Persistent
|
Current
|
3
|
Additional Length = 04h
|
4
|
Resvd
|
BUF
|
Resvd
|
R-W Raw
|
R-W Pack
|
Test Write
|
CD-RW
|
R-W Sub-code
|
5
|
Reserved
|
6
|
(MSB)
|
Data Type Supported
(LSB)
|
Рисунок 12. Формат дескриптора свойства «СD Track at Once»
Устройство способно выполнить запись трека на компакт-диск в режиме TAO в том случае, если бит CD-RW установлен в единицу.
Рассмотрим функцию, выполняющую проверку наличия у устройства свойства «СD Track at Once» и значение бита CD-RW. Функция принимает один параметр – код свойства. Полный текст программы приведен в файле SG/get_conf.c.
int get_conf(__u16 f_num)
{
__u8 get_conf_cmd[10];
__u8 data_buff[16]; // результаты чтения
__u32 data_length = 0; // реальная длина данных
__u16 current_prof = 0; // значение текущего профиля
__u16 f_code = 0; // код свойства
/* Ждем готовность устройства */
if(test_unit_ready() < 0) exit(-1);
/* Формируем командный пакет */
memset(data_buff, 0, 16);
memset(get_conf_cmd, 0, 10);
get_conf_cmd[0] = 0x46; // код команды GET CONFIGURATION
get_conf_cmd[1] = 2; // RT= 10b
get_conf_cmd[8] = 16;
/* В поле Starting Feature Number заносим код свойства */
f_num = __swab16(f_num);
memcpy((get_conf_cmd + 2), (void *)&f_num, 2);
/* Посылаем устройству команду */
if(send_cmd(get_conf_cmd, 10, SG_DXFER_FROM_DEV, data_buff, 16, 20000) < 0) return -1;
/* Определяем длину считанных данных */
memcpy((void *)&data_length, data_buff, 4);
data_length = __swab32(data_length);
printf(" Feature data length - %u ", data_length);
/* Если длина считанных данных равна 4, то запрашиваемое свойство не поддерживается */
if(data_length == 4) return -1;
/* Определяем значение текущего профиля */
memcpy((void *)¤t_prof, data_buff + 6, 2);
current_prof = __swab16(current_prof);
printf("Current profile - 0x%.4X ", current_prof);
/* Код свойства, значение должно совпадать с параметром f_num */
memcpy((void *)&f_code, (data_buff + 8), 2);
f_code = __swab16(f_code);
printf("Feature Code - 0x%.4X ", f_code);
printf("Byte 4: 0x%X ", data_buff[12]);
/* Проверяем значение бита CD-RW. Если бит установлен в единицу – запрашиваемое свойство устройством поддерживается */
if(data_buff[12] & 0x02) printf("Feature CD TAO support ");
else return -1;
return 0;
}
Устанавливаем в привод CD-RW диск и запускаем программу на выполнение. Результаты работы:
Feature data length - 12
Current profile - 0x000A
Feature Code - 0x002D
Byte 4: 0x6
Feature CD TAO support
|
Текущий профиль устройства – CD-RW, см. п. 5.4.10 «Profile 000Ah: CD-RW» спецификации SCSI MMC-4 ([1]). Список свойств, соответствующих данному профилю, приведен в этом же пункте, в таблице 192 «Mandatory Feature for CD-RW». Свойство «CD Track at Once» входит в их число.
Теперь установим в привод диск CD-ROM и опять запустим программу на выполнение. Результаты работы программы:
Feature data length - 12
Current profile - 0x0008
Feature Code - 0x002D
Byte 4: 0x6
Feature CD TAO support
|
Свойство «CD Track at Once» приводом поддерживается, но текущий профиль – 0x0008, CD-ROM – не позволяет это свойство применять. Список свойств, соответствующих профилю «CD-ROM», приведен в таблице 188 «Mandatory Feature for CD-ROM», п. 5.4.8 спецификации SCSI MMC-4 ([1]).
Страницы режимов
Для установки или определения параметров работы устройства используются страницы режимов (Mode Page). Каждая страница режима характеризуется кодовым номером, длиной и набором параметров. В таблице 5 приведен список кодов некоторых страниц режимов. Полный перечень находится в спецификации SCSI MMC-4, п. 7.1.3 «Mode Pages».
Таблица 5
Код страницы
|
Назначение страницы
|
0x01
|
Параметры режима коррекции ошибок чтения/записи
|
0x05
|
Параметры режима записи
|
0x0D
|
Параметры CD-дисковода
|
0x0E
|
Параметры управления звуковоспроизведением
|
0x1A
|
Параметры энергопотребления
|
0x1C
|
Управление сообщениями о сбоях и неисправностях
|
0x1D
|
time-out и защита
|
Прием и передача страниц осуществляется при помощи списка параметров режима Mode Parameter List. Список страниц начинается с заголовка (Mode Parameter Header), за которым могут следовать одна или несколько страниц режимов (рис. 13).
Mode Parameter List
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0-7
|
Mode Parameter Header
|
8-n
|
Mode Page(s)
|
Рисунок 13. Формат списка Mode Parameter List
Mode Parameters Header
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
(MSB)
|
Mode Data Length
(LSB)
|
1
|
2
|
Reserved
|
3
|
Reserved
|
4
|
Reserved
|
5
|
Reserved
|
6
|
(MSB)
|
(LSB)
|
Рисунок 14. Формат заголовка списка страниц (Mode Parameter Header)
Поле Mode Data Length содержит размер блока данных, следующего сразу за этим полем, т.е. 6 оставшихся байт заголовка плюс длину запрашиваемой страницы. Если страница передается устройству, то значение поля Mode Data Length не используется (зарезервировано).
Страница параметров режима записи
Рассмотрим подробнее, что из себя представляет страница режима, на примере страницы параметров режима записи, Write Parameters Mode Page.
Write Parameters Page
Bit
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
PS
|
Reserved
|
Page Code (05h)
|
1
|
Page Length (32h or 36h)
|
2
|
Reserved
|
BUFE
|
LS_V
|
Test Write
|
Write Type
|
3
|
Multi-session
|
FP
|
Copy
|
Track Mode
|
4
|
Reserved
|
Data Block Type
|
5
|
Link Size
|
6
|
Reserved
|
7
|
Reserved
|
Initiator Application Code
|
8
|
Session Format
|
9
|
Reserved
|
10
|
(MSB)
Packet Size
(LSB)
|
11
|
12
|
13
|
14
|
(MSB)
|
Audio Pause Length
(LSB)
|
15
|
16
|
(MSB)
...
Media Catalog Number
...
(LSB)
|
17
|
……
|
30
|
31
|
32
|
(MSB)
...
International Standard Recording Code
...
(LSB)
|
33
|
……
|
46
|
47
|
48
|
Sub-header Byte 0
|
49
|
Sub-header Byte 1
|
50
|
Sub-header Byte 2
|
51
|
Sub-header Byte 3
|
52-55
|
Vendor Specific
|
Рисунок 15. Формат страницы параметров режима записи
Назначение полей:
- Page Code – код страницы, содержит значение 0x05.
- Page Length – размер страницы в байтах.
- Write Type – используемый режим записи:
- 01 – Track-at-once (TAO);
- 02 – Session-at-once (SAO);
- 03 – RAW.
- Test Write – режим имитации записи данных на носитель. Бит имеет значение только для режимов TAO и SAO.
- Track Mode – содержит значение поля управления Control Field Q-субканала при ADR = 1 (см. «Физический формат данных на компакт-диске»). В данной статье будет использовано только два значения этого поля:
- 0 – аудио-трек;
- 4 – трек данных.
- Multi-session – показывает, как закрытие текущей сессии влияет на открытие следующей:
- 00b – указатель B0 отсутствует в TOC, открытие новой сессии запрещено ([3, 5]);
- 01b – указатель B0 содержит значение FF:FF:FF, открытие новой сессии запрещено;
- 11b – открытие новой сессии разрешено. Указатель B0 содержит координаты начала следующей области программ.
- Data Block Type – определяет тип блока данных и его размер. Перечень всех значений этого поля находится в таблице 619 «Data Block Type Codes» спецификации MMC-4. В данной статье будет использовано только два значения:
- 0 – блок «сырых» данных размером 2352 байт (блок аудиоданных);
- 8 – блок данных размером 2048 байт, формат блока данных Mode 1.
- Session Format – формат сессии. Это значение записывается в поле PSEC указателя A0 таблицы содержания диска TOC. Поле может принимать следующие значения:
- 00h – диск CD-DA или CD-ROM
- 01h – диск CD-I
- 20h – диск CD-ROM XA
В поле Sub-Header устройству передается информация для заполнения подзаголовка сектора при записи на диск данных в формате Mode 2 Form 1/2 (см. табл. 2 и 3).
Во второй части статьи будут рассмотрены примеры программ, выполняющих запись на компакт-диск CD-R/RW различной информации, музыкальных треков и данных.
Литература, ссылки:
- Спецификация SCSI Multimedia Commands-4 (SCSI MMC-4), http://www.t10.org/ftp/t10/drafts/mmc4/mmc4r03d.pdf
- Спецификация SCSI-3 Multimedia Commands, http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf
- Specification for ATAPI DVD Devices, ftp.seagate.com/sff/INF-8090.pdf
- SCSI-Generic-HOWTO, http://www.linux.org/docs/ldp/howto/SCSI-Generic-HOWTO/index.html
- Мешков В. Пакетные команды интерфейса ATAPI. – Журнал «Системный администратор», № 9(22), сентябрь 2004 г. – 70-84 с.