Написание USB драйвера
Подход к написанию драйвера USB устройства аналогичен драйверу PCI: драйвер регистрирует свой объект драйвера с USB подсистемой и затем использует идентификаторы поставщика и устройства для сообщения, когда его оборудование было установлено.
Какие устройства поддерживает драйвер?
Структура struct usb_device_id содержит список различных типов USB устройств, которые поддерживает этот драйвер. Этот список используется ядром USB, чтобы решить, какой драйвер предоставить устройству, или скриптами горячего подключения, чтобы решить, какой драйвер автоматически загрузить, когда устройство подключается к системе.
Структура struct usb_device_id определена со следующими полями:
Определяет, какие из следующих полей в структуре устройства должны сопоставляться. Это битовое поле определяется разными значениями USB_DEVICE_ID_MATCH_* , указанными в файле include/linux/mod_devicetable.h . Это поле, как правило, никогда не устанавливается напрямую, а инициализируется с помощью макросов типа USB_DEVICE , описываемых ниже.
Идентификатор поставщика USB для устройства. Этот номер присваивается форумом USB для своих членов и не может быть присвоен кем-то еще.
Идентификатор продукта USB для устройства. Все поставщики, которые имеют выданный им идентификатор поставщика, могут управлять своими идентификаторами продукта, как они предпочитают.
Определяют нижнюю и верхнюю границу диапазона назначаемого поставщиком номера версии продукта. Значения bcdDevice_hi является включительным; его значение является значением наибольшего номера устройства. Обе эти величины представлены в двоично-десятичной (BCD) форме. Эти переменные в сочетании с idVendor и idProduct используются для определения данного варианта устройства.
Определяют класс, подкласс и протокол устройства, соответственно. Эти номера присваиваются форумом USB и определены в спецификации USB. Эти значения определяют поведение для всего устройства, в том числе все интерфейсы на этом устройстве.
Подобно зависимым от устройства вышеприведённым величинам, эти определяют класса, подкласс и протокол отдельного интерфейса, соответственно. Эти номера присваиваются форумом USB и определены в спецификации USB.
Это значение не используется для сравнения, но оно содержит информацию о том, что драйвер может использовать, чтобы отличать разные устройства друг от друга в функции обратного вызова probe драйвера USB.
Как и с PCI устройствами, существует ряд макросов, которые используются для инициализации этой структуры:
Создаёт struct usb_device_id , которая может быть использована только для соответствия указанными значениям идентификаторов поставщика и продукта. Она очень часто используется для устройств USB, которым необходим специальный драйвер.
USB_DEVICE_VER(vendor, product, lo, hi)
Создаёт struct usb_device_id , которая может быть использована только для соответствия указанным значениям идентификаторов поставщика и продукта внутри диапазона версий.
USB_DEVICE_INFO(class, subclass, protocol)
Создаёт struct usb_device_id , которая может быть использованы для соответствия определённому классу USB устройств.
USB_INTERFACE_INFO(class, subclass, protocol)
Создаёт struct usb_device_id , которая может быть использована для соответствия определённому классу USB интерфейсов.
Итак, для простого драйвера USB устройства, который управляет только одним USB устройством от одного поставщика, таблица struct usb_device_id будет определяться как:
/* таблица устройств, которые работают с этим драйвером */
static struct usb_device_id skel_table [ ] = <
MODULE_DEVICE_TABLE (usb, skel_table);
Как и с драйвером PCI, необходим макрос MODULE_DEVICE_TABLE , чтобы разрешить инструментам пространства пользователя выяснить, какими устройствами может управлять этот драйвер. Но для USB драйверов первым значением в этом макросе должна быть строка usb .
Регистрация USB драйвера
Основной структурой, которую должны создать все USB драйверы, является struct usb_driver . Эта структура должна быть заполнена драйвером USB и состоит из ряда функций обратного вызова и переменных, описывающих USB драйвер для кода USB ядра:
struct module *owner
Указатель на модуль владельца этого драйвера. Ядро USB использует его для правильного подсчёта ссылок на этот драйвер USB, чтобы он не выгружался в несвоевременные моменты. Переменной должен быть присвоен макрос THIS_MODULE .
const char *name
Указатель на имя драйвера. Он должен быть уникальным среди всех USB драйверов в ядре и, как правило, установлен на такое же имя, что и имя модуля драйвера. Оно проявляется в sysfs в /sys/bus/usb/drivers/ , когда драйвер находится в ядре.
const struct usb_device_id *id_table
Указатель на таблицу struct usb_device_id , которая содержит список всех различных видов устройств USB, которые драйвер может распознать. Если эта переменная не установлена, функция обратного вызова probe в драйвере USB никогда не вызывается. Если вы хотите, чтобы ваш драйвер всегда вызывался для каждого USB устройства в системе, создайте запись, которая устанавливает только поле driver_info :
static struct usb_device_id usb_ids[ ] = <
int (*probe) (struct usb_interface *intf, const struct usb_device_id *id)
Указатель на зондирующую функцию в USB драйвере. Эта функция (описанная в разделе "probe и disconnect в деталях") вызывается USB ядром, когда оно думает, что оно имеет структуру usb_interface , которую этот драйвер может обработать. Указатель на struct usb_device_id , который использовало USB ядро, чтобы принять это решение также передается в эту функцию. Если USB драйвер признаёт переданную ему структуру usb_interface , он должен правильно проинициализировать устройство и вернуть 0. Если драйвер не хочет признавать устройство или произошла ошибка, он должен вернуть отрицательное значение ошибки.
void (*disconnect) (struct usb_interface *intf)
Указатель на функцию отключения в USB драйвере. Эта функция (описанная в разделе "probe и disconnect в деталях") вызывается USB ядром, когда структура usb_interface была удалена из системы, или когда драйвер выгружается из ядра USB.
Таким образом, чтобы создать значимую структуру struct usb_driver , должны быть проинициализированы только пять полей:
static struct usb_driver skel_driver = <
struct usb_driver содержит несколько больше обратных вызовов, которые, как правило, очень часто не используются, и не требуются для правильной работы USB драйвера:
int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf)
Указатель на функцию ioctl в USB драйвере. Если он присутствует, то вызывается, когда программа пользовательского пространства делает вызов ioctl для записи файловой системы устройств usbfs , связанной с устройством USB, относящемуся к этому USB драйверу. На практике только драйвер USB концентратора использует этот ioctl , так как любому другому USB драйверу нет иной реальной необходимости его использовать.
int (*suspend) (struct usb_interface *intf, u32 state)
Указатель на функцию приостановки в USB драйвере. Она вызывается, когда работа устройства должна быть приостановлена USB ядром.
int (*resume) (struct usb_interface *intf)
Указатель на функцию возобновления в USB драйвере. Она вызывается, когда работа устройства возобновляется USB ядром.
Чтобы зарегистрировать struct usb_driver в USB ядре, выполняется вызов usb_register_driver с указателем на struct usb_driver . Для USB драйвера это традиционно делается в коде инициализации модуле:
static int __init usb_skel_init(void)
/* регистрируем этот драйвер в подсистеме USB */
err("usb_register failed. Error number %d", result);
Когда драйвер USB будет выгружаться, необходимо разрегистрировать struct usb_driver в ядре. Это делается с помощью вызова usb_deregister . Когда происходит этот вызов, любые USB интерфейсы, которые в настоящее время связаны с этим драйвером, отключаются и для них вызывается функция disconnect .
static void __exit usb_skel_exit(void)
/* отменяем регистрацию этого драйвера в подсистеме USB */
probe и disconnect в деталях
В структуре struct usb_driver structure , описанной в предыдущем разделе, драйвер указывает две функции, которые в соответствующее время вызывает ядро USB. Функция probe вызывается, когда установлено устройство, которым, как думает ядро USB, должен управлять этот драйвер; функция probe должна выполнять проверки информации, переданной ей об устройстве, и решать, действительно ли этот драйвер подходит для этого устройства. Функция disconnect вызывается, когда по каким-то причинам драйвер не должен больше управлять устройством и может делать очистку.
Оба функции обратного вызова probe и disconnect вызываются в контексте потока USB узла ядра, так что засыпать в них допускается. Тем не менее, рекомендуется, чтобы большая часть работы выполнялась, когда устройство открыто пользователем, если это возможно, чтобы сократить время зондирования USB к минимуму. Такое требование появляется потому, что USB ядро обрабатывает добавление и удаление устройств USB в одном потоке, так что любой медленный драйвер устройства может привести к замедлению обнаружения USB устройства и это станет заметно для пользователя.
В функции обратного вызова probe , USB драйвер должен проинициализировать любые локальные структуры, которые он может использовать для управления USB устройством. Следует также сохранить в локальные структуры любую необходимую информацию об устройстве, так как это обычно легче сделать в данное время. Например, USB драйверы обычно хотят обнаружить адрес оконечной точки и размеры буферов для данного устройства, так как они необходимы для общения с устройством. Вот пример некоторого кода, который определяет две оконечные точки ВХОДА и ВЫХОДА поточного типа и сохраняет некоторую информацию о них в локальной структуре устройства:
Форумы Modlabs.net: Программирование драйверов устройств для чайников — Форумы Modlabs.net
Вход
Новый пользователь? Регистрация
Помощь
- Вы не можете создать новую тему
- Вы не можете ответить в тему
Программирование драйверов устройств для чайников
#1
dE fENDER
- Member



- Группа: Пользователи
- Сообщений: 271
- Регистрация: 18 Декабрь 08
#2
dE fENDER
- Member



- Группа: Пользователи
- Сообщений: 271
- Регистрация: 18 Декабрь 08
Введение
В этой теме я планирую дать серию уроков, которые позволят любому человеку получить базовое представление о том, как устроена система взаимодействия прикладного ПО и драйверов ОС Windows, научиться читать исходные коды существующих драйверов устройств или написать свой собственный драйвер, работающий с его собственным устройством.
Также эти уроки могут помочь аудитории владельцев видеокарт с графическими чипами, произведенными компанией 3dfx, разобраться в доступных исходных кодах драйверов этих видеокарт. Упомянутые исходники могут быть с наименьшим количеством переделок откомпилированы под Windows XP/Windows 2003 Server, которые и будут являться основной целевой системой. В более современной Windows Vista/7 несколько изменилась модель драйверов, наиболее сильно это затронуло графическую подсистему. Это означает, что для их корректной работы придется переписать весьма значительную часть кода. Кроме того, под х64 версиями Vista/7 и более старших операционных систем просто так нельзя загрузить драйвер, не имеющей цифровой подписи. Подпись стоит порядка 500 долларов в год (150, если найти купон на скидку), их не любят давать частным лицам и даже небольшим организациям. Кроме того, если в подписанном драйвере обнаружится уязвимость и ей воспользуются хакеры – то подпись данного [почти всегда юридического] лица аннулируется и у него возникают проблемы с получением новой. Еще есть такая процедура, как WHQL-сертификация, но ее я вообще не собираюсь пока здесь обсуждать.
Весьма приветствуется, если другие люди будут давать здесь свои собственные уроки, не выходящие за пределы темы. Также здесь можно задавать любые вопросы, предлагать свои идеи для следующих уроков и отписываться об своих удачных/неудачных результатах.
Для начала работы требуется иметь некоторое знакомство с любым языком программирования. Думаю, для этого вполне достаточно школьного / вузовского курса для непрограммистов. Если же в современных программах образования знакомство с программированием не было предусмотрено/за давностью лет курс забыт или просто что-то непонятно – отписывайтесь в теме, я напишу другие уроки, подробней раскрывающие непонятную тему.
#3
White
- Белый человер







- Группа: Главный Администратор
- Сообщений: 12 167
- Регистрация: 16 Июль 05
#4
dE fENDER
- Member



- Группа: Пользователи
- Сообщений: 271
- Регистрация: 18 Декабрь 08
Урок 0. Установка и настройка программного обеспечения
Список используемого программного обеспечения:
- Windows XР или Windows 2003 Server х86 – операционная система, под которую будем писать драйверы;
- Visual Studio 2010 – среда разработки приложений на языках С/С++ и других. Будет использоваться для написания различных простых прикладных программ, в т.ч. и управляющей программы драйвера. Можно попробовать воспользоваться Visual Studio 11 beta, которая доступна для скачивания по ссылке — http://www.microsoft. studio/11/en-us;
- Windows Driver Kit – набор инструментов, необходимых для разработки драйвера. Включает в себя компилятор, заголовочные файлы и много другого. Требуется версия 7.1.0, ее можно взять по ссылке
http://www.microsoft. ang=en&id=11800; - VMWare – при отсутствии физической машины операционную систему можно запустить в виртуальной. Это также безопаснее при разработке — при ошибке в драйвере система уйдет в синий экран;
- Daemon Tools – средство для открытия образов CD и DVD дисков в формате iso. WDK распространяется в виде такого образа. В случае использования VMWare использовать не обязательно, т.к. VMWare умеет монтировать такие образы самостоятельно. Бесплатную lite-версию можно скачать здесь: http://www.disc-tool. download/daemon
- DebugView – утилита Марка Руссиновича, которая позволяет увидеть текстовые сообщения, выдаваемые драйверами, собранными в отладочном режиме. Скачивать здесь — http://technet.micro. ernals/bb896647
- Far Manager – файловый менеджер, с которым легче работать с консольными утилитами. Взять можно здесь — http://www.farmanage. wnload.php?l=ru.
Все используемое мною программное обеспечение – на английском языке. В большинстве случаев можно использовать и русские версии, но может возникнуть путаница в командах или другие проблемы с совместимостью. Для начала работы потребуется компьютер с установленной обычной 32-разрядной Windows XP/2003. Продвинутые пользователи могут пользоваться необычной – отладочной, она же — checked build. Эта версия показывает больше информации при отладке устройств. Обычная же версия Windows носит название free build. Компьютер для экспериментов может быть как реальным, так и виртуальным. Разрабатываемые программы я буду проверять на одной реальной машине и одной виртуальной. На обоих установлен Windows Server 2003 R2 Enterprise Edition c SP2. Виртуальная машина запущена под VMWare Workstation 8.0.2.
Установка Visual Studio
Я буду использовать Visual Studio 2010 Ultimate. В принципе, ставить ее не обязательно, так как все необходимые инструменты, включая компилятор и заголовки есть и в WDK. Но для написания прикладных программ, в особенности для новичка, она намного удобней вызова компилятора из консоли. Если ее все же планируется установить, то лучше делать это перед установкой WDK.
Берем диск со студией в iso-формате, монтируем его в Daemon Tools, либо подключаем как компакт-дисковод в VMWare. Запускаем с диска setup.exe, выбираем «Install Microsoft Visual Studio 2010». На следующем шаге под Windows 2003 может появится сообщение, что требуется Windows Imaging Component. Щелкаем по этой строке, запускается браузер – скачиваем подходящий по языку операционной системы (у меня английский, значит wic_x86_enu.exe), устанавливаем. Заново запускаем setup.exe с диска. Нажимаем Next, соглашаемся с лицензионным соглашением, затем идет выбор типа установки. Выбираем Custom, изменяем путь установки – для избежания ошибок Visual Studio и все любые другие инструменты следует ставить по максимально короткому пути без русских букв и пробелов. Мой вариант – C:\Programs\VS10. Следующая страница – выбор пакетов. Устанавливаем в соответствии с рисунком:
Рис 0.1 – Выбор пакетов в установщике Visual Studio
Кроме показанных, можно также выбрать «Visual C#». C# бывает полезен для расширения возможностей самой Visual Studio и написания небольших утилит. Нажимаем Install. Кроме самой студии ставится куча бесполезной, ненужной и вредной дряни. Если на компьютере была старая версия Windows Installer'а – потребуется перезагрузка. После установки – Finish, Exit.
Установка WDK
Монтируем скачанный iso-образ аналогично тому, как это было сделано с Visual Studio. Запускаем KitSetup.exe, на этапе выбора пакетов устанавливаем галочки в соответствии с рисунком:
Рис 0.2 – Выбор пакетов в установщике WDK
Нажимаем Ок, укорачиваем путь установки до C:\WinDDK, может появится окно установки .net 2.0. Устанавливаем .net. Появляется окно с лицензией WDK, соглашаемся. Ждем завершения установки. Нажимаем Finish. Установочный диск WDK не удаляем, а сохраняем до лучших времен, предыдущую версию 7.0 невозможно было корректно удалить без образа именно того диска, с которого ее устанавливали.
Устанавливать Visual Studio и WDK не обязательно на той же машине, на которой планируется проверять работу программ. Для проверки я поставил их на реальной машине с Windows 7 х64 и откомпилировал драйвер, который заработал под Windows 2003 Server х86.
Создаем на диске каталог для проектов, учитывая вышеописанные рекомендации (без пробелов и русских букв), например C:\Projects. Запускаем Visual Studio, открываем настройки (меню Tools/Option), выбираем в дереве «Projects and Solutions/General», в параметре Projects location выбираем/указываем созданный каталог.
Также настоятельно рекомендую установить Far Manager 2 и работать через него. Его преимущество над Windows/Total Commander'ами и Explorer'ами в том, что через него нормально видно содержимое консоли (команда ctrl + O), куда выдается полезная информация при компиляции и запуске консольных программ. Путь установки желательно записать в переменную PATH.
В дальнейшем рассмотрим и драйверы для Windows 9x. Для этого потребуется другое программное обеспечение, но программирование драйверов для Windows 9x проще.
#5
dE fENDER
- Member


