Что такое драйвер контроллера
В этой статье я хочу провести краткий обзор шины SPI (интерфейса, широко распространённого во встраиваемой технике, используемого для подключения различных устройств) и попытаюсь описать процесс создания драйвера протокольного уровня SPI устройства для Linux. Данный документ не претендует на роль полного руководства, а скорее преследует цель указать нужное направление. Так как статья не вошла в размер одного топика, мне пришлось разбить её на две части.
0. Вместо введения
Что это за статья?
Эта статья представляет собой компиляцию информации из различных источников, вольный перевод некоторых частей документации, а также мои собственные комментарии, дополнения и описания возникших проблем.
- Что такое SPI?
- Обзор SPI подсистемы в Linux
- Разработка userspace протокольного SPI драйвера с использованием spidev
- Разработка протокольного SPI драйвера уровня ядра
- Документация
Первый подраздел описывает работу шины SPI, данная часть статьи конкретно к Linux никак не привязана, поэтому её можно читать тем, кому Linux не интересен, а нужно лишь получить информацию об этом интерфейсе.
Второй подраздел описывает структуры и механизмы лежащие в основе работы с SPI в Linux, его нужно прочесть для понимания того, о чём пойдёт речь в третьей и четвёртой частях.
Если вас не интересует мои переводы и дополнения, можете смело переходить сразу к пятой части, там можно найти информацию о том, где получить всю необходимую информацию по данному вопросу.
Если вы видите ссылки в названии какой-либо структуры или функции, можете открыть её в новой вкладке, так вы сможете попасть непосредственно на описание данной структуры/функции в официальной документации к ядру Linux.
Ошибки
Я не волшебник, я только учусь. Если найдёте какие-либо ошибки или неточности, пожалуйста, сообщите мне.
1. Что такое SPI?
Аббревиатура SPI означает «Serial Peripheral Interface» или в русском варианте «последовательный периферийный интерфейс». Название говорит само за себя, данный интерфейс используется для работы с различными периферийными устройствами. Например, это могут быть различные ЦАП/АЦП, потенциометры, датчики, расширители портов ввода/вывода (GPIO), различная память и даже более сложная периферия, такая как звуковые кодеки и контроллеры Ethernet.
С технической точки зрения SPI — это синхронная четырёхпроводная шина. Она представляет собой соединение двух синхронных сдвиговых регистров, которые является центральным элементом любого SPI устройства. Для соединения используется конфигурацию ведущий/ведомый. Только ведущий может генерировать импульсы синхронизации. В схеме всегда только один ведущий (в отличие от той же шины I2C, где возможен вариант с более чем одним ведущим), количество ведомых может быть различно. В общем случае выход ведущего соединяется со входом ведомого, и наоборот, выход ведомого соединяется со входом ведущего. При подаче импульсов синхронизации на выход SCK, данные выталкиваются ведущим с выхода MOSI, и захватываются ведомым по входу MISO. Таким образом если подать количество импульсов синхронизации соответствующее разрядности сдвигового регистра, то данные в регистрах обменяются местами. Отсюда следует что SPI всегда работает в полнодуплексном режиме. А вот нужны ли нам данные, полученные от устройства при записи какого-либо параметра, это уже другой вопрос. Часто бывает что данные полученные от устройства при записи в него данных являются мусором, в таком случае их просто игнорируют, но мы их получим вне зависимости от нашего желания.
Контроллер SPI, как правило, реализуется периферийным блоком в MCU или eMPU. В большинстве чипов он может работать как в режиме ведущего, так и в режиме ведомого. Но на данный момент Linux поддерживает только режим ведущего (Master).
Существует несколько способов включения SPI устройств.
Простейший из них вы видите на рисунке выше (спасибо Wikipedia за рисунки под свободной лицензией GFDL). В данном случае к ведущему все ведомые подключаются параллельно, за исключением сигнала выбора ведомого (~CS). Для каждого ведомого необходим отдельный сигнал выбора ведомого (на рисунке они обозначены как SSx). Для сигналов выбора ведомого могут использоваться как специально предназначенные для этого выходы SPI-контроллера, так и порты ввода/вывода общего назначения (GPIO) микроконтроллера.
- MOSI — Master Output, Slave Input (выход ведущего, вход ведомого). Данный сигнал предназначен для последовательной передачи данных от ведущего к ведомому. Также может называться SDO, DO и т.п.
- MISO — Master Input, Slave Output (вход ведущего, выход ведомого). Данный сигнал предназначен для последовательной передачи данных от ведомого к ведущему. Может называться SDI, DI и т.п.
- SCK — Serial Clock (сигнал синхронизации). Используется для синхронизации при передаче данных. Также может иметь название SCLK, CLK и др.
- ~CS — Chip Select (выбор микросхемы). С помощью данного сигнала происходит активация ведомого устройства. Обычно он является инверсным, то есть низкий уровень считается активным. Иногда его называют ~SS (Slave Select, рус. «выбор ведомого»).
Частным случаем независимого подключения является вариант с одним единственным ведомым. В таком случае может возникнуть желание подтянуть сигнал ~CS к земле, чтобы устройство всегда было в активном состоянии. Но делать это крайне не рекомендуется, так как ведомое устройство может использовать сигнал CS для инициализации или для других служебных целей.
Основное неудобство при независимом подключении ведомых в том, что для каждого из ведомых необходим отдельный сигнал ~CS. Каскадная схема подключения, в зарубежной литературе называемая «daisy-chain» (можно перевести как «гирлянда»), лишена такого недостатка.
Как видно из рисунка выше, здесь используется общий сигнал выбора ведомого для всех ведомых. Выход каждого из ведомых соединяется со входом следующего. Выход последнего ведомого соединяется со входом ведущего, таким образом образуется замкнутая цепь. При таком подключении можно считать что последовательно соединённые устройства образуют один большой сдвиговый регистр. Соответственно, данные можно записать во все устройства «за один присест», предварительно собрав нужный пакет, объединяющий данные для каждого из устройств в порядке соответствующем физическому порядку соединения. Но тут есть один тонкий момент. Во-первых, все микросхемы должны поддерживать такой тип подключения; во-вторых, ядро Linux не поддерживает такой тип подключения, так что если всё же захотите его использовать, то вам придётся модифицировать существующие драйвера, либо же написать собственные.
- CPOL (Clock Polarity) — определяет начальный уровень (полярность) сигнала синхронизации.
CPOL=0 показывает, что сигнал синхронизации начинается с низкого уровня, так что передний фронт является нарастающим, а задний — падающим.
CPOL=1, сигнал синхронизации начинается с высокого уровня, таким образом передний фронт является падающим, а задний — нарастающим. - CPHA (Clock Phase) — фаза синхронизации, определяет по какому из фронтов синхронизирующего сигнала производить выборку данных.
CPHA=0 показывает что необходимо производить выборку по переднему фронту, а
CPHA=1 показывает что выборку данных необходимо производить по заднему фронту.
2. Обзор SPI подсистемы в Linux
Вторая часть — это протокольные драйверы, используемые для работы с различными ведомыми устройствами, которые подключены к шине SPI. Данные драйверы называют «протокольными», потому что они лишь отправляют и получают различные данные от ведомых устройств, при этом не работая напрямую с каким-либо оборудованием. Именно данный тип драйверов нам наиболее интересен, так как позволяет добавить поддержку интересующего ведомого устройства в систему, его то мы и рассмотрим.
Большинство протокольных драйверов представляет собой модули ядра. Например, если устройство представляет собой аудиокодек подключаемый по SPI, то драйвер будет также использовать функции предоставляемые ALSA, а программы (например, madplay) смогут работать с ним посредством символьного устройства /dev/audio, не имея ни малейшего понятия о том как он аппаратно устроен и к какой шине подключен.
Также ядро предоставляет протокольный драйвер общего назначения, называемый spidev, с интерфейсом в виде символьного устройства. Он позволяет совершать полудуплексные обращения к ведомому SPI-устройству посредством стандартных системных вызовов read() и write(), устанавливать режим работы, а также производить полнодуплексный обмен данными посредством ioctl() вызовов.
- userspace драйверы, работающие в пространстве пользователя и представляющие собой обычные программы на любом языке, работающие с SPI устройством посредством чтения/записи соответствующего символьного устройства spidev.
- драйверы, работающие в пространстве ядра и предоставляющие интерфейс для userspace посредством файлов устройств в каталоге /dev, либо с помощью атрибутов в каталоге устройства в sysfs.
tx_buf — указатель на буфер данных в пространстве памяти ядра, которые необходимо передать, либо NULL;
rx_buf — указатель на буфер данных в пространстве памяти ядра, в который данные следует считать, либо NULL;
len — размер буферов rx и tx в байтах;
tx_dma — DMA адрес tx_buf, используется если установлен параметр spi_message.is_dma_mapped;
rx_dma — DMA адрес rx_buf, используется если установлен параметр spi_message.is_dma_mapped;
speed_hz — устанавливает скорость для передачи, отличную от установленной по-умолчанию для устройства. Если данное значение равно 0, то используется скорость по-умолчанию, указанная в поле max_speed_hz структуры spi_device.
bits_per_word — устанавливает количество бит на слово, отличное от определённого по умолчанию. Если данное значение равно 0, то используется значенние по-умолчанию, указанное в поле bits_per_word структуры spi_device.
delay_usecs — время ожидания в микросекундах, после того как был отправлен последний бит передачи и перед тем как сменить состояние chipselect'а, либо начать передачу следующей передачи в очереди. Будьте крайне осторожны с данным параметром, нужно смотреть в какой части драйвера контроллера реализуется задержка. Например, для чипов серии at91 она реализована в обработчике прерывания, так что её использование чревато последствиями.
При инициализации структуры spi_transfer существует очень важный момент, они обязательно должны быть выделены в области памяти доступной для DMA через kmalloc, kzalloc и иже с ними. Если master-драйер использует dma, то при использовании статически объявленных массивов драйвер будет падать при попытке передачи.
При передаче данных по SPI количество записанных бит всегда равно количеству считанных. Протокольные драйверы всегда должны предоставлять указатели на буферы tx_buf и/или rx_buf. В некоторых случаях они могут предоставлять DMA адреса для передаваемых данных.
Возможность переопределения скорости передачи данных и количества бит на слово для каждой передачи в отдельности зависит от конкретной реализации драйвера и аппаратных возможностей контроллера. Например, для контроллера SPI в чипах серии at91 возможность переопределения полей speed_hz и bits_per_word не предусмотрена, поэтому они должны быть всегда установлены в 0, иначе вы получите ошибку при попытке передачи данных.
Если указатель на tx_buf установлен как NULL, то SPI контроллер будет выталкивать нули при заполнении буфера rx_buf. В случае, когда rx_buf установлен в NULL, считываемые данные будут игнорироваться. Количество выталкиваемых (и захватываемых) байтов всегда равно len. Попытка вытолкнуть только часть слова приведёт к ошибке. (Например, при попытке выталкивании трёх байт и длине слова 16 бит или 20 бит, в первом случае будет использовано 2 байта на слово, во втором — 4 байта).
Данные для передачи всегда хранятся в порядке специфичном для данной аппаратной платформы. При отправке/считывании данных происходит автоматическое конвертирование порядка байт из специфичного для SPI (обычно big-endian, за исключением случая когда выставлен параметр SPI_LSB_FIRST) в аппаратно-специфичный порядок для данного CPU. Например, если параметр bits_per_word равен 16, то буферы будут занимать по 2N байт, и содержать по N слов с длиной 16 бит каждое, хранящемся в байтовом порядке, специфичным для данного CPU.
В том случае, если размер слова не является степенью двойки, то представление слова в памяти включает дополнительные биты. Слова, хранящиеся в памяти для протокольного драйвера всегда являются выровненными по правому краю (right-justified), так что дополнительные биты всегда будут являться старшими разрядами.
Для наглядности снова приведу осциллограмму:
В данном случае tx-буфер содержит значение 0xf98e, установленное значение bits_per_word соответствует 12 битам на слово. Устройство работает в SPI_MODE_0. На рисунке синяя линия соответствует выходу MOSI контроллера, а жёлтая — SCK. Здесь хорошо видно что при отправке пришло только 0x098e, старшие четыре бита были отброшены, так как они считаются дополнительными. Если совсем просто, то одно 12-битное слово занимает в памяти два байта, а разница между размером слова в памяти и его действительным размером составляет 2*8 — 12 = 4 бита, которые отбрасываются при передаче.
SPI не поддерживает какого-либо механизма автоматического обнаружения устройств. К тому же, в большинстве случаев, SPI устройства не предусматривают горячее подключение/отключение, поэтому они, как правило, просто распаиваются непосредственно на плате. В связи с этим данные устройства считаются специфичными для конкретной платы (board-specific). Параметры для таких устройств указываются в файле платы: arch/. /mach-*/board-*.c.
Например, вот так будет выглядеть установка параметров для аудиокодека tlv320aic23b для отладочной платы SK-AT91SAM9260:
где modalias – название драйвера ядра, отвечающего за обслуживание устройства (в нашем случае “tlv320aic23b”);
chip_select – номер соответсвующего chip select'а;
max_speed_hz – максимальная частота в Гц;
mode – режим SPI, определяемый константами SPI_MODE_0… SPI_MODE_3, также через операцию битового “или” могут быть добавлены флаги SPI_CS_HIGH (устанавливает активным высокий уровень для chipselect-а ), SPI_NO_CS (передача данных без активации CS в принципе). Полный список возможных флагов можно посмотреть в описании структуры spi_device;
bus_num – номер шины (как правило, соответсвует номеру SPI контроллера в даташите на MCU/eMPU).
Также структура spi_board_info содержит следующие поля, не инициализированные в примере выше:
const void *platform_data – данное поле предназначено для хранения указателя на данные специфичные для конкретного драйвера;
void *controller_data – для некоторых контроллеров необходима информация о настройке устройства, например, DMA;
int irq – зависит от подключения устройства.
Все поля структуры spi_board_info устанавливают соответствующие поля структуры spi_device.
В случае необходимости установки параметров для других SPI устройств, в масив добавляются ещё аналогичые элементы.
Данные структуры хранят информацию, которая не может быть всегда определена драйверами. Информация, которая может быть определена функцией probe() драйвера (например, количество бит на слово), в данную структуру не включается.
Стоит заметить, что всё же существует возможность горячего подключения ведомых SPI устройств. В этом случае используют функцию spi_busnum_to_master() для получения указателя на структуру spi_master по номеру шины SPI и дальнейшего перебора устройств на шине. Но данная тема выходит за рамки данной статьи.
Дра́йвер (англ. driver) (множественное число дра́йверы) — это компьютерная программа, с помощью которой другая программа (обычно операционная система) получает доступ к аппаратному обеспечению некоторого устройства. В общем случае, для использования любого устройства (как внешнего, так и внутреннего) необходим драйвер. Но обычно с операционными системами поставляются драйверы для ключевых компонентов аппаратного обеспечения, без которых система не сможет работать. Однако для некоторых устройств (таких, как графическая плата или принтер) могут потребоваться специальные драйверы, обычно предоставляемые производителем устройства.
Контроллер (калька с англ. controller — регулятор, управляющее устройство) — устройство управления в электронике и вычислительной технике:
* Игровой контроллер
* Контроллер домена
* Контроллер прерываний
* Контроллер электрического двигателя (например у машинистов электричек)
* Микроконтроллер — однокристалльный микрокомпьютер, управляющий различными устройствами и их отдельными блоками.
* Программируемый логический контроллер — устройство управления для промышленности, транспорта и других технологических систем
Дра́йвер (англ. driver) (множественное число дра́йверы) — это компьютерная программа, с помощью которой другая программа (обычно операционная система) получает доступ к аппаратному обеспечению некоторого устройства.
Контроллер (калька с англ. controller — регулятор, управляющее устройство) — устройство управления в электронике и вычислительной технике:
Игровой контроллер — это устройство ввода информации, которое используется в видеоиграх и компьютерных играх. Контроллер обычно присоединяется к игровой приставке или персональному компьютеру.
При помощи игрового контроллера игрок управляет движением и действиями элементов игры. При этом тип элементов зависит от самой игры, но чаще всего это один из персонажей игры.
Контролёр-это устройство, довольно материальная штука, а вот драйвер-это програмное обеспечение для опрелённого контролёра (как переводчик для системы, который помогает понять друг дгуга, двум объектам, говорящим на разных языках.
Основное различие между драйвером устройства и контроллером устройства состоит в том, что Драйвер устройства - это программное обеспечение, которое служит интерфейсом для контроллера устройства для связи с операционной системой или прикладной программой.Принимая во внимание, что контроллер устройства является аппаратным компонентом, который работает как мост между аппаратным устройством и операционной системой или прикладной программой.
Следовательно, существует четкое различие между драйвером устройства и контроллером устройства, даже если эти термины используются взаимозаменяемо. Драйвер устройства зависит от операционной системы и зависит от оборудования. Он обеспечивает обработку прерываний, необходимую для необходимого асинхронного зависящего от времени аппаратного интерфейса. С другой стороны, контроллер устройства - это печатная плата между устройством и операционной системой.
Ключевые области покрыты
1. Что такое драйвер устройства
- определение, функциональность
2. Что такое контроллер устройства
- определение, функциональность
3. Какова связь между драйвером устройства и контроллером устройства
- Схема ассоциации
4. В чем разница между драйвером устройства и контроллером устройства
- Сравнение основных различий
Основные условия
Драйвер устройства, контроллер устройства
Что такое драйвер устройства
Драйвер устройства работает с конкретным устройством, подключенным к компьютеру. Он предоставляет программный интерфейс для контроллера устройства для доступа к аппаратным устройствам. Следовательно, операционная система или некоторые другие компьютерные программы могут получить доступ к этому оборудованию, не зная подробностей об этом аппаратном компоненте. Драйвер устройства позволяет отправлять данные и получать данные с подключенного аппаратного устройства.
Рисунок 1: Драйвер устройства
Когда операционная система или программа должны обмениваться данными с аппаратным устройством, она вызывает процедуру в драйвере. Затем драйвер выдает команды этому устройству. Когда устройство отправляет данные обратно в драйвер, драйвер вызывает подпрограммы в исходной вызывающей программе.
Что такое контроллер устройства
Контроллер устройства - это система, которая обрабатывает входящие и исходящие сигналы ЦПУ. Устройство подключается к компьютеру через разъем и розетку, а разъем подключается к контроллеру устройства. Контроллеры устройств используют двоичные и цифровые коды. Устройство ввода-вывода содержит механические и электрические детали. Контроллер устройства - это электрическая часть устройства ввода-вывода.
Рисунок 2: Контроллер устройства
Контроллер устройства получает данные от подключенного устройства. Он временно хранит эти данные в специальном регистре, называемом локальным буфером внутри контроллера. Каждый контроллер устройства имеет соответствующий драйвер устройства. Память подключена к контроллеру памяти. Монитор подключен к видеоконтроллеру, а клавиатура подключена к контроллеру клавиатуры. Дисковод подключен к контроллеру диска, а USB-накопитель подключен к контроллеру USB. Эти контроллеры подключены к процессору через общую шину.
Связь между драйвером устройства и контроллером устройства
- Каждое устройство имеет контроллер устройства и драйвер устройства для связи с операционной системой.
Разница между драйвером устройства и контроллером устройства
Определение
Драйвер устройства - это компьютерная программа, которая управляет или управляет устройством определенного типа, подключенным к компьютеру. Контроллер устройства является частью компьютерной системы, которая распознает сигналы, поступающие и поступающие от ЦП. Таким образом, основное отличие между драйвером устройства и контроллером устройства ясно из этого определения.
В то время как драйвер устройства является программным, контроллер устройства является аппаратным.
Основная задача
Основное различие между драйвером устройства и контроллером устройства состоит в том, что драйвер устройства работает как переводчик между аппаратным устройством и приложением или операционной системой, которая его использует. С другой стороны, контроллер устройства преобразует последовательный поток битов в блок байтов и выполняет исправление ошибок по мере необходимости.
Заключение
Драйвер устройства - это программное обеспечение, которое служит интерфейсом для контроллера устройства для связи с операционной системой или прикладной программой. Контроллер устройства - это аппаратный компонент, который работает как мост между аппаратным устройством и операционной системой или прикладной программой. В этом основное отличие драйвера устройства от контроллера устройства. Вкратце, драйвер устройства является программным, а контроллер устройства аппаратным.
Как уважаемый хабрапользователь наверняка знает, «драйвер устройства» — это компьютерная программа управляющая строго определенным типом устройства, подключенным к или входящим в состав любого настольного или переносного компьютера.
Основная задача любого драйвера – это предоставление софтового интерфейса для управления устройством, с помощью которого операционная система и другие компьютерные программы получают доступ к функциям данного устройства, «не зная» как конкретно оно используется и работает.
Обычно драйвер общается с устройством через шину или коммуникационную подсистему, к которой подключено непосредственное устройство. Когда программа вызывает процедуру (очередность операций) драйвера – он направляет команды на само устройство. Как только устройство выполнило процедуру («рутину»), данные посылаются обратно в драйвер и уже оттуда в ОС.
Любой драйвер является зависимым от самого устройства и специфичен для каждой операционной системы. Обычно драйверы предоставляют схему прерывания для обработки асинхронных процедур в интерфейсе, зависимом от времени ее исполнения.
Любая операционная система обладает «картой устройств» (которую мы видим в диспетчере устройств), для каждого из которых необходим специфический драйвер. Исключения составляют лишь центральный процессор и оперативная память, которой управляет непосредственно ОС. Для всего остального нужен драйвер, который переводит команды операционной системы в последовательность прерываний – пресловутый «двоичный код».
Как работает драйвер и для чего он нужен?
Основное назначение драйвера – это упрощение процесса программирования работы с устройством.
Он служит «переводчиком» между хардовым (железным) интерфейсом и приложениями или операционными системами, которые их используют. Разработчики могут писать, с помощью драйверов, высокоуровневые приложения и программы не вдаваясь в подробности низкоуровневого функционала каждого из необходимых устройств в отдельности.
Как уже упоминалось, драйвер специфичен для каждого устройства. Он «понимает» все операции, которые устройство может выполнять, а также протокол, с помощью которого происходит взаимодействие между софтовой и железной частью. И, естественно, управляется операционной системой, в которой выполняет конкретной приложение либо отдельная функция самой ОС («печать с помощью принтера»).
Если вы хотите отформатировать жесткий диск, то, упрощенно, этот процесс выглядит следующим образом и имеет определенную последовательность: (1) сначала ОС отправляет команду в драйвер устройства используя команду, которую понимает и драйвер, и операционная система. (2) После этого драйвер конкретного устройства переводит команду в формат, который понимает уже только устройство. (3) Жесткий диск форматирует себя, возвращает результат драйверу, который уже впоследствии переводит эту команду на «язык» операционной системы и выдает результат её пользователю (4).
Как создается драйвер устройства
Для каждого устройства существует свой строгий порядок выполнения команд, называемой «инструкцией». Не зная инструкцию к устройству, невозможно написать для него драйвер, так как низкоуровневые машинные команды являются двоичным кодом (прерываниями) которые на выходе отправляют в драйвер результат, полученный в ходе выполнения этой самой инструкции.
При создании драйвера для Линукса, вам необходимо знать не только тип шины и ее адрес, но и схематику самого устройства, а также весь набор электрических прерываний, в ходе исполнения которых устройство отдает результат драйверу.
Написание любого драйвера начинается с его «скелета» — то есть самых основных команд вроде «включения/выключения» и заканчивая специфическими для данного устройства параметрами.
И чем драйвер не является
Часто драйвер устройства сравнивается с другими программами, выполняющими роль «посредника» между софтом и/или железом. Для того, чтобы расставить точки над «i», уточняем:
- Драйвер не является интерпретатором, так как не исполняется напрямую в софтовом слое приложения или операционной системы.
- Драйвер не является компилятором, так как не переводит команды из одного софтового слоя в другой, такой же.
Ну и на правах рекламы – вы всегда знаете, где скачать новейшие драйвера для любых устройств под ОС Windows.
Сложно дать одно точное определение для драйвера термина. В самом фундаментальном смысле драйвер — это программный компонент, который позволяет операционной системе и устройству взаимодействовать друг с другом.
Например, предположим, что приложению необходимо считывать некоторые данные с устройства. Приложение вызывает функцию, реализованную операционной системой, а операционная система вызывает функцию, реализованную драйвером. Драйвер, написанный той же компанией, которая разработала и произвела устройство, знает, как взаимодействовать с оборудованием устройства для получения данных. После того как драйвер получает данные с устройства, он возвращает данные в операционную систему, которая возвращает его приложению.
Расширение определения
Наше объяснение до сих пор слишком упрощено несколькими способами:
Не все драйверы должны быть написаны компанией, которая разработала устройство.
Во многих случаях устройство разработано в соответствии с опубликованным стандартом оборудования. Это означает, что драйвер может быть написан корпорацией Майкрософт, и конструктор устройств не должен предоставлять драйвер.
Не все драйверы взаимодействуют напрямую с устройством.
Для заданного запроса ввода-вывода (например, для чтения данных с устройства) часто существует несколько драйверов, многоуровневые в стеке драйверов, которые участвуют в запросе. Обычный способ визуализации стека — с первым участником вверху и последним участником внизу, как показано на этой схеме. Некоторые драйверы в стеке могут участвовать, преобразовав запрос из одного формата в другой. Эти драйверы не взаимодействуют напрямую с устройством; они просто управляют запросом и передают запрос вместе с драйверами, которые ниже в стеке.
Драйвер функции: один драйвер в стеке, который напрямую взаимодействует с устройством, называется драйвером функции.
Драйвер фильтра: драйверы, выполняющие вспомогательную обработку, называются драйверами фильтров.
Дополнительные сведения о стеках см. в разделе "Стеки драйверов".
Некоторые драйверы фильтров отслеживают и записывают сведения о запросах ввода-вывода, но не участвуют в них активно. Например, некоторые драйверы фильтров выполняют роль проверяющих, чтобы убедиться, что другие драйверы в стеке правильно обрабатывают запрос ввода-вывода.
Мы могли бы расширить определение драйвера , сказав, что драйвер является любым программным компонентом, который наблюдает или участвует в обмене данными между операционной системой и устройством.
Драйверы программного обеспечения
Расширенное определение является достаточно точным, но по-прежнему неполным, так как некоторые драйверы вообще не связаны с каким-либо аппаратным устройством.
Например, предположим, что необходимо написать средство, которое имеет доступ к основным структурам данных операционной системы, доступ к которым можно получить только с помощью кода, выполняемого в режиме ядра. Это можно сделать, разделив средство на два компонента. Первый компонент выполняется в пользовательском режиме и представляет пользовательский интерфейс. Второй компонент выполняется в режиме ядра и имеет доступ к данным основной операционной системы. Компонент, который выполняется в пользовательском режиме, называется приложением, а компонент, который выполняется в режиме ядра, называется драйвером программного обеспечения. Программный драйвер не связан с аппаратным устройством.
На этой схеме показано приложение в пользовательском режиме, взаимодействующее с драйвером программного обеспечения в режиме ядра.
Драйверы программного обеспечения всегда выполняются в режиме ядра. Основной причиной написания драйвера программного обеспечения является получение доступа к защищенным данным, доступным только в режиме ядра. Однако драйверам устройств не всегда требуется доступ к данным и ресурсам в режиме ядра. Поэтому некоторые драйверы устройств работают в пользовательском режиме.
Дополнительные сведения о режимах процессора см. в разделе "Режим пользователя" и "Режим ядра".
Водители автобуса
Существует категория водителя, который мы еще не упомянули, водитель автобуса. Чтобы понять драйверы шины, необходимо понять узлы устройств и дерево устройств.
Сведения о деревьях устройств, узлах устройств и драйверах шины см. в разделе "Узлы устройств" и "Стеки устройств".
Дополнительные возможности драйверов функций
Наше объяснение до сих пор упрощает определение драйвера функции. Мы сказали, что драйвер функции для устройства является одним драйвером в стеке, который взаимодействует напрямую с устройством. Это верно для устройства, которое подключается непосредственно к шине взаимодействия периферийных компонентов (PCI). Драйвер функции для устройства PCI получает адреса, сопоставленные с ресурсами порта и памяти на устройстве. Драйвер функции напрямую взаимодействует с устройством, записывая их на эти адреса.
Однако во многих случаях устройство не подключается непосредственно к шине PCI. Вместо этого устройство подключается к адаптеру шины узла, подключенного к шине PCI. Например, USB-тостер подключается к адаптеру шины узла (называемому контроллером USB-узла), который подключен к шине PCI. Usb-тостер имеет драйвер функции, а контроллер узла USB также имеет драйвер функции. Драйвер функции для тостера косвенно взаимодействует с тостером, отправив запрос драйверу функции для контроллера узла USB. Драйвер функции для контроллера узла USB затем взаимодействует напрямую с оборудованием контроллера узла USB, который взаимодействует с тостером.
Читайте также: