Интерфейс между 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>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.