Меню Рубрики

Как написать драйвер для звуковой карты

Как написать и подключить драйвер звука

Информацию, приведённую на Alsa-sound-mini-HOWTO (http://tldp.org/HOWTO/Alsa-sound-6.html) следует тщательно проверять по другим источникам.

• Включить поддержку Device Drivers -> Sound card support -> Advanced Linux Sound Architecture для поддержки вывода звука через интерфейс ALSA;

• Включить поддержку Device Drivers -> Sound card support -> Advanced Linux Sound Architecture -> OSS PCM (digital audio) API чтобы при сборке модуля звуковой карты были доступны функции из заголовка ;
судя по всему, в конфигураторе ядра имеется ошибка, потому что при отключенной опции эмуляции OSS одновременно отключаются опции CONFIG_SND_TIMER и CONFIG_SND_PCM, необходимые для сборки модулей ALSA.

Проверка версии ALSA

В исходниках ядра: посмотреть include/sound/version.h .

Файловая система

Создать узлы для устройства в каталоге /dev/snd :

crw-rw—- 1 root root 116, 0 Aug 19 16:02 controlC0

crw-rw—- 1 root root 116, 24 Aug 19 16:02 pcmC0D0c

crw-rw—- 1 root root 116, 16 Aug 19 16:02 pcmC0D0p

crw-rw—- 1 root root 116, 1 Aug 19 16:01 seq

crw-rw—- 1 root root 116, 33 Aug 19 16:01 timer

Если используется эмуляция OSS, создать узлы устройств OSS:

mknod -m 660 sequencer c 14 1

mknod -m 660 sndstat c 14 6

mknod -m 660 dmmidi c 14 9

mknod -m 660 amixer c 14 11

mknod -m 660 amidi c 14 13

mknod -m 660 admmidi c 14 14

Шаблон

При подключении микросхем ЦАП и АЦП или кодека через интерфейс SSC проще всего использовать как шаблон драйвер /sound/spi/at73c213.c . Общим шаблоном является /sound/drivers/dummy.c . Интересна также реализация работы с памятью в rme32.c и rme96.c .

Информация, опубликованная на сайтах ALSA, часто не соответствует действительности, поэтому лучше всего смотреть реализацию в драйверах, находящихся в ядре.

Драйвер для неуправляемого ЦАП TDA1543 или TDA1541: sound.zip.

Как проверить

Проверка, предложенная на http://tldp.org/HOWTO/Alsa-sound-6.html в п.6.3 не работает.

Если ALSA собрана с поддержкой OSS, проверить можно так:

# cat pcm-48000-16-stereo.wav > /dev/dsp

Музыки ожидать не стоит, будет просто цифровой шум.

Либо сыграть что-нибудь через aplay или speaker-test .

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

Например, если SSC работает на частоте 47348:

# speaker-test -r 47348 -f 1000 -c 2

Другие параметры можно использовать только при наличии библиотек-конвертеров. Хороший набор в libasound2 для Debian.

При проигрывании звукового PCM файла с помощью aplay загрузка процессора 1% . 6%.

При проигрывании звукового mp3 файла 44100, 192кбит/сек с помощью madplayer загрузка процессора 25% . 30%, прерывающая при интенсивной работе через ftp.

Для проигрывания через mplayer мощности процессора не хватает.

Для сравнения ARM11 S3C6410, 532 Мгц: madplayer загрузка процессора около 10%, mpalyer — около 40%.

Базовые частоты

SSC использует частоту шины процессора и делитель в диапазоне от 2 до 8190. Для звука обычно используют фиксированные частоты: 5512Hz, 8000Hz, 11025Hz, 16000Hz, 22050Hz, 32000Hz, 44100Hz, 48000Hz, 64000Hz, 88200Hz, 96000Hz, 176400Hz, 192000Hz. Однако, точные значения этих частот можно получить только при определённых значениях основной частоты.

DIV = clock / (bitrate * stereo * 16-bit)

Теперь округляем делитель до чётного значения.

BITRATE = clock / (DIV * stereo * 16-bit)

DIV = 100000000 / (48000 * 2 * 16) = 65

BITRATE = 100000000 / (66 * 2 * 16) = 47348,48

Таким образом, значения делителя и основной частоты для получения точных значений:

Конфигурация

Общесистемная конфигурация находится в файле /etc/asound.conf .

Конфигурация для пользователя в файле $HOME/.asoundrc .

Конфигурация подключаемых модулей библиотеки alsa-lib находится в файле /usr/share/alsa/alsa.conf .

Параметры подключаемых модулей можно посмотреть на странице

Поиск и решение проблем

Посмотреть список карт, которые видит ALSA:

Посмотреть /sys/class/sound и проверить соответствующие устройства:

lrwxrwxrwx 1 root root 0 Aug 25 12:50 audio -> ../../devices/virtual/sound/card0/audio

lrwxrwxrwx 1 root root 0 Aug 25 12:50 card0 -> ../../devices/virtual/sound/card0

lrwxrwxrwx 1 root root 0 Aug 25 12:50 controlC0 -> ../../devices/virtual/sound/card0/controlC0

lrwxrwxrwx 1 root root 0 Aug 25 12:50 dsp -> ../../devices/virtual/sound/card0/dsp

lrwxrwxrwx 1 root root 0 Aug 25 12:50 mixer -> ../../devices/virtual/sound/card0/mixer

lrwxrwxrwx 1 root root 0 Aug 25 12:50 pcmC0D0p -> ../../devices/virtual/sound/card0/pcmC0D0p

lrwxrwxrwx 1 root root 0 Aug 25 12:50 timer -> ../../devices/virtual/sound/timer

Проверить младшие номера устройств и сравнить их со списком в /proc/asound/devices :

16: [ 0- 0]: digital audio playback

Устройство с Linux как звуковая карта для компьютера

К сожалению, не работает. Причина непонятна. На ПК с Windows устройство не стартует, при подключении к ПК с Linux плата виснет.

Gadget Audio имеет класс USB Audio, воспринимаемый базовым компьютером как звуковая карта. Он принимает с компьютера через USB PCM поток и посылает его в звуковой кодек на плате для проигрывания. Для записи аналогично выполняется обратная работа.

Конфигурирование Audio Gadget в ядре

Перед включением данной функции убедитесь, что аудиокодек на вашей плате работает нормально.

[Linux Kernel Configuration] → [Device Drivers] → [USB support] → [USB Gadget Support]

Audio Gadget (EXPERIMENTAL)

Сначала на плате загружается драйвер аудио кодека.

Затем загружается драйвер Audio Gadget.

Если всё нормально, появится сообщение, похожее на это:

g_audio gadget: Hardware params: access 3, format 2, channels 2, rate 48000

g_audio gadget: audio_buf_size 48000, req_buf_size 200, req_count 256

g_audio gadget: Linux USB Audio Gadget, version: Dec 18, 2008

g_audio gadget: g_audio ready

# g_audio gadget: high speed config #1: Linux USB Audio Gadget

0 [Intel ]: HDA-Intel — HDA Intel

HDA Intel at 0xdfdfc000 irq 16

1 [Gadget ]: USB-Audio — Linux USB Audio Gadget

Linux 2.6.31.6-ADI-2010R1-pre-svn7883 with musb_h Linux USB Audio Gadget at usb

here,audio gadget device is shown up as sound card 1.

На стороне ПК с Windows появится новое устройство.

Тестирование

Проигрывание музыки на ПК под Linux через новое устройство, как показано выше, это звуковая карта 1:

Playing WAVE ‘a.wav’ : Signed 16 bit Little Endian, Rate 22050 Hz, Stereo

1. Где брать корректную информацию. Ссылки с сайта проекта либо не открываются, либо содержат устаревшую или некорректную информацию. Попытки получить ответы по указанным электронным адресам и на IRC канале также успехом не увенчались.

2. Как можно сделать простейшую проверку драйвера?

3. Почему при отключении эмуляции OSS в ядре отключаются интерфейсы timer и PCM и невозможно скомпилировать драйвер?

4. Можно ли проигрывать звук не пользуясь интерфейсом PCM. Например, если кодек поддерживает аппаратное кодирование/декодирование данных?

5. Как расчитывать параметры драйвера period_bytes_min, period_bytes_max, periods_min, periods_max для получения требуемой задержки?

6. При трассировке плеера aplay видны запросы библиотеки libasound_module_rate_speexrate.so. Однако, это библиотека входит в набор для Debian. Каким образом происходит проигрывание на других системах?

Драйверы для микросхем Analog Devices

Ben Collins. Writing an ALSA driver

Introduction to Sound Programming with ALSA

Audio in embedded Linux systems

A Guide Through The Linux Sound API Jungle

Драйвер под Linux (не ALSA) для звукового кодека vs1053 с примером под плату MMnet1002

Источник статьи: http://dmilvdv.narod.ru/AT91SAM9260/howto_audio.html

Пишем свой первый Windows-драйвер

Итак, после моей предыдущей статьи я понял что тема про программирование драйверов Windows интересна хабровчанам, поэтому продолжу. В этой статье я решил разобрать простую программу-драйвер, которая делает только то, что пишет отладочное сообщение «Hello world!» при старте драйвера и «Goodbye!» при завершении, а также опишу те средства разработки, которые нам понадобятся для того, чтобы собрать и запустить драйвер.

Итак, для начала приведем текст этой несложной программы.

  1. // TestDriver.c
  2. #include
  3. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
  4. VOID UnloadRoutine(IN PDRIVER_OBJECT DriverObject);
  5. #pragma alloc_text(INIT, DriverEntry)
  6. #pragma alloc_text(PAGE, UnloadRoutine)
  7. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
  8. <
  9. DriverObject->DriverUnload = UnloadRoutine;
  10. DbgPrint( «Hello world!\n» );
  11. return STATUS_SUCCESS;
  12. >
  13. VOID UnloadRoutine(IN PDRIVER_OBJECT DriverObject)
  14. <
  15. DbgPrint( «Goodbye!\n» );
  16. >

* This source code was highlighted with Source Code Highlighter .

Итак, теперь сначала разберемся, что делает каждая инструкция. Перво-наперво мы подключаем заголовочный файл ntddk.h. Это один из базовых подключаемых файлов во всех драйверах: в нем содержатся объявления типов NTSTATUS, PDRIVER_OBJECT, PUNICODE_STRING, а также функции DbgPrint.

Далее идет объявление двух функций: DriverEntry и UnloadRoutine. Расскажу о первой поподробнее. Итак, как уважаемые читатели знают, в каждой программе есть точка входа, в программах на языке C это функция main или WinMain. В драйвере роль точки входа выполняет функция DriverEntry, которая получает на вход указатель на структуру DriverObject, а также указатель на строку реестра, соответствующую загружаемому драйверу.

Структура DriverObject содержит множество полей, которые определяют поведение будущего драйвера. Наиболее ключевые из них — это указатели на так называемые вызываемые (или callback) функции, то есть функции, которые будут вызываться при наступлении определенного события. Одну из таких функций мы определяем: это функция UnloadRoutine. Указатель на данную функцию помещается в поле DriverUnload. Таким образом при выгрузке драйвера сначала будет вызвана функция UnloadRoutine. Это очень удобно, когда драйвер имеет какие-то временные данные, которые следует очистить перед завершением работы. В нашем примере эта функция нужна только чтобы отследить сам факт завершения работы драйвера.

Для того, чтобы выводить отладочные сообщения мы используем функцию DbgPrint, которая имеет синтаксис, аналогичной функции printf из пользовательского режима (userspace).

В этом простом примере мы использовали также директивы #pragma alloc_text(INIT, DriverEntry) и #pragma alloc_text(PAGE, UnloadRoutine). Объясню что они означают: первая помещает функцию DriverEntry в INIT секцию, то есть как бы говорит, что DriverEntry будет выполнена один раз и после этого код функции можно спокойно выгрузить из памяти. Вторая помечает код функции UnloadRoutine как выгружаемый, т.е. при необходимости, система может переместить его в файл подкачки, а потом забрать его оттуда.

Вы можете задуматься, мол ну с первой-то директивой понятно, типа оптимизация и все такое, но зачем мы используем вторую директиву, зачем помечать код как возможный к выгрузке в файл подкачки? Поясню этот вопрос: каждый процесс в системе имеет такой параметр, как IRQL (подробнее читаем по ссылке Interrupt request level ибо это материал отдельной статьи), то есть некоторый параметр, отвечающий за возможность прерывания процесса: чем выше IRQL тем меньше шансов прервать выполнение процесса. Возможности процесса так же зависят от IRQL: чем выше IRQL тем меньше возможности процесса, это вполне логично, т.е. такой подход побуждает разработчиков выполнять только самые необходимые операции при высоком IRQL, а все остальные действия делать при низком. Вернемся к основной теме, о том, почему мы делаем для функции UnloadRoutine возможность выгрузки в файл подкачки: все опять же сводится к оптимизации: работа с файлом подкачки недоступна при высоком IRQL, а процедура выгрузки драйвера гарантированно выполняется при низком IRQL, поэтому мы специально указываем руками что код функции выгрузки драйвера можно поместить в своп.

Ух, вроде как с обсуждением кода этой, казалось бы небольшой программки закончено, теперь разберемся как скомпилировать и запустить наш драйвер.

Для этого нам понадобится:

  • WDK или DDK
  • Текстовый редактор
  • Программа DbgView — бесплатная программа для просмотра отладочных сообщений, получаемых от драйверов, ее можно найти на сайте sysinternals
  • Программа KmdManager — бесплатная программа для регистрации, запуска и тестирования драйвера, ее можно найти на сайте wasm.ru

Теперь последовательность действий: сначала мы пишем два файла, один называется MAKEFILE, с таким содержимым

##################################################
# DO NOT EDIT THIS FILE. Edit .\sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#

а второй называется sources и содержит в себе следующее:

Эти файлы нужны для сборки драйвера. Да, забыл сказать, что в WDK нет встроенной среды разработки, поэтому и нужен текстовый редактор, чтобы набирать текст драйверов. Для этой цели можно использовать и Visual Studio (некоторые даже интегрируют возможность сборки драйверов из VS), и любой другой текстовый редактор.

Сохраняем код драйвера в файл TestDriver.c и кладем его в ту же директорию, что и файлы MAKEFILE и souces. После этого запускаем установленный build environment (это командная строка с заданными переменными окружения для компиляции драйвера; она входит в WDK, и запустить ее можно как-то так: «Пуск->Программы->Windows Driver Kits->. ->Build Environments->WindowsXP->Windows XP x86 Checked Build Environment»). Переходим в директорию, куда мы положили файл с драйвером (у меня это C:\Drivers\TestDriver) с помощью команды cd (у меня команда выглядит следующим образом: cd C:\Drivers\TestDriver) и набираем команду build.

Данная команда соберет нам драйвер TestDriver.sys и положит его в папку «objchk_wxp_x86\i386».

Теперь нам нужно запустить программу DbgView чтобы увидеть сообщения, которые будет выдавать драйвер. После запуска данной программы нам нужно указать, что мы хотим просматривать сообщения из ядра (Capture->Capture Kernel).

Теперь запукаем программу KmdManager, указываем путь к нашему драйверу (файл TestDriver.sys) нажимаем кнопку Register, затем Run. Теперь драйвер зарегистрирован в системе и запущен. В программе DbgView мы должны увидеть наше сообщение «Hello World!». Теперь завершаем работу драйвера кнопкой Stop и убираем регистрацию драйвера кнопкой Unregister. Кстати, в DbgView дожна появиться еще одна строка.

Итак, чего же мы достигли: мы написали, скомпилировали и запустили свой первый Windows-драйвер! Добавлю только, что при написании сложный драйверов для отладки используется двухмашинная конфигурация, когда на одном компьтере ведется написание драйвера, а на другом — запуск и тестирование. Это делается из-за того, что неправильно написанный драйвер может обрушить всю систему, а на ней может быть очень много ценных данных. Часто в качестве второго компьютера используется виртуальная машина.

Источник статьи: http://habr.com/ru/post/40466/


0 0 голоса
Article Rating
Подписаться
Уведомить о
guest

0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии