diff --git a/ru_RU.KOI8-R/books/arch-handbook/sound/chapter.sgml b/ru_RU.KOI8-R/books/arch-handbook/sound/chapter.sgml new file mode 100644 index 0000000000..c937ac5ee7 --- /dev/null +++ b/ru_RU.KOI8-R/books/arch-handbook/sound/chapter.sgml @@ -0,0 +1,708 @@ + + + + + + + Jean-Francois + Dockes + Автор: + + + + + + Подсистема звука + + + Введение + + Перевод на русский язык: Виталий + Богданов (gad@gad.glazov.net) + + подсистема звука + + В подсистеме звука FreeBSD существует чёткое разделение + между частью, поддерживающей общие звуковые возможности и + аппаратно зависимой частью. Данная особенность делает + более простым добавление поддержки новых устройств. + + &man.pcm.4; занимает центральное место в подсистеме + звука. Его основными элементами являются: + + интерфейс системных вызовов + + + + Интерфейс системных вызовов (read, write, ioctls) к + функциям оцифрованного звука и микшера. Командный набор + ioctl совместим с интерфейсом OSS + или Voxware, позволяя тем самым + портирование мультимедиа приложений без дополнительной + модификации. + + + Общий код обработки звуковых данных (преобразования + форматов, виртуальные каналы). + + + Единый программный интерфейс к аппаратно-зависимым + модулям звукового интерфейса. + + + Дополнительная поддержка нескольких общих аппаратных + интерфейсов (ac97) или разделяемого аппаратно-специфичного + кода (например: функции ISA DMA). + + + + Поддержка отдельных звуковых карт осуществляется с помощью + аппаратно-специфичных драйверов, обеспечивающих канальные и + микшерные интерфейсы, включаемые в + общий pcm код. + + В этой главе термином pcm мы + будем называть центральную, общую часть звукового драйвера, как + противопоставление аппаратно-специфичным модулям. + + Человек, решающий написать драйвер наверняка захочет использовать + в качестве шаблона уже существующий код. Но, если звуковой код хорош и + чист, он также в основном лишён комментариев. Этот документ - попытка + рассмотрения базового интерфейса и попытка ответить на вопросы, возникшие + при адаптировании существующего кода. + + Для старта с рабочего примера, вы можете найти шаблон + драйвера, оснащенного комментариями на + http://people.FreeBSD.org/~cg/template.c + + + + + Файлы + + Весь исходный код, на сегодняшний момент (FreeBSD 4.4), содержится + в каталоге /usr/src/sys/dev/sound/, за исключением + публичных определений интерфейса ioctl, находящихся в + /usr/src/sys/sys/soundcard.h + + В подкаталоге pcm/ родительского + каталога /usr/src/sys/dev/sound/ находится + главный код, а + в каталогах isa/ и pci/ + содержатся драйвера для ISA и PCI карт. + + + + + Обнаружение, подключение, и т.д. + + Обнаружение и подключение звуковых драйверов во многом схоже с + драйвером любого другого устройства. За дополнительной информацией + вы можете обратиться к главам ISA или PCI данного руководства. + + Но всё же, звуковые драйвера немного отличаются: + + + + + Они объявляют сами себя, как устройства класса pcm, + с частной структурой устройства struct + snddev_info : + + static driver_t xxx_driver = { + "pcm", + xxx_methods, + sizeof(struct snddev_info) + }; + + DRIVER_MODULE(snd_xxxpci, pci, xxx_driver, pcm_devclass, 0, 0); + MODULE_DEPEND(snd_xxxpci, snd_pcm, PCM_MINVER, PCM_PREFVER,PCM_MAXVER); + + драйвера устройствзвук + Большинство звуковых драйверов нуждаются в сохранении личной + информации, касающейся их устройства. Структура с личными + данными обычно выделяется при вызове функции attach. Её адрес + передаётся pcm посредством вызовов + pcm_register() + и mixer_init(). Позже + pcm передаёт назад этот адрес, в + качестве параметра в вызовах к интерфейсам звукового + драйвера. + + + + Функция подключения звукового драйвера должна объявлять + её микшерный или AC97 интерфейс + pcm посредством + вызова mixer_init(). Для микшерного + интерфейса это взамен вернёт вызов + xxxmixer_init(). + + + + Функция подключения звукового драйвера передаёт + общие настройки каналов pcm посредством + вызова pcm_register(dev, sc, nplay, + nrec), где sc - адрес + структуры данных устройства, используемой в дальнейших + вызовах от pcm, а nplay + и nrec - количество каналов проигрывания и + записи. + + + + Функция подключения звукового драйвера объявляет каждый + из её каналов с помощью вызовов + pcm_addchan(). Это установит занятость + канала в pcm и вызовет + взамен вызов + + xxxchannel_init(). + + + + Функция отключения должна вызывать + pcm_unregister() перед объявлением её ресурсов + свободными. + + + + Существует два метода работы с не PnP устройствами: + + + Использование метода device_identify() + (пример смотрите в: sound/isa/es1888.c). + device_identify() пытается обнаружить + оборудование, использующее известные адреса, и если найдёт + поддерживаемое устройство, то создаст новое pcm + устройство, которое затем будет передано процессу + обнаружения/подключения. + + + Использование выборочной конфигурации ядра с соответствующими + хинтами для pcm устройств (пример: + sound/isa/mss.c). + + + + pcm драйверы должны поддерживать + device_suspend, + device_resume и + device_shutdown функции, для корректного + функционирования управления питанием и процесса выгрузки модуля. + + + + + Интерфейсы + + Интерфейс между pcm + и звуковыми драйверами определён в терминах объектов ядра. + + Есть 2 основных интерфейса, которые обычно обеспечивает + звуковой драйвер: канальный и, либо + микшерный либо AC97. + + Интерфейс AC97 довольно мало использует + доступ к ресурсам оборудования (чтение/запись регистров). Данный + интерфейс реализован в драйверах для карт с кодеком AC97. В + этом случае фактический микшерный интерфейс обеспечивается разделяемым + кодом AC97 в pcm. + + + Канальный интерфейс + + + Общие заметки о параметрах функций + + Звуковые драйверы обычно имеют структуру с личными + данными для описания их устройства и по одной структуре на + каждый поддерживаемый канал проигрывания или записи данных. + + Для всех функций канального интерфейса первый параметр - + непрозрачный указатель. + + Второй параметр это указатель на структуру с + данными канала. Исключение: + У channel_init() это указатель на + частную структуру устройства (данная функция возвращает + указатель на канал для дальнейшего использования + в pcm). + + + + + Обзор операций передачи данных + + Для передачи данных, + pcm и звуковые драйвера + используют разделяемую область памяти, описанную + в struct snd_dbuf. + + struct snd_dbuf принадлежит + pcm, и звуковые драйверы + получают нужные значения с помощью вызовов функций + (sndbuf_getxxx()). + + Область разделяемой памяти имеет размер, определяемый с помощью + sndbuf_getsize() и разделён на блоки + фиксированного размера, определённого в + sndbuf_getblksz() количества байт. + + При проигрывании, общий механизм передачи данных примерно + следующий (обратный механизму, используемому при записи): + + + + В начале, pcm заполняет + буфер, затем вызывает функцию звукового драйвера + xxxchannel_trigger() + с параметром PCMTRIG_START. + + + + Затем звуковой драйвер многократно передаёт всю + область памяти + (sndbuf_getbuf(), + sndbuf_getsize()) устройству, с + количеством байт, определённым в sndbuf_getblksz() . + Взамен это вызовет chn_intr() + pcm функцию для каждого + переданного блока (это обычно происходит во время + прерывания). + + + + chn_intr() копирует новые + данные в область, которая была передана устройству (сейчас + свободная) и вносит соответствующие изменения в + структуру snd_dbuf . + + + + + + + + channel_init + + xxxchannel_init() вызывается для + инициализации каждого из каналов проигрывания или + записи. Вызовы инициируются функцией подключения + звукового драйвера. (Подробнее + в главе + Обнаружение и подключение). + + static void * + xxxchannel_init(kobj_t obj, void *data, + struct snd_dbuf *b, struct pcm_channel *c, int dir) + { + struct xxx_info *sc = data; + struct xxx_chinfo *ch; + ... + return ch; + } + + + + + b - это адрес канальной + struct snd_dbuf. Она должна + быть инициализирована в функции посредством + вызова sndbuf_alloc(). Нормальный + размер буфера для использования - наименьшее кратное + размера передаваемого блока данных для вашего устройства. + + c - это + указатель на структуру + контроля pcm канала. Это не прозрачный + объект. Функция должна хранить его в локальной структуре + канала, для дальнейшего использования в вызовах к + pcm (например в: + chn_intr(c)). + + dir определяет для каких целей + используется канал + (PCMDIR_PLAY или + PCMDIR_REC). + + + + Функция должна возвращать указатель на личную, + область, используемую для контроля этого + канала. Он будет передаваться в качестве параметра в + других вызовах канального интерфейса. + + + + + + + + channel_setformat + + xxxchannel_setformat() настраивает + устройство на конкретный канал определённого формата звука. + + static int + xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format) + { + struct xxx_chinfo *ch = data; + ... + return 0; + } + + + + format используется, как + AFMT_XXX значение + (soundcard.h). + + + + + + + channel_setspeed + + xxxchannel_setspeed() устанавливает + оборудование канала на определённую шаблонную скорость и возвращает + возможную корректирующую скорость. + + static int + xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed) + { + struct xxx_chinfo *ch = data; + ... + return speed; + } + + + + + channel_setblocksize + + xxxchannel_setblocksize() устанавливает + размер передаваемого блока между + pcm и звуковым драйвером, и между + звуковым драйвером и устройством. Обычно это будет количество + переданных байт перед прерыванием. Во время трансфера звуковой + драйвер должен должен вызывать + pcm функцию chn_intr() каждый + раз при передаче блока данных такого размера. + + Большинство звуковых драйверов только берут на заметку + размер блока для использования во время передачи данных. + + static int + xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) + { + struct xxx_chinfo *ch = data; + ... + return blocksize; + } + + + + Функция возвращает возможно согласованный размер + блока. В случае, если размер блока действительно + изменился должен быть произведён вызов + sndbuf_resize() для корректирования + буфера. + + + + + + + + channel_trigger + + xxxchannel_trigger() вызывается + pcm для контроля над трансферными + операциями в драйвере. + + static int + xxxchannel_trigger(kobj_t obj, void *data, int go) + { + struct xxx_chinfo *ch = data; + ... + return 0; + } + + + + go определяет действие для + текущего вызова. Возможные значения: + + + + PCMTRIG_START: драйвер + должен начать передачу данных из или в канальный + буфер. Буфер и его размер могут быть получены через + вызов sndbuf_getbuf() и + sndbuf_getsize(). + + + + PCMTRIG_EMLDMAWR / + PCMTRIG_EMLDMARD: говорит + драйверу, что входной или выходной буфер возможно + был обновлён. Большинство драйверов игнорируют + эти вызовы. + + + + PCMTRIG_STOP / + PCMTRIG_ABORT: драйвер должен + остановить текущую передачу данных. + + + + + + + Если драйвер использует ISA DMA, + sndbuf_isadma() должна вызываться + перед выполнением действий над устройством, она также + позаботится о вещах со стороны DMA чипа. + + + + + + channel_getptr + + xxxchannel_getptr() возвращает + текущее смещение в передаваемом буфере. Обычно вызывается + в chn_intr(), и так + pcm узнаёт, где брать данные для + новой передачи. + + + + + channel_free + + xxxchannel_free() вызывается для + освобождения ресурсов канала. Например: должна вызываться, + при выгрузке драйвера, если структуры данных канала + распределялись динамично или, если + sndbuf_alloc() не использовалась + для выделения памяти под буфер. + + + + + channel_getcaps + + struct pcmchan_caps * + xxxchannel_getcaps(kobj_t obj, void *data) + { + return &xxx_caps; + } + + + + + Подпрограмма возвращает указатель на (обычно + статически-определяемую) структуру + pcmchan_caps (описанную в + sound/pcm/channel.h. Структура содержит + данные о минимуме и максимуме шаблонных частот и + воспринимаемых звуковых форматах. Для примера смотрите + исходный код любого звукового драйвера. + + + + + + + + Другие функции + + channel_reset(), + channel_resetdone(), и + channel_notify() предназначены для + специальных целей и не должны употребляться в драйвере + без обсуждения с авторами (&a.cg;). + + channel_setdir() is deprecated. + + + + + + Микшерный интерфейс + + + mixer_init + + xxxmixer_init() инициализирует + оборудование и говорит pcm какие микшерные + устройства доступны для проигрывания и записи + + static int + xxxmixer_init(struct snd_mixer *m) + { + struct xxx_info *sc = mix_getdevinfo(m); + u_int32_t v; + + [Initialize hardware] + + [Set appropriate bits in v for play mixers] + mix_setdevs(m, v); + [Set appropriate bits in v for record mixers] + mix_setrecdevs(m, v) + + return 0; + } + + + + Устанавливает биты в целом значении и вызывает + mix_setdevs() и + mix_setrecdevs() чтобы сообщить + pcm какие устройства существуют. + + + + Определения битов микшера могут быть найдены в + soundcard.h + (SOUND_MASK_XXX значения и + SOUND_MIXER_XXX битовые сдвиги). + + + + + mixer_set + + xxxmixer_set() устанавливает уровень + громкости для одного микшерного устройства. + + static int + xxxmixer_set(struct snd_mixer *m, unsigned dev, + unsigned left, unsigned right) + { + struct sc_info *sc = mix_getdevinfo(m); + [set volume level] + return left | (right << 8); + } + + + + Устройство определяется, как SOUND_MIXER_XXX + значение Допустимые значения уровней громкости лежат + в пределах [0-100]. Равное нулю значение должно выключать звук + устройства. + + + + Вероятно уровни оборудования не будут совпадать с + входной шкалой, и будет происходить некоторое округление, подпрограмма + будет возвращает точные значения (в промежутке 0-100), как уже + было сказано. + + + + + + + mixer_setrecsrc + + xxxmixer_setrecsrc() устанавливает + исходное записывающее устройство. + + static int + xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src) + { + struct xxx_info *sc = mix_getdevinfo(m); + + [look for non zero bit(s) in src, set up hardware] + + [update src to reflect actual action] + return src; + } + + + + Желаемые записывающие устройства указываются в битовом поле + + + + Возвращается фактический набор устройств для записи. + Некоторые драйверы могут устанавливать только одно устройство для + записи. Функция должна возвращать -1, в случае возникновения + ошибки. + + + + + + mixer_uninit, mixer_reinit + + xxxmixer_uninit() должна проверить, + что все звуки выключены (mute), и, если возможно выключить + оборудование микшера + + xxxmixer_reinit() должна удостовериться, + что оборудование микшера включено и все установки, неконтролируемые + mixer_set() или + mixer_setrecsrc() восстановлены. + + + + + + Интерфейс AC97 + + AC97 + + Поддержка интерфейса AC97 осуществляется + драйверами с кодеком AC97. Он поддерживает только три метода: + + + + xxxac97_init() возвращает + количество найденных ac97 кодеков. + + + ac97_read() и + ac97_write() читают или записывают + данные определенного регистра. + + + + + Интерфейс AC97 используется кодом + AC97 в pcm для выполнения операций + более высокого уровня. За примером обращайтесь к + sound/pci/maestro3.c или к другим + файлам из каталога sound/pci/. + + + + + +