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

Обновлено: 01.07.2024

Подсистема USB в Linux увеличилась с поддержки только двух различных типов устройств в ядре 2.2.7 (мыши и клавиатуры) до более чем 20 различных типов устройств в ядре 2.4. В настоящее время Linux поддерживает почти все устройства класса USB (стандартные типы устройств, такие как клавиатуры, мыши, модемы, принтеры и динамики) и постоянно растущее число устройств, зависящих от поставщиков (например, преобразователи USB в последовательные порты, цифровые камеры, Ethernet-устройства и MP3-устройства). игроки). Полный список различных USB-устройств, поддерживаемых в настоящее время, см. в разделе Ресурсы.

Остальные типы USB-устройств, которые не поддерживаются в Linux, почти все зависят от производителя. Каждый поставщик решает внедрить собственный протокол для связи со своим устройством, поэтому обычно необходимо создать собственный драйвер. Некоторые поставщики открыты со своими USB-протоколами и помогают с созданием драйверов для Linux, тогда как другие не публикуют их, и разработчики вынуждены заниматься реинжинирингом. Ссылки на удобные инструменты обратного проектирования см. в разделе Ресурсы.

Поскольку каждый другой протокол приводит к созданию нового драйвера, я написал общий скелет драйвера USB, смоделированный по образцу файла pci-skeleton.c в дереве исходного кода ядра, на котором основаны многие сетевые драйверы PCI. Этот скелет USB можно найти в drivers/usb/usb-skeleton.c в дереве исходного кода ядра. В этой статье я расскажу об основах скелетного драйвера, объяснив его различные части и то, что необходимо сделать, чтобы настроить его для вашего конкретного устройства.

Основы работы с USB в Linux¶

Если вы собираетесь написать драйвер USB для Linux, ознакомьтесь со спецификацией протокола USB. Его можно найти вместе со многими другими полезными документами на домашней странице USB (см. Ресурсы). Отличное введение в USB-подсистему Linux можно найти в списке рабочих устройств USB (см. Ресурсы). Он объясняет, как устроена подсистема USB в Linux, и знакомит читателя с концепцией USB urbs (блоки запросов USB), которые необходимы для драйверов USB.

Первое, что необходимо сделать драйверу USB для Linux, — это зарегистрироваться в подсистеме USB для Linux, предоставив ей некоторую информацию о том, какие устройства поддерживает драйвер и какие функции вызывать, когда устройство, поддерживаемое драйвером, вставляется или удаляется из подсистемы USB. система. Вся эта информация передается подсистеме USB в структуре usb_driver. Скелетный драйвер объявляет usb_driver как:

Имя переменной представляет собой строку, описывающую драйвер. Он используется в информационных сообщениях, выводимых в системный журнал. Указатели функций probe и disconnect вызываются, когда устройство, которое соответствует информации, предоставленной в переменной id_table, либо обнаружено, либо удалено.

Фопс и второстепенные переменные являются необязательными. Большинство драйверов USB подключаются к другой подсистеме ядра, такой как SCSI, сеть или подсистема TTY. Эти типы драйверов регистрируются в другой подсистеме ядра, и любое взаимодействие с пользовательским пространством осуществляется через этот интерфейс. Но для драйверов, не имеющих соответствующей подсистемы ядра, таких как MP3-плееры или сканеры, необходим метод взаимодействия с пользовательским пространством. Подсистема USB предоставляет способ регистрации младшего номера устройства и набора указателей на функции file_operations, которые обеспечивают взаимодействие между пользователем и пространством. Скелетному драйверу нужен такой интерфейс, поэтому он предоставляет младший начальный номер и указатель на свои функции file_operations.

Когда драйвер выгружается из системы, ему необходимо отменить регистрацию в подсистеме USB. Это делается с помощью функции usb_deregister():

Чтобы позволить системе linux-hotplug автоматически загружать драйвер при подключении устройства, необходимо создать MODULE_DEVICE_TABLE . Следующий код сообщает сценариям горячего подключения, что этот модуль поддерживает одно устройство с определенным поставщиком и идентификатором продукта:

Существуют и другие макросы, которые можно использовать при описании структуры usb_device_id для драйверов, поддерживающих целый класс USB-драйверов. См. usb.h для получения дополнительной информации об этом.

Работа устройства¶

Когда к шине USB подключается устройство, соответствующее шаблону идентификатора устройства, зарегистрированному вашим драйвером в ядре USB, вызывается функция проверки. В функцию передаются структура usb_device, номер интерфейса и идентификатор интерфейса:

Теперь драйверу необходимо убедиться, что это устройство действительно является тем, которое он может принять. Если это так, она возвращает 0. В противном случае или при возникновении какой-либо ошибки во время инициализации функция probe возвращает код ошибки (например, -ENOMEM или -ENODEV ).

В драйвере скелета мы определяем, какие конечные точки помечаются как массовые поступления и массовые исходящие. Мы создаем буферы для хранения данных, которые будут отправлены и получены с устройства, и инициализируется USB-порт для записи данных на устройство.

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

Теперь, когда устройство подключено к системе и драйвер привязан к устройству, любая из функций в структуре file_operations, которые были переданы подсистеме USB, будет вызываться из пользовательской программы, пытающейся связаться с устройством. Первая вызываемая функция будет открыта, так как программа пытается открыть устройство для ввода/вывода. Мы увеличиваем наш частный счетчик использования и сохраняем указатель на нашу внутреннюю структуру в файловой структуре. Это сделано для того, чтобы будущие вызовы файловых операций позволили драйверу определить, к какому устройству обращается пользователь. Все это делается с помощью следующего кода:

После вызова функции открытия вызываются функции чтения и записи для приема и отправки данных на устройство. В функции skel_write мы получаем указатель на некоторые данные, которые пользователь хочет отправить на устройство и размер данных. Функция определяет, сколько данных она может отправить на устройство, исходя из размера созданного ею урба записи (этот размер зависит от размера конечной точки массового вывода, которая есть на устройстве). Затем он копирует данные из пользовательского пространства в пространство ядра, указывает urb на данные и отправляет urb в подсистему USB. Это можно увидеть в следующем коде:

Когда урб записи заполняется нужной информацией с помощью функции usb_fill_bulk_urb(), мы указываем обратному вызову завершения урба вызов нашей собственной функции skel_write_bulk_callback. Эта функция вызывается, когда подсистема USB заканчивает urb. Функция обратного вызова вызывается в контексте прерывания, поэтому необходимо соблюдать осторожность, чтобы не выполнять слишком много обработки в это время. Наша реализация skel_write_bulk_callback просто сообщает, был ли урб успешно завершен или нет, а затем возвращается.

Функция чтения работает немного иначе, чем функция записи, поскольку мы не используем urb для передачи данных с устройства на драйвер. Вместо этого мы вызываем функцию usb_bulk_msg(), которую можно использовать для отправки или получения данных с устройства без необходимости создавать urbs и обрабатывать функции обратного вызова завершения urb. Мы вызываем функцию usb_bulk_msg(), задавая ей буфер, в который можно поместить любые данные, полученные от устройства, и значение тайм-аута. Если период тайм-аута истекает без получения каких-либо данных от устройства, функция завершится ошибкой и вернет сообщение об ошибке. Это можно показать с помощью следующего кода:

Функция usb_bulk_msg() может быть очень полезна для однократного чтения или записи на устройство; однако, если вам необходимо постоянно читать или записывать на устройство, рекомендуется настроить собственные urbs и отправить их в подсистему USB.

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

Одна из наиболее сложных проблем, с которой драйверы USB должны справляться, заключается в том, что USB-устройство может быть удалено из системы в любой момент времени, даже если с ним в данный момент взаимодействует программа. Он должен иметь возможность останавливать любые текущие операции чтения и записи и уведомлять программы пользовательского пространства о том, что устройства больше нет. Следующий код (функция skel_delete) является примером того, как это сделать:

Если программа в настоящее время имеет открытый дескриптор устройства, мы сбрасываем флаг device_present . Для каждой функции чтения, записи, выпуска и других функций, которые ожидают присутствия устройства, драйвер сначала проверяет этот флаг, чтобы убедиться, что устройство все еще присутствует. Если нет, то сообщается, что устройство исчезло, и программе пользовательского пространства возвращается ошибка -ENODEV. Когда в конце концов вызывается функция освобождения, она определяет, нет ли устройства, а если нет, то выполняет очистку, которую обычно выполняет функция skel_disconnect, если на устройстве нет открытых файлов (см. листинг 5).

Изохронные данные¶

В этом драйвере usb-скелета нет примеров прерываний или изохронных данных, отправляемых на устройство или с устройства. Данные прерывания отправляются почти так же, как и объемные данные, за некоторыми небольшими исключениями. Изохронные данные работают по-разному с непрерывными потоками данных, отправляемых на устройство или с устройства. Драйверы аудио- и видеокамер являются очень хорошими примерами драйверов, обрабатывающих изохронные данные, и они будут полезны, если вам также потребуется это сделать.

Заключение¶

Как показывает драйвер usb-skeleton, написание драйверов USB-устройств Linux — несложная задача. Этот драйвер в сочетании с другими текущими USB-драйверами должен предоставить достаточно примеров, чтобы помочь начинающему автору создать работающий драйвер за минимальное время.Архивы списка рассылки linux-usb-devel также содержат много полезной информации.

В этом разделе описывается поддержка универсальной последовательной шины (USB) в операционной системе Windows, что позволяет разрабатывать драйверы USB-устройств, совместимые с Windows.

Где применимо

USB-устройства — это периферийные устройства, такие как мыши и клавиатуры, которые подключаются к компьютеру через один порт. Драйвер USB-клиента — это программное обеспечение, установленное на компьютере, которое взаимодействует с оборудованием для обеспечения работы устройства. Если устройство принадлежит к классу устройств, поддерживаемому корпорацией Майкрософт, Windows загружает для устройства один из предоставленных корпорацией Майкрософт драйверов USB (входящие в комплект драйверы классов). В противном случае производитель оборудования или сторонний поставщик должен предоставить специальный клиентский драйвер. Пользователь устанавливает клиентский драйвер для устройства, когда оно впервые обнаруживается Windows. После успешной установки Windows загружает драйвер клиента каждый раз, когда устройство подключается, и выгружает драйвер, когда устройство отсоединяется от главного компьютера.

Вы можете разработать собственный клиентский драйвер для USB-устройства, используя Windows Driver Frameworks (WDF) или Windows Driver Model (WDM). Вместо прямого взаимодействия с оборудованием большинство клиентских драйверов отправляют свои запросы предоставленному Microsoft стеку USB-драйверов, который выполняет вызовы функций уровня аппаратной абстракции (HAL) для отправки запроса клиентского драйвера оборудованию. Темы в этом разделе описывают типичные запросы, которые может отправлять клиентский драйвер, и интерфейсы драйверов устройств (DDI), которые клиентский драйвер должен вызывать для создания таких запросов.

Аудитория разработчиков

Клиентский драйвер для USB-устройства — это драйвер WDF или WDM, который взаимодействует с устройством через DDI, предоставляемые стеком драйверов USB. Этот раздел предназначен для программистов на C/C++, знакомых с WDM. Прежде чем использовать этот раздел, вы должны понять основы разработки драйверов. Дополнительные сведения см. в разделе Начало работы с драйверами Windows. Для драйверов WDF клиентский драйвер может использовать интерфейсы Kernel-Mode Driver Framework (KMDF) или User-Mode Driver Framework (UMDF), разработанные специально для работы с целевыми устройствами USB. Дополнительные сведения об интерфейсах, специфичных для USB, см. в справочнике WDF USB и целевых интерфейсах ввода-вывода USB UMDF.

Инструменты разработки

Набор драйверов для Windows (WDK) содержит ресурсы, необходимые для разработки драйверов, такие как заголовки, библиотеки, инструменты и примеры.

Справочник по программированию USB

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

Образцы драйверов USB

Используйте эти примеры, чтобы начать программирование клиентского USB-драйвера.

Соответствующие стандарты и спецификации

Вы можете загрузить официальные спецификации USB с веб-сайта Universal Serial Bus Documents. Этот веб-сайт содержит ссылки на спецификацию универсальной последовательной шины версии 3.0 и спецификацию универсальной последовательной шины версии 2.0.

Разделы документации

Знакомство с разработкой USB-драйверов. Предоставляет информацию о выборе наиболее подходящей модели драйвера USB для вашего устройства. Напишите, создайте и установите свои первые скелетные USB-драйверы пользовательского режима и режима ядра, используя шаблоны USB, включенные в Microsoft Visual Studio.

Обзор архитектуры стека драйверов USB.

Узнайте, как драйвер клиента создает структуру данных переменной длины, называемую блоком запроса USB (URB), для отправки запросов в стек драйвера USB.

Узнайте, как драйвер клиента создает структуру данных переменной длины, называемую блоком запроса USB (URB), для отправки запросов в стек драйвера USB.

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

Описывает USB-каналы, URB для запросов ввода-вывода и то, как драйвер клиента может использовать интерфейсы драйверов устройств (DDI) для передачи данных на USB-устройство и с него.

Многие аппаратные компоненты компьютера, такие как видеокарта, звуковая карта, Wi-Fi или материнская плата, требуют установки драйверов для правильной работы. Кроме того, если у существующего драйвера есть проблемы, его переустановка может быть хорошим способом устранения неполадок. Способ сохранения и упаковки драйвера определяет способ его установки. Ниже приведена информация о каждом методе, используемом разработчиками для распространения своих драйверов и их установки в Microsoft Windows. Кроме того, некоторые общие сведения помогают предотвратить разочарование во время процесса.

В большинстве случаев драйверы устанавливаются после установки или подключения оборудования к компьютеру. Если вам нужна помощь в установке оборудования, см. статью Как установить компьютерное оборудование.

Драйверы с компакт-диска или DVD

Компакт-диск с драйверами и утилитами Dell

Почти все производители компьютеров и оборудования включают группу драйверов для различных аппаратных устройств и часто для каждой поддерживаемой версии Windows. Например, компакт-диск с драйверами, который вы получаете вместе с принтером, скорее всего, содержит драйверы для многих разных принтеров и может не содержать приобретенный вами принтер. При установке драйверов убедитесь, что вы устанавливаете драйверы для своего принтера, а не для другой модели. Кроме того, убедитесь, что вы устанавливаете его для той версии Windows, которая установлена ​​на вашем компьютере.

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

Например, если у вас есть PrinterA200 и вы используете Windows XP, вы найдете свои драйверы в папке PrinterA200\WinXP. Как только расположение драйверов найдено, необходимо определить, как они упакованы. Если папка содержит исполняемые файлы или установочный файл, вы можете установить драйвер с помощью исполняемого файла. Если каталог содержит INF-файлы, вы можете установить драйвер с помощью INF-файла или использовать опцию «иметь диск» во время установки.

Если у вас есть компакт-диск с драйверами, но на компьютере не работает дисковод, вы также можете загрузить драйверы из Интернета. Или, если у вас есть доступ к другому компьютеру, вы можете скопировать драйверы с компакт-диска на флешку. Справку по копированию файлов см. в разделе Как копировать файлы.

Установка драйверов с USB-накопителя или дискеты

После того как драйверы скопированы на USB-накопитель, дискету или другой диск, их также можно установить с этого диска. После подключения диска к компьютеру откройте проводник Windows и введите букву диска компьютера. Например, если у вас есть USB-накопитель, которому назначен диск E: при подключении, вы должны открыть диск E:.

После того как драйверы будут найдены на диске, необходимо определить, как они упакованы. Если каталог содержит исполняемые файлы или установочный файл, вы можете установить драйвер с помощью исполняемого файла. Если каталог содержит INF-файлы, вы можете установить драйвер с помощью INF-файла или использовать опцию «иметь диск» во время установки. Если драйверы сжаты в ZIP-файл, необходимо распаковать файл.

Загрузка и установка драйвера

Загрузить из Интернета на компьютер.

Если вы еще не загрузили драйверы, вы можете найти их для своего компьютера у его производителя. Ссылки на веб-сайты известных производителей компьютерного оборудования см. в нашем указателе драйверов оборудования.

Если вы загружаете драйверы для установки на другое устройство, вы можете скопировать или извлечь файлы на флэш-накопитель USB и подключить его к другому компьютеру.

После загрузки драйверов необходимо определить, как они упакованы. Если каталог содержит исполняемые файлы или установочный файл, вы можете установить драйвер с помощью исполняемого файла. Если каталог содержит INF-файлы, вы можете установить драйвер с помощью INF-файла или использовать опцию «иметь диск» во время установки. Если драйверы сжаты в ZIP-файл, необходимо распаковать файл.

При извлечении драйверов помните, где находится папка драйвера, поскольку ее необходимо знать в процессе установки драйвера. Мы рекомендуем извлекать файлы в папку на рабочем столе Windows.

Установка драйвера из исполняемого файла

Исполняемый файл

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

Исполняемый файл может быть упакован в сжатый файл, что означает, что перед поиском установочного файла его необходимо распаковать. Справку по распаковке файла см. в разделе Как извлечь или распаковать сжатый файл. Если после распаковки файла он по-прежнему не содержит исполняемый файл, установочный файл или не устанавливает ваше аппаратное устройство, следуйте приведенным ниже рекомендациям.

Наконец, если вы успешно устанавливаете драйверы и появляется сообщение о перезагрузке компьютера, не забудьте перезагрузить компьютер после установки драйвера.

Использование опции «есть с диска» для установки драйверов

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

Установка нового устройства

    .
  1. В Диспетчере устройств убедитесь, что устройство, которое вы пытаетесь установить, еще не указано в списке предыдущих попыток установки. Если устройство найдено, выделите его и удалите из диспетчера устройств, чтобы предотвратить конфликты при установке.
    1. После того, как Диспетчер устройств будет выглядеть нормально, перезагрузите компьютер.
    2. При перезагрузке компьютера должен появиться мастер Установить новое оборудование, если Windows обнаружит новое оборудование. С помощью этого мастера укажите Windows папку с вашими драйверами на компакт-диске, дискете, флэш-накопителе USB или папку, содержащую загруженные вами файлы.

    Если Windows не обнаруживает новое оборудование, откройте панель управления и дважды щелкните значок Добавить оборудование, чтобы запустить мастер обнаружения оборудования. На этих этапах вы можете установить пользовательские драйверы Windows из папки на диске. Выберите загрузку драйверов, затем выберите папку, содержащую драйверы для вашего устройства.

    Значок "Добавить оборудование" доступен только в Windows XP и более ранних версиях Windows.

    После установки драйверов перезагрузите компьютер.

    Обновление драйверов для уже существующего устройства

      .
    1. В диспетчере устройств найдите устройство, которое хотите обновить. устройство и выберите Свойства.
    2. В окне Свойства перейдите на вкладку Драйвер.
    3. Нажмите кнопку "Обновить драйвер".
    4. В Мастере обновления оборудования укажите Windows расположение обновленных файлов драйверов на жестком диске.

    После установки драйверов перезагрузите компьютер.

    Установите драйвер с помощью INF-файла

    Наконец, если приведенные выше рекомендации не работают, вы можете найти инструкции по установке драйверов и аппаратных устройств в его INF-файле.

    1. Найдите INF-файл для своей версии Windows. этот файл и выберите "Установить" в раскрывающемся меню.
    2. Следуйте инструкциям для завершения установки. .

    Убедитесь, что вы устанавливаете правильный файл .inf, а не файл .inf для другого устройства или другой версии Windows.

    Одна из трех приведенных выше рекомендаций должна была установить или обновить драйверы. Если у вас по-прежнему возникают трудности с установкой устройства, возможно, проблема не в оборудовании. Дополнительные сведения и помощь см. в инструкциях по устранению неполадок для вашего устройства.

    С самого начала этой статьи в ней обсуждалось, как разработчик драйверов Linux может создавать различные типы драйверов ядра, объясняя различные интерфейсы драйверов ядра, включая TTY, последовательный порт, I2C и ядро ​​драйвера. Пришло время двигаться дальше и сосредоточиться на написании реальных драйверов для реального оборудования. Мы начнем с объяснения того, как определить, какой тип интерфейса драйвера ядра использовать, трюков, помогающих понять, как на самом деле работает оборудование, и множества других практических знаний.


    Рис. 1. USB Visual Signal Indicator компании Delcom — это простой первый проект программирования USB.

    Первой целью при написании драйвера для устройства является определение способа управления устройством. Компания Delcom Engineering достаточно любезна, чтобы предоставить всю спецификацию протокола USB, которую используют их устройства, вместе с продуктом, и она также доступна в Интернете бесплатно. В этой документации показано, какие команды принимает микросхема контроллера USB и как их использовать. Они также предоставляют DLL Microsoft Windows, чтобы помочь пользователям других операционных систем писать код для управления устройством.

    Документация для этого устройства является документацией только для контроллера USB в фонаре. В нем явно не сказано, как включить разные цветные светодиоды. Для этого нам нужно провести небольшое исследование.

    Нет документов? Обратный инжиниринг!

    Еще один метод, который несколько человек использовали для обратного проектирования USB-протокола устройства, заключается в запуске экземпляра Windows с помощью VMware поверх Linux. VMware позволяет экземпляру Windows взаимодействовать со всеми USB-устройствами, подключенными к машине Linux, отправляя данные в Linux через интерфейс usbfs. Простая модификация usbfs приводит к тому, что все данные, проходящие через него, регистрируются в журнале ядра. С его помощью можно захватить весь поток USB-трафика и затем проанализировать его.

    После вскрытия лампового устройства, убедившись, что не потерялась пружина, которая легко выдвигается при отвинчивании устройства, можно осмотреть печатную плату (рис. 2). С помощью омметра или любого другого устройства для обнаружения замкнутой цепи было установлено, что три разных светодиода подключены к первым трем контактам порта 1 на основной микросхеме контроллера.

    Если читать документацию, команда USB для управления уровнями контактов порта 1: Major 10, Minor 2, Length 0. Команда записывает младший значащий байт командного пакета USB в порт 1, а после сброса порт 1 по умолчанию имеет высокий уровень.Итак, это команда USB, которую нам нужно отправить на устройство, чтобы изменить различные светодиоды.


    Рис. 2. Три светодиода подключены к первым трем контактам микросхемы контроллера.

    Теперь, когда мы знаем команду для включения вывода порта, нам нужно определить, какой цвет светодиода подключен к какому выводу. Это легко сделать с помощью простой программы, которая перебирает все возможные комбинации различных значений для трех выводов порта, а затем отправляет значение на устройство. Эта программа позволила мне создать таблицу значений и цветов светодиодов (таблица 1).

    Таблица 1. Значения портов и результирующие шаблоны светодиодов

    Значение порта в шестнадцатеричном форматеЗначение порта в двоичном форматеСветодиоды на
    0x00000Красный, Зеленый, Синий
    0x01 001Красный, Синий
    0x02010Зеленый, Синий
    0x03011Синий
    0x04100Красный, Зеленый
    0x05101Красный
    0x06110Зеленый
    0x07111 Индикаторы не горят

    Итак, если все контакты порта включены (значение 0x07 в шестнадцатеричном формате), светодиоды не горят. Это совпадает с примечанием в техпаспорте, в котором говорилось: «Порт 1 по умолчанию имеет высокий уровень после сброса». Было бы разумно не включать какие-либо светодиоды при первом подключении устройства. Это означает, что нам нужно перевести контакты порта в низкий уровень (выключить), чтобы включить светодиод для этого контакта. Используя таблицу, мы можем определить, что синий светодиод управляется выводом 2, красный светодиод — выводом 1 и зеленый светодиод — выводом 0.

    Вооружившись полученной информацией, мы приступили к быстрому созданию драйвера ядра. Это должен быть USB-драйвер, но какой интерфейс для пользовательского пространства мы должны использовать? Блочное устройство не имеет смысла, так как этому устройству не нужно хранить данные файловой системы, но символьное устройство подойдет. Однако, если мы используем драйвер символьного устройства, для него необходимо зарезервировать старший и младший номера. И сколько младших номеров нам понадобится для этого драйвера? Что если кто-то захочет подключить к этой системе 100 различных USB-ламп? Чтобы предвидеть это, нам нужно было бы зарезервировать как минимум 100 младших номеров, что было бы пустой тратой времени, если бы все, кто когда-либо когда-либо использовал, было бы одним устройством за раз. Если мы создадим драйвер персонажа, нам также нужно будет придумать какой-нибудь способ указать драйверу включать и выключать разные цвета по отдельности. Традиционно это можно было сделать с помощью других команд ioctl в драйвере персонажа, но мы гораздо лучше, чем когда-либо, умеем создавать новую команду ioctl в ядре.

    Поскольку все USB-устройства отображаются в своем собственном каталоге в дереве sysfs, почему бы не использовать sysfs и не создать в каталоге USB-устройства три файла: синий, красный и зеленый? Это позволит любой программе пользовательского пространства, будь то программа на C или сценарий оболочки, изменять цвета на нашем светодиодном устройстве. Это также избавит нас от необходимости писать символьный драйвер и выпрашивать кусок младших номеров для нашего устройства.

    Чтобы запустить наш USB-драйвер, нам нужно предоставить USB-подсистеме пять компонентов:

    Указатель на владельца модуля этого драйвера: это позволяет ядру USB правильно управлять счетчиком ссылок на модуль драйвера.

    Имя USB-драйвера.

    Список идентификаторов USB, которые должен предоставить этот драйвер: эта таблица используется ядром USB для определения того, какой драйвер должен соответствовать какому устройству; сценарии пользовательского пространства с возможностью горячей замены используют его для автоматической загрузки этого драйвера, когда устройство подключается к системе.

    Функция probe(), вызываемая ядром USB при обнаружении устройства, соответствующего таблице идентификаторов USB.

    Функция разъединения(), вызываемая при удалении устройства из системы.

    Драйвер извлекает эту информацию с помощью следующего фрагмента кода:

    Переменная id_table определяется как:

    Функции led_probe() и led_disconnect() описаны позже.

    Когда загружается модуль драйвера, эта структура led_driver должна быть зарегистрирована в ядре USB. Это достигается одним вызовом функции usb_register():

    Функция led_probe() вызывается, когда ядро ​​USB нашло наше USB-ламповое устройство. Все, что ему нужно сделать, это инициализировать устройство и создать три файла sysfs в нужном месте. Это делается с помощью следующего кода:

    Функция led_disconnect() столь же проста, поскольку нам нужно только освободить выделенную память и удалить файлы sysfs:

    При чтении файлов sysfs мы хотим показать текущее значение этого индикатора; когда он записывается, мы хотим установить этот конкретный светодиод. Для этого следующий макрос создает две функции для каждого цветного светодиода и объявляет файл атрибутов устройства sysfs:

    Это создает шесть функций: show_blue(), set_blue(), show_red(), set_red(), show_green() и set_green(); и три структуры атрибутов, dev_attr_blue, dev_attr_red и dev_attr_green. Из-за простой природы обратных вызовов файла sysfs и того факта, что нам нужно делать одно и то же для каждого другого значения (синего, красного и зеленого), был использован макрос для сокращения ввода. Это обычное явление для файловых функций sysfs; примером этого в дереве исходного кода ядра являются драйверы микросхем I2C в drivers/i2c/chips.

    Итак, чтобы включить красный светодиод, пользователь записывает 1 в красный файл в sysfs, что вызывает функцию set_red() в драйвере, которая вызывает функцию change_color(). Функция change_color() выглядит следующим образом:

    Эта функция начинается с установки всех битов в переменной цвета в 1. Затем, если какие-либо светодиоды должны быть включены, она выключает только этот конкретный бит. Затем мы отправляем управляющее сообщение USB на устройство, чтобы записать это значение цвета на устройство.

    При создании, сборке и загрузке этого драйвера ядра при подключении USB-лампового устройства драйвер привязывается к нему. Все USB-устройства, привязанные к этому драйверу, можно найти в каталоге sysfs драйвера:

    Файл в этом каталоге является символической ссылкой на реальное местоположение в дереве sysfs для этого USB-устройства. Если мы заглянем в этот каталог, то увидим файлы, созданные драйвером для светодиодов:

    Затем, записывая 0 или 1 в синий, зеленый и красный файлы в этом каталоге, светодиоды меняют цвет:

    Это дает цвет, показанный на рисунке 3.


    Рис. 3. Устройство с включенными красным и синим светодиодами

    Если вы хотите, чтобы драйверы ядра были написаны для любых других типов устройств, в разумных пределах — я не собираюсь пытаться писать драйвер видеокарты NVIDIA с нуля — сообщите мне об этом.

    Спасибо Дону Марти за то, что заставил меня заставить это устройство работать на Linux. Без его настойчивости это никогда бы не было закончено.

    Читайте также: