netlib.narod.ru | < Назад | Оглавление | Далее > |
Небольшой, хорошо подобранный набор функций выполняет связывание и разрыв связи между действиями и IRQ. В этом разделе рассмотрены эти функции, а также функции, которые инициализируют систему IRQ в целом.
1597: init_IRQ инициализирует обработку IRQ.
1601: Символ CONFIG_X86_VISWS_APIC определен для рабочих станций SGI Visual Workstation, линии рабочих станций производства SGI, собранных на основе центрального процессора х86. Хотя они основываются на центральном процессоре х86, рабочие станции Visual Workstation не обладают многими другими характеристиками архитектуры IBM PC — в частности, они несколько иначе обрабатывают прерывания. Код, характерный для Visual Workstation, в книге рассматриваться не будет.
1609: Устанавливает таблицу дескриптора прерываний, присваивая стандартные значения записям с десятичными номерами от 32 до 95 (включительно). При этом используется функция set_intr_gate (строка 6647), которая вскоре будет рассмотрена.
1651: Устанавливает IRQ 2 (прерывание каскада) и 13 (для FPU — см. примечание в строке 955). Связанными с этими IRQ структурами struct irqactions соответственно являются irq2 (строка 979) и irq13 (строка 974).
1578: Эта функция заполняет массив irq_desc, инициализируя IRQ для компьютеров с шинами ISA (т.е. для всех стандартных PC). Хотя эта функция не объявляется static и не помечается тэгом __initfunc, она вызывается только функцией init_IRQ и, следовательно, нужна только во время инициализации ядра.
1583: Для каждого элемента массива irq_desc вполне оправданными и объяснимыми стандартными значениями являются значения, присваиваемые членам status, action и depth.
1589: Старые (использовавшиеся до появления PCI) IRQ обрабатываются структурой i8259A-irq-type (строка 723).
1592: IRQ с наибольшими номерами инициализируются значением no_irq_type (строка 701), которая по существу представляет собой ничего не выполняющий обработчик. Они могут быть изменены впоследствии — в действительности это и происходит при наличии каких-либо плат PCI, как имеет место в современных ПК.
6647: set_intr_gate устанавливает запись в таблице дескрипторов прерываний (interrupt descriptor table — IDT) процессора x86. Каждое аппаратное или программное прерывание, происходящее в системе на базе процессора х86, имеет номер, который используется центральным процессором в качестве индекса этой таблицы. (Включая прерывание системных функций — с номером 0x80 — которое было рассмотрено в главе 5.) Соответствующими записями в таблице являются адреса функций (ядра), к которым необходимо выполнить переход в случае прерывания.
1388: setup_x86_irq добавляет действие (структуру struct irqaction) для данного IRQ. Например, в строке 6088 это используется для регистрации прерывания таймера. Эта функция используется также, во время выполнения функции request_irq (строка 1439), которая исследуется в следующем разделе.
1398: Linux использует несколько источников физических случайных величин — например, прерываний — для передачи потока случайных значений устройствам /dev/random, источника ограниченных, но выбираемых по совершенно случайному закону данных и /dev/urandom, неограниченного, но менее случайного аналога /dev/random. Система генерации случайных значений в целом не освещается в этой книге, но если не знать о ее существовании, этот фрагмент кода кажется весьма непонятным.
1412: Если существующий список действий не пуст, setup_x86_irq должна убедиться, что существующие и новое действия согласны совместно использовать IRQ.
1414: Убеждается, что IRQ может использоваться совместно всеми существующими структурами struct irqaction, уже связанными с этим IRQ. Эта проверка очень эффективна, частично благодаря тому, что нет необходимости выполнять цикл по всем действиям в очереди и что каждое из них будет использовать IRQ совместно с другими. Ни одному действию, следующему за первым, не будет разрешено присоединиться к очереди, если только это действие не согласится использовать IRQ совместно с первым действием. Таким образом, если первое действие будет использовать IRQ совместно, это же будут делать и остальные действия в очереди; а если первое действие не согласно использовать IRQ совместно с другими, в очереди вообще не будет никаких других действий.
1420: IRQ, подлежащий совместному использованию, setup_x86 перемещает указатель р к концу очереди действий, оставляя его указывающим на поле next последнего элемента очереди. Кроме того, устанавливает флаг shared, который будет использоваться в строке 1429.
1427: Теперь указатель р указывает на поле next последнего элемента очереди, если IRQ должен использоваться совместно, или на irq_desc[irq].action — указатель начала очереди — если он не будет использоваться совместно. В любом случае указатель устанавливается на новый элемент.
1429: Если с IRQ еще не были связаны никакие действия, остальная часть структуры irq_desc[irq] еще не установлена и, следовательно, нуждается в инициализации в этом месте. В частности, обратите внимание на строку 1433, в которой вызывается функция startup для этого IRQ.
1439: request_irq создает из переданных значений структуру struct irqaction и добавляет ее в список структур struct irqaction для данного IRQ. (Если вы знакомы с языками программирования C++ или Java, можете считать эту функцию конструктором действий.) Ее реализация достаточно проста.
1448: Выполняет профилактическую проверку нескольких входных значений. Обратите внимание, что нет никакой необходимости проверять, меньше ли 0 значение irq, поскольку оно имеет тип без знака.
1453: Динамически выделяет новую структуру struct irqaction. Используемая для этой цели функция kmalloc кратко освещается в главе 8.
1458: Заполняет новое действие и с помощью setup_x86_irq предпринимает попытку добавить его в список действий.
1472: Действие функции free_irq противоположно действию request_irq. Если request_irq аналогична конструктору действий, то эта функция по своему действию наиболее напоминает деструктор.
1481: Убедившись, что значение irq находится в допустимом диапазоне, функция free_irq находит соответствующую запись в массиве irq_desc и начинает итерации по ее списку действий.
1483: Игнорирует этот элемент очереди, если только он не имеет правильный идентификатор устройства.
1487: Удаляет этот элемент из очереди и освобождает выделенную ему память.
1489: Если теперь очередь действий пуста — т.е., если только что был удален единственный элемент очереди — устройство отключается.
1495: Если поток управления доходит до этой точки, значит функция free_irq прошла весь список действий, не найдя походящего dev_id. Если бы она нашла соответствующий идентификатор устройства, оператор goto в строке 1493 привел бы к пропуску этой строки. Следовательно, имела место ошибочная попытка освободить действие IRQ; функция free_irq выводит предупреждение об этом.
1506: Функция probe_irq_on реализует значительную часть автоматического зондирования IRQ ядра. Описание всего процесса приведено в заглавном комментарии, начинающемся в строке 14889. Задачей этой функции является реализация третьего шага (только) этого описания: временно активизировать любые неприсвоенные IRQ, чтобы функция, вызывающая функцию probe_irq_on, могла их прозондировать.
1514: Для каждого IRQ, за исключением IRQ 0 (таймера), если IRQ еще не имеет никаких связанных с ним действий, функция probe_irq_on записывает, что данный IRQ должен быть определен автоматически, и запускает связанное с ним устройство. Кстати, не думаю, что выполнение этого цикла в обратном направлении обусловлено какой-либо специальной причиной.
1524: Занято — выжидает около одной десятой доли секунды, чтобы дать возможность выдать себя любым устройствам, которые генерируют фальшивые прерывания. Этот цикл мог бы начинаться с 1 а не с 0, поскольку IRQ, которые не выявляются автоматически, игнорируются, a IRQ 0 никогда не выявляется автоматически. Не то, чтобы это ускорение имело какое-либо значение в данном случае; по сравнению с задержкой в одну десятую секунды — целая вечность с точки зрения даже самого медленного процессора — выполнение на один цикл больше или меньше не имеет значения.
1537: Если устройство запускает прерывание во время задержки в строке 1524, вероятно, прерывание является фальшивым: во время этой задержки система не должна обращаться к этому устройству, значит, и устройство не должно было обращаться к системе. Бит автоматического выявления очищается и обработчик снова отключается.
1544: Возвращает магический номер 0x12345678, по причинам, которые станут понятны в ходе дальнейшего рассмотрения.
1547: probe_irq_off реализует вторую важную часть автоматического зондирования IRQ. В данном случае задача состоит в определении того, какие IRQ ответили на зондирующий запрос, и в возврате номера IRQ одного из них.
1551: Проверяет неудачно названный аргумент unused, чтобы выяснить является ли он тем же магическим номером, который возвращает функция probe_irq_on. Предполагается, что вызывающая функция выполняет нечто вроде следующего:
magic = probe_irq_on(); /* ... */ probe_irq_off (magic);
Если функция probe_irq_off оказывается вызванной каким-либо иным образом (например, какая-либо дополнительная логика в вызывающей функции случайно приведет к пропуску вызова функции probe_irq_on), то переданный аргумент вряд ли имеет правильное значение. Вероятно, еще большее значение имеет то, что этот аргумент передает определенную информацию программисту, который создает код для его использования: при исследовании того, каким должен быть этот аргумент, приходится выяснять протокол, который предполагается использовать при вызове этого аргумента. Эта тактика вполне могла бы иметь более широкое распространение. Исходя строго из следующего сообщения об ошибке, кажется, что предыдущая версия функции могла принять в качестве своего аргумента что-то вроде адреса вызывающей функции. Если это так, то эта проверка служит и третьей цели: выявлению того, что какая-то вызывающая функция продолжает неверно использовать функцию.
1557: Выполняет цикл по всем IRQ, отыскивая любые устройства, которые ответили на зондирующий запрос вызывающей функции. Этот цикл также мог бы начинаться с 1, по тем же причинам, что были приведены во время предшествующего рассмотрения функции probe_irq_on.
1560: Ядро не пытается выявить что-либо, связанное с этим IRQ; оно переходит к следующему.
1563: Флаг IRQ_INPROGRESS указывает, что прерывание прибыло для этого IRQ. Поскольку предположительно функция probe_irq_on отсекает любые фальшивые прерывания, представляется вполне разумным ответить на зондирующий запрос. Значение счетчика успешно автоматически прозондированных IRQ увеличивается с сохранением номера первого IRQ.
1568: Независимо от того, был ли этот IRQ успешно автоматически прозондирован, флаг автоматического выявления снимается, и обработчик снова отключается.
1573: Если было успешно автоматически прозондировано более одного IRQ, это сообщается вызывающей функции путем отрицания значения irq_found.
1575: Возвращает значение irq_found — 0 или (возможно отрицательный) номер первого успешно автоматически прозондированного IRQ. Обратите внимание, что это значение никогда не равно 0, если устройство было найдено, поскольку ядро никогда не пытается автоматически выявить IRQ 0. Следовательно, функция probe_irq_off возвращает 0 только тогда, когда никакие IRQ не были выявлены автоматически.
netlib.narod.ru | < Назад | Оглавление | Далее > |