12.4. Интерфейсы

Интерфейс между pcm и звуковыми драйверами определён в терминах объектов ядра.

Есть 2 основных интерфейса, которые обычно обеспечивает звуковой драйвер: канальный и, либо микшерный либо AC97.

Интерфейс AC97 довольно мало использует доступ к ресурсам оборудования (чтение/запись регистров). Данный интерфейс реализован в драйверах для карт с кодеком AC97. В этом случае фактический микшерный интерфейс обеспечивается разделяемым кодом AC97 в pcm.

12.4.1. Канальный интерфейс

12.4.1.1. Общие заметки о параметрах функций

Звуковые драйверы обычно имеют структуру с личными данными для описания их устройства и по одной структуре на каждый поддерживаемый канал проигрывания или записи данных.

Для всех функций канального интерфейса первый параметр - непрозрачный указатель.

Второй параметр это указатель на структуру с данными канала. Исключение: У channel_init() это указатель на частную структуру устройства (данная функция возвращает указатель на канал для дальнейшего использования в pcm).

12.4.1.2. Обзор операций передачи данных

Для передачи данных, 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 .

12.4.1.3. channel_init

xxxchannel_init() вызывается для инициализации каждого из каналов проигрывания или записи. Вызовы инициируются функцией подключения звукового драйвера. (Подробнее в главе Обнаружение и подключение).

          static void *
          xxxchannel_init(kobj_t obj, void *data, 
             struct snd_dbuf *b, struct pcm_channel *c, int dir)(1)
          {
              struct xxx_info *sc = data;
              struct xxx_chinfo *ch;
               ...
              return ch;(2)
           }
(1)
b - это адрес канальной struct snd_dbuf. Она должна быть инициализирована в функции посредством вызова sndbuf_alloc(). Нормальный размер буфера для использования - наименьшее кратное размера передаваемого блока данных для вашего устройства.

c - это указатель на структуру контроля pcm канала. Это не прозрачный объект. Функция должна хранить его в локальной структуре канала, для дальнейшего использования в вызовах к pcm (например в: chn_intr(c)).

dir определяет для каких целей используется канал (PCMDIR_PLAY или PCMDIR_REC).

(2)
Функция должна возвращать указатель на личную, область, используемую для контроля этого канала. Он будет передаваться в качестве параметра в других вызовах канального интерфейса.

12.4.1.4. channel_setformat

xxxchannel_setformat() настраивает устройство на конкретный канал определённого формата звука.

          static int
          xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)(1)
          {
              struct xxx_chinfo *ch = data;
               ...
              return 0;
           }
(1)
format используется, как AFMT_XXX значение (soundcard.h).

12.4.1.5. channel_setspeed

xxxchannel_setspeed() устанавливает оборудование канала на определённую шаблонную скорость и возвращает возможную корректирующую скорость.

          static int
          xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
          {
              struct xxx_chinfo *ch = data;
               ...
              return speed;
           }

12.4.1.6. 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;(1)
           }
(1)
Функция возвращает возможно согласованный размер блока. В случае, если размер блока действительно изменился должен быть произведён вызов sndbuf_resize() для корректирования буфера.

12.4.1.7. channel_trigger

xxxchannel_trigger() вызывается pcm для контроля над трансферными операциями в драйвере.

          static int
          xxxchannel_trigger(kobj_t obj, void *data, int go)(1)
          {
              struct xxx_chinfo *ch = data;
               ...
              return 0;
           }
(1)
go определяет действие для текущего вызова. Возможные значения:
  • PCMTRIG_START: драйвер должен начать передачу данных из или в канальный буфер. Буфер и его размер могут быть получены через вызов sndbuf_getbuf() и sndbuf_getsize().

  • PCMTRIG_EMLDMAWR / PCMTRIG_EMLDMARD: говорит драйверу, что входной или выходной буфер возможно был обновлён. Большинство драйверов игнорируют эти вызовы.

  • PCMTRIG_STOP / PCMTRIG_ABORT: драйвер должен остановить текущую передачу данных.

Замечание: Если драйвер использует ISA DMA, sndbuf_isadma() должна вызываться перед выполнением действий над устройством, она также позаботится о вещах со стороны DMA чипа.

12.4.1.8. channel_getptr

xxxchannel_getptr() возвращает текущее смещение в передаваемом буфере. Обычно вызывается в chn_intr(), и так pcm узнаёт, где брать данные для новой передачи.

12.4.1.9. channel_free

xxxchannel_free() вызывается для освобождения ресурсов канала. Например: должна вызываться, при выгрузке драйвера, если структуры данных канала распределялись динамично или, если sndbuf_alloc() не использовалась для выделения памяти под буфер.

12.4.1.10. channel_getcaps

          struct pcmchan_caps *
          xxxchannel_getcaps(kobj_t obj, void *data)
          {
              return &xxx_caps;(1)
           }
(1)
Подпрограмма возвращает указатель на (обычно статически-определяемую) структуру pcmchan_caps (описанную в sound/pcm/channel.h. Структура содержит данные о минимуме и максимуме шаблонных частот и воспринимаемых звуковых форматах. Для примера смотрите исходный код любого звукового драйвера.

12.4.1.11. Другие функции

channel_reset(), channel_resetdone(), и channel_notify() предназначены для специальных целей и не должны употребляться в драйвере без обсуждения с авторами (Cameron Grant ).

channel_setdir() is deprecated.

12.4.2. Микшерный интерфейс

12.4.2.1. 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](1)
              mix_setdevs(m, v);
              [Set appropriate bits in v for record mixers]
              mix_setrecdevs(m, v)

              return 0;              
          }
(1)
Устанавливает биты в целом значении и вызывает mix_setdevs() и mix_setrecdevs() чтобы сообщить pcm какие устройства существуют.

Определения битов микшера могут быть найдены в soundcard.h (SOUND_MASK_XXX значения и SOUND_MIXER_XXX битовые сдвиги).

12.4.2.2. mixer_set

xxxmixer_set() устанавливает уровень громкости для одного микшерного устройства.

          static int
          xxxmixer_set(struct snd_mixer *m, unsigned dev, 
                           unsigned left, unsigned right)(1)
          {
              struct sc_info *sc = mix_getdevinfo(m);
              [set volume level]
              return left | (right << 8);(2)
          }
(1)
Устройство определяется, как SOUND_MIXER_XXX значение

Допустимые значения уровней громкости лежат в пределах [0-100]. Равное нулю значение должно выключать звук устройства.

(2)
Вероятно уровни оборудования не будут совпадать с входной шкалой, и будет происходить некоторое округление, подпрограмма будет возвращает точные значения (в промежутке 0-100), как уже было сказано.

12.4.2.3. mixer_setrecsrc

xxxmixer_setrecsrc() устанавливает исходное записывающее устройство.

          static int
          xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)(1)
          {
              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;(2)
           }
(1)
Желаемые записывающие устройства указываются в битовом поле
(2)
Возвращается фактический набор устройств для записи. Некоторые драйверы могут устанавливать только одно устройство для записи. Функция должна возвращать -1, в случае возникновения ошибки.

12.4.2.4. mixer_uninit, mixer_reinit

xxxmixer_uninit() должна проверить, что все звуки выключены (mute), и, если возможно выключить оборудование микшера

xxxmixer_reinit() должна удостовериться, что оборудование микшера включено и все установки, неконтролируемые mixer_set() или mixer_setrecsrc() восстановлены.

12.4.3. Интерфейс AC97

Поддержка интерфейса AC97 осуществляется драйверами с кодеком AC97. Он поддерживает только три метода:

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