Главная » Ассемблер, Железо » Работа с мышью через интерфейс USB

0

Клавиатура и мышь по классификации, принятой для устройств USB, относятся к группе устройств человеко-машинного интерфейса (Human Interface Devices, сокращенно HID) [92].

Клавиатуры с интерфейсом USB до сих пор почти не применяются, так как в среднем стоят дороже стандартных клавиатур и никаких особых преимуществ в работе не дают. Кроме того, могут возникать проблемы, связанные со старым программным обеспечением для MS-DOS и с BIOS SETUP (теоретически во время начальной загрузки BIOS должен работать с клавиатурой USB в режиме эмуляции клавиатуры PS/2, но на практике эта возможность реализуется не всегда).

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

Код класса для устройств, принадлежащих к группе HID, имеет значение 03h. Мышь и клавиатура участвуют в процессе начальной загрузки компьютера, поэтому их относят к подклассу загрузочных устройств (Boot Devices), который обозначается кодом Olh. Код протокола для клавиатуры имеет значение Olh, а для мыши — значение 02h.

Пакет данных о текущем состоянии устройства HID и выполняемых с ним операциях именуется в документации рапортом (report). Мышь передает хосту рапорты в режиме передачи по прерываниям. Поскольку мышь является загрузочным устройством, начальный участок рапорта стандартизирован:

•         байт О содержит информацию о состоянии клавиш мыши;

•         байт 1 передает значение перемещения по оси X;

•         байт 2 передает значение перемещения по оси Y. Назначение остальных байтов рапорта мыши определяется изготовителем (для так называемых трехкоординатных устройств координата Z обычно передается в байте 3).

ПРИМЕЧАНИЕ

Значение перемещения передается в виде двоичного числа со знаком (при определении знака предполагается, что ось X направлена слева направо, ось Y — сверху вниз).

Структура байта 0 стандартизирована не полностью:

•         бит 0 — состояние клавиши 1 (0 — отпущена, 1 — нажата);

•         бит 1 — состояние клавиши 2 (0 — отпущена, 1 — нажата);

•         бит 2 — состояние клавиши 3 (0 — отпущена, 1 — нажата);

•         биты 3-7 используются по усмотрению изготовителя устройства.

ПРИМЕЧАНИЕ

Значение бита 0 соответствует состоянию левой клавише мыши.

Размер рапорта определяется изготовителем, но не может быть меньше трех байт. Получить размер рапорта в байтах можно из поля максимального размера пакета в дескрипторе конечной точки. Если включен режим эмуляции стандартного периферийного оборудования (мыши и клавиатуры PS/2), BIOS обрабатывает только

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

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

•    процедура IntEndpointDescri ptor позволяет определить номер конечной точки, осуществляющей передачу данных от мыши, и размер передаваемого блока данных;

•    процедура InterruptIN_Transaction осуществляет прием данных от мыши в режиме передачи по прерываниям;

•    процедура ShowNewMouseCursorPosition отображает курсор мыши на экране монитора путем инверсии байта атрибута символа.

Кроме того, программа USB_Mouse использует универсальные процедуры ввода-вывода из листинга 1.2, процедуру переключения в линейный режим адресации из листинга 2.1 и набор процедур для работы с контроллером и устройствами USB из листинга 8.1.

Листинг 8.4.

IDEAL

Р386

LOCALS

MODEL MEDIUM

; Физический адрес области памяти для списка кадров USB FrameLi stBaseAddr equ 200000h

; Параметры экрана в текстовом режиме ScreenLength equ 80 ;количество символов в строке ScreenHeigth equ 25 количество строк ма экраме

: Подключить файл мнемонических обозначений

; кодов управляющих клавиш и цветовых кодов

Include "listl_03.inc"

; Подключить файл макросов

Include "listl_04.inc"

DATASEG

: Старое значение фона символа 01dCharBackground

DB OFh : Текущее состояние кнопок

ButtonsStatus

DB 0

; Текущие координаты курсора мыши XCoordinate DW О YCoordinate DW О : Предыдущая позиция курсора мыши 01dXCoordinate DW О 01 dYCoordinate DW О : Текстовые сообщения

TxtO

DB LIGHTBLUE,0,25,"ПОИСК И ТЕСТИРОВАНИЕ МЫШИ USB",0

DB LIGHTMAGENTA.12,9,"Отображение курсора "

DB "осуществляется инверсией атрибута символа",О

DB YELLOW,24,21

DB "Для выхода нажмите левую клавишу мыши",О Txtl

DB 2,24,"Порядковый номер контроллера:",0

DB 4,В,"Базовый адрес набора регистров:",О

DB 5,8,"Номер используемого прерывания:",О

DB 7,23,"Регистр команды:",О

DB В,21."Регистр состояния:".О

DB 9,7,"Регистр управления прерываниями:",О

DB 10.27,"Номер кадра:",О

DB 11,11,"Базовый адрес списка кадров:",О

DB 12,14,"Модификация начала кадра:",О

DB 13,13,"Регистр состояния порта 1:",0

DB 14,13."Регистр состояния порта 2:",О

DB 16,17,"Адрес активного порта:",О AnyK

DB YELLOW,24,29,"Нажмите любую клавишу",О : Сообщения об ошибках NoMouse

DB 12,31,"Мышь не обнаружена",О

: ДЕСКРИПТОРЫ КОМАНД

; Дескриптор команды "Get Device Descriptor" GetDevDesc

DB 80h,6

DW 100h.0.8 : Дескриптор команды "Set Address" SetAddrDesc

DB 0.5 DW 0.0,0

: Дескриптор команды "Get Configuration Descriptor" GetConfDesc

DB 80h,6

DW 200h,0,8

; Дескриптор команды "Set Configuration" SetConfigur

DB 00h.9 DW 1.0.0

ENDS

SEGMENT sseg para stack ‘STACK’

DB 400h DUP(?)

ENDS

; Область памяти для хранения дескрипторов передачи SEGMENT USBDESCR para public ‘DATA’

Листинг 8.4(продолжение)

: Заголовок очереди дескрипторов QHDescriptor DD 00000003h единственный заголовок DD OOOOOOOOh указатель на первый TD DD 0,0,0,0,0,0 :область данных ПО

; Список дескрипторов для одной транзакции TD_Array DD 8*16 DUP(0) ENDS

CDDESEG

;*****************************

;* Основной модуль программы *  *****************************

PROC USB_Mouse

mov AX.DGROUP

mov DS.AX

mov [CS:MainDataSeg],AX : Установить текстовый режим и очистить экран

mov АХ.З int 10h

: Скрыть курсор – убрать за нижнюю границу экрана

mov [ScreenString].25

mov [ScreenColumn],0 call SetCursorPosition

; Проверить наличие PCI BIOS

mov AX,0B101h int lAh

jc

@@PCIBIOSNotFound cmp EDX.20494350h jne GtfPCIBIOSNotFound

; Установить режим прямой адресации памяти

call Initialization

; Инициализировать дескрипторы USB

call InitializeDeascriptors

: ЦИКЛ ПОИСКА ХОСТ-КОНТРОЛЛЕРОВ

mov [SearchResult],0

mov [USB_HostIndex],0

@@NextHost:

; Найти контроллер USB

call FindUSBController cmp [SearchResult],0 jne

@@NoHost

; Произвести глобальный сброс контроллера

mov DX, [USBBaseAddr]

mov AX,100bустановить сигнал сброса

out DX.AX

; Ожидать не менее 10 мс call Wait05s

; Снять сигнал сброса

mov АХ,О out DX.AX

; Ожидать не менее 10 мс call Wait05s

; Обнулить счетчик номеров

mov [USB_Device_Number],0 : Загрузить указатель на список кадров в регистр

; адреса списка кадров

mov DX,[USB_BaseAddr]

add DX.6

mov AX.О out DX.AX

add DX,2

mov EAX.FrameListBaseAddr out DX.EAX

; Активизировать хост-контроллер

mov DX,[USB_BaseAddr]

mov AX,1 out DX.AX : Проверить регистр состояния порта 1

mov [USBPortNum],1

; Вычислить адрес регистра состояния порта

mov DX,[USB_BaseAddr]

add DX.lOh

: Запомнить адрес регистра состояния порта

mov [USB_PortReg],DX

; Проверить наличие устройства in AX.DX test AX.OOOFh jz

@@TestPort2

; Присвоить устройству порядковый номер call Enumeration

; Получить дескриптор конфигурации cal1 GetConfigurationDescriptor

; Устройство является мышью? cmp [byte ptr DataBuffer+9+5],03h jne

@@TestPort2 cmp [byte ptr DataBuffer+9+7].02h

je

@@MouseFound

; Проверить регистр состояния порта 2

@@TestPort2:

mov [USBPortNum],2

; Вычислить адрес регистра состояния порта

mov DX, [USBBaseAddr]

add DX,12h

; Запомнить адрес регистра состояния порта

mov [USBPortReg] ,DX : Проверить наличие устройства in AX.DX test AX.OOOFh

Листинг 8.4(продолжение) jz

@@ContrStop

: Присвоить устройству порядковый нонер call Enumeration

; Получить дескриптор конфигурации call GetConfigurationDescriptor cmp [byte ptr DataBuffer+9+5],03h jne

@@TestPort2 cmp [byte ptr DataBuffer+9+7],02h

je

@@MouseFound

; Остановить контроллер

@@ContrStop:

mov DX,[USB_BaseAddr]

mov AX.O out DX.AX jmp

@@NextHost

@@MouseFound:

; Вывести текстовые сообщения на экран

MShowColorText 3,TxtO

; СКОНФИГУРИРОВАТЬ УСТРОЙСТВО

; Подать команду "Set Configuration"

mov SI.offset SetConfigur call SetupTransaction

; Определить адрес конечной точки и размер пакета call IntEndpolntDescriptor

; Отобразить курсор мыши первый раз

call ShowNewMouseCursorPosition

; Сбросить триггер данных

mov [dword ptr DataTrigger],0

@@NextInterrupt:

; Принять от мыши пакет данных

call InterruptlNTransaction

; Прибавить перемещение по X к координате X

mov AL,[DataBuffer+l] cbw

add AX,[XCoordinate] js РШ cmp AX,ScreenLength jb P0X2

mov AX.ScreenLength-1 jmp

@@X2 0Ш: xor AX, AX P0X2:

mov [XCoordinate],AX

; Прибавить перемещение no Y к координате Y

mov AL,[DataBuffer+2] cbw

add AX,[YCoordinate] js P@Y1

cmp АХ,ScreenHeigth jb

@@Y2

mov AX,ScreenHeigth-l jmp

@@Y2

@@Y1: xor AX.AX

@@Y2:

mov [YCoordinate],AX : Показать курсор в новой позиции

call ShowNewMouseCursorPosition

; Проверить состояние левой кнопки

test [DataBuffer],00000001b jz

@@NextInterrupt

; Остановить контроллер

mov DX,[USB_BaseAddr]

mov AX,0 out DX.AX

; Переустановить текстовый режим и очистить экран

mov АХ.З int 10h : Выход в DOS

mov AH,4Ch int 21h

: Обработка ошибок

@@NoHost:

cmp [USBHostlndex] ,0

je

@@HostNotFound

jmp short

@@MouseNotFound

; He поддерживается PCI BIDS

@@PC IВI OSNot Found:

MFatalError NoPCI

; Неверный номер регистра PffiadRegisterNumber:

MFatalError BadRg

; Нет ни одного контроллера USB PPHostNotFound:

MFatalError NoUSB : Мышь USB не найдена

@@MouseNotFound:

MFatalError NoMouse ENDP USBMouse

;* ОТОБРАЖЕНИЕ КУРСОРА МЫШИ ПУТЕМ ИНВЕРСИИ * ;* АТРИБУТА СИМВОЛА В ПОЗИЦИИ КУРСОРА *

PROC ShowNewMouseCursorPosition NEAR pusha

push ES

; Настроить ES на видеопамять

Листинг 8.4 (продолжение)

mov AX.0B800h

mov ES.AX

; Вычислить старую координату курсора

mov АХ.[01dYCoordi nate]

mov DX.160 mul DX

add AX.[OldXCoordinate]

add AX,[OldXCoordinate]

inc AX

mov DI,AX

; Восстановить атрибут синвола

mov AL,[01dCharBackground]

mov [ES:DI].AL

: Вычислить новую координату курсора

mov АХ.[YCoordi nate]

mov DX.160

mul DX

add AX.[XCoordinate]

add AX.[XCoordinate]

inc AX

mov DI .AX

; Сохранить атрибут синвола

mov AL,[ES:DI]

mov [01dCharBackground],AL

: Инвертировать атрибут

xor [byte ptr ES:DI],1111111b

; Запомнить координаты символа

mov AX,[XCoordinate]

mov [01dXCoordinate].AX

mov AX.[YCoordinate]

mov [01dYCoordi nate].AX

pop ES

popa

ret

ENDP ShowNewMouseCursorPosition

;*ПРИНЯТЬ ПАКЕТ ПО ПРЕРЫВАНИЮ *

;* Передаваемые параметры:*

;* INTDataSize – объем принимаемых данных. *

PROC InterruptlN Transaction near pushad

: Загрузить в ESI указатель на массив дескрипторов

mov ESI, [AddrTDArray]

: Загрузить в ЕВХ указатель на буфер данных

mov ЕВХ,[Addr_DataDescr]

: Сформировать дескриптор данных

; Указатель на следующий TD

mov [dword ptr GS:ESI].lb последний TD

: Слово управления

mov ЕАХ,[ShDevType] :тип устройства or ЕАХ.00800000h :признак активности

mov [GS:ESI+4],ЕАХ : Маркер

mov EAX.69h;приен данных

or EAX.[ShFuncNum] ;нонер функции

or ЕАХ.[ShEndpNum] .-конечная точка

or EAX,[DataTrigger]

or EAX.[ShPackSize] ;разнер блока

mov [GS:ESI+8].EAX

; Переключить триггер данных

xor [dword ptr DataTrigger],80000h

mov [GS:ESI+12],EBX :буфер данных

xor EAX.EAX

mov [GS:ESI+16],EAX

mov [GS: ESI+20]. EAX

mov [GS:ESI+24],EAX

mov [GS:ESI+28].EAX

; Установить указатель на список дескрипторов : (контроллер начинает передачу данных)

mov EAX,[Addr_TD_Array]

mov ESI,[Addr_QH]

add ESI,4

mov [GS:ESI],EAX

; Ожидать завершения операции

@@Wait_OpComplete:

cmp [dword ptr GS:ESI],lb jne

@@Wait_0pComp1ete • popad ret

ENDP InterruptlN Transaction

* ОПРЕДЕЛИТЬ МАКСИМАЛЬНЫЙ РАЗМЕР ПАКЕТА * ;* ДЛЯ ИСПОЛЬЗУЕМОЙ КОНЕЧНОЙ ТОЧКИ *

PROC IntEndpointDescriptor near pusha

: Поиск дескриптора конечной точки в списке дескрипторов

mov ВХ,0 ;счетчик байтов

@@NextDescriptor:

cmp [word ptr DataBuffer+BX],0507h

je P@Endpoint

@@NextDescOffset:

: Вычислить снещение следующего дескриптора

add BL,[DataBuffer+BX]

Листинг 8.4(продолжение) adc ВН.О

; Проверка на превышение длины массива cmp BX.[word ptr DataBuffer+2] jb

@@NextDescriptor MFatalError NoDev

@@Endpoi nt:

; Точка передачи по прерываниям?

test [DataBuffer+BX+2].10000000b jz

@@NextDescOffset cmp [DataBuffer+BX+3].3 jne

@@NextDescDffset

; Запомнить адрес конечной точки xor ЕАХ.ЕАХ

mov AL,[DataBuffer+BX+2] and AL,00001111b shl EAX,15

mov [ShEndpNum].EAX : Запомнить размер пакета xor EAX.EAX

mov AX,[word ptr DataBuffer+BX+4]

dec AX

shl EAX,21

mov [ShPackSize].EAX

popa

ret

ENDP IntEndpointDescriptor ENDS

: Подключить процедуры ввода данных и вывода на экран

; в текстовой режиме

Include "listl_02.inc"

; Подключить подпрограмму, переводящую сегментный

; регистр GS в режим линейной адресации

Include "list2_01.inc"

; Подключить процедуры для работы с контроллером USB

Include "listB_01.inc"

END

ПРИМЕЧАНИЕ

Программа USB Mouse осуществляет поиск мыши только непосредственно по портам хост-контроллера, поэтому перед запуском теста нужно подсоединить мышь к одному из USB-портов системного блока.

Источник: Кулаков В. К90 Программирование на аппаратном уровне: специальный справочник (+дискета). 2-е издание. — СПб.: Питер, 2003. — 847 е.: ил.

По теме:

  • Комментарии