Драйвери пристроїв, частина 12 Драйвери USB в Linux

Частина 12: Драйвери USB в Linux - продовження

Пагс продовжив: "Давай зберемо драйвер пристрою USB, який ми закодували попередній раз, і буде використовувати той же зручний флеш-пристрій JetFlash фірми Transcend, що має ідентифікаційний код постачальника 0x058f (vendor ID) і ідентифікаційний код виробу 0×638 . Для цього давай докладніше розглянемо протокол USB, а потім перетворимо наші знання на код".

Джерела / приймачі даних пристроїв USB та їх типи

Крім того, для всіх випадків, крім джерел/приймачів даних типу control, повинен вказуватися режим "in" або "out", що визначає напрямок передачі даних; "in" означає передачу даних із пристрою USB на хост-машину, а "out" - навпаки.

Технічно, джерело/приймач даних ідентифікується за допомогою 8-бітового числа, у найстаршому біті (MSB) якого вказується напрямок потоку даних: 0 означає "out", а 1 - "in". Джерела / приймачі даних типу control є двонаправленими та біт MSB ігнорується.

На рис.1 показаний типовий фрагмент специфікацій пристроїв USB, підключених до системи.

пристрою

Рис.1: Фрагмент даних із proc, що описують пристрої USB

Якщо конкретно, то в рядках для пристрою E: , що зображуються на малюнку, показані приклади джерела / приймача даних хост контролера UHCI і двох джерел / приймачів даних типу bulk для флеш-пристрою. Крім того, показано, що номери джерел / приймачів даних рівні (в шістнадцятковому вигляді) 0x81 , 0x01 і 0x82 відповідно; старші біти (MSB) у першому і третьому випадку дорівнюють 1, що вказує на джерела / приймачі типу "in" - на малюнку вони вказуються за допомогою I, а в другому випадку -джерело/приймач даних виду "out", що вказується за допомогою O . У бітах MxPS вказується максимальний розмір пакета, т. е. розмір даних, які можна передані за один раз. Знову ж таки, як передбачається, що для джерела/приймача даних типу interrupt це буде 2 ( ), і 64 - для джерел/приймачів даних типу bulk. У Ivl визначається інтервал у мілісекундах, який повинен бути між двома послідовними передачами пакетів даних для правильної їх передачі, і він важливіший для джерел/приймачів даних типу interrupt.

Розбираємось із секцією пристрою USB

Як ми тільки-но ми з'ясували під час обговорення рядка для пристрою E:, зараз потрібно також розібратися з полями в інших рядках. Якщо коротко, то в цих рядках у секції USB-пристрою наведено повний опис пристрою, відповідний специфікаціям USB, які обговорювалися в попередній статті.

Тут буде стільки рядків C, скільки конфігурацій, хоча, як правило, використовується одна конфігурація. У конфігураційному дескрипторі C вказується індекс конфігурації, атрибути пристрою для цієї конфігурації, максимальна потужність (насправді струм), споживана пристроєм в даній конфігурації, і кількість інтерфейсів для цієї конфігурації.

Залежно від цього визначатиметься кількість рядків I . Їх буде більше у випадку, якщо є альтернативні варіанти інтерфейсів, тобто з тим самим номером інтерфейсу, але з різними властивостями - типовий сценарій для веб-камер.

Клас інтерфейсу може збігатися з класом пристрою або може від нього відрізнятися. І, як про це вже говорилося раніше, рядків E, залежно від числа джерел/приймачів даних, кінцевих точок, може бути багато.

Символ * , розташований після C іI , вказує на використовувану зараз конфігурацію та інтерфейс відповідно. У рядку P вказуються ідентифікаційний код постачальника (vendor ID), ідентифікаційний код виробу (product ID) та версія виробу. Рядки S є текстовими дескрипторами, в яких наводиться опис пристрою, який надається деякими конкретними виробниками пристроїв.

"Було б добре заглянути в директорій /proc/bus/usb/devices для того, щоб з'ясувати, чи було виявлено пристрій чи ні, і, можливо, отримати перші короткі відомості про пристрій. Але, швидше за все, ці відомості також будуть потрібні для щоб написати драйвер пристрою. Отже, чи є спосіб отримати до цих відомостей з коду мовою C?" - Запитала Світлана.

"Так, звичайно; це якраз те, про що я збираюся розповісти тобі далі. Чи пам'ятаєш ти, що як тільки USB-пристрій підключається до системи, драйвер хост контролера USB заносить інформацію про цей пристрій в загальний шар ядра USB? Щоб бути точним, він поміщає цю інформацію в набір структур, що входять одна в одну так само, як це визначено в специфікаціях USB" - відповів Пагс.

Нижче показані конкретні структури даних, які визначені в ; для кращого розуміння вони наведені тут у зворотному порядку:

Отже, при доступі до дескриптора struct usb_device для конкретного пристрою, можна отримати всю інформацію про конкретний USB-пристрій, точно таку, яка є в /proc . Але як отримати дескриптор?

Оскільки драйвери USB пишуться для інтерфейсів пристроїв, а не для всього пристрою в цілому, дескриптор пристрою насправді не знаходиться безпосередньо в драйвері; натомість кожного інтерфейсу є дескриптор інтерфейсу (що вказує на структуру struct usb_interface ).

Нагадаємо, що у зворотних викликах probe та disconnect, які виконуються ядром USB для кожного інтерфейсу зареєстрованого пристрою, як перший параметр вказується дескриптор відповідного інтерфейсу. Нижче наведені прототипи:

Отже, якщо є покажчик на інтерфейс, можна отримати доступ до всієї інформації про відповідний інтерфейс, а для отримання дескриптора пристрою можна скористатися наступним макросом:

Додаємо отримані знання до нашого драйвера, який раніше міг виконувати тільки реєстрацію пристрою, і отримуємо наступний листинг з кодом ( pen_info.c ):

Потім, разом із спеціальними операціями з флеш-пристроєм, можемо повторити звичайні операції, які виконуються для всіх драйверів Linux:

  • Збираємо драйвер (файл .ko) за допомогою запуску команди make .
  • Завантажуємо драйвер за допомогою insmod pen_info.ko
  • Підключаємо флейш-пристрій (після того, як ми побачили, що драйвер usb-storage ще не завантажено)
  • Від'єднуємо флеш-пристрій.
  • Перевіряємо журнали за допомогою команди dmesg
  • Вивантажуємо драйвер за допомогою команди rmmod pen_info.

На рис.2 показана частина описаних вище кроків, виконаних у системі Пагса. Не забудьте перевірити (дивіться висновок команди cat /proc/bus/usb/devices ), що до інтерфейсу флеш-пристрою підключено не звичайний драйвер usb-storage, а драйвер pen_info.

даних

Рис.2: Виведення даних за допомогою dmesg

Підведемо підсумок

"Раніше ти також згадував про те, що для одного пристрою пишуться кілька драйверів. А як, загалом, ми при реєстрації інтерфейсів пристрою USB вибираємо, який інтерфейс реєструвати, а який - ні?" - Запитала Світлана. "Зрозуміло, це тема подальшого обговорення нашоїостанньої теми для драйверів будь-якого пристрою – механізмів передачі даних” – відповів Пагс.