Unix - статьи

       

Управление файлами устройств


В качестве примера использования системных вызовов для работы с файлами устройств мы напишем программу, копирующую аудиоданные с audio-CD в wav- файлы (так называемый «риппер»). Файлы устройств, как известно, расположены в директории /dev/. В этой директории мы найдем и устройство /dev/cdrom, представляющее первый из установленных в вашей системе CD-приводов. Прежде, чем мы приступим к написанию программы-риппера, имеет смысл обратить внимание на врезку, посвященную устройству Audio CD.

Audio CD изнутри

Запись на любом компакт-диске состоит из нескольких треков. Треки нумеруются начиная с нуля (трек 0 содержит оглавление диска). Номер трека не может превышать значение 99. На аудио CD каждый музыкальный фрагмент как правило записывается на отдельном треке. На одном и том же диске могут быть записаны как аудио-треки, так и треки данных. Аудиоданные на CD записываются в 16-битном представлении с чередующимися сэмплами для правого и левого канала, с частотой дискретизации 44.1 КГц (если вы не знаете, что такое сэмплы и частота дискретизации, не волнуйтесь, для нашего примера это не принципиально).
Запись на диске разбивается на фреймы. Каждый фрейм содержит 2352 байта. Нетрудно подсчитать, что для обеспечения указанных выше характеристик цифровой записи чтение данных должно выполняться со скоростью 75 фреймов в секунду (что и соответствует однократной скорости чтения CD-ROM). С фреймами связан и один из форматов адресации на аудио CD. Адресация осуществляется в единицах MSF - минуты, секунды, фреймы - где фрейм можно рассматривать как 1/75 секунды. Другой формат адресации, связанный с логическими блоками (LBA), используется в основном при работе с не- аудиодисками.

Работа с CD-ROM с помощью устройства /dev/cdrom обычно выполняется по следующему сценарию: открытие файла устройства, настройка параметров с помощью ioctl(2), чтение (запись) данных, закрытие устройства. Полный текст программы вы найдете , а тут мы рассмотрим только самые интересные части, имеющие отношение к управлению устройствами-файлами. Текст программы начинается с директив включения заголовочных файлов. Файлы unistd.h и sys/fcntl.h содержат функции для работы с системными вызовами. Заголовочный файл linux/cdrom.h содержит различные константы и макросы, используемые при работе с CD-ROM, но, увы, не содержит макросов, с помощью которых можно было бы преобразовать MSF во фреймы и обратно. Мы сами определяем соответствующие функции. Мы открываем файл устройства с помощью системного вызова open(2): int cdd = open("/dev/cdrom", O_RDONLY);




Флаг, переданный функции open, указывает, что файл открыт только для чтения. Дальнейший доступ к устройству будет выполняться с помощью полученного дескриптора cdd. В Linux 2.4.22 каждый процесс может открыть не более 1048576 дескрипторов одновременно []. Нашим программам этого будет вполне достаточно. Мы предполагаем, что устройство /dev/cdrom установлено в системе и работает правильно, однако, в общем случае неплохо проверить значение дескриптора, возвращенное open, на предмет ошибки (в этом случае функция возвращает -1, переменная errno содержит дополнительный код ошибки).

Вызовы ioctl, связанные с воспроизведением Audio CD, приведены в таблице 1.

Вызов Описание Дополнительный параметр

CDROM_DRIVE_STATUS Получение данных о состоянии устройства константа CDSL_XXX
CDROM_DISC_STATUS Получение данных о диске константа CDSL_XXX
CDROMREADTOCHDR Чтение заголовка оглавления диска структура cdrom_tochdr
CDROMREADTOCENTRY Чтение элемента оглавления диска структура cdrom_tocentry
CDROMSUBCHNL Чтение данных о параметрах воспроизведения структура cdrom_subchnl
CDROMPLAYTRKIND, CDROMPLAYMSF Воспроизведение аудиозаписи Структуры cdrom_ti и cdrom_msf
CDROMSTOP Остановка воспроизведения значение 0
CDROMPAUSE, CDROMRESUME Приостановка, возобновление воспроизведения значение 0
CDROMEJECT Открытие лотка устройства значение 0
CDROMCLOSETRAY Закрытие лотка устройства значение 0
Таблица 1.Вызовы ioctl, связанные с воспроизведением Audio CD

Результат запросов CDROM_DRIVE_STATUS и CDROM_DISC_STATUS возвращается не в параметре-ссылке, а как результат функции ioctl. В качестве третьего аргумента в этих запросах выступает одна из констант CDSL_XXX, определенных в файле cdrom.h. Эти константы предназначены для работы с устройствами автоматической смены компакт-дисков (CD changers). В случае "однодискового" устройства следует использовать CDSL_CURRENT. Результатом вызова CDROM_DRIVE_STATUS могут быть значения CDS_NO_DISC (нет диска в устройстве), CDS_DRIVE_NOT_READY (устройство не готово), CDS_DISC_OK (диск обнаружен), а также некоторые другие константы из файла cdrom.h. Среди значений, возвращаемых вызовом CDROM_DISC_STATUS, следует отметить CDS_NO_DISC (см. выше) CDS_AUDIO (диск опознан как аудио) и CDS_MIXED (диск опознан как "смешанный"). Остальные значения соответствуют не- аудиодискам. Нижеследующий фрагмент программы проверяет, готов ли CD- дисковод к передаче данных:



disc_stat = ioctl(cdd, CDROM_DRIVE_STATUS, CDSL_CURRENT); if ((disc_stat != CDS_DISC_OK) && (disc_stat != CDS_NO_INFO)) { close(cdd); printf("Устройство не готово\n"); return 1; }

Вызовы CDROMREADTOCHDR и CDROMREADTOCENTRY предназначены для работы с оглавлением диска. Вызов CDROMREADTOCHDR позволяет получить данные о номере первого и последнего информационных треков на диске, а вызов CDROMREADTOCENTRY - данные об отдельном треке: адрес начала трека (в формате MSF или LBA), тип трека (аудио или данные) и т.п. Вызов CDROMSUBCHNL позволяет получить информацию о текущем состоянии устройства - находится ли диск в режиме воспроизведения, и в какой позиции выполняется чтение данных. Строка программы ioctl(cdd, CDROMREADTOCHDR, &toc);

заполняет переменную toc типа cdrom_tochdr данными заголовка оглавления диска. Структура cdrom_tochdr позволяет нам узнать количество треков на диске.

Вызов ioctl(cdd, CDROMREADTOCENTRY, &entry);

позволяет получить информацию о заданном треке. Дополнительный параметр вызова имеет тип «указатель на структуру cdrom_tocentry». Перед вызовом ioctl мы заполняем поля format (формат длительности трека) и track (номер трека) этой структуры. В этой же структуре системный вызов возвращает информацию о выбранном треке, в том числе тип трека (аудио или данные) и длительность трека. В файле cdrom.h определена константа CDROM_LEADOUT, указывающая на условный трек, расположенный после последнего трека.

Чтение данных трека выполняется с помощью вызова ioctl(cdd, CDROMREADAUDIO, &rdaudio);

где rdaudio – структура cdrom_read_audio.

Наша программа считывает данные CD и записывает их в файл формата wav. Строка вызова программы должна выглядеть так (исполнимый файл названии cdripper) cdripper

где трек – номер трека (первый трек, содержащий пользовательские данные имеет номер 1), файл – имя файла в котором будут сохранены аудиоданные в формате wav.

Принцип, согласно которому любой объект системы должен быть представлен в виде файла, приводит к тому, что даже дескрипторы файлов представлены в Linux в виде файлов. В директории /dev/fd можно увидеть файлы-ссылки с именами 0, 1, 2 и так далее. Эти файлы представляют дескрипторы файлов, открытых процессом, который читает директорию /dev/fd. Именно так, каждый процесс видит в этой директории только свои дескрипторы. Как некий артефакт из фантастического мира, директория /dev/fd выглядит по-разному в зависимости от того, кто на нее «смотрит» (этим свойством обладают также многие директории и файлы из виртуальной файловой системы /proc, которую мы рассмотрим ниже).

Открытие файла ссылки из /dev/fd эквивалентно созданию дубликата дескриптора, который представляет файл. Например, вызов fd = open("/dev/fd/1", 0);

присваивает fd дубликат дескриптора, представленного файлом /dev/fd/1 (файлы /dev/fd/0, /dev/fd/1 и /dev/fd/2 по умолчанию соответствуют стандартным потокам ввода, вывода и ошибок).


Содержание раздела