Первоначально опубликовано на
Linux.com
(URL статьи)
Публикуется с разрешения Linux.com и поправками авторa
Иногда я удивляюсь, как просто изобрести колесо еще раз, и потом болтать
о том, скольких трудов
это стоило вначале. Эта статья для тех симпатизирующих мне "крепких орешков" :),
которые считают, что удовольствие от того, что ты сделал что-то самостоятельно, более
важно, чем быть пионером, первым человеком на земле, ступившем не луну ....
Я решил заставить PC speaker извергать рок музыку.
(Speaker - это та маленькая невидимая штучка в корпусе компьютера, которая пищит у вас под кожей,
когда вы становитесь непослушным.)
Я хотел заставить её играть настоящую музыку.
Мне не хотелось суетиться и писать весь код с нуля, для декодирования mp3, и т.д. и т.п.
Поэтому я поленился и решил немного поиграть с cамым задокументированным, самым изощренным из созданных когда-либо ядер операционных систем - Линукс ;)
Что вы делаете, когда вы впервые в городе и хотите попасть из точки 'a'
в точку 'b'? Я делаю глубокий вдох и начинаю свою прогулку по
деловому центру города. Я начинаю собирать информацию и открывать места.
Идиотизм? Просто попробуйте этот метод в городе ядра Линукс. Это головоломка
кода, головокружительный лабиринт перекрестно связанных директорий и makefile'ов.
Когда я начинал, я знал что это будет длительный проект. Но у меня
был 'посох' DOS и 'жезл' Peter Norton's guide to the IBM PC and Compatibles
со мной, чтобы придать мне немного храбрости. Поэтому я пошел большим шагом,
держа нос по ветру, готовый принять худших 'демонов' ;).
Патчи с драйверами для PC-speaker доступны для загрузки по следующим адресам,
ftp://ftp.uk.linux.org/pub/people/dwmw2/pcsp/ (Автор Michael Beck, поддержка David Woodhouse см.
http://linux-patches.rock-projects.com/v2.2-d/pcsp.html )
Я понимаю, нужно перекомпилировать ядро, чтобы они заработали. Когда я начинал,
я был готов свалять дурака и получить быстрые результаты. В конце концов это все игра, не так ли ? ;-)
Вот почему вы обнаружите ассемблерные фрагменты в коде. В любом случае, вот как это работает ...........
PC speaker: общие сведения
Внутренний динамик привязан к буфферизированному выводу микросхемы
таймера 8254 на всех PC. Затем вывод таймера 8254 запирается через встроенный
системный периферийный чип, через порт 61h. Небольшая диаграмма должна помочь,
я думаю. Вот она:
PIC расшифровывается как программируемый контроллер прерываний
Базовая частота 8254 - 1193180Hz, что, по совпадению, составляет 1/4 стандартной частоты NTSC.
Счетчики имеют значение делителей, которые, грубо говоря, используются для деления базовой частоты. Поэтому вывод канала 0 будет иметь частоту 1193180Hz если counter0=1,
596590Hz если counter0=2 и так далее. Поэтому сounter0=0 => частота приблизительно
18.2Hz, что точно соответствуют частоте с которой PIC прерывает процессор. В DOS,
PIC программировался чтобы вызывать Interrupt Service Routine (процедуру обработки прерывания) (ISR), по вектору 8.
На самом деле это значит, что значение counter0 будет определять
частоту с которой вызывается ISR таймера (Вектор 8 в DOS).
Изменение значения counter0, изменяет частоту с которой вызывается ISR таймера.
Поэтому если один и тот-же человек написал код для ISR и для программирования counter 0,
чипа таймера 8254, то он может заставить его ISR вызываться с заданной частотой.
Все это ведет в другую сторону.
Другая сторона: цифровое аудио
Когда вы слышите звук, вы знаете, что нечто рядом с вами вибрирует.
Если это что-то - динамик спикера, вы знаете, что есть электрический сигнал,
управляющий им. Поэтому мы всегда можем взять генератор сигнала за шкирку,
если мы хотим прекратить шум. Если нам нужно аудио, нам нужны вибрации, или
переменное напряжение. И мы знает что слово "цифровой" предполагает цифры, 1 и 0.
Как нам сложить это все вместе и получить цифровое аудио?
Давайте представим, что мы хотим, чтобы продолжительный гул будил нас ото сна по
утрам. Пожелайте удачи тому человека, который попробует продать такую поделку
мне :) ! Нам нужна продолжительная синусоидальная волна. Нечто вроде:
Цифры представляют насколько громким становиться звук в каждый момент.
Вы невольно выполняете здесь DSP (цифровую обработку сигнала). DSP - это
самая большая головная боль второго года обучения для большинства
студентов обучающихся Electrical Engineering. (Я один из них. Примите мои
искренные соболезнования.) Поэтому я лучше упомяну, что вы сейчас смотрите на
образцы. Эти значения -- все что вам нужно, чтобы воссоздать нужную нам волну.
Повторяйте это, и вы получите продолжительную волну. Итак если мы пробежимся через цифры
начиная с 1 через 7 через 0 через -1 через -7 через -1 к 0, в течении секунды,
мы получим очень приблизительную синусоидальную волну с частотой 1Гц. (Помните, Герцы это
количество циклов в секунду). Поняли механику работы? Хотите синусоидальную
волну с более плавными изгибами? Просто увеличьте число 'образцов', которые
вы берете за секунду. У нас взято 14. Что если бы их было 44000?
Это частота с которой CD проигрыватель изрыгает числа в свой DAC.
DAC - это ЦАП (Цифро-Аналоговый Преобразователь), небольшое устройство
которое преобразует 1 и 0, образующие двоичные числа, о которых мы ведем беседу,
в настоящее аналоговое, изменяющее во времени напряжение.
Наша небольшая техника кодирования, называется импульсной модуляцией кода.
Есть разные пути кодирования импульсов, поэтому у нас есть PCM, ADPCM и т.д.
Форма волны приведенная выше может быть описана как "4 бита, со знаком, моно PCM
с частотой сэмплирования 14Гц".
1 битный ЦАП
Итак вы спрашиваете меня, как это все используется, когда мы говорим о PC
speaker'е? Как насчет специального ISR таймера, которые заставил бы динамик
speaker'а вибрировать с предустановленной частотой, так, чтобы все, что программисту ISR
оставалось сделать - это заставить динамик двигаться с определенной амплитудой (
расстояние от нулевой линии) в соответствии со значением образца, которое он
получает из цифровых данных, например с CDROM. Это значит, что вы можете настроить таймер
ISR на 44000Гц и вот она - музыка CD качества - смотрит на нас! Совершенная логика,
если у вас есть ЦАП, чтобы преобразовывать каждый образец в соответствующее аналоговое
напряжение. На самом деле ЦАП парралельного порта делает именно это.
Просто оснастите его лесенкой резисторов R - 2R и приделайте конденсатор
к выходу, скормите это любому усилителю, даже микрофонный вход подойдет, и вуаля,
у вас есть цифровая музыка!
К сожалению, все не так просто с PC speaker.
Все потому-что PC speaker подсоединен не к ЦАП, а к чипу таймера.
Взгляните на форму выходной волны чипа таймера, к примеру для
синусоидальной волны:
У нас есть две дискретные величины, с которыми мы можем работать: Одна +5В,
другая 0В и ничего между ними. Как же нам получить Аналоговую волну?
О человек, зачем ты просишь о невозможном? Спросите инженеров из IBM, которые
разработали первые материнские платы для XT!
Но у нас есть очень тонкое и хитрое решение.
В технических терминах это означает: 1 битный DAC, Колебания и тому подобное.
Это нечто достаточно простое и легкое в реализации, и когда-то в конце концов оно было обречено на свое воплощение в жизнь. Я сомневаюсь, что старый XT-шный бедолага из IBM, когда либо мечтал о 1,5 Ггц Пентиумах, когда он устанавливал свой 8086 на материнской плате в первый раз.
Идея состоит в том, чтобы двигать динамик PC speaker'а рывками, когда мы не можем просто
перевести его на отметку постепенно. Напомню вам, на 22Кгц динамик это
здоровенный ленивый парень, он неохотно двигается на установленную отметку.
На полпути туда, беря передышку, так, что если он перегружен и динамик
зашел слишком далеко, у него появляется время, чтобы вернуться назад.
Нечто вроде анти-блокировочных тормозов в автомобилях. Когда вы наполовину
вжимаете педаль тормоза, механизм начинает попеременно включать и выключать тормоза.
Когда вы выжимаете педаль, тормозные колодки на самом деле не прижимаются
к колесному диску, они бьются об него в яростном темпе. Так что колесо не блокируется.
Аналогично, чем быстрее вы бьете динамик пяти-вольтовым импульсом, тем дальше
он двигается от центральное линии. Бинго! Изменяйте частоту импульсов
в соответствии с нужной амплитудой. Я назвал DOS версию fm.com, просто чтобы напомнить
себе что идея на самом деле проста.
Теперь отправляйтесь назад к первой иллюстрации и посмотрите на счетчик 2, чипа 8254.
Куда он ведет? К PC speaker, конечно. Теперь все, что нам нужно сделать, чтобы получить НАСТОЯЩИЙ
звук, - это сбросить отмаштабированное значение (помните 1 < значение счетчика < 65535) что пропорционально
значению образца (значение => амплитуды в PCM). Мы делаем это из нашего хэка ISR таймера.
Посмотрите на функцию myhandler() в myaudio.h.
Время экзамена!!!!!
smpl1 smpl2 smpl3
_______ ___ _
| | | | | |
| | | | | |
| |_| |___| |_____
Можете ли вы угадать значения smpl1,smpl2 и smpl3 ?
Линукc, а вот и мы !
Ядро Линукс - это потрясающий пример программирования, с той точки зрения, что
он был организован настолько хорошо, что человек с небольшими знаниями или вообще
без знаний ассемблера, может написать большой фрагмент кода ядра (на самом деле около 99% [поспорим :)] написано на "c"). Оно также спроектировано таким образом, что драйвера устройств
получают предопределенное окружение и элегантный, исчерпывающий программный интерфейс для
написания кода.
Код ядра очень портабелен, т.е. он может быть скомпилирован на разнообразных машинах
(процессорах вроде i86, alpha, sparc). Я думаю, что это правильная логика,
писать шаблоны кода, которые могут быть тщательно проработаны и приспособлены
для конкретного "железа". Говоря по Английски :), я могу лучше проиллюстрировать этот
принцип при помощи примера. Предположим, что вы хотите опубликовать свою докторскую диссертацию о том, как
стирать бельё, используя вашу марку стиральной машины.
Вы напишите последовательность шагов, начиная с:
1) Вставьте шнур питания в настенную розетку и включите питание
...
n) Наконец, выньте вашу одежду из кучи и вывесите на веревочке.
Последовательность от 1 до n может быть различна, в зависимости от того,
была ли ваша стиральная машина полу- или полностью автоматической, обладала
ли загрузкой сверху или сбоку (попробуйте шаг 'n' для машины с боковой загрузкой, и
пришлите мне e-mail об этом) и других переменных. Инструкции в вашем очерке будут
подходить для одной стиральной машины, но что если вы свободный писатель пользовательских
руководств и вам нужно написать руководство для тысячи марок?
Возьмем случай с интерфейсом устройства /dev/dsp, интерфейс по умолчанию для PCM
(импульсно модулированный код) и закодированного PCM звука.
Hannu Savolainen сконструировал большую часть интерфейса, а Alan Cox сделал
примечательные дополнения. Но эти разработчики -- конечно правильно -- не оставили места для
одного маленького устройства, называемого PC-speaker, в пользу AWE 64 и тому подобных карт.
Они решили что все DSP устройства имеют как минимум поддержку DMA (Direct Memory Access
это технология, при помощи которой "умные" периферийные чипы берут на себя заботу о
чтении/записи данных в RAM, без вовлечения процессора), или буферы на карте,
если не сопроцессоры (т.е. процессоры на плате). Поэтому они поместили код DMA
регистрации в качестве обязательной части OSS API. OSS API имеет два уровня экспортированных
функций: одни экспортируемые soundcore.o и другой набор, экспортируемый sound.o
sound.o размещается поверх soundcore.o и использует его экспортированные функции, как и любой другой драйвер устройства. Он предоставляет простой интерфейс для портабельных драйверов устройств и
поддерживает "продвинутые" функции вроде DMA доступа. (Современные звуковые карты поддерживают как минимум DMA)
Вот где начинается "взлом". Мы должны обойти стандартный интерфейс OSS, и использовать
интерфейс soundcore напрямую. Это означает, что пришло время для другого технического разговора -- символьные устройства в Линукс.
Символьные устройства в Линукс
В Линукс, два основных типа устройств: блочные и символьные.
(Мы игнорируем сетевые устройства, т.к. они не являются настоящими "устройствами",
скорее интерфейсами.)
Блочные устройства подразумевают наличие некоторых определенных характеристик,
таких как чтение и запись блоками, буферизация, разбиение на разделы и т.д.
Жесткий диск - это отличный пример блочного устройства. Приложение обычно
обращается к жесткому диску через драйвер файловой системы. Вот почему в
Unix вы монтируете накопители и не обращаетесь к ним сектор-за-сектором.
Символьные устройства предназначены для по-байтного чтения и записи (например
последовательный порт), но прозрачно буфферизируются, чтобы улучшить пропускную
способность системы. Приложение обращается к ним при помощи обычных файловых
операций с соответствующими нодами. Ноды устройств это специальные "файлы", к которым
можно обращаться через обычное дерево каталогов. Если вы хотите писать в звуковое устройство,
по умолчанию, /dev/dsp это нода устройства используемая для этого.
Заметьте, что нода любого устройства, которая указывает на соответствующий номер устройства,
зарегистрированный драйвером, может использоваться для доступа к этому драйверу.
Например, нода /dev/dsp привязана к номеру устройства 14/3. (попробуйте: file /dev/dsp;
на вашей системе). Вы с равным успехом можете обращаться к нему через /dev/mynode,
если /dev/mynode указывает на 14/3. Проверьте man страницы mknod на предмет
точного синтаксиса команды.
Теперь, если у вас есть .wav файл специфичного формата, скажем 16-бит, стерео,
чистый pcm, чтобы проиграть его на вашем системном звуковом устройстве, вы можете открыть
ноду /dev/dsp, используя системный вызов open, и открыть ваш .wav файл, считать блок данных из .wav файла, и записать его в ноду /dev/dsp, используя системные вызовы read и write соответственно.
АГА! И угадайте - какая программа способная сделать это уже доступна? Наша любимая cp!
Поэтому в следующий раз попробуйте, cp -f fart.wav /dev/dsp. И расскажите мне, как это звучало.
Бьюсь об заклад, что, если вы не очень удачливы, вы не получите правильный звук, даже если вы играете Celine Dione. Это происходит потому-что звуковому драйверу нужно сказать, какой формат необработанных данных он получает.
Чаще всего, вы будете пытаться проигрывать 16-битные стерео файлы с частотой 44khz на 8-битном моно 8Кгц драйвере. Это все равно что пытаться проигрывать LP диск на неправильной частоте вращения.
Системный вызов ioctl (input/output control -- управление вводом/выводом) используется на /dev/dsp, чтобы говорить с драйвером устройством. К сожалению, конкретный синтаксис вызова ioctl
оставлен на усмотрение автора драйвера устройства. Это похоже на хаос,
творящийся на рынке приложений для DOS. К счастью у нас есть несколько распознаваемых
соглашений в Линукс, самые популярные из которых это OSS или Open Sound System (Открытая Звуковая система). Это интерфейс встроенный в Линукс Sovolainen & Co.
Итак у нас есть XMMS plug-in'ы для OSS на стороне приложений, и множество драйверов
на стороне ядра.
Ядро
Когда приложение делает "вызов" open, оно на самом деле вызывает что-то.
Это что-то - это процедура ядра (помните, open это системный вызов).
Ядро сконструировано так, чтобы передавать вызов к соответствующему драйверу устройства.
Восхитительно прекрасная особенность ядра Линукс -- это то, что вы можете приказать ядру
вызывать вашу функцию, для конкретного номера устройства. Эта называется регистрацией
обработчика устройства, и это вызов в режиме ядра, т.е., вы не можете писать приложения,
которые делают эти вызовы, и могут быть запущены с терминала. Аналогично вы
можете "играть" с ядром, и передавать вызовы пользователя последующим функциям,
если вы сконструируете и экспортируете свои собственные функции регистрации.
Это точно то, что делает soundcore.o, через register_sound_dsp(). (Хорошо, орошо
, подождите, спросите меня. Мы скоро "нырнем" в звуковые модули OSS. Просто надо
убедиться, что в бассейне есть вода!). Вы используете для этого insmod, и пишите
специальную программу называемую модулем ядра, которую insmod может загрузить
в пространство ядра и присоединить к системным вызовам ядра.
Главное различие между системными вызовами и вызовами в режиме ядра, это то что
системные вызовы должны соответствовать общепринятым соглашениям, если они должны
распознаваться как часть Unix. (Помните "what is Linux" FAQ?) Говоря
по другому, ядро - это Линукс. Итак, нам нужно следовать лишь соглашениям ядра Линукс
при программировании ядра, и напомню вам, от 9 до дюжины соглашений ядра Линукс
меняется с каждым релизом. Вот почему у нас есть "pre-x.xx.xx version compile only"
предупреждения со многими релизами двоичных модулей. По минимуму, нам нужно иметь
функции read и write, не считая open и close. Ядро Линукс определяет функцию, называемую
init_module и другую называемую cleanup_module, которые вызываются ядром при подключении
и изъятии нашего модуля. (Нечто вроде main() в пространстве пользователя). Другими словами,
когда мы пишем функцию init_module, мы подразумеваем, что имеем полный контроль над системными
портами, памятью и т.д. и что мы можем вызывать все доступные функции ядра. Другая
интересная вещь заключается в том, что любая функция ядра или модуля может быть экспортирована
в таблицу символов ядра (смотри /proc/ksysm на предмет списка), так, что её можно вызвать
из любой другой функции ядра или модуля. Другими словами, исполнимый файл ядра, /boot/vmlinuz,
в оригинально был C программой запускаемой с main(), также как и любая другая программа
написанная вами или мной на C.
Не считая того, что скобочки были заполнены
весьма талантливым программистом по имени Линус Торвальдс.
Регистрация нашего драйвера
Самая критичная часть всей дискуссии - это, конечно, сам код. Регистрация драйвера производится
при помощи функции register_sound_dsp, экспортированной модулем soundcore.o,
который, как я объяснял раньше, часть стандартного дистрибутива OSS.
Все, что она делает, это пропускает вызов open от приложения пользователя.
Большая часть кода интуитивно-понятна. Ассемблер GNU (оригинальный
формат ассемблера AT&T) имеет дело с "прицеплением" обработчика прерывания таймера.
Функции setvect и getvect работают в целом так же, как они делают это в DOS.
(ОК давайте, вперед, скажите ХЭЙ - я знаю что ты врешь. Я не был рожден
в Bell labs, знаете-ли :)
К рабочему драйверу устройства
Для нас основная работа заключается в том, чтобы получить работающий драйвер устройства,
который может получить доступ к PC speaker через порт таймера 8254, и проделывать
фокусы, которые будут копировать звуковые данные приложения в PC speaker, байт за
байтом.
OSS создает ноду устройства называемую /dev/dsp для нас. Наш драйвер
называемый myaudio.o может быть загружен в действующее ядро при помощи
insmod myaudio.o, и удален rmmod myaudio. /dev/dsp указывает на наш драйвер,
после insmod.
Давайте взглянем на структуру программы. Нам нужно сделать следующее:
1) Зарегистрировать наше поддельное dsp устройство
2) Прицепиться к прерыванию таймера и установить прерывание на нужную
частоту сэмплирования.
3) Напечатать сообщение, которое говорит "Фью"!
Ядро скажет вам, если что-то пошло не так. Во многих случаях, оно перезагрузит
для вас систему.
Когда драйвер выгружен, нам нужно восстановить систему к её предыдущему
состоянию, выполнив следующие шаги:
4) "Отцепить" вектор прерывания таймера и сбросить прерывание на старую частоту.
5) Отменить регистрацию устройства dsp
6) Напечатать сообщение об успехе.
Взглянем на myhandler()
Код примера находиться в двух файлах называемых myaudio.c и myaudio.h.
myaudio.c содержит функции регистрации устройства, которые делают всё
вышеописанное. myaudio.h содержит очень важную функцию называемую ISR (
Interrupt Service Routine -- Процедура обслуживания прерывания).
Она называется myhandler(). Я думаю, что шаги описанные выше, лучше объясняются
путем чтения кода myaudio.c. Обратите свое внимание на myaudio.h, в частности
на myhandler().
Шаг 2 описанный выше, говорит: "прицепиться к вектору прерывания таймера".
Это означает, что ISR настраивается так, чтобы вызываться с нужной нам частотой.
Это означает, что когда я пишу код в ISR, я могу быть уверен в следующем:
a) Следующие данные приложения пользователя, если они доступны, должны быть
получены. b) Их нужно преобразовать в значение счетчика (counter) 2 8254 (
подробно обсужденного выше). c) Это значение счетчика должно быть сброшено
в регистр счетчика 2, 8254: т.е. задержка для PC-speaker устанавливается
в соответствии с значение полученных данных и d) Системный планировщик еще
не был вызван ! Решить вызывать-ли его.
Шаг d) требует отступления:
Если вы читали код setvect() в myaudio.c, вы должны были обнаружить, что
setvect использует несколько уловок, чтобы поместить myhandler в системную таблицу
векторов. Это специфично для Intel 386+. В режиме реальных адресов 8086,
все что нужно сделать чтобы перенаправить указатель ISR, это сохранить соответствующее
значение в таблице векторов прерываний (IVT), которая начинается с адреса 0000:0000 и
хранит 4х байтовые значения. (Т.к. полный длинный указатель в 8086 длиной 32 бита cs:ip).
Другими словами, для прерывания 8, которое является установленным BIOS по умолчанию для
IRQ 7 PIC'а (программируемый контроллер прерываний), просто измените значение указателя
по адресу 0000:0020 на полный адрес myhandler(). Здесь все немного усложняется.
В защищенном режиме i386+, в котором работает ядро Линукс, процессора, IVT называется IDT,
или Таблица Дескрипторов Прерываний. Более менее полное описание IDT заняло-бы
весь HOWTO (врет, все не так страшно :) - Прим. переводчика.), но я, подразумевая то, что вы знаете о защищенном режиме i386, если это
вам нужно, оставляю все жуткие детали для вашего докторской диссертации. Что
нам действительно нужно знать, это то, что указатель на myhandler разбросан по 8-байтной
области. Эта информация собирается вместе при помощи некоторых хитрых
инструкций ассемблера GNU, чтобы создать оригинальный ISR указатель, который
на самом деле указывает на системный ПЛАНИРОВЩИК (специальная программная процедура
в любой многозадачной операционной системе), указывающий на myhandler().
В задачи ПЛАНИРОВЩИКА входит отбирать управление у одной программы, когда истечет
её кусочек времени, и передавать его следующей.
Это называется pre-emptive многозадачность. В Линукс, временной фрагмент
выделяемый процессу равен 10 миллисекундам. Можете-ли вы угадать частоту с которой вызывается
ISR таймера, установленное по умолчанию? Это значение называется HZ, в ядре Линукс.
Весь фокус в том, что оригинальный ISR (планировщик) должен вызываться
с частотой 100Hz, но ISR требует вызова на частоте сэмплирования, обычно 22Кгц.
И если мы пренебрежем вызовом оригинального ISR, вся система развалится к чертям собачьим :).
Но есть простое решение. Если вы знаете частоту, с которой вы вызываетесь и с которой
должен вызываться оригинальный ISR, просто вызывайте его 1 раз, из нескольких.
Другими словами: на 22Кгц, увеличивайте значение счетчика на 1 при каждом вызове
и когда счетчик достигнет 220, вызывайте старый ISR, иначе шлите EOI (Конец прерывания)
PIC. Таким образом старый ISR будет вызываться ровно на 100Гц! Черная Магия !
Если вы забудете компенсацию для частоты, то будет очень интересно наблюдать, что
произойдет. Просто попробуйте. На моей системе, минутная стрелка xclock
вращалась как колесо рулетки!
Если вы взгляните на иллюстрацию выше, которая показывает, как прерывание
таймера 8254 прицепляется к PIC, вы заметите, что когда 8254 хочет прерваться,
он говорит PIC, через линию IRQ номер 7, (которая на самом деле просто кусок
медного провода встроенного в материнскую плату). В наши дни, конечно, множество
старых чипов интегрировано в один, так что можете не искать провод обозначенный
IRQ7 на вашей плате! PIC решает как и когда прерывать процессор. Есть стандартный
метод распределения прерываний, он называется определением приоритета прерывания (
prioritization), который находится целиком в ведении PIC. В Линукс, PIC
перепрограммируется, чтобы вызывать вектор 20, для ISR таймера (IRQ 7) как
для вектора 8 в BIOS и DOS. После каждого прерывания, соответствующая ISR
должна делать EOI, которое на самом деле означает outportb(0x20,0x20).
Поэтому нужно быть осторожным, чтобы убедиться, что не будет послано двойное EOT,
одно от вас, и одно от оригинального ISR, который не знает о вас.
Последний пункт.
Я полагаю, что это все, но перед тем как я уйду с чувством полного удовлетворения,
что я "запихал Латынь в тысячу глоток", я хочу прояснить несколько вещей о примере, который
я сделал в моем myaudio.x. Линукс имеет формальный метод объявления прерываний для
драйверов устройств. Проблема в том, что к тому времени, как загружается модуль,
планировщик уже объявил прерывание таймера. Поэтому нам нужно пойти на небольшой
взлом и украсть его у планировщика. Вот почему мы обсуждали IDT и все прочее.
Интерфейс OSS, который я написал в коде, это pre-alpha. На самом деле, вы можете
запускать приложения вроде mpg123, play и даже xmms и вы получите возможность
взглянуть на синхронизацию событий в Мульти-Мульти Операционных системах, если
вы добавите -D SPKDBG в опции компилятора в myaudio.mak. "-D SPKDBG" включает
отладочные сообщения. Однако будьте осторожны, ваша машина может не справиться
с огромным количеством данных поступающих в логи. Поэтому делайте это
только если вы действительно знаете, что делаете. Я поставил доработку OSS в
список TODO. Можете завершить её.
Сделайте следующее, чтобы использовать наш драйвер: Как пользователь root, перейдите в директорию
куды вы скопировали исходные файлы:
myaudio.c, myaudio.h, и myaudio.mak. Запустите:
make -f myaudio.mak
подразумевается, что вы имеете стандартный дистрибутив OSS на вашей машине.
(Путь в /usr/src/linux/drivers/sound. Проверьте это.)
modprobe sound
insmod myaudio.o
Теперь драйвер активен. Проверьте его при помощи:
lsmod
Поищите myaudio на верху списка. mpg123, play и xmms теперь должны работать как обычно.
Если не одно из выше указанных приложений не работает, то можно слушать MP3 музыку при помощи
следующей команды:
mpg123 -m -r 22000 --8bit -w /dev/dsp x.mp3 #это должно воспроизвести x.mp3
Наслаждайтесь!!!!
Примечание: Все эти операции необходимо проделывать как пользователь root.
Поэтому я предполагаю что вы используете вашу собственную машину, и готовы
испортить любую её часть, возможно навсегда. Я не могу взять на себя какую-либо
ответсвенность за то что случится с вашей системой из-за моего кода, поэтому
я настаиваю, чтобы вы пробовали его только на ваш страх и риск. Я проверял мой
пример на RedHat 7.1, запущенной на Celeron 366/64МБ RAM. Действительно
заинтересованным людям, которые не хотят рисковать своей машиной, я рекомендую
использовать патчи от Michael Beck, но тогда вы не читали бы этого, не так-ли?
Если ваш ответ был таков
smpl1>smpl2>smpl3, и smpl2=127
то вы прошли тест. Теперь можете наниматься в Creative labs ;)
Листинг программы:
Cherry George Mathew
Я студент, третий год обучающийся на инженера-электронщика в College of
Engineering, Adoor, Kerala, India. Вы можете связаться со мной по адресу http://berryplum.homestead.com/ или
[email protected],
я постараюсь ответить, если позволит время
.
|