С общими принципами организации работы с USB можно познакомиться в работах Павла Агурова, а здесь будет рассмотрена только одна простая схема, комментирующая принцип работы с любым USB-устройством. В простейшем виде USB-устройство можно представить как некую древовидную структуру, включающую в себя «Конфигурации» (configurations), «Интерфейсы» (interfaces) и «Конечные точки» (endpoints).
«Конечная точка» устройства — это программная сущность, у которой есть свой уникальный идентификатор и которая может иметь буфер с некоторым числом байтов для приема-передачи информации. Но чтобы добраться до нее, приложению (под управлением хоста) нужно программным путем пройти через уровни «Устройства», «Конфигурации» и «Интерфейса». Каждый из них описывается стандартной программной структурой, и есть возможность выбирать, какие именно интерфейсы следует использовать, чтобы попасть в требуемую конечную точку.
Важная особенность USB — наличие только одного Мастера (ведущего), которым обычно является компьютер. Само USB-устройство всегда отвечает на разные запросы компьютера, о чем бы ни шла речь и в какую бы сторону ни передавалась информация.
Разработчик может написать полноценный драйвер для работы со своим USB-устройством, применяя уже имеющийся в системе заголовочный файл linux/usb.h.
Дело в том, что большинство низкоуровневых задач в Linux уже решены, и любая написанная программа будет иметь прикладной характер, хотя формально и получит название драйвера. Справедливо также заметить, что с каждой новой версией ядра Linux работа с USB становится проще.
Драйвер, написанный для поддержки USB-устройства, призван решать следующие задачи:
- регистрация и удаление драйвера;
- регистрация и удаление устройства;
- обмен данными с устройством.
Но можно точно назвать один важный и естественный недостаток, который несет в себе программный модуль уровня драйвера, — платформенная непереносимость.
А как быть, если нет времени писать драйвер, но надо срочно создать программу, работающую с USB-устройством, которая сама будет решать, как, когда и с каким из таких устройств ей работать? Да к тому же хотелось бы, чтобы она легко переносилась на другие платформы (Windows, Mac OS и т.д.) хотя бы с минимальными изменениями в тексте или вовсе без них.
При этом ее требуется писать на Паскале или даже на С#. Возможно ли это? Вполне. Но для этого необходима библиотека libusb (http://www.libusb.org/). Если в дистрибутиве Linux нет такого «зверя» (ничего не отображается в ответ на команду locate libusb.so), то существует несколько путей:
- поставить этот пакет с помощью штатного инсталлятора, к примеру, для Fedora написать в консоли: yum install libusb;
- самостоятельно скачать RPM-пакет (http://sourceforge.net/projects/libusb/) и попробовать его установить;
- скачать пакет «исходников» (http://sourceforge.net/projects/libusb/files/) и собрать на своей машине библиотеку.
Важное замечание. На сайте libusb.org выложены две ветки проекта — версии 1.0 и 0.1. В статье описана работа со старой стабильной версией, по этому будьте внимательны: при использовании версии 1.0, есть расхождения в API.
Чтобы понять, имеются ли в системе устройства, соответствующие USB-интерфейсу, можно, например, воспользоваться утилитой usbview (http://usbview.sourceforge.net) либо ее продвинутым аналогом — usbview2 (http://usbview2.sourceforge.net/), хотя в любом современном Linux найдутся встроенные консольные команды для таких целей.
В этой статье мы ограничимся основами и попробуем разобраться в алгоритме создания аналогичной программы для просмотра устройств USB, только работать она будет в консоли.
А за основу мы возьмем простую программу вот отсюда — http://www.linuxquestions.org/linux/answers/Programming/Developing_Linux_Device_Drivers_using_Libusb_API. Внесем в нее русские комментарии и откомпилируем в режиме программы С++. При этом в настройках компилятора укажем на использование библиотеки libusb.so (листинг 1).
Как видно, этот пример полностью соответствует описанной ранее логической схеме — мы начинаем работу с общего перебора устройств и заканчиваем конкретными логическими точками. В данном примере идет простой перебор всего, что содержится в системе и что имеет отношение к USB. Но так делать необязательно. Для работы с конкретным устройством нас может интересовать определенный код изготовителя продукта (idVendor) и код продукта (idProduct). Если в этом примере уже указанный заголовочный usb.h заменить на , то это будет уже совсем другая библиотека, которую используют для создания полноценных (непереносимых на другие типы систем) драйверов в среде Linux.
Аналогичный пример нетрудно найти в Сети для языка Free Pascal, а значит, несложно написать собственную графическую утилиту, аналогичную usbview, и в среде Lazarus (http://www.lazarus.freepascal.org/).
Для этого потребуется скачать файл libusb.pp (например, здесь http://www.sciencetronics.com/download/fpc_libusb.tgz).
Фрагмент программы, написанной в Lazarus для чтения списка устройств USB (листинг 2) представлен на стр. 58.
Итак, мы выяснили, что в нашем распоряжении языки Си, C++ и Паскаль. Но это не предел, рассмотрим простой пример на языке С# (листинг 3).
В данном примере (который успешно запускается в среде Linux с помощью платформы Mono) для доступа к библиотеке libusb.so применяется специальная .NET-обертка под названием #USBlib. Разработчики утверждают, что она одинаково подходит как для libusb.so, так и для своего собрата, функционирующего под управлением Windows (http://libusb-win32.sourceforge.net/). Кстати, важно отметить, что наборы функций libusb-win32 и libusb совпадают, а особые платформенные различия указаны в документации. Это и есть основное достоинство библиотеки libusb — блестящая платформенная переносимость исходного кода.
В заключение стоит напомнить, что та конкретная задача, над которой мы трудились, используя разные языки и инструментарии, — вывод списка устройств USB, решается в Linux с помощью встроенных команд
Разработчики утверждают, что #USBlib одинаково подходит как для libusb.so, так и для своего собрата, функционирующего под управлением Windows (http://libusb-win32.sourceforge.net/). Кстати, важно отметить, что наборы функций libusb-win32 и libusb совпадают, а особые платформенные различия указаны в документации.