Чтение rma области dvd-r/-rw диска☛Технология DVD ✎ |
Операция чтения RMA области позволяет получить информацию о логической структуре DVD-диска: режиме записи данных (DAO/Incremental), расположении (координатах) RZone и Border областей, количестве записанных на диск RZone.
Отметим, что эту информацию можно прочитать как из RMA, так и из последней Border-out области диска. Для чтения RMD блоков, записанных в RMA область, поле Format команды READ DVD STRUCTURE должно быть равно 0x0D. В поле Address записывается стартовый номер сектора RMA области, начиная с которого будет выполняться чтение, в поле Allocation Length – размер считываемых данных. За одно обращение к диску можно прочитать один RMD блок размером 32768 байт (16 секторов).
Давайте проследим, как изменяется содержимое RMA области DVD-RW диска при записи на диск данных в режиме Sequentinal. Для этого из Format 1 RMD будем считывать поля Field 0 для определения статуса диска, и Field 4, содержащее координаты первых 254 RZone (см. табл. 6). Для чтения полей Field 0 и Field 4 из Format 1 RMD необходимо определить смещение к ним в секторах относительно начала RMA. Это смещение определяется по формуле: Start_Sector = 16 x (5 + N) + F + 1, где 16 – это число секторов в одном RMD блоке, N – номер RMD блока, из которого поле Field будет считываться, F – номер поля (0 или 4).
Для чтения Field 4 необходимо пропустить 16 х 5 секторов, принадлежащих RMD Set (см. рис. 16), и затем сместится к нужному RMD блоку. Пятый сектор этого блока и будет искомым полем Field 4.
Чтение RMA области DVD-RW диска выполняет функция read_RMA:__u8 disk_status = 0; // статус диска
__u8 erase_code = 0;
__u16 alloc_size = SIZE;
__u16 EOC = 0; // Erase Operation Count
__u16 RMD_Format = 0; // from RMD Header (Field 0)
__u16 Inv_RZone_num = 0; // Invisible RZone Number (Last Rzone Number)
__u32 addr; // Поле Address командного пакета
__u32 LRS = 0; // Last Recorded RMA sector number
__u32 F3_RMD_Set_Pointer = 0; // Format 3 RMD Set Pointer
__u32 Update_Counter = 0;
__u32 EI1 = 0, EI2 = 0; // Erase Information 1/2
__u32 Start_RZone = 0; // Start Sector Number of RZone #n
__u32 LRA_RZone = 0; // Last Recorded Address of RZone #n
memset(buff, 0, SIZE);
/* Из Format 2 RMD считываем поля Field #0 (RMD Header) для определения статуса диска и
* формата остальных RMD блоков, Field #1 для опр. количества операций стирания и перезаписи,
* Field #2 RMD для опр. кода операции стирания и участка с которого cтиралась информация
*/
memset(read_dvd_struct_cmd, 0, 12);
read_dvd_struct_cmd[0] = 0xAD;
read_dvd_struct_cmd[5] = 1; // адрес сектора для считывания
read_dvd_struct_cmd[7] = 0x0D; // read RMA
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) <0) return -1;
/* Определяем номер последнего сектора, записанного в RMA */
memcpy((void *)&LRS, buff + 4, 4);
LRS = __swab32(LRS);
printf("Last recorded RMA sector number: %u\n", LRS);
/* Field #0, первый сектор RMD блока. Отсчет секторов ведется с 0, 0-й сектор - это Linking Loss area */
*((__u8 *)&RMD_Format) = RMD[1];
*((__u8 *)&RMD_Format + 1) = RMD[0];
disk_status = RMD[2];
printf(“Field 0 (RMD Header)\n”);
printf("RMD Format: %d\n", RMD_Format);
printf("Disk Status: %.2Xh\n", disk_status);
/* Field #1, 2-й сектор RMD блока */
memcpy((void *)&Update_Counter, RMD + 0x800, 4);
Update_Counter = __swab32(Update_Counter);
memcpy((void *)&F3_RMD_Set_Pointer, (RMD + 4 + 0x800), 4);
F3_RMD_Set_Pointer = __swab32(F3_RMD_Set_Pointer);
*((__u8 *)&EOC) = *(RMD + 13 + 0x800);
*((__u8 *)&EOC + 1) = *(RMD + 12 + 0x800);
printf(“Format 2 RMD Set Field 1\n”);
printf("Update Counter: %u\n", Update_Counter);
printf("Format 3 RMD Set Pointer: %u\n", F3_RMD_Set_Pointer);
printf("Erase Operation Counter: %d\n", EOC);
/* Field #2, 3-й сектор RMD блока */
erase_code = RMD[0 + 0x1000];
memcpy((void *)&EI1, RMD + 2 + 0x1000, 4);
EI1 = __swab32(EI1);
memcpy((void *)&EI2, RMD + 6 + 0x1000, 4);
int read_RMA()
{
#define SIZE 6152 // 2048 * 3 (3 сектора: Field 0, 1, 2) и 8 байт заголовка
#define SIZE1 2056 // 2048 (1 сектор) и 8 байт заголовка
int i = 0, n = 0, k = 0;
__u8 read_dvd_struct_cmd[12];
__u8 buff[SIZE]; // буфер для данных
__u8 *RMD = buff + 8; // указатель на начало RMD области
EI2 = __swab32(EI2);
printf(“Format 2 RMD Set Field 2\n”);
printf("Erase Operation Code: %d\n", erase_code);
printf("Erase Information 1: %u\n", EI1);
printf("Erase Information 2: %u\n\n", EI2);
}
/* Cчитываем информацию об RZone */
alloc_size = SIZE1; // размер данных для чтения – 1 сектор
memset(buff, 0, SIZE);
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
/* Пропускаем первые пять RMD блоков формата Format 2,
* и считываем все Field #0 и Field #4 из каждого следующего RMD блока формата Format 1.
* Field #0 - это 1й сектор от начала RMD блока, а Field #4 - 5й сектор от начала RMD блока
* формата Format 1 (включая Linking Loss area)
*/
for(k = 5;;k++) {
addr = 16 * k + 1;
if(addr > LRS) break;
read_dvd_struct_cmd[2] = *((__u8 *)&addr + 3);
read_dvd_struct_cmd[3] = *((__u8 *)&addr + 2);
read_dvd_struct_cmd[4] = *((__u8 *)&addr + 1);
read_dvd_struct_cmd[5] = *((__u8 *)&addr);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 200) < 0) return -1;
*((__u8 *)&RMD_Format + 1) = RMD[0];
*((__u8 *)&RMD_Format) = RMD[1];
disk_status = RMD[2];
printf("\nField #0 (sector %u)\n", addr);
printf("RMD Format: %d\t", RMD_Format);
printf("Disk Status: %.2X\n", disk_status);
/* Считываем Field #4 */
addr += 4;
read_dvd_struct_cmd[2] = *((__u8 *)&addr + 3);
read_dvd_struct_cmd[3] = *((__u8 *)&addr + 2);
read_dvd_struct_cmd[4] = *((__u8 *)&addr + 1);
read_dvd_struct_cmd[5] = *((__u8 *)&addr);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 200) < 0) return -1;
printf("\nField #4 (sector %u)\n", addr);
*((__u8 *)&Inv_RZone_num + 1) = RMD[0];
*((__u8 *)&Inv_RZone_num) = RMD[1];
printf("Invisible/Incomplete RZone Number: %d\n", Inv_RZone_num);
printf("RZone\tSTART\tLAST\n");
for(i = 1, n = 16; i <= Inv_RZone_num; i++, n += 8) {
memcpy((void *)&Start_RZone, RMD + n, 4);
Start_RZone = __swab32(Start_RZone);
memcpy((void *)&LRA_RZone, RMD + n + 4, 4);
LRA_RZone = __swab32(LRA_RZone);
printf("%-d\t%-d\t%-d\n", i, Start_RZone, LRA_RZone);
}
}
printf("\n");
return 0;
}
Полный текст программы чтения RMA области DVD-RW диска находится в файле
SOURCE/DVD/READ_DVD_STRUCT/read_RMA_DVDRW_SEQ.c.
Устанавливаем в привод полностью очищенный DVD-RW диск и запускаем программу на выполнение. Проанализируем
результаты работы программы.
Вначале программа определяет номер последнего сектора, записанного в RMA область:
Last recorded RMA sector number: 111
Далее считывается Field 0 из первого блока RMD Set:
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Значение RMD Format = 2 говорит о том, что поля Field 1~14 данного RMD записаны в формате Format 2. Диск записан в
режиме Sequential, и текущее состояние диска определяет поле Disk Status из RMD блока формата Format 1 (см. таблицу
10).
Считывается Format 2 RMD Field 1:
Format 2 RMD Set Field 1
Update Counter: 50
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 17
Текущий RMD Set перезаписывался 50 раз. С диска 17 раз стиралась информация. RMD блоков формата Format 3 в RMA
области нет, и соответствующий указатель установлен в 0.
Считывается Format 2 RMD Field 2:
Format 2 RMD Set Field 2
Erase Operation Code: 1
Erase Information 1: 132144
Erase Information 2: 2495151
Диск подвергался полной очистке, код операции очистки равен 1. Адрес стартового сектора, с которого начиналась
очистка информации, равен 132144. При полной очистке диска информация стирается из части RMA области и области
данных пользователя + три ECC блока (см. [2], табл. 109 «Blanking Types for DVD-RW»). В RMA области нетронутыми
остаются RMA Lead-in и шесть первых ECC блоков в составе RMD Set и одного Format 1 RMD блока. Зная, что стартовый
адрес RMA области равен 132032 (203C0h, см. [2], рис.8), определим, с какого адреса будет выполняться операция полной
очистки диска: 132032 + 16 * 7 = 132144.
Закончили чтение RMD Set, и переходим к чтению инфомации об RZone:
Field 0 (sector 81)
RMD Format: 1 Disk Status: 00
Field 4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field 0 (sector 97)
RMD Format: 1 Disk Status: 00
Field 4 (sector 101)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Тут все понятно – поле Disk Status равно 0, это значит что диск не содержит информации в области данных пользователя.
Теперь записываем на DVD-RW диск один трек размером 706240 Кбайт, или 353120 секторов. Режим записи - Incremental.
Запускаем программу на выполнение и анализируем результаты.
Last recorded RMA sector number: 143
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Format 2 RMD Set Field 1
Update Counter: 50
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 17
Format 2 RMD Set Field 2
Erase Operation Code: 1
Erase Information 1: 132144
Erase Information 2: 2495151
Field #0 (sector 81)
RMD Format: 1 Disk Status: 00
Field #4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field #0 (sector 97)
RMD Format: 1 Disk Status: 02
Field #4 (sector 101)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 0
2 549744 0
Field #0 (sector 113)
RMD Format: 1 Disk Status: 02
Field #4 (sector 117)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 549727
2 578416 0
Field #0 (sector 129)
RMD Format: 1 Disk Status: 02
Field #4 (sector 133)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 549727
2 578416 0
Хорошо видно, как меняется содержание RMA области при записи на диск новых данных. Самую «свежую» информацию
содержит сектор, который находится по адресу (Last Recorded RMA Sector Number – 10), но это только для нашего случая,
т.к. мы ограничили число RZone до 254 и не двигаемся дальше поля Field 4 RMD блока.
А теперь выполним минимальную очистку диска и снова прочитаем RMA.
Last recorded RMA sector number: 111
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Format 2 RMD Set Field 1
Update Counter: 51
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 18
Format 2 RMD Set Field 2
Erase Operation Code: 2
Erase Information 1: 132144
Erase Information 2: 196607
Field #0 (sector 81)
RMD Format: 1 Disk Status: 04
Field #4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field #0 (sector 97)
RMD Format: 1 Disk Status: 04
Field #4 (sector 101)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Изменились поля Update Counter, счетчик количества операций стирания и код операции стирания – все значения
увеличились на 1. Поле Disk Status (Field #0) содержит значение 04 – была выполнена операция минимальной очистки
диска (см. табл.10).
В отличии от DVD-RW, RMA область DVD-R диска не содержит набора RMD Set (рис.66), поэтому при чтении RMD нет
необходимости смещаться на 5 ECC блоков вперед, и цикл чтения полей Field 4 RMD блоков примет следующий вид:
for(k = 0;;k++) {
. . .
/* Тело цикла аналогично предыдущему примеру */
. . .
}
Копию последнего записанного в RMA область RMD блока (точнее, пять копий) содержит последняя Border-out область
DVD-R/-RW диска, поэтому для получения информации о диске RMD блоки предпочтительнее считывать из этой области.
Чтобы прочитать RMD блок из последней Border-out, поле Format команды READ DVD STRUCTURE должно быть равно
0x0C, в поле Address указывается номер поля Field, содержимое которого мы хотим прочитать.
Чтение полей RMD блока из последней Border-out выполняет следующая функция:
int read_RMD()
{
/* Размер считываемых данных (в байтах) */
#define SIZE 2052 // 2048 bytes (1 sector) + 4 header`s bytes
int i, n = 16;
__u8 read_dvd_struct_cmd[12];
__u8 buff[SIZE]; // буфер для считываемых данных
__u8 *RMD = buff + 4; // указатель на начало данных RMD блока
__u8 disk_status = 0;
__u16 alloc_size = SIZE;
__u16 dvd_data_len = 0;
__u16 Inv_RZone_num = 0; // номер последней невидимой/незавершенной RZone
__u32 Start_BOUT = 0, Start_RZone = 0, LRA_RZone = 0;
/* Считываем Field #0 и проверяем статус диска */
memset(buff, 0, SIZE);
memset(read_dvd_struct_cmd, 0, 12);
read_dvd_struct_cmd[0] = 0xAD;
read_dvd_struct_cmd[7] = 0x0C; // read RMD in the last Border-out
read_dvd_struct_cmd[5] = 0; // Address = 0, read Field #0
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Размер считанных данных */
*((__u8 *)&dvd_data_len) = buff[1];
*((__u8 *)&dvd_data_len + 1) = buff[0];
dvd_data_len += 2; // учитываем длину самого поля (2 bytes)
printf("DVD STRUCTURE Data Length: %d\n", dvd_data_len);
/* Определяем статус диска */
disk_status = *(RMD + 2);
printf("Disk status: %d\n", disk_status);
/* Считываем Field #3, информацию о Border Zone */
memset(buff, 0, SIZE);
read_dvd_struct_cmd[5] = 3; // Address = 3, read Field #3
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Отображаем информацию о стартовых координатах Border-out областей диска */
for(i = 0; i <= 2044; i += 4) {
memcpy((void *)&Start_BOUT, RMD + i, 4);
if(!Start_BOUT) break;
Start_BOUT = __swab32(Start_BOUT);
printf("Start Sector Number of Border-out #%d: %u\n", i/4 + 1, Start_BOUT);
}
/* Считываем Field #4, информацию об RZone */
memset(buff, 0, SIZE);
read_dvd_struct_cmd[5] = 4; // Address = 4, read RMD #4
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Определяем номер невидимой/незавершенной RZone */
*((__u8 *)&Inv_RZone_num + 1) = RMD[0];
*((__u8 *)&Inv_RZone_num) = RMD[1];
printf("Invisible/Incomplete RZone Number: %d\n", Inv_RZone_num);
/* Отображаем значения стартовой координаты и последнего записанного сектора данных RZone */
printf("RZone\tSTART\tLAST\n");
for(i = 1; i <= Inv_RZone_num; i++, n += 8) {
memcpy((void *)&Start_RZone, RMD + n, 4);
Start_RZone = __swab32(Start_RZone);
memcpy((void *)&LRA_RZone, RMD + n + 4, 4);
LRA_RZone = __swab32(LRA_RZone);
printf("%-d\t%-d\t%-d\n", i, Start_RZone, LRA_RZone);
}
return 0;
}
Результат работы функции для DVD-RW диска, на котором записано два трека (размер первого трека – 718720 секторов,
размер второго – 330992 секторов):
DVD STRUCTURE Data Length: 30724
Disk status: 2
Start Sector Number of Border-out #1: 915344
Start Sector Number of Border-out #2: 1284240
Invisible/Incomplete RZone Number: 3
RZone START LAST
1 196608 915327
2 953232 1284223
3 1291920 0
Значение статуса диска = 2, что соответствует режиму записи Incremental. Физический адрес стартового сектора первого
трека – 196608, второго трека – 756624, третьего (невидимого) трека – 1095312. Для перевода в логический формат от
каждого значения надо отнять 30000h. Информация о порядке определения стартовых адресах треков понадобится нам в
следующем пункте, при рассмотрении режима записи Incremental.
Полный текст программы чтения RMD блоков из Border-out области находится в файле
SOURCE/DVD/READ_DVD_STRUCT/read_RMD.c.
Отметим, что эту информацию можно прочитать как из RMA, так и из последней Border-out области диска. Для чтения RMD блоков, записанных в RMA область, поле Format команды READ DVD STRUCTURE должно быть равно 0x0D. В поле Address записывается стартовый номер сектора RMA области, начиная с которого будет выполняться чтение, в поле Allocation Length – размер считываемых данных. За одно обращение к диску можно прочитать один RMD блок размером 32768 байт (16 секторов).
Давайте проследим, как изменяется содержимое RMA области DVD-RW диска при записи на диск данных в режиме Sequentinal. Для этого из Format 1 RMD будем считывать поля Field 0 для определения статуса диска, и Field 4, содержащее координаты первых 254 RZone (см. табл. 6). Для чтения полей Field 0 и Field 4 из Format 1 RMD необходимо определить смещение к ним в секторах относительно начала RMA. Это смещение определяется по формуле: Start_Sector = 16 x (5 + N) + F + 1, где 16 – это число секторов в одном RMD блоке, N – номер RMD блока, из которого поле Field будет считываться, F – номер поля (0 или 4).
Для чтения Field 4 необходимо пропустить 16 х 5 секторов, принадлежащих RMD Set (см. рис. 16), и затем сместится к нужному RMD блоку. Пятый сектор этого блока и будет искомым полем Field 4.
Чтение RMA области DVD-RW диска выполняет функция read_RMA:__u8 disk_status = 0; // статус диска
__u8 erase_code = 0;
__u16 alloc_size = SIZE;
__u16 EOC = 0; // Erase Operation Count
__u16 RMD_Format = 0; // from RMD Header (Field 0)
__u16 Inv_RZone_num = 0; // Invisible RZone Number (Last Rzone Number)
__u32 addr; // Поле Address командного пакета
__u32 LRS = 0; // Last Recorded RMA sector number
__u32 F3_RMD_Set_Pointer = 0; // Format 3 RMD Set Pointer
__u32 Update_Counter = 0;
__u32 EI1 = 0, EI2 = 0; // Erase Information 1/2
__u32 Start_RZone = 0; // Start Sector Number of RZone #n
__u32 LRA_RZone = 0; // Last Recorded Address of RZone #n
memset(buff, 0, SIZE);
/* Из Format 2 RMD считываем поля Field #0 (RMD Header) для определения статуса диска и
* формата остальных RMD блоков, Field #1 для опр. количества операций стирания и перезаписи,
* Field #2 RMD для опр. кода операции стирания и участка с которого cтиралась информация
*/
memset(read_dvd_struct_cmd, 0, 12);
read_dvd_struct_cmd[0] = 0xAD;
read_dvd_struct_cmd[5] = 1; // адрес сектора для считывания
read_dvd_struct_cmd[7] = 0x0D; // read RMA
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) <0) return -1;
/* Определяем номер последнего сектора, записанного в RMA */
memcpy((void *)&LRS, buff + 4, 4);
LRS = __swab32(LRS);
printf("Last recorded RMA sector number: %u\n", LRS);
/* Field #0, первый сектор RMD блока. Отсчет секторов ведется с 0, 0-й сектор - это Linking Loss area */
*((__u8 *)&RMD_Format) = RMD[1];
*((__u8 *)&RMD_Format + 1) = RMD[0];
disk_status = RMD[2];
printf(“Field 0 (RMD Header)\n”);
printf("RMD Format: %d\n", RMD_Format);
printf("Disk Status: %.2Xh\n", disk_status);
/* Field #1, 2-й сектор RMD блока */
memcpy((void *)&Update_Counter, RMD + 0x800, 4);
Update_Counter = __swab32(Update_Counter);
memcpy((void *)&F3_RMD_Set_Pointer, (RMD + 4 + 0x800), 4);
F3_RMD_Set_Pointer = __swab32(F3_RMD_Set_Pointer);
*((__u8 *)&EOC) = *(RMD + 13 + 0x800);
*((__u8 *)&EOC + 1) = *(RMD + 12 + 0x800);
printf(“Format 2 RMD Set Field 1\n”);
printf("Update Counter: %u\n", Update_Counter);
printf("Format 3 RMD Set Pointer: %u\n", F3_RMD_Set_Pointer);
printf("Erase Operation Counter: %d\n", EOC);
/* Field #2, 3-й сектор RMD блока */
erase_code = RMD[0 + 0x1000];
memcpy((void *)&EI1, RMD + 2 + 0x1000, 4);
EI1 = __swab32(EI1);
memcpy((void *)&EI2, RMD + 6 + 0x1000, 4);
int read_RMA()
{
#define SIZE 6152 // 2048 * 3 (3 сектора: Field 0, 1, 2) и 8 байт заголовка
#define SIZE1 2056 // 2048 (1 сектор) и 8 байт заголовка
int i = 0, n = 0, k = 0;
__u8 read_dvd_struct_cmd[12];
__u8 buff[SIZE]; // буфер для данных
__u8 *RMD = buff + 8; // указатель на начало RMD области
EI2 = __swab32(EI2);
printf(“Format 2 RMD Set Field 2\n”);
printf("Erase Operation Code: %d\n", erase_code);
printf("Erase Information 1: %u\n", EI1);
printf("Erase Information 2: %u\n\n", EI2);
}
/* Cчитываем информацию об RZone */
alloc_size = SIZE1; // размер данных для чтения – 1 сектор
memset(buff, 0, SIZE);
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
/* Пропускаем первые пять RMD блоков формата Format 2,
* и считываем все Field #0 и Field #4 из каждого следующего RMD блока формата Format 1.
* Field #0 - это 1й сектор от начала RMD блока, а Field #4 - 5й сектор от начала RMD блока
* формата Format 1 (включая Linking Loss area)
*/
for(k = 5;;k++) {
addr = 16 * k + 1;
if(addr > LRS) break;
read_dvd_struct_cmd[2] = *((__u8 *)&addr + 3);
read_dvd_struct_cmd[3] = *((__u8 *)&addr + 2);
read_dvd_struct_cmd[4] = *((__u8 *)&addr + 1);
read_dvd_struct_cmd[5] = *((__u8 *)&addr);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 200) < 0) return -1;
*((__u8 *)&RMD_Format + 1) = RMD[0];
*((__u8 *)&RMD_Format) = RMD[1];
disk_status = RMD[2];
printf("\nField #0 (sector %u)\n", addr);
printf("RMD Format: %d\t", RMD_Format);
printf("Disk Status: %.2X\n", disk_status);
/* Считываем Field #4 */
addr += 4;
read_dvd_struct_cmd[2] = *((__u8 *)&addr + 3);
read_dvd_struct_cmd[3] = *((__u8 *)&addr + 2);
read_dvd_struct_cmd[4] = *((__u8 *)&addr + 1);
read_dvd_struct_cmd[5] = *((__u8 *)&addr);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 200) < 0) return -1;
printf("\nField #4 (sector %u)\n", addr);
*((__u8 *)&Inv_RZone_num + 1) = RMD[0];
*((__u8 *)&Inv_RZone_num) = RMD[1];
printf("Invisible/Incomplete RZone Number: %d\n", Inv_RZone_num);
printf("RZone\tSTART\tLAST\n");
for(i = 1, n = 16; i <= Inv_RZone_num; i++, n += 8) {
memcpy((void *)&Start_RZone, RMD + n, 4);
Start_RZone = __swab32(Start_RZone);
memcpy((void *)&LRA_RZone, RMD + n + 4, 4);
LRA_RZone = __swab32(LRA_RZone);
printf("%-d\t%-d\t%-d\n", i, Start_RZone, LRA_RZone);
}
}
printf("\n");
return 0;
}
Полный текст программы чтения RMA области DVD-RW диска находится в файле
SOURCE/DVD/READ_DVD_STRUCT/read_RMA_DVDRW_SEQ.c.
Устанавливаем в привод полностью очищенный DVD-RW диск и запускаем программу на выполнение. Проанализируем
результаты работы программы.
Вначале программа определяет номер последнего сектора, записанного в RMA область:
Last recorded RMA sector number: 111
Далее считывается Field 0 из первого блока RMD Set:
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Значение RMD Format = 2 говорит о том, что поля Field 1~14 данного RMD записаны в формате Format 2. Диск записан в
режиме Sequential, и текущее состояние диска определяет поле Disk Status из RMD блока формата Format 1 (см. таблицу
10).
Считывается Format 2 RMD Field 1:
Format 2 RMD Set Field 1
Update Counter: 50
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 17
Текущий RMD Set перезаписывался 50 раз. С диска 17 раз стиралась информация. RMD блоков формата Format 3 в RMA
области нет, и соответствующий указатель установлен в 0.
Считывается Format 2 RMD Field 2:
Format 2 RMD Set Field 2
Erase Operation Code: 1
Erase Information 1: 132144
Erase Information 2: 2495151
Диск подвергался полной очистке, код операции очистки равен 1. Адрес стартового сектора, с которого начиналась
очистка информации, равен 132144. При полной очистке диска информация стирается из части RMA области и области
данных пользователя + три ECC блока (см. [2], табл. 109 «Blanking Types for DVD-RW»). В RMA области нетронутыми
остаются RMA Lead-in и шесть первых ECC блоков в составе RMD Set и одного Format 1 RMD блока. Зная, что стартовый
адрес RMA области равен 132032 (203C0h, см. [2], рис.8), определим, с какого адреса будет выполняться операция полной
очистки диска: 132032 + 16 * 7 = 132144.
Закончили чтение RMD Set, и переходим к чтению инфомации об RZone:
Field 0 (sector 81)
RMD Format: 1 Disk Status: 00
Field 4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field 0 (sector 97)
RMD Format: 1 Disk Status: 00
Field 4 (sector 101)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Тут все понятно – поле Disk Status равно 0, это значит что диск не содержит информации в области данных пользователя.
Теперь записываем на DVD-RW диск один трек размером 706240 Кбайт, или 353120 секторов. Режим записи - Incremental.
Запускаем программу на выполнение и анализируем результаты.
Last recorded RMA sector number: 143
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Format 2 RMD Set Field 1
Update Counter: 50
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 17
Format 2 RMD Set Field 2
Erase Operation Code: 1
Erase Information 1: 132144
Erase Information 2: 2495151
Field #0 (sector 81)
RMD Format: 1 Disk Status: 00
Field #4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field #0 (sector 97)
RMD Format: 1 Disk Status: 02
Field #4 (sector 101)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 0
2 549744 0
Field #0 (sector 113)
RMD Format: 1 Disk Status: 02
Field #4 (sector 117)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 549727
2 578416 0
Field #0 (sector 129)
RMD Format: 1 Disk Status: 02
Field #4 (sector 133)
Invisible/Incomplete RZone Number: 2
RZone START LAST
1 196608 549727
2 578416 0
Хорошо видно, как меняется содержание RMA области при записи на диск новых данных. Самую «свежую» информацию
содержит сектор, который находится по адресу (Last Recorded RMA Sector Number – 10), но это только для нашего случая,
т.к. мы ограничили число RZone до 254 и не двигаемся дальше поля Field 4 RMD блока.
А теперь выполним минимальную очистку диска и снова прочитаем RMA.
Last recorded RMA sector number: 111
Field 0 (RMD Header)
RMD Format: 2
Disk Status: 00h
Format 2 RMD Set Field 1
Update Counter: 51
Format 3 RMD Set Pointer: 0
Erase Operation Counter: 18
Format 2 RMD Set Field 2
Erase Operation Code: 2
Erase Information 1: 132144
Erase Information 2: 196607
Field #0 (sector 81)
RMD Format: 1 Disk Status: 04
Field #4 (sector 85)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Field #0 (sector 97)
RMD Format: 1 Disk Status: 04
Field #4 (sector 101)
Invisible/Incomplete RZone Number: 1
RZone START LAST
1 196608 0
Изменились поля Update Counter, счетчик количества операций стирания и код операции стирания – все значения
увеличились на 1. Поле Disk Status (Field #0) содержит значение 04 – была выполнена операция минимальной очистки
диска (см. табл.10).
В отличии от DVD-RW, RMA область DVD-R диска не содержит набора RMD Set (рис.66), поэтому при чтении RMD нет
необходимости смещаться на 5 ECC блоков вперед, и цикл чтения полей Field 4 RMD блоков примет следующий вид:
for(k = 0;;k++) {
. . .
/* Тело цикла аналогично предыдущему примеру */
. . .
}
Копию последнего записанного в RMA область RMD блока (точнее, пять копий) содержит последняя Border-out область
DVD-R/-RW диска, поэтому для получения информации о диске RMD блоки предпочтительнее считывать из этой области.
Чтобы прочитать RMD блок из последней Border-out, поле Format команды READ DVD STRUCTURE должно быть равно
0x0C, в поле Address указывается номер поля Field, содержимое которого мы хотим прочитать.
Чтение полей RMD блока из последней Border-out выполняет следующая функция:
int read_RMD()
{
/* Размер считываемых данных (в байтах) */
#define SIZE 2052 // 2048 bytes (1 sector) + 4 header`s bytes
int i, n = 16;
__u8 read_dvd_struct_cmd[12];
__u8 buff[SIZE]; // буфер для считываемых данных
__u8 *RMD = buff + 4; // указатель на начало данных RMD блока
__u8 disk_status = 0;
__u16 alloc_size = SIZE;
__u16 dvd_data_len = 0;
__u16 Inv_RZone_num = 0; // номер последней невидимой/незавершенной RZone
__u32 Start_BOUT = 0, Start_RZone = 0, LRA_RZone = 0;
/* Считываем Field #0 и проверяем статус диска */
memset(buff, 0, SIZE);
memset(read_dvd_struct_cmd, 0, 12);
read_dvd_struct_cmd[0] = 0xAD;
read_dvd_struct_cmd[7] = 0x0C; // read RMD in the last Border-out
read_dvd_struct_cmd[5] = 0; // Address = 0, read Field #0
read_dvd_struct_cmd[8] = *((__u8 *)&alloc_size + 1);
read_dvd_struct_cmd[9] = *((__u8 *)&alloc_size);
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Размер считанных данных */
*((__u8 *)&dvd_data_len) = buff[1];
*((__u8 *)&dvd_data_len + 1) = buff[0];
dvd_data_len += 2; // учитываем длину самого поля (2 bytes)
printf("DVD STRUCTURE Data Length: %d\n", dvd_data_len);
/* Определяем статус диска */
disk_status = *(RMD + 2);
printf("Disk status: %d\n", disk_status);
/* Считываем Field #3, информацию о Border Zone */
memset(buff, 0, SIZE);
read_dvd_struct_cmd[5] = 3; // Address = 3, read Field #3
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Отображаем информацию о стартовых координатах Border-out областей диска */
for(i = 0; i <= 2044; i += 4) {
memcpy((void *)&Start_BOUT, RMD + i, 4);
if(!Start_BOUT) break;
Start_BOUT = __swab32(Start_BOUT);
printf("Start Sector Number of Border-out #%d: %u\n", i/4 + 1, Start_BOUT);
}
/* Считываем Field #4, информацию об RZone */
memset(buff, 0, SIZE);
read_dvd_struct_cmd[5] = 4; // Address = 4, read RMD #4
test_unit_ready();
if(send_cmd(read_dvd_struct_cmd, 12, SG_DXFER_FROM_DEV, \
buff, alloc_size, 20) < 0) return -1;
/* Определяем номер невидимой/незавершенной RZone */
*((__u8 *)&Inv_RZone_num + 1) = RMD[0];
*((__u8 *)&Inv_RZone_num) = RMD[1];
printf("Invisible/Incomplete RZone Number: %d\n", Inv_RZone_num);
/* Отображаем значения стартовой координаты и последнего записанного сектора данных RZone */
printf("RZone\tSTART\tLAST\n");
for(i = 1; i <= Inv_RZone_num; i++, n += 8) {
memcpy((void *)&Start_RZone, RMD + n, 4);
Start_RZone = __swab32(Start_RZone);
memcpy((void *)&LRA_RZone, RMD + n + 4, 4);
LRA_RZone = __swab32(LRA_RZone);
printf("%-d\t%-d\t%-d\n", i, Start_RZone, LRA_RZone);
}
return 0;
}
Результат работы функции для DVD-RW диска, на котором записано два трека (размер первого трека – 718720 секторов,
размер второго – 330992 секторов):
DVD STRUCTURE Data Length: 30724
Disk status: 2
Start Sector Number of Border-out #1: 915344
Start Sector Number of Border-out #2: 1284240
Invisible/Incomplete RZone Number: 3
RZone START LAST
1 196608 915327
2 953232 1284223
3 1291920 0
Значение статуса диска = 2, что соответствует режиму записи Incremental. Физический адрес стартового сектора первого
трека – 196608, второго трека – 756624, третьего (невидимого) трека – 1095312. Для перевода в логический формат от
каждого значения надо отнять 30000h. Информация о порядке определения стартовых адресах треков понадобится нам в
следующем пункте, при рассмотрении режима записи Incremental.
Полный текст программы чтения RMD блоков из Border-out области находится в файле
SOURCE/DVD/READ_DVD_STRUCT/read_RMD.c.
Еще материалы по теме:
- Стандарт записи dvd-r (w) был разработан в 1997 г- Дорого-богато или умно-доступно: Собираем аудиосистему с разным бюджетом
- Говоря о достоинствах dvd-формата
- Существует несколько способов первичной прошивки чистой микросхемы
- Типы dvd-дисков
