Интерфейс между 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
.
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).
xxxchannel_setformat()
настраивает устройство на
конкретный канал определённого формата звука.
static int xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format){ struct xxx_chinfo *ch = data; ... return 0; }
xxxchannel_setspeed()
устанавливает оборудование канала
на определённую шаблонную скорость и возвращает возможную корректирующую скорость.
static int xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed) { struct xxx_chinfo *ch = data; ... return speed; }
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;}
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 чипа.
xxxchannel_getptr()
возвращает текущее смещение в
передаваемом буфере. Обычно вызывается в chn_intr()
, и так
pcm узнаёт, где брать данные для новой передачи.
xxxchannel_free()
вызывается для освобождения ресурсов
канала. Например: должна вызываться, при выгрузке драйвера, если структуры данных канала
распределялись динамично или, если sndbuf_alloc()
не
использовалась для выделения памяти под буфер.
struct pcmchan_caps * xxxchannel_getcaps(kobj_t obj, void *data) { return &xxx_caps;}
channel_reset()
, channel_resetdone()
, и channel_notify()
предназначены для специальных целей и не должны
употребляться в драйвере без обсуждения с авторами (Cameron Grant <cg@FreeBSD.org>
).
channel_setdir()
is deprecated.
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; }
Определения битов микшера могут быть найдены в soundcard.h (SOUND_MASK_XXX значения и SOUND_MIXER_XXX битовые сдвиги).
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);
}
Допустимые значения уровней громкости лежат в пределах [0-100]. Равное нулю значение должно выключать звук устройства.
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;
}
xxxmixer_uninit()
должна проверить, что все звуки
выключены (mute), и, если возможно выключить оборудование микшера
xxxmixer_reinit()
должна удостовериться, что
оборудование микшера включено и все установки, неконтролируемые mixer_set()
или mixer_setrecsrc()
восстановлены.
Поддержка интерфейса AC97 осуществляется драйверами с кодеком AC97. Он поддерживает только три метода:
xxxac97_init()
возвращает количество найденных ac97
кодеков.
ac97_read()
и ac97_write()
читают или записывают данные определенного регистра.
Интерфейс AC97 используется кодом AC97 в pcm для выполнения операций более высокого уровня. За примером обращайтесь к sound/pci/maestro3.c или к другим файлам из каталога sound/pci/.
Пред. | Начало | След. |
Обнаружение, подключение, и т.д. | Уровень выше | Приложения |
Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.
По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.