Драйвери на устройства, част 12 USB драйвери в Linux
Част 12: Linux USB драйвери - продължение
Пъгс продължи: „Нека изградим драйвера за USB устройство, който кодирахме миналия път и използваме същото удобно флаш устройство Transcend JetFlash с Vendor ID 0x058f (идентификатор на доставчик) и ID на продукта 0x6387 (идентификатор на продукта). За да направим това, нека разгледаме по-отблизо USB протокола и след това да преобразуваме нашите знания в код.“
Източници на данни / дестинации на USB устройства и техните видове
Освен това, за всички случаи, с изключение на източници / приемници на данни от тип контрол, трябва да се посочи режимът "вход" или "изход", който определя посоката на прехвърляне на данни; "in" означава прехвърляне на данни от USB устройството към хост машината, а "out" означава обратното.
Технически, източникът/поглъщателят на данни се идентифицира с 8-битово число, чийто най-значим бит (MSB) показва посоката на потока от данни: 0 означава „изход“, а 1 означава „влизане“. Източниците/приемниците на данни за управление на типа са двупосочни и MSB битът се игнорира.
Фигура 1 показва типичен фрагмент от спецификации на USB устройство, свързано към системата.
Фигура 1: Фрагмент от данни от proc, описващ USB устройства
По-конкретно, редовете за устройство E:, показани на фигурата, показват примери за UHCI хост контролер източник/приемник на данни и два източника/приемника на масивни данни за нашето флаш устройство. В допълнение, номерата на източника/приемника на данни са показани като (в шестнадесетичен) 0x81, 0x01 и 0x82, съответно; най-значимите битове (MSB) в първия и третия случай са 1, което показва източници / приемници от тип "in" - на фигурата те са обозначени с I, а във втория случай -източник/дестинация на данни във формата „out“, която е обозначена с O . MxPS битовете показват максималния размер на пакета, т.е. количеството данни, което може да бъде предадено наведнъж. Отново се предполага, че това е 2 ( ) за източник/приемник на данни за прекъсване и 64 за източници/приемници на масивни данни. Ivl дефинира интервала в милисекунди, който трябва да бъде между две последователни предавания на пакети данни, за да бъдат предадени правилно, и е по-важен за източници на данни / приемници от тип прекъсване.
Разбиране на раздела за USB устройство
Както току-що научихме, когато обсъждахме низа за устройство E:, сега трябва да се справим и с полета в други низове. Накратко, тези редове в секцията за USB устройство предоставят пълно описание на устройството според USB спецификациите, разгледани в предишната статия.
Ще има толкова реда на C, колкото има конфигурации, въпреки че обикновено се използва една конфигурация. Конфигурационният дескриптор C определя индекса на конфигурацията, атрибутите на устройството за дадената конфигурация, максималната мощност (действителен ток), консумирана от устройството в дадената конфигурация, и броя на интерфейсите за дадената конфигурация.
В зависимост от това ще се определи броят на редовете I. Ще има повече от тях, ако има алтернативни опции за интерфейс, т.е. със същия номер на интерфейс, но с различни свойства - типичен сценарий за уеб камери.
Класът на интерфейса може или не може да бъде същият като класа на устройството. И, както беше споменато по-рано, може да има много редове E, в зависимост от броя на източниците на данни / приемниците, крайните точки.
Символът * след C иI , показва текущо използваната конфигурация и съответно интерфейс. Ред P съдържа идентификационния код на доставчика (ID на доставчика), идентификационния код на продукта (ID на продукта) и версията на продукта. S низовете са текстови дескриптори, които предоставят описание на устройството, предоставено от някои конкретни производители на устройства.
„Би било добре да погледнете в директорията /proc/bus/usb/devices, за да видите дали дадено устройство е било открито или не, и може би да получите първата кратка информация за устройството. Но най-вероятно тази информация също ще е необходима, за да напишете драйвер за устройство. И така, има ли начин да стигнете до тази информация от C кода?“ - попита Светлана.
„Да, разбира се; точно това ще ви разкажа по-нататък. Спомняте ли си, че веднага щом USB устройство е свързано към системата, драйверът на USB хост контролера поставя информация за това устройство в общия слой на USB ядрото? За да бъдем точни, той поставя тази информация в набор от структури, които пасват една в друга точно както е определено в спецификациите на USB“, отговори Пъгс.
Следното показва специфичните структури от данни, които са дефинирани в ; За по-добро разбиране те са изброени тук в обратен ред:
Така че, чрез достъп до дескриптора struct usb_device за конкретно устройство, можете да получите цялата информация за конкретно USB устройство, точно както е в /proc. Но как да получите дръжката на устройството?
Тъй като USB драйверите са написани за интерфейси на устройства, а не за устройството като цяло, дескрипторът на устройството всъщност не се намира в самия драйвер; вместо това всеки интерфейс има интерфейсен дескриптор (сочещ към struct usb_interface).
Спомнете си, че обратните извиквания за проверка и изключване, които се изпълняват от USB ядрото за всеки интерфейс на регистрирано устройство, приемат съответния манипулатор на интерфейса като първи параметър. По-долу са прототипите:
Така че, ако има указател към интерфейс, можете да получите достъп до цялата информация за съответния интерфейс и за да получите дескриптора на устройството, можете да използвате следния макрос:
Добавяме придобитите знания към нашия драйвер, който преди това можеше да извършва само регистрация на устройство, и получаваме следния списък с кода ( pen_info.c ):
След това, заедно със специалните операции на флаш устройството, можем да повторим обичайните операции, които се извършват за всички Linux драйвери:
- Изграждане на драйвера (.ko файл) чрез изпълнение на командата make.
- Изтеглете драйвера с помощта на командата insmod pen_info.ko
- Свържете флаш устройството (след като видяхме, че драйверът за USB памет все още не е зареден)
- Изключете флашката.
- Проверка на регистрационни файлове с командата dmesg
- Разтоварваме драйвера с помощта на командата rmmod pen_info.
Фигура 2 показва част от стъпките, описани по-горе, които са извършени в системата Pugs. Не забравяйте да проверите (вижте изхода на cat /proc/bus/usb/devices), че драйверът pen_info е свързан към интерфейса на флаш устройството, а не към обичайния драйвер за USB памет.
Фигура 2: dmesg изход
Обобщете
"По-рано споменахте също, че за едно устройство се пишат няколко драйвера. И как в общия случай при регистриране на интерфейси на USB устройства избираме кой интерфейс да регистрираме и кой не?" - попита Светлана. „Разбира се, това е тема за допълнително обсъждане на нашитенай-новата тема за драйвери на всяко устройство - механизми за пренос на данни", отговори Pugs.