The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

Глава 7. API для кодека AC97

Глава 7. API для кодека AC97

Предыдущая  Содержание  Следующая V*D*V

Общие сведения

Уровень кодека AC97 в ALSA чётко определён, и вам не придётся писать много кода, чтобы им управлять. Необходимы только процедуры низкоуровневого управления. API кодека AC97 определён в <sound/ac97_codec.h>.

Полный пример кода

Пример 7.1. Пример интерфейса AC97

 

struct mychip {

    ....

    struct snd_ac97 *ac97;

    ....

};

 

static unsigned short snd_mychip_ac97_read(struct snd_ac97 *ac97,

                                           unsigned short reg)

{

    struct mychip *chip = ac97->private_data;

    ....

    /* здесь из кодека читаем значение регистра */

    return the_register_value;

}

 

static void snd_mychip_ac97_write(struct snd_ac97 *ac97,

                                  unsigned short reg, unsigned short val)

{

    struct mychip *chip = ac97->private_data;

    ....

    /* записываем в кодек значение данного регистра */

}

 

static int snd_mychip_ac97(struct mychip *chip)

{

    struct snd_ac97_bus *bus;

    struct snd_ac97_template ac97;

    int err;

    static struct snd_ac97_bus_ops ops = {

        .write = snd_mychip_ac97_write,

        .read = snd_mychip_ac97_read,

    };

 

    err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus);

    if (err < 0)

        return err;

    memset(&ac97, 0, sizeof(ac97));

    ac97.private_data = chip;

    return snd_ac97_mixer(bus, &ac97, &chip->ac97);

}

 

Конструктор

Чтобы создать экземпляр AC97, сначала вызывается snd_ac97_bus используя объект ac97_bus_ops_t, содержащий функции обратного вызова.

 

struct snd_ac97_bus *bus;

static struct snd_ac97_bus_ops ops = {

    .write = snd_mychip_ac97_write,

    .read = snd_mychip_ac97_read,

};

 

snd_ac97_bus(card, 0, &ops, NULL, &pbus);

 

Объект bus является общим объектом для всего, связанного с экземплярами AC97.

 

А затем вызывается snd_ac97_mixer() с объектом struct snd_ac97_template вместе с указателем bus, созданным до этого.

 

struct snd_ac97_template ac97;

int err;

 

memset(&ac97, 0, sizeof(ac97));

ac97.private_data = chip;

snd_ac97_mixer(bus, &ac97, &chip->ac97);

 

где chip->ac97 является указателем на вновь созданный экземпляр ac97_t. В данном случае указатель chip сохраняется в  закрытых данных, так что функции обратного вызова для чтения/записи могут обращаться к этому экземпляру chip. Экземпляр ac97 не обязательно хранить в объекте chip. Если вам необходимо изменять значения регистров из драйвера или необходимо приостанавливать/возобновлять работу кодеков AC97, сохраните этот указатель для передачи соответствующим функциям.

Обратные вызовы

Стандартными обратными вызовами являются read и write. Очевидно, что они соответствуют низкоуровневым функциям обращения к оборудованию для чтения и записи.

 

Обратный вызов read возвращает значение регистра, указанного в аргументе.

 

static unsigned short snd_mychip_ac97_read(struct snd_ac97 *ac97,

                                           unsigned short reg)

{

    struct mychip *chip = ac97->private_data;

    ....

    return the_register_value;

}

 

Здесь chip может быть получен приведением ac97->private_data.

 

Обратный же вызов write используется для установки значения регистра.

 

static void snd_mychip_ac97_write(struct snd_ac97 *ac97,

                                  unsigned short reg, unsigned short val)

 

Эти обратные вызовы не являются атомарными, подобно обратным вызовам API управления.

 

Есть также другие функции обратного вызова: reset, wait и init.

 

Обратный вызов reset используется для сброса кодека. Если чип требует особый способ сброса, можно определить этот обратный вызов.

 

Обратный вызов wait используется для добавления некоторого времени ожидания в стандартную инициализацию кодека. Если чип требует дополнительного времени ожидания, определите этот обратный вызов.

 

Обратный вызов init используется для дополнительной инициализации кодека.

Обновление регистров в драйвере

Если необходимо обращаться к кодеку из драйвера, можно вызывать следующие функции: snd_ac97_write(), snd_ac97_read (), snd_ac97_update() и snd_ac97_update_bits().

 

Обе функции, snd_ac97_write() и snd_ac97_update(), используются для установки значения указанного регистра (AC97_XXX). Разница между ними в том, что snd_ac97_update() не записывает значение, если данное значение уже установлено, а snd_ac97_write() переписывает значение всегда.

 

snd_ac97_write(ac97, AC97_MASTER, 0x8080);

snd_ac97_update(ac97, AC97_MASTER, 0x8080);

 

snd_ac97_read() используется для чтения значения заданного регистра. Например,

 

value = snd_ac97_read(ac97, AC97_MASTER);

 

snd_ac97_update_bits() используется для обновления некоторых битов в заданном регистре.

 

snd_ac97_update_bits(ac97, reg, mask, value);

 

Кроме того, есть функция изменения частоты дискретизации (значение в указанном регистре, таком как AC97_PCM_FRONT_DAC_RATE), если кодеком поддерживается VRA (Variable Rate PCM audio, звук с PCM и изменяемой частотой дискретизации) или DRA (Double-Rate PCM audio, звук с PCM с удвоенной частотой дискретизации): snd_ac97_set_rate().

 

snd_ac97_set_rate(ac97, AC97_PCM_FRONT_DAC_RATE, 44100);

 

Для установки частоты дискретизации доступны следующие регистры: AC97_PCM_MIC_ADC_RATE, AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE, AC97_SPDIF. Если указан AC97_SPDIF, регистр на самом деле не изменяется, а будут обновляться соответствующие биты статуса IEC958.

Регулировка тактовой частоты

В некоторых чипах частота кодека не 48000, а используется частота PCI (для экономии кварца!). В этом случае измените поле bus->clock на соответствующее значение. Например, драйверы intel8x0 и es1968 имеют свои собственные функции для чтения частоты.

Файлы интерфейса Proc

ALSA AC97 интерфейс создаёт файлы proc, такие как /proc/asound/card0/codec97#0/ac97#0-0 и ac97#0-0+regs. Можно обращаться к этим файлам, чтобы увидеть текущее состояние и регистры кодека.

Несколько кодеков

Если на одной карте есть несколько кодеков, необходимо вызывать snd_ac97_mixer() несколько раз с ac97.num=1 или большим значением. Поле num указывается количество кодеков.

 

Если указано несколько кодеков, необходимо либо писать разные функции обратного вызова для каждого кодека, либо в процедурах обратного вызова проверять ac97->num.

 

Предыдущая  Содержание  Следующая