Назад на список статей

Текст: (C) Кулаков В.Г. (С) ЗАО Издательский дом „ ПИТЕР ” , 2003

Сканирование, редактирование, перевод в HTML: (C) VetaSoft, 2004

 

Глава 8

Шина USB

 

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

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

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

Универсальная последовательная шина (Universal Serial Bus, сокращенно USB) разрабатывалась как промышленный стандарт расширения архитектуры РС, ориентированный на интеграцию с устройствами телефонии и бытовой электроники. Разработка шины ведется с 1994 года. Первоначально в группу разработчиков входили Compaq, DEC, IBM, Intel, Microsoft, NEC и Northern Telecom, а затем количество заинтересованных участников стало расширяться. Первая официальная версия стандарта на шину USB (спецификация 1.0) была опубликована в 1996 году, доработанный вариант (спецификация 1.1) [95] появился в 1998 году, а в 2000 году опубликована вторая версия стандарта (спецификация 2.0.). К сожалению, использование последней версии стандарта в течение длительного времени тормозилось, в том числе по вине самих разработчиков: устройства с интерфейсом USB 2.0 не выпускались потому, что для них отсутствовало системное программное обеспечение, которое не удавалось отладить потому, что не выпускались устройства!

Так как устройства, соответствующие спецификации USB 2.0, до сих пор мало распространены, ниже мы будем рассматривать устаревшую, но широко используемую в данный момент версию 1.1. Подробную документацию по всем версиям стандарта можно найти в Интернете, на сайте USB -консорциума www.usb.org.

 

Архитектура шины USB

 

Архитектура и основные параметры шины USB определяются возложенными на нее задачами. Физическая топология шины USB, изображенная на рис. 8.1, имеет следующие основные особенности:

Хост-контроллер (Host Controller) — это главный контроллер, который входит в состав системного блока компьютера и управляет работой всех устройств на шине USB.

На шине USB допускается наличие только одного хоста. Системный блок АТ-совместимого персонального компьютера может содержать от одного до трех хост-контроллеров [80], каждый из которых управляет отдельной шиной USB.

Устройство (Device) USB может быть хабом или функцией.

Хаб (Hub) — это устройство, которое обеспечивает дополнительные точки подключения к шине USB.

Каждый хаб имеет один восходящий порт (Upstream Port), предназначенный для подключения к хабу верхнего уровня, и несколько нисходящих портов (Downstream Ports), предназначенных для подключения функций или хабов нижнего уровня.

 

 

Рис. 8.1. Физическая топология шины USB

 

Хаб может иметь собственный источник питания (Self-powered Hub) или получать питание от шины USB (Bus-powered Hub). Хаб управляет работой нисходящих портов, осуществляет контроль подключения и отключения устройств. Через порты хаб управляет электропитанием устройств, не имеющих собственных источников энергии.

Корневой хаб (Root Hub) — это хаб, который входит в состав хост-контроллера.

Функция (Function) — это периферийное устройство или отдельный блок периферийного устройства, способный передавать и принимать информацию по шине USB.

Составное устройство (Compound Device) — это периферийное устройство со встроенным хабом.

Различают три уровня взаимодействия хоста с физическим устройством:

Используемая на среднем уровне взаимодействия логическая топология шины USB (рис. 8.2) гораздо проще физической: хост обменивается информацией с логическими устройствами таким образом, что точка подключения устройства не имеет значения, как если бы все устройства были подключены к корневому хабу. Верхний уровень взаимодействия вопросы топологии шины вообще не затрагивает.

 

 

Рис. 8.2. Логическая топология шины USB

 

Режимы передачи данных

 

Пропускная способность шины USB, соответствующей спецификации 1.1, составляет 12 Мбит/с (1,5 Мбайт/с). Полоса пропускания шины делится между всеми устройствами, подключенными к шине.

Шина USB имеет два режима передачи: в полноскоростном (full-speed) режиме скорость передачи составляет 12 Мбит/с, в низкоскоростном (low-speed) — 1,5 Мбит/с. Полноскоростной режим используется принтерами, сканерами, видеокамерами и другими устройствами, передающими больше объемы информации. Низкоскоростной

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

Устройство, использующее полную скорость передачи, именуется полноскоростным (Full-speed Device), а устройство, использующее пониженную скорость — низкоскоростным (Low-speed Device).

 

Модель передачи данных

 

Логическое устройство USB представляет собой набор конечных точек.

Конечная точка (Endpoint) — это часть устройства USB, которая имеет уникальный идентификатор и является получателем или отправителем информации, передаваемой по шине USB.

Основными для конечной точки являются следующие параметры :

Любое USB -устройство имеет конечную точку с нулевым номером, которая в документации именуется Endpoint Zero или Endpoint 0. Нулевая точка позволяет хосту опрашивать устройство с целью определения его типа и параметров, выполнять инициализацию и конфигурирование устройства.

Каждая конечная точка может работать только с одним типом посылок (типы посылок описаны ниже). Нулевая точка поддерживает управляющие посылки и поэтому может выполнять как прием, так и передачу данных.

Кроме нулевой точки, функции обычно имеют дополнительные конечные точки, которые используются для обмена данными с хостом. Дополнительные точки могут работать либо только на прием, либо только на передачу информации. Точки, передающие данные хосту, именуются входными (IN), а точки, принимающие данные от хоста — выходными (OUT). Низкоскоростные устройства могут иметь до двух дополнительных точек, а полноскоростные — до 15 дополнительных входных и до 15 дополнительных выходных точек.

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

Для описания порядка прохождения информации через буфер данных между программным обеспечением и конечной точкой в спецификации USB введено понятие канала.

Канал (pipe) — это модель взаимодействия конечной точки с программным обеспечением хоста. Имеется два типа каналов:

Основными характеристиками каналов являются:

Канал сообщений, связанный с нулевой конечной точкой, называется в документации Основным каналом сообщений (Default Control Pipe). Спецификация USB запрещает для канала сообщений одновременную обработку нескольких запросов: нельзя начинать передачу нового сообщения, пока не завершена обработка предыдущего. В случае возникновения ошибки, однако, передача сообщения может быть прервана хостом, после чего хост может начать передачу нового сообщения.

 

Структура пакетов

 

Вся информация передается по шине USB в виде пакетов. Каждый пакет начинается с поля синхронизации (SYNC), за которым следует идентификатор пакета ( PID ). Идентификатор пакета состоит из четырехразрядного кода типа пакета и четырехразрядного контрольного поля, каждый разряд которого является инверсией соответствующего разряда кода типа пакета (код пакета и контрольное поле комплементарны). Принятые по стандарту USB 1.1 коды PID перечислены в табл.8.1. Как видно из таблицы, имеется четыре группы идентификаторов, причем принадлежность к определенной группе задается в двух младших разрядах PID:

Таблица 8.1 . Список кодов PID

Тип PID

Обозна- чение

Код

типа

Описание пакета

Маркер

OUT

 

000 1b

 

Адрес и номер конечной точки при передаче от хоста к функции

IN

 

1001b

 

Адрес и номер конечной точки при передаче от функции к хосту

SOF

0101b

Маркер начала кадра и номер кадра

SETUP

1101b

Адрес и номер конечной точки при передаче команды от хоста к функции

Данные

DATA0

001 1b

Четный пакет данных

DATA1

1011b

Нечетный пакет данных

Подтверждение

ACK

0010 b

Подтверждение приема пакета

NAK

1010b

Ответ на запрос не готов

STALL

1110b

Произошел сбой в конечной точке или запрос не поддерживается

Специальный

PRE

1100b

Преамбула запроса, которая разрешает замедленный трафик для низкоскоростных устройств

 

Структура пакета зависит от группы, к которой он относится.

 

Порядок выполнения транзакций

Все транзакции на шине USB выполняются под управлением хост контроллера.

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

Разные способы передачи отличаются друг от друга своими характеристиками, к которым относятся:

 

Различают следующие типы транзакций:

 

 

Транзакция передачи команды включает в себя следующие операции:

 

Транзакция передачи данных с подтверждением включает следующие операции:

 

Транзакция приема данных с подтверждением включает следующие операции:

 

Транзакция изохронной передачи данных включает следующие операции:

 

Транзакция изохронного приема данных включает следующие операции:

 

При выполнении транзакций используется три типа пакетов подтверждения:

 

Если при выполнении транзакции передачи данных с подтверждением в пакете данных обнаружена ошибка по контрольному коду CRC, получатель пакета данных не высылает пакет подтверждения. Отправитель при отсутствии подтверждения от получателя должен зафиксировать ошибку передачи данных и повторить транзакцию.

 

Типы посылок

 

Архитектура USB предусматривает четыре типа посылок.

 

Порядок передачи управляющих посылок

 

Есть три типа управляющих посылок:

 

Управляющая посылка записи данных включает следующие транзакции:

 

Управляющая посылка чтения данных включает следующие транзакции:

 

Управляющая посылка без данных включает следующие транзакции:

 

При выполнении транзакции передачи команды признак синхронизации данных должен быть сброшен в ноль (блок данных, содержащий код команды, имеет PID DATA0).

Если команда предполагает прием или передачу данных, то после каждой транзакции признак синхронизации данных инвертируется: первый блок данных имеет идентификатор DATA1, второй — DATA0, третий — DATA1 и т. д.

Пустой пакет данных, подтверждающий завершение управляющей посылки, должен иметь идентификатор DATA1.

При передаче управляющей посылки максимальный размер пакета для полноскоростного устройства может составлять 8, 16, 32 или 64 байта, а для низкоскоростного всегда равен 8 байтам.

 

ПРИМЕЧАНИЕ

На практике для передачи сообщений по Основному каналу сообщений всегда используется максимальный размер пакета, равный 8 байтам.

 

Порядок передачи массивов данных

 

Различают два вида передачи массивов:

Передача данных от хоста к конечной точке состоит из следующих друг за другом транзакций передачи данных с подтверждением , а передача данных от конечной точки к хосту - из следующих друг за другом транзакций приема данных с подтверждением. И в том, и в другом случае перед началом передачи массива триггер синхронизации данных должен быть сброшен в 0: при выполнении первой транзакции блок данных имеет идентификатор DATA0, второй — DATA1, третий — DATA0 и т. д.

Прием и передачу массивов данных могут выполнять только полноскоростные устройства. Максимальный размер пакета при передаче массива может быть равен 8, 16, 32 или 64 байтам (обычно используется значение 64 байта),

 

Порядок передачи данных по прерываниям

 

Различают два вида передачи по прерываниям:

 

Передача данных по прерыванию заключается в выполнении транзакции передачи пакета данных (с подтверждением) от хоста к конечной точке. Прием данных заключается в выполнении транзакции приема пакета данных (с подтверждением) от конечной точки. При приеме или передаче каждого блока данных происходит переключение триггера данных. Первый передаваемый (или принимаемый) блок имеет идентификатор DATA0, следующий — DATA1 и т. д. Максимальный размер пакета при передаче по прерываниям для низкоскоростного устройства не может быть более 8 байт, для полноскоростного — более 64 байт.

Порядок выполнения изохронной передачи

 

Различают два вида изохронной передачи:

 

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

Изохронную передачу могут выполнять только полноскоростные устройства. Максимальный размер пакета данных при изохронной передаче — 1023 байта.

 

Структура кадра USB

 

Длительность каждого кадра USB по времени равна одной миллисекунде. Хост-контроллер в начале каждого кадра генерирует маркер начала кадра, после чего начинает выполнять передачу данных. Передачи внутри кадра выполняются в следующем порядке:

Таким образом, изохронные передачи имеют высший приоритет, а передачи массивов данных — самый низкий.

 

Регистры хост-контроллера

 

Драйвер интерфейса USB управляет работой хост-контроллера через регистры. Регистры универсального хост-контроллера принято разделять на две группы: группу конфигурационных регистров PCI (USB PCI Configuration Registers) и группу регистров пространства ввода-вывода (USB Host Controller IO Space Registers). Ниже мы будем рассматривать только регистры ввода-вывода, так как непосредственная работа с конфигурационными регистрами из прикладных программ нежелательна (может привести к «зависанию» системы).

Для описания режима доступа к данным в регистрах USB используются следующие стандартные обозначения:

 

Список регистров ввода-вывода хост-контроллера шины USB приведен в табл. 8.2. Доступ к этим регистрам осуществляется через группу портов ввода/вывода, базовый адрес которой задан в конфигурационном регистре USBBA.

 

Таблица 8.2. Регистры ввода-вывода универсального хост-контроллера шины USB

 

Смещение

Размер

Доступ

Мнемоника

Наименование регистра

00h

WORD

R/W

USBCMD

Регистр команды USB

02h

WORD

R/WC

USBSTS

Регистр состояния USB

04h

WORD

R/W

USBINTR

Регистр управления прерываниями USB

06h

WORD

R/W

FRNUM

Регистр номера кадра USB

08h

DWORD

R/W

FLBASEADD

Регистр базового адреса списка кадров USB

0Ch

BYTE

R/W

SOFTMOD

Регистр модификатора начала кадра USB

10h

WORD

R/WC

PORTSC0

Регистр состояния и управления порта 0

12h

WORD

R/WC

PORTSC1

Регистр состояния и управления порта 1

 

Регистр команды USB (USBCMD) предназначен для передачи команд хост-контроллеру и доступен как для записи, так и для считывания данных. Контроллер начинает выполнение команды сразу же после того, как она записана в регистр.

Рассмотрим назначение разрядов регистра команды USB.

Бит 1 (HCRESET) — сброс хост-контроллера. Запись единицы в данный разряд приводит к сбросу регистров, отражающих внутреннее состояние контроллера; механизм, обеспечивающий обнаружение подсоединения и отсоединения

 

После аппаратного или программного сброса контроллера регистр команды USB содержит значение 0000 h .


Регистр состояния USB (USBSTS) отражает текущее состояние хост-контроллера. Регистр USBSTS доступен для чтения и сброса (запись единиц в какие-либо его разряды сбрасывает эти разряды в ноль). Рассмотрим назначение разрядов регистра состояния USB:

 

После аппаратного или программного сброса контроллера регистр состояния USB содержит значение 0020h.

 

Регистр управления прерываниями (USBINTR) позволяет разрешать и запрещать генерацию прерываний различных типов хост-контроллером. Регистр USBINTR доступен для записи и считывания. Назначение разрядов регистра управления прерываниями:

 

Таким образом, регистр управления прерываниями позволяет заблокировать любые прерывания от контроллера USB, кроме прерываний, генерируемых при обнаружении ошибок в работе самого контроллера.

После аппаратного или программного сброса контроллера регистр USBINTR содержит значение 0000 h: все прерывания (за исключением прерываний по сбоям в работе контроллера) запрещены.

 

Регистр номера кадра (FRNUM) содержит текущий номер кадра US B. Младшие 11 разрядов регистра (биты 0-10) содержат текущий номер кадра, а остальные разряды зарезервированы и должны содержать нули. Регистр доступен для чтения в любой момент времени, а запись данных разрешена только в том случае, если работа контроллера приостановлена (бит RS в регистре команды USB сброшен в ноль).

Значение, содержащееся в разрядах 0-10 регистра FRNUM, увеличивается на единицу (инкрементируется) после завершения каждого кадра; после достижения значения 7FFh регистр обнуляется. Содержимое разрядов 0-10 служит номером кадра и передается в начале кадра в SOF -пакете. Кроме того, разряды 0-9 используются при формировании индекса текущего элемента в списке кадров (соответствуют разрядам 2-11 индекса).

После аппаратного или программного сброса контроллера регистр FRNUM содержит значение 0000 h.

 

Регистр базового адреса списка кадров USB (FRBASEADD) содержит начальный (абсолютный) адрес списка кадров в оперативной памяти компьютера. Регистр доступен FRBASEADD для записи и считывания данных. Используются только старшие 20 бит регистра FRBA-SEADD, соответствующие битам 12-31 линейного адреса, а младшие 12 бит зарезервированы и должны содержать нули. Таким образом, базовый адрес списка кадров должен быть выровнен на границу гранулярности свопинга памяти процессоров Intel x86 (4 Кбайт).

Контроллер формирует указатель на текущий элемент списка кадров путем комбинирования сдвинутых влево на два разряда битов 0-9 из регистра номера кадра и битов 12-31 из регистра базового адреса. Разряды 0 и 1 указателя всегда равны нулю (указатель выровнен на границу двойного слова). Количество указателей в списке кадров равно 1024, а размер списка составляет 4 Кбайт.

После аппаратного или программного сброса контроллера значение регистра базового адреса считается "неопределенным": перед запуском контроллера надлежит создать в оперативной памяти список кадров и загрузить его абсолютный (линейный) адрес в регистр FRBASEADD.

 

Регистр модификатора начала кадра USB (SOFMOD) служит для подстройки частоты кадров USB с целью обеспечения синхронизации всех устройств системы при работе в режиме реального времени. Значение младших семи разрядов этого регистра складывается с числом 11936, в результате чего формируется делитель частоты кварцевого резонатора генератора тактовой частоты. Старший разряд регистра SOFMOD (бит 7) зарезервирован и должен содержать значение 0.

Частота кварцевого резонатора составляет 12 МГц, а значение, устанавливаемое в регистре модификатора начала кадра после аппаратного или программного сброса контроллера равно 64 (40h), поэтому частота генерации кадров равна 1 кГц. Изменяя значение модификатора от 0 до 127, можно осуществлять подстройку частоты кадров USB в пределах ± 0,5 %.

 

Регистр состояния и управления порта (PORTSC) позволяет контролировать режим работы порта хост-контроллера. Регистры PORTSC0 и PORTSC 1 доступны для записи и считывания данных. Назначение разрядов регистра состояния порта :

бит 8 — признак подключения низкоскоростного устройства. Данный бит доступен только для считывания и устанавливается в единицу, если к порту

 

После аппаратного или глобального сброса оба регистра PORTSC содержат значение 0080 h: бит 7 имеет значение 1, остальные разряды сброшены. После сброса контроллера (HCRESET) могут быть установлены биты 1 и 3. В современных контроллерах после осуществления сброса бит 11 может иметь значение 1.

 

Структуры данных хост-контроллера

 

Описание используемых хост-контроллером шины USB 1.1 структур данных содержится в спецификации Universal Host Controller Interface Design Guide [91].

 

Список кадров

 

Список кадров (Frame List) представляет собой массив, который состоит из 1024 указателей кадров по 32 разряда и занимает 4 Кбайт оперативной памяти. Начальный адрес списка хранится в регистре базового адреса списка кадров FLBASEADD (он должен быть выровнен на границу 4 Кбайт).

 

31

4

3

2

1

0

Указатель кадра

0

0

Q

T

Рис. 8.3. Структура элемента списка кадров

Структура элемента списка кадров показана на рис. 8.3. Разряды элемента списка имеют следующее назначение:

 

Указатель кадра (Frame List Pointer) содержит линейный (абсолютный) 32-разрядный адрес области памяти, по которому размещен объект данных списка кадров — заголовок очереди или дескриптор передачи.

Адрес объекта данных должен быть выровнен по границе 16 байт; младшие 4 разряда адреса всегда равны нулю.

 

Дескриптор передачи

 

Дескриптор передачи (Transfer Descriptor, сокращенно — TD) описывает параметры транзакции, запрашиваемой клиентом USB. Начало дескриптора должно быть выровнено на границу в 16 байт.

 

Указатель на следующий элемент списка

00- 03h

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

04-07h

Маркер дескриптора

08-0Bh

Указатель на буфер данных

0C-0Fh

Зарезервировано для использования

программным обеспечением

10-13h

14-17h

18-1 Bh

1C-1Fh

Рис. 8.4. Структура дескриптора передачи .

 

Несмотря на то, что USB может выполнять передачи четырех различных типов, все дескрипторы имеют одинаковую структуру, изображенную на рис. 8.4. Каждый дескриптор передачи занимает 32 байта памяти и состоит из двух частей: младшие четыре 32-разрядных слова занимает область данных хост-контроллера, старшие четыре слова — область данных программного обеспечения:

 

Область данных программного обеспечения хост-контроллером не обрабатывается и на его функционирование никак не влияет.

 

31

4

3

2

1

0

Указатель на следующий элемент списка

0

Vt

Q

T

Рис. 8.5. Структура указателя на следующий элемент списка дескрипторов.

 

Указатель на следующий элемент списка дескрипторов имеет структуру, изображенную на рис. 8.5:

 

Следует уделить особое внимание биту 2, задающему порядок обработки очередей дескрипторов: если этот бит имеет значение 0, то после завершения обработки данного дескриптора контроллер переключится на следующую очередь (обработка списка в ширину), а если бит 2 установлен в 1 — будет обрабатываться следующая транзакция в текущей очереди (обработка списка в глубину).

 

31

30

29

28

27

26

25

24

23

16

15

11

10

0

Зарез.

SPD

C_Err

LS

ISO

IOC

Status

Зарез.

ActLen

Рис. 8.6. Структура слова управления и состояния дескриптора передачи .

 

Структура слова управления и состояния дескриптора передачи показана на рис. 8.6. Разряды слова имеют следующее назначение:

 

Биты 16-23 совместно образуют поле состояния процесса выполнения команды (Status Field), которое перезаписывается хост-контроллером после завершения транзакции. Кроме того, после транзакции хост может записывать информацию в поле ActLen и декрементировать счетчик ошибок. Остальные поля заполняются программным обеспечением в процессе создания дескриптора и в дальнейшем не изменяются.

 

31

21

20

19

18

15

14

8

7

0

MaxLen

R

D

EndPt

Адрес устройства

PID

Рис. 8.7. Структура маркера дескриптора передачи.

 

Маркер дескриптора передачи (TD Token) содержит заголовок пакета, который передается в стартовом маркере USB. Структура маркера показана на рис. 8.7. Разряды слова маркера имеют следующее назначение:

 

Указатель на буфер данных содержит 32-разрядный адрес буфера, предназначенного для приема или передачи данных. Объем буфера должен быть не меньше, чем максимальный объем передаваемых данных, закодированный в поле MaxLen маркера дескриптора передачи.

 

Заголовок очереди

 

Заголовок очереди (Queue Head, сокращенно QH) — это специальная структура данных, предназначенная для создания очередей, используемых при передачах типов Control, Bulk и Interrupt.

 

Указатель на следующий заголовок очереди

00- 03h

Указатель на первый элемент очереди дескрипторов

04-07h

Зарезервировано для использования программным обеспечением

08-0Bh

0C-0Fh

10-13h

14-17h

18-1Bh

1C-1Fh

Рис. 8.8. Структура заголовка очереди

 

Структура заголовка очереди показана на рис. 8.8. Заголовок очереди состоит из двух 32-разрядных слов:

Заголовок очереди должен быть выровнен на границу 16 байт.

Указатель на следующий заголовок очереди имеет структуру, изображенную на
рис. 8.9:

 

31

4

3

2

1

0

Указатель на следующий заголовок очереди

0

0

Q

T

Рис. 8.9. Структура указателя на следующий заголовок очереди.

 

Указатель на первый элемент очереди дескрипторов передачи имеет структуру, изображенную на рис. 8.10:

 

31

4

3

2

1

0

Указатель на первый элемент очереди дескрипторов

0

R

Q

T

Рис. 8.10. Структура указателя на первый элемент очереди дескрипторов передачи.

 

Порядок обработки списка дескрипторов

 

Порядок выполнения запросов определяется структурой списка дескрипторов, который в спецификации хост-контроллера [91] именуется «планом» (Schedule). Для обеспечения нормальной работы шины USB дескрипторы в списке должны размещаться в определенном порядке, как показано на рис. 8.11.

 

ПРИМЕЧАНИЕ

Каждый элемент списка кадров может быть действительным или недействительным. Действительный элемент списка кадров должен содержать указатель на дескриптор передачи или очередь заголовка. В нормальном режиме работы контроллера все элементы списка должны быть действительными.

 

 

Когда начинается выполнение очередного кадра, хост-контроллер получает из списка кадров указатель на список дескрипторов, который должен быть обработан в данном кадре.

 

Рис. 8.11. Пример построения списка дескрипторов.

 

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

 

ПРИМЕЧАНИЕ

Список дескрипторов изохронной передачи в каждом кадре свой, а список заголовков очередей — общий для всех кадров.

 

Каждый заголовок очереди указывает на первый из находящихся в очереди дескрипторов передачи. Обычно список заголовков очередей обрабатывается по горизонтали (в ширину): контроллер извлекает из заголовка первый дескриптор в очереди, обрабатывает его и переходит к следующему заголовку очереди. При необходимости можно установить режим обработки очереди по вертикали: контроллер в этом случае вначале обработает всю очередь и только потом перейдет к заголовку следующей очереди. Если выполнение операции, заданной дескриптором передачи, не завершено в текущем кадре (например, данные не готовы для передачи), в следующем кадре операция повторяется. Когда операция завершена, дескриптор передачи помечается как обслуженный и удаляется из очереди: контроллер извлекает из него указатель на следующий дескриптор и переписывает его в заголовок очереди. Область, зарезервированная в дескрипторе передачи для программного обеспечения, в первую очередь предназначена для «сборки мусора»: из обслуженных и не нужных более дескрипторов можно сформировать очередь с целью повторного использования занимаемых ими участков памяти.

Каждая очередь дескрипторов передачи обычно формируется прикладной программой для работы с определенной функцией или даже одной конечной точкой функции. Если программа работает с несколькими конечными точками или в системе параллельно выполняется несколько прикладных программ, в списке будут присутствовать несколько очередей дескрипторов.

 

Запросы к устройствам USB

 

Все устройства USB принимают запросы от хост-контроллера и отвечают на них через Основной канал сообщений. Запросы выполняются при помощи управляющих посылок.

Запрос и его параметры передаются устройству в Setup -пакете, структура которого показана в табл. 8.3. Каждый Setup -пакет имеет размер 8 байт.

 

Таблица 8.3. Структура Setup -пакета.

Смещение

Мнемоника

Размер

Описание

0

bmRequestType

BYTE

Характеристики запроса: биты 0-4 — код получателя (0 — устройство, 1 — интерфейс, 2 — другой получатель; коды 4-31 зарезервированы); биты 5-6 — код типа запроса (0 — стандартный запрос, 1 — специфический запрос для данного класса, 2 — специфический запрос изготовителя, 3 — зарезервирован); бит 7 — направление передачи данных (0 — от хоста к устройству, 1 — от устройства к хосту)

1

bRequest

BYTE

Код запроса

2

wValue

WORD

Параметр запроса

4

wlndex

WORD

Индекс или смещение

6

wLength

WORD

Количество байтов, подлежащих передаче на стадии передачи данных

 

Поле кода запроса определяет тип запроса. В спецификации USB определены только коды стандартных запросов к устройству:

 

Значение параметров wValue, wIndex зависят от типа запроса. В запросах на прием или передачу дескрипторов параметр wValue содержит тип дескриптора в старшем байте и индекс дескриптора — в младшем. Каждому типу дескрипторов поставлен в соответствие определенный числовой код:

 

Поле wIndex обычно используется для задания номера интерфейса или конечной точки. Если поле wIndex задает конечную точку, оно имеет следующий формат:

 

Если поле wIndex задает номер интерфейса, то младший байт (биты 0-7) содержит номер интерфейса, а старший байт не используется (биты 8-15 зарезервированы и должны содержать нули).

Запрос Get Status позволяет определить состояние устройства, интерфейса или конечной точки. Запрос имеет следующие параметры:

 

По запросу Get Status устройство возвращает 16-разрядное слово состояния, описывающее текущее состояние устройства, интерфейса или конечной точки. Разряды слова состояния устройства имеют следующее назначение:

 

Слово состояния интерфейса зарезервировано и содержит нули во всех разрядах.

Разряды слова состояния конечной точки имеют следующее назначение:

 

В спецификации USB 1.1 определены только два значения с e лектора свойств:

 

Передача данных по запросу Clear Feature не производится. Сброс состояния ENDPOINT_HALT разблокирует конечную точку; сброс состояния DEVICE_REMOTE_WAKEUP лишает устройство способности реагировать на сигнал пробуждения.

Запрос Set Feature используется для того, чтобы разрешить свойство или состояние, указанное значением селектора свойств. Запрос - имеет следующие параметры:

 

Передача данных по запросу Set Feature не производится. Установка состояния ENDPOINT_HALT блокирует конечную точку; установка состояния DEVICE_REMOTE_WAKEUP позволяет устройству реагировать на сигнал пробуждения.

Запрос Set Address позволяет присвоить устройству новое значение адреса на шине USB. Запрос имеет следующие параметры:

 

Передача данных при выполнении запроса Set Address не производится.

Запрос Get Descriptor позволяет получить дескриптор устройства, дескриптор конфигурации или дескриптор строки. Запрос имеет следующие параметры:

 

ПРИМЕЧАНИЕ

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

 

 


По запросу Get Descriptor хаб передает хосту дескриптор, тип которого указан в запросе.

Запрос Set Descriptor позволяет дополнить существующий (или добавить новый) дескриптор устройства, конфигурации или строки. Запрос имеет следующие параметры:

 

В процессе выполнения запроса Set Descriptor хост передает периферийному устройству дескриптор, тип которого определяется параметрами запроса.

По запросу Get Configuration устройство выдает код своей текущей конфигурации. Запрос имеет следующие параметры:

 

При выполнении запроса Get Configuration от устройства к хосту передается один байт данных, содержащий код конфигурации устройства.

Запрос Set Configuration позволяет задать устройству новую конфигурацию. Запрос имеет следующие параметры:

 

При выполнении запроса Set Configuration от хоста к устройству передается один байт данных, содержащий код конфигурации, которую требуется установить.

Запрос Get Interface позволяет получить код текущей настройки для указанного интерфейса. Запрос имеет следующие параметры:

 

При выполнении запроса Get Interface от устройства к хосту передается один байт данных, содержащий код текущего варианта настройки интерфейса.

Запрос Set Interface позволяет задать новый вариант настройки для указанного интерфейса. Запрос имеет следующие параметры :

 

Передача данных при выполнении запроса Set Interface не производится.

Запрос Synch Frame используется для задания номера кадра синхронизации. Запрос имеет следующие параметры:

С помощью запроса Set Interface хост передает заданной конечной точке, работающей в изохронном режиме, 16-разрядное слово данных, содержащее номер кадра, который конечная точка должна использовать для синхронизации передачи.

 

Стандартные дескрипторы USB

 

В спецификации на шину USB указана группа дескрипторов, которые должны выдаваться устройствами USB в ответ на стандартные запросы. Структура таких дескрипторов стандартизирована, а в документации они именуются стандартными дескрипторами (standard descriptors).

 

Дескриптор устройства

 

Стандартный дескриптор устройства (Standard Device Descriptor) содержит основную информацию об устройстве USB. Структура Стандартного дескриптора устройства показана в табл. 8.4

 

Таблица 8.4. Структура Стандартного дескриптора устройства.

Смещение

Мнемоника

Размер

Описание

0

bLength

BYTE

Размер данного дескриптора в байтах

1

bDescriptorType

BYTE

Тип дескриптора (DEVICE)

2

bcdUSB

WORD

Номер версии спецификации USB, шторой соответствует дескриптор, представленный в двоично-десятичном формате BCD

4

bDeviceClass

BYTE

Код класса устройства US8 (если в данном поле записано значение 0, то интерфейсы функционируют независимо друг от друга , и каждый из них имеет собственный код класса; если в поле записано значение FFh, то класс устройства определяется изготовителем)

5

bDeviceSubCIass

BYTE

Код подкласса устройства USB

6

bDeviceProtocol

BYTE

Код протокола USB (если в данном поле записано значение 0, то устройство не использует специфические протоколы своего класса, однако может использовать специфическое протоколы интерфейса; если в поле записано значение FFh, то устройство использует протокол, определяемый изготовителем)

7

bMaxPacketSize

BYTE

Максимальный размер пакета для нулевой конечной точки (допускается использование значений 8, 16, 32 и 64)

8

idVendor

WORD

Идентификатор изготовителя устройства

10

idProduct

WORD

Идентификатор продукта (определяется изготовителем)

12

b с dDevice

WORD

Номер версии устройства в формате BCD

14

iManufacturer

BYTE

Индекс дескриптора строки, описывающей изготовителя

15

iProduct

BYTE

Индекс дескриптора строки, описывающей продукт

16

iSerialNumber

BYTE

Индекс дескриптора строки, содержащей серийный номер устройства

17

bNumConfigu rations

BYTE

Количество возможных конфигураций.

 

Некоторые поля Стандартного дескриптора устройства традиционно содержат фиксированные значения и не несут информационной нагрузки:

 

 

Код версии спецификации USB может принимать следующие значения: 0100 h - версия 1.0, 011 0h - версия 1.1, 0200h - версия 2.0.

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

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

Индексы дескрипторов строк используются для получения информации об устройстве в текстовом формате: при подаче запроса на получение дескриптора строки индекс дескриптора передается в младшем байте параметра wValue.

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

 

Дескриптор конфигурации

 

Стандартный дескриптор конфигурации (Standard Configuration Descriptor) содержит информацию об одной из возможных конфигураций устройства. Структура Стандартного дескриптора конфигурации показана в табл. 8.5.

 

Таблица 8.5. Структура Стандартного дескриптора конфигурации .

Смещение

Мнемоника

Размер

Описание

0

bLength

BYTE

Размер данного дескриптора в байтах

1

bDescriptorType

BYTE

Тип дескриптора (CONFIGURATION)

2

wTotalLength

WORD

Общий объем данных в байтах, возвращаемый для этой конфигурации (суммарная длина всех дескрипторов для этой конфигурации)

4

bNumlnterfaces

BYTE

Количество интерфейсов, поддерживаемых данной конфигурацией

5

bConfiguration-Value

BYTE

Значение, которое должно использоваться в качестве аргумента в запросе SET_CONFIGURATION для установки данной конфигурации

6

iConfiguration

BYTE

Индекс дескриптора строки, описывающей данную конфигурацию

7

bmAttributes

BYTE

Характеристики конфигурации:

биты 0-4 зарезервированы и должны содержать нули;

бит 5 — признак возможности пробуждения устройства по внешнему сигналу (устанавливается в единицу, если данная возможность поддерживается);

бит 6 — признак наличия собственного источника питания (0 — устройство получает питание по шине USB, 1 — имеет собственный источник питания)

бит 7 зарезервирован и должен быть установлен в 1

8

MaxPower

BYTE

Код мощности, потребляемой устройством от шины USB (максимальный ток в миллиамперах, потребляемый устройством от шины, вычисляется путем умножения значения данного поля на два)

 

Устройство может иметь один или несколько дескрипторов конфигурации в соответствии с количеством возможных конфигураций, указанных в Стандартном дескрипторе устройства.

Каждая конфигурация описывается одним стандартным дескриптором. Размер Стандартного дескриптора конфигурации всегда составляет 9 байт, а код типа дескриптора имеет значение 2.

 

ВНИМАНИЕ

По запросу «Получить Стандартный дескриптор конфигурации» устройство выдает не только дескриптор конфигурации, но и все имеющиеся дескрипторы интерфейсов и конечных точек.

 

Для определения общей длины (в байтах) возвращаемого списка дескрипторов служит поле wTotalLength. Чтобы получить весь список дескрипторов, нужно запросить от устройства первые 8 байт Стандартного дескриптора конфигурации, запомнить значение поля wTotalLength, а затем использовать это значение в качестве параметра при повторной подаче запроса.

Каждая конфигурация может иметь один или несколько интерфейсов. Количество доступных интерфейсов указывается в поле bNumInterfaces.

 

Дескриптор интерфейса

 

Стандартный дескриптор интерфейса (Standard Interface Descriptor) содержит информацию об одном из интерфейсов, доступных при определенной конфигурации устройства. Структура Стандартного дескриптора интерфейса показана в табл. 8.6.

 

Таблица 8.6. Структура Стандартного дескриптора интерфейса.

Смещение

Мнемоника

Размер

Описание

0

bLength

BYTE

Размер данного дескриптора в байтах

1

bDescriptorType

BYTE

Тип дескриптора (INTERFACE)

2

blnterfaceNumber

BYTE

Порядковый номер интерфейса в данной конфигурации

3

bAlternateSetting

BYTE

Код варианта для данного интерфейса

4

bNumEndpoints

BYTE

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

5

blnterfaceClass

BYTE

Код класса интерфейса (нулевое значение кода зарезервировано; код FFh указывает, что интерфейс определяется изготовителем)

6

blnterfaceSubClass

BYTE

Код подкласса интерфейса

7

BlnterfaceProtocol

BYTE

Код протокола (если поле имеет значение FFh, то протокол определяется изготовителем)

8

iInterface

BYTE

Индекс дескриптора строки, описывающей интерфейс

 

Размер Стандартного дескриптора интерфейса всегда составляет 9 байт, а код типа дескриптора имеет значение 4.

 

ПРИМЕЧАНИЕ

При выполнении идентификации и нумерации устройств на шине USB дескриптор интерфейса может использоваться для определения типа устройства по кодам класса, подкласса и протокола.

 

Дескриптор конечной точки

 

Стандартный дескриптор конечной точки (Standard Endpoint Descriptor) содержит информацию об одной из конечных точек, доступных при использовании определенного интерфейса. Структура Стандартного дескриптора конечной точки показана в табл. 8.7.

 

Таблица 8.7. Структура Стандартного дескриптора конечной точки.

Смещение

Мнемоника

Размер

Описание

0

bLength

BYTE

Размер данного дескриптора в байтах

1

bDescriptorType

BYTE

Тип дескриптора (ENDPOINT)

2

bEndpointAddress

BYTE

Код адреса конечной точки, описываемой данным дескриптором;

биты 0-3 — номер конечной точки;

биты 4-6 зарезервированы и должны содержать нули;

бит 7 — направление передачи (0 — OUT, 1 — IN). Для канала сообщений направление игнорируется

3

bmAttributes

BYTE

Атрибуты конечной точки. Используются биты 0 и 1 (остальные разряды зарезервированы и содержат нули):

00b — канал сообщений,

01 b — изохронный канал,

10 b — канал сплошной передачи;

11 b — канал прерываний

4

wMaxPacketSize

WORD

Максимальный размер пакета для конечной точки

6

blnterval

BYTE

Интервал опроса конечной точки при передаче данных (задается в миллисекундах)

 

Размер Стандартного дескриптора конечной точки всегда составляет 7 байт, а код типа дескриптора имеет значение 5.

Код адреса bEndpointAddress и байт атрибутов bmAttributes для многих классов периферийных устройств позволяют однозначно определить функциональное назначение конечной точки.

Поле размера пакета wMaxPacketSize задает предельный размер пакета данных для конечной точки.

Интервал опроса конечной точки имеет значение только в том случае, если точка используется для передачи данных по прерываниям : если точка является точкой сообщений или сплошной передачи, значение поля blnterval игнорируется, а для изохронных конечных точек поле blnterval всегда содержит значение 1.

 

Дескриптор строки

 

Дескриптор строки (UNICODE String Descriptor) содержит текст в формате UNICODE. Строка не ограничивается нулем: длина строки вычисляется путем вычитания 2 из размера дескриптора. Структура Дескриптора строки показана в табл. 8.8.

 

Таблица 8.8. Структура Дескриптора строки.

Смещение

Мнемоника

Размер

Описание

0

bLength

BYTE

Размер данного дескриптора

в байтах (N + 2)

1

bDescriptorType

BYTE

Тип дескриптора (STRING)

2

bString

N байт

Строка символов UNICODE

 

Дескриптор строки не является обязательным. Если устройство не поддерживает дескрипторы строк, все ссылки на такие дескрипторы из дескрипторов устройства, конфигурации или интерфейса должны иметь нулевое значение.

Устройство может поддерживать несколько различных языков, поэтому при запросе дескриптора строки нужно задавать 16-разрядный идентификатор языка (LANGID).

Строковый индекс 0 для всех языков соответствует дескриптору строки, содержащей массив 16-разрядных идентификаторов всех поддерживаемых устройством языков. Массив идентификаторов не ограничен нулем: размер массива в байтах вычисляется путем вычитания 2 из размера дескриптора. Структура массива следующая: байт 0 содержит размер дескриптора в байтах (число идентификаторов + 2), байт 1 описывает тип дескриптора (STRING), далее следуют 16-разрядные идентификаторы языка.

Примеры использования стандартных дескрипторов приведены в листингах 8.1 и 8.2. Листинг 8.1 содержит набор процедур общего назначения, предназначенных для работы с устройствами USB:

 

Листинг 8.1 . Процедуры для работы с устройствами USB.

 

DATASEG

; Признак успешного завершения поиска

SearchResult DB 0

; Индекс хост-контроллера

USB_HostIndex DW 0

; ПАРАМЕТРЫ КОНТРОЛЛЕРА USB

; Координаты устройства PCI

USB_BusNum DB ? ;номер шины

USB_DevNum DB ? ;номер устройства и номер функции

; Идентификаторы устройства PCI

USB_VendorID DW ? ;идентификатор изготовителя

USB_DeviceID DW ? ;идентификатор устройства

; Адрес блока регистров контроллера PCI USB

USB_BaseAddr DW ?

; Номер используемого прерывания IRQ

USB_IntLine DB ?

; Сообщения об ошибках

BadRg DB LIGHTRED,12,28,"Неверный номер регистра",0

NoPCI DB 12,24,"Система не поддерживает PCI BIOS",0

NoUSB DB 12,28,"Контроллер USB не найден",0

NoDev DB 12,26,"Устройство USB не обнаружено",0

TmOut DB 12,21,"Превышен допустимый интервал ожидания",0

BfErr DB 12,28,"Буфер данных переполнен",0

DsErr DB 12,25,"Список дескрипторов переполнен",0

; ПАРАМЕТРЫ УСТРОЙСТВА

; Номер используемого устройством порта USB

USB_PortNum DB ?

; Адрес регистра состояния используемого порта

USB_PortReg DW 0

; Тип устройства:

; 0 - полноскоростное, 1 - низкоскоростное

USB_Device_Type DB 0

; Номер устройства на шине USB

USB_Device_Number DB 0

; Номер конечной точки

USB_EnpointNumber DB 0

; ПРЕОБРАЗОВАННЫЕ ЗНАЧЕНИЯ ПАРАМЕТРОВ УСТРОЙСТВА

; Сдвинутый влево на 7 разрядов номер функции

ShFuncNum DD ?

; Сдвинутый влево на 15 разрядов номер конечной точки

ShEndpNum DD ?

; Сдвинутый влево на 26 разрядов тип устройства

ShDevType DD ?

; Сдвинутый влево на 21 размер пакета

ShPackSize DD ?

; ФИЗИЧЕСКИЕ АДРЕСА СТРУКТУР ДАННЫХ USB

; Линейный адрес заголовка списка дескрипторов

Addr_QH DD ?

; Линейный адрес массива дескрипторов передачи

Addr_TD_Array DD ?

; Линейный адрес дескриптора команды

Addr_CommandDescr DD ?

; Линейный адрес буфера данных

Addr_DataDescr DD ?

; ПАРАМЕТРЫ ТРАНЗАКЦИЙ

; Номер кадра в момент начала транзакции

StartFrame DW ?

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

DataTrigger DD ?

; Объем данных в передаваемом массиве

BULK_DataSize DW 0

; БУФЕР ДАННЫХ

DataBuffer DB 4096 DUP(?)

ENDS

 

CODESEG

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

;* НАЙТИ ХОСТ-КОНТРОЛЛЕР USB И ОПРЕДЕЛИТЬ *

;* ЕГО ОСНОВНЫЕ ПАРАМЕТРЫ *

;* Подпрограмма выполняет поиск хост-контроллеров *

;* USB, подключенных к шине PCI. *

;* Входные параметры: *

;* USB_HostIndex - индекс хост-контроллера. *

;* В случае успешного завершения операции поиска *

;* параметры контроллера сохраняются в глобальных *

;* переменных USB_BusNum, USB_DevNum, USB_VendorID, *

;* USB_DeviceID, USB_BaseAddr и USB_IntLine. *

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

PROC FindUSBController near

pushad

; Найти первый USB-контроллер по коду класса

mov AX,0B103h

mov ECX,0C0300h

mov SI,[USB_HostIndex]

int 1Ah

jnc @@ReadPCIRegisters ;устройство найдено

; Выход: контроллер USB не найден

mov [SearchResult],1

popad

ret

; Устройство обнаружено, его координаты на шине PCI

; находятся в регистре BX

@@ReadPCIRegisters:

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

mov [USB_BusNum],BH

mov [USB_DevNum],BL

; Получить идентификатор изготовителя

mov AX,0B109h ;читать слово

mov DI,0 ;смещение слова

int 1Ah

jc @@BadRegisterNumber

mov [USB_VendorID],CX

; Получить идентификатор устройства

mov AX,0B109h ;читать слово

mov DI,2 ;смещение слова

int 1Ah

jc @@BadRegisterNumber

mov [USB_DeviceID],CX

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

mov AX,0B10Ah ;читать двойное слово

mov DI,20h ;смещение слова

int 1Ah

jc @@BadRegisterNumber

; Обнулить 5 младших битов

and CX,0FFE0h

; Сохранить только младшее слово адреса

mov [USB_BaseAddr],CX

; Получить номер используемого устройством

; прерывания IRQ

mov AX,0B108h ;читать байт

mov DI,3Ch ;смещение байта

int 1Ah

jc @@BadRegisterNumber

mov [USB_IntLine],CL

; Выход: контроллер найден, увеличить значение индекса

inc [USB_HostIndex]

popad

ret

; ОБРАБОТКА ОШИБОК

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

@@BadRegisterNumber:

MFatalError BadRg

ENDP FindUSBController

 

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

;* ЗАДЕРЖКА НА ОДИН ТИК СИСТЕМНОГО ТАЙМЕРА *

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

PROC Wait05s near

push ES

push EAX

mov AX,0

mov ES,AX

mov EAX,[ES:046Ch]

inc EAX

@@Wait: cmp EAX,[ES:046Ch]

jae @@Wait

pop EAX

pop ES

ret

ENDP Wait05s

 

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

;* ИНИЦИАЛИЗИРОВАТЬ ДЕСКРИПТОРЫ USB *

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

PROC InitializeDeascriptors near

pushad

; Очистиь 1 Мбайт памяти

mov EBX,FrameListBaseAddr

mov ECX,100000h/4

xor EAX,EAX

@@ClearMemory:

mov [GS:EBX],EAX

add EBX,4

dec ECX

jnz @@ClearMemory

 

; ПОДГОТОВИТЬ СТРУКТУРЫ ДАННЫХ ДЛЯ РАБОТЫ С USB

; Вычислить линейный адрес буфера данных

xor EAX,EAX

xor EBX,EBX

mov AX,DS

shl EAX,4

mov BX,offset DataBuffer

add EAX,EBX

mov [Addr_DataDescr],EAX

; Вычислить линейный адрес сегмента дескрипторов

xor EAX,EAX

mov AX,USB_DESCR

shl EAX,4

mov EDX,EAX ;запомнить адрес сегмента

; Вычислить линейный адрес заголовка списка

xor EBX,EBX

mov BX,offset QH_Descriptor

add EAX,EBX

mov [Addr_QH],EAX

; Вычислить линейный адрес массива дескрипторов

mov EAX,EDX

mov BX,offset TD_Array

add EAX,EBX

mov [Addr_TD_Array],EAX

; Настроить указатели кадров на заголовок очереди

mov EBX,FrameListBaseAddr

mov EAX,[Addr_QH]

or EAX,10b ; T=0, Q=1

mov CX,1024

@@ActivateNextFrame:

mov [GS:EBX],EAX

add EBX,4

loop @@ActivateNextFrame

popad

ret

ENDP InitializeDeascriptors

 

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

;* ЗАПРОСИТЬ ИНФОРМАЦИЮ ОБ УСТРОЙСТВЕ USB *

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

;* SI - смещение дескриптора команды в сегменте данных.*

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

PROC StatusIN_Transaction near

pushad

; Запомнить в DX объем передаваемых данных

mov DX,[SI+6]

; Вычислить линейный адрес данных дескриптора команды

xor EAX,EAX

mov AX,DS

shl EAX,4

and ESI,0FFFFh

add EAX,ESI

mov [Addr_CommandDescr],EAX

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

mov ESI,[Addr_TD_Array]

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

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

mov EAX,ESI

add EAX,32

mov [GS:ESI],EAX

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,00E0002Dh ;передать 8 байт

mov [GS:ESI+8],EAX

; Указатель на дескриптор команды

mov EAX,[Addr_CommandDescr]

mov [GS:ESI+12],EAX

xor EAX,EAX

mov [GS:ESI+16],EAX

mov [GS:ESI+20],EAX

mov [GS:ESI+24],EAX

mov [GS:ESI+28],EAX

add ESI,32

 

; Вычислить количество 8-байтных блоков

; и размер последнего блока данных

mov CX,DX

shr CX,3 ;количество 8-байтных блоков

cmp CX,64-3

ja @@TD_Array_Error

and EDX,111b ;размер последнего блока

mov EBX,[Addr_DataDescr]

mov EDI,80000h ;триггер данных

cmp CX,0

je @@ShortDataBlock

@@NextDataBlock:

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

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

mov EAX,ESI

add EAX,32

mov [GS:ESI],EAX

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,00E00069h ;принять 8 байт

or EAX,EDI ;триггер данных

mov [GS:ESI+8],EAX

xor EDI,80000h ;переключить триггер

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

add EBX,8

xor EAX,EAX

mov [GS:ESI+16],EAX

mov [GS:ESI+20],EAX

mov [GS:ESI+24],EAX

mov [GS:ESI+28],EAX

add ESI,32

loop @@NextDataBlock

 

; Имеется короткий блок?

@@ShortDataBlock:

cmp DX,0

je @@NoShortBlock

; Сформировать дескриптор данных короткого блока

mov EAX,ESI

add EAX,32

mov [GS:ESI],EAX

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

dec DX

shl EDX,21

or EAX,EDX ;размер блока

or EAX,EDI ;триггер данных

or EAX,69h

mov [GS:ESI+8],EAX

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

add ESI,32

 

@@NoShortBlock:

; Сформировать дескриптор пустого пакета

mov [dword ptr GS:ESI],1b ;последний TD

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,0FFE800E1h ;передать пустой блок

mov [GS:ESI+8],EAX

xor EAX,EAX

mov [GS:ESI+12],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

; Запомнить номер текущего кадра

mov DX,[USB_BaseAddr]

add DX,6

in AX,DX

mov [StartFrame],AX

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

@@Wait_OpComplete:

; Проверить номер кадра

in AX,DX

sub AX,[StartFrame]

and AX,7FFh ;выделить младшие 11 разрядов

cmp AX,500 ;ожидать не более 500 кадров

ja @@TimeOut ;превышен интервал ожидания

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

cmp [dword ptr GS:ESI],1b

jne @@Wait_OpComplete

popad

ret

; Превышен допустимый интервал ожидания

@@TimeOut:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError TmOut

; Переполнен массив дескрипторов

@@TD_Array_Error:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError DsErr

ENDP StatusIN_Transaction

 

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

;* ПЕРЕДАТЬ КОМАНДУ УСТРОЙСТВУ USB *

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

;* SI - смещение дескриптора команды в сегменте данных.*

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

PROC Setup_Transaction near

pushad

; Вычислить линейный адрес данных дескриптора команды

xor EAX,EAX

mov AX,DS

shl EAX,4

and ESI,0FFFFh

add EAX,ESI

mov [Addr_CommandDescr],EAX

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

mov ESI,[Addr_TD_Array]

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

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

mov EAX,ESI

add EAX,32

mov [GS:ESI],EAX

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,00E0002Dh ;передать 8 байт

mov [GS:ESI+8],EAX

; Указатель на дескриптор команды

mov EAX,[Addr_CommandDescr]

mov [GS:ESI+12],EAX

xor EAX,EAX

mov [GS:ESI+16],EAX

mov [GS:ESI+20],EAX

mov [GS:ESI+24],EAX

mov [GS:ESI+28],EAX

add ESI,32

 

; Сформировать дескриптор для приема пустого пакета

mov [dword ptr GS:ESI],1b ;последний TD

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,0FFE80069h ;принять пустой блок

mov [GS:ESI+8],EAX

xor EAX,EAX

mov [GS:ESI+12],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

; Запомнить номер текущего кадра

mov DX,[USB_BaseAddr]

add DX,6

in AX,DX

mov [StartFrame],AX

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

@@Wait_OpComplete:

; Проверить номер кадра

in AX,DX

sub AX,[StartFrame]

and AX,7FFh ;выделить младшие 11 разрядов

cmp AX,500 ;ожидать не более 500 кадров

ja @@TimeOut ;превышен интервал ожидания

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

cmp [dword ptr GS:ESI],1b

jne @@Wait_OpComplete

popad

ret

; Превышен допустимый интервал ожидания

@@TimeOut:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError TmOut

ENDP Setup_Transaction

 

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

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

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

;* USB_PortReg - адрес регистра порта; *

;* USB_Device_Number - порядковый номер устройства. *

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

PROC Enumeration near

pushad

; Разблокировать порт

mov DX,[USB_PortReg]

mov AX,1110b

out DX,AX

; Определить и запомнить тип устройства

mov DX,[USB_PortReg]

in AX,DX

test AX,100000000b

jnz @@Low

mov [dword ptr ShDevType],0

jmp short @@DeviceTypeSaved

@@Low: mov [dword ptr ShDevType],4000000h

@@DeviceTypeSaved:

 

; После сброса устройство имеет нулевой номер

mov [dword ptr ShFuncNum],0

; Вычислить порядковый номер

inc [USB_Device_Number]

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

xor AX,AX

mov AL,[USB_Device_Number]

mov [word ptr SetAddrDesc+2],AX

mov SI,offset SetAddrDesc

call Setup_Transaction

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

xor EAX,EAX

mov AL,[USB_Device_Number]

shl EAX,8

mov [ShFuncNum],EAX

popad

ret

ENDP Enumeration

 

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

;* ПОЛУЧИТЬ ДЕСКРИПТОР КОНФИГУРАЦИИ *

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

PROC GetConfigurationDescriptor near

pusha

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

mov SI,offset GetConfDesc

call StatusIN_Transaction

; Запомнить полный размер группы дескрипторов

; конфигурации

mov AX,[word ptr DataBuffer+2]

mov [word ptr GetConfDesc+6],AX

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

mov SI,offset GetConfDesc

call StatusIN_Transaction

popa

ret

ENDP GetConfigurationDescriptor

ENDS

 

Листинг 8.2 содержит программу USB_Dev1ce_Search, предназначенную для тестирования интерфейса USB. Программа выполняет поиск устройства USB по всем портам всех имеющихся в системе хост-контроллеров. Как только программа обнаруживает какое-либо устройство, она прекращает процесс поиска и выводит на экран содержимое регистров хост-контроллера, к которому подсоединено найденное устройство. Далее программа запрашивает у устройства и отображает на экран содержимое дескриптора устройства и дескриптора конфигурации.

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

 

ПРИМЕЧАНИЕ

Программа может обнаружить только устройство с включенным электропитанием.

 

Листинг 8.2. Поиск устройств на шине USB и считывание параметров первого обнаруженного устройства.

 

IDEAL

P386

LOCALS

MODEL MEDIUM

 

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

FrameListBaseAddr equ 200000h

 

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

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

include "list1_03.inc"

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

include "list1_04.inc"

 

DATASEG

; ТЕКСТОВЫЕ СООБЩЕНИЯ

Txt0 DB LIGHTCYAN,0,26

DB "ПОИСК И ОПРОС УСТРОЙСТВА USB",0

Txt1 DB 2,27,"ПАРАМЕТРЫ ХОСТ-КОНТРОЛЛЕРА",0

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

DB 5,8,"Базовый адрес набора регистров:",0

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

DB 9,24,"СОДЕРЖИМОЕ РЕГИСТРОВ КОНТРОЛЛЕРА",0

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

DB 12,21,"Регистр состояния:",0

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

DB 14,27,"Номер кадра:",0

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

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

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

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

DB 20,0,"Устройство подключено к порту N",0

DB 22,0,"Тип устройства:",0

Full DB LIGHTCYAN,22,16,"полноскоростное",0

LowS DB LIGHTMAGENTA,22,16,"низкоскоростное",0

Txt2 DB 2,23,"СТАНДАРТНЫЙ ДЕСКРИПТОР УСТРОЙСТВА",0

DB 4,14,"Размер дескриптора, байт:",0

DB 5,18,"Код типа дескриптора:",0

DB 6,9,"Номер версии спецификации USB:",0

DB 7,17,"Код класса устройства:",0

DB 8,14,"Код подкласса устройства:",0

DB 9,14,"Код протокола устройства:",0

DB 10,1,"Макс. размер пакета для нулевой точки:",0

DB 11,22,"Код изготовителя:",0

DB 12,27,"Код изделия:",0

DB 13,10,"Число доступных конфигураций:",0

Txt3 DB 2,23,"СТАНДАРТНЫЙ ДЕСКРИПТОР КОНФИГУРАЦИИ",0

DB 4,14,"Размер дескриптора, байт:",0

DB 5,18,"Код типа дескриптора:",0

DB 6,14,"Общий объем данных, байт:",0

DB 7,16,"Количество интерфейсов:",0

DB 8,15,"Код данной конфигурации:",0

DB 9,11,"Характеристики конфигурации:",0

DB 10,13,"Потребляемая мощность, мА:",0

AnyK DB YELLOW,24,29,"Нажмите любую клавишу",0

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

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

GetDevDesc DB 80h,6

DW 100h,0,8

; Создать дескриптор команды "Set Address"

SetAddrDesc DB 0,5

DW 1,0,0

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

GetConfDesc DB 80h,6

DW 200h,0,8

ENDS

 

; Область памяти для хранения дескрипторов передачи

SEGMENT USB_DESCR para public 'DATA'

; Заголовок очереди дескрипторов

QH_Descriptor DD 00000003h ;единственный заголовок

DD 00000000h ;указатель на первый TD

DD 0,0,0,0,0,0 ;область данных ПО

; Список дескрипторов для одной транзакции

TD_Array DD 8*64 DUP(?)

ENDS

 

SEGMENT sseg para stack 'STACK'

DB 400h DUP(?)

ENDS

 

CODESEG

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

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

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

PROC USB_Device_Search

mov AX,DGROUP

mov DS,AX

mov [CS:MainDataSeg],AX

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

mov AX,3

int 10h

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

mov [ScreenString],25

mov [ScreenColumn],0

call SetCursorPosition

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

mov AX,0B101h

int 1Ah

jc @@PCIBIOSNotFound

cmp EDX,20494350h

jne @@PCIBIOSNotFound

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

call Initialization

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

call InitializeDeascriptors

 

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

mov [USB_HostIndex],0

@@NextHost:

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

call FindUSBController

cmp [SearchResult],0

jne @@NoHost

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

mov DX,[USB_BaseAddr]

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

out DX,AX

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

call Wait05s

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

mov AX,0

out DX,AX

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

call Wait05s

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

mov [USB_PortNum],1

mov DX,[USB_BaseAddr]

add DX,10h

in AX,DX

test AX,000Fh

jnz @@SavePortReg

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

mov [USB_PortNum],2

add DX,2

in AX,DX

test AX,000Fh

jz @@NextHost

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

@@SavePortReg:

mov [USB_PortReg],DX

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

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

mov DX,[USB_BaseAddr]

add DX,6

mov AX,0

out DX,AX

add DX,2

mov EAX,FrameListBaseAddr

out DX,EAX

 

; ОТОБРАЗИТЬ СОДЕРЖИМОЕ РЕГИСТРОВ ВВОДА-ВЫВОДА

; Очистить экран

call ClearScreen

; Вывести заголовок экрана

MShowColorString Txt0

; Вывести заголовки полей

mov [TextColorAndBackground],LIGHTGREEN

MShowText 15,Txt1

; Вывести базовый адрес и номер прерывания

mov [TextColorAndBackground],LIGHTGREY

MShowDecByte 4,40,<[byte ptr USB_HostIndex]>

MShowHexWord 5,40,[USB_BaseAddr]

MShowHexByte 6,40,[USB_IntLine]

; Вывести содержимое регистров

mov DX,[USB_BaseAddr]

in AX,DX

MShowHexWord 11,40,AX

add DX,2

in AX,DX

MShowHexWord 12,40,AX

add DX,2

in AX,DX

MShowHexWord 13,40,AX

add DX,2

in AX,DX

MShowHexWord 14,40,AX

add DX,2

in EAX,DX

MShowHexDWord 15,40,EAX

add DX,4

in AL,DX

MShowHexByte 16,40,AL

mov DX,[USB_BaseAddr]

add DX,10h

in AX,DX

MShowHexWord 17,40,AX

add DX,2

in AX,DX

MShowHexWord 18,40,AX

 

; Показать номер используемого порта

MShowDecByte 20,32,[USB_PortNum]

; Указать тип устройства

mov DX,[USB_PortReg]

in AX,DX

test AX,100000000b

jnz @@Low

mov [dword ptr ShDevType],0

MShowColorString Full

jmp short @@WaitAnyKey

@@Low: mov [dword ptr ShDevType],4000000h

MShowColorString LowS

 

; Ожидать нажатия любой клавиши

@@WaitAnyKey:

MShowColorString AnyK

call GetChar

 

; Включить хост-контроллер

mov DX,[USB_BaseAddr]

mov AX,1

out DX,AX

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

mov [USB_Device_Number],0

call Enumeration

 

; ПОЛУЧИТЬ И ОТОБРАЗИТЬ НА ЭКРАНЕ ДЕСКРИПТОР УСТРОЙСТВА

; Подать команду "Get Device Descriptor"

mov SI,offset GetDevDesc

call StatusIN_Transaction

; Очистить экран

call ClearScreen

; Вывести заголовок экрана

MShowColorString Txt0

; Вывести заголовки полей

mov [TextColorAndBackground],LIGHTGREEN

MShowText 11,Txt2

; Вывести базовый адрес и номер прерывания

mov [TextColorAndBackground],LIGHTGREY

MShowDecByte 4,40,[DataBuffer]

MShowHexByte 5,40,<[DataBuffer+1]>

MShowHexWord 6,40,<[word ptr DataBuffer+2]>

MShowHexByte 7,40,<[DataBuffer+4]>

MShowHexByte 8,40,<[DataBuffer+5]>

MShowHexByte 9,40,<[DataBuffer+6]>

MShowDecByte 10,40,<[DataBuffer+7]>

MShowHexWord 11,40,<[word ptr DataBuffer+8]>

MShowHexWord 12,40,<[word ptr DataBuffer+10]>

MShowDecByte 13,40,<[DataBuffer+17]>

; Ожидать нажатия любой клавиши

MShowColorString AnyK

call GetChar

 

; ПОЛУЧИТЬ И ОТОБРАЗИТЬ НА ЭКРАНЕ ДЕСКРИПТОР КОНФИГУРАЦИИ

call GetConfigurationDescriptor

; Очистить экран

call ClearScreen

; Вывести заголовок экрана

MShowColorString Txt0

; Вывести заголовки полей

mov [TextColorAndBackground],LIGHTGREEN

MShowText 8,Txt3

; Вывести базовый адрес и номер прерывания

mov [TextColorAndBackground],LIGHTGREY

MShowDecByte 4,40,[DataBuffer]

MShowHexByte 5,40,<[DataBuffer+1]>

MShowDecWord 6,40,<[word ptr DataBuffer+2]>

MShowDecByte 7,40,<[DataBuffer+4]>

MShowHexByte 8,40,<[DataBuffer+5]>

MShowBinByte 9,40,<[DataBuffer+7]>

xor AX,AX

mov AL,[DataBuffer+8]

shl AX,2

MShowDecWord 10,40,AX

; Ожидать нажатия любой клавиши

MShowColorString AnyK

call GetChar

 

; ВЫКЛЮЧИТЬ ХОСТ-КОНТРОЛЛЕР

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

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

mov AX,3

int 10h

; Выход в DOS

mov AH,4Ch

int 21h

 

; ОБРАБОТКА ОШИБОК

; Не поддерживается PCI BIOS

@@PCIBIOSNotFound:

MFatalError NoPCI

; Не найден хост или устройство

@@NoHost:

cmp [USB_HostIndex],0

je @@HostNotFound

; Устройство USB не найдено

@@DeviceNotFound:

MFatalError NoDev

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

@@HostNotFound:

MFatalError NoUSB

ENDP USB_Device_Search

ENDS

 

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

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

include "list1_02.inc"

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

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

include "list2_01.inc"

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

include "list2_05.inc"

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

include "list8_01.inc"

END

 

Взаимодействие хост-контроллера с хабом

 

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

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

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

Время реакции хаба на стандартные запросы не должно превышать 50 мс. Хаб поддерживает следующие стандартные запросы: Get Status, Clear Feature, Set Feature, Set Address, Get Descriptor, Set Descriptor , Get Configuration, Set Configuration. Реакция на запросы Get Interface и Set Interface не определена, так как хаб может иметь только один интерфейс; реакция на запрос Synch Frame не определена, так как хаб не имеет изохронных конечных точек.

 

Дескриптор хаба

 

Кроме стандартных дескрипторов, по запросу может быть выдан специфический Дескриптор хаба (Hub Descriptor), структура которого приведена в табл. 8.9.

 

Таблица 8.9. Структура Дескриптора хаба.

Смещение

Мнемоника

Размер

Описание

0

bDescLength

BYTE

Размер данного дескриптора в байтах

1

bDescriptorType

BYTE

Тип дескриптора (29h)

2

bNbrPorts

BYTE

Количество нисходящих портов

3

wHubCharacteri - tics

WORD

Характеристики хаба:

биты 0-1 — логический режим управления энергией (00 b — подача энергии включаются одновременно для всех портов, 01 b — возможно индивидуальное управление подачей энергии для каждого порта, 1 0b или 11 b — у хаба отсутствует схема управления энергией) ;

бит 2 — признак составного устройства (0 — хаб является самостоятельным устройством, 1 — хаб входит в состав периферийного устройства);

биты 3-4 — режим защиты от перегрузки (00b — глобальная защита от перегрузки по сумме токов всех портов, 01 b — индивидуальная защита для каждого порта, 1 0b или 1 1b — защита отсутствует);

биты 5-15 зарезервированы

5

bPwrOn2Pwr-Good

BYTE

Величина временного интервала от подачи команды включения энергии до стабилизации напряжения питания на выходе порта, заданная с шагом 2 мс

6

bHubContrCurrent

BYTE

Величина тока (мА), потребляемого контроллером хаба

7

DeviceRemovable

К байт

Битовая карта подключения съемных устройств к портам:

бит 0 зарезервирован,

бит 1 соответствует порту 1 ,

бит 2 — порту 2,

бит n — порту n .

Если бит имеет значение 0, к порту подключено съемное устройство, если 1 — несъемное

7 + К

PortPwrCtrlMask

К байт

Маска контроля питания портов (каждому порту соответствует один бит маски). Маска входит в дескриптор для сохранения совместимости со стандартом USB 1.0 и в настоящее время не используется (все разряды установлены в 1)

 

Запросы, специфические для хабов

 

В спецификации USB для хабов определены следующие коды специфических запросов:

 

Кроме того, для хабов в спецификации USB определены следующие значения селектора свойств:

 

Для портов хабов в спецификации USB определены следующие значения селектора свойств:

 

Запрос Clear Hub Feature используется для того, чтобы сбросить признак состояния хаба, указанный значением селектора свойств. Запрос имеет следующие параметры:

 

Передача данных по запросу Clear Hub Feature не производится.

Запрос Clear Port Feature используется для того, чтобы сбросить состояние порта хаба, указанное значением селектора свойств. Запрос имеет следующие параметры:

 

Передача данных по запросу Clear Port Feature не производится.

Запрос Clear Port Feature допускает использование следующих селекторов: PORT_ENABLE, PORT_SUSPEND, PORT_POWER, C_PORT_CONNECTION, C_PORT_ENABLE, CPORT_SUSPEND, C_PORT_OVERECURRENT, C_PORT_RESET.

Сброс свойства PORT_SUSPEND вызывает формирование сигнала пробуждения для порта, который находится в состоянии ожидания.

После сброса свойства PORT_ENABLE работа порта будет запрещена. Сброс свойства PORT_POWER вызывает отключение питания порта. Запрос Get Bus State используется для диагностики порта с заданным номером. Запрос имеет следующие параметры:

 

По запросу Get Bus State хаб возвращает один байт данных со следующей структурой:


Запрос Get Hub Descriptor позволяет хосту получить дескриптор хаба. Запрос имеет следующие параметры:

 

По запросу Get Hub Descriptor хаб возвращает дескриптор, структура которого описана в табл. 8.9.

Запрос Get Hub Status позволяет определить текущее состояние хаба. Запрос имеет следующие параметры:

 

По запросу Get Hub Status хаб возвращает 16-разрядное слово состояния wHubStatus и 16-разрядное слово индикаторов изменения состояния wHubChange.

Слово состояния хаба имеет следующую структуру:

 

Слово индикаторов изменения состояния хаба имеет следующую структуру:

 

Запрос Get Port Status позволяет определить текущее состояние заданного порта хаба. Запрос имеет следующие параметры:

 

По запросу Get Port Status хаб возвращает 16-разрядное слово состояния порта wPortStatus и 16-разрядное слово индикаторов изменения состояния порта wPortChange.

Слово состояния порта имеет следующую структуру:

 

Слово индикаторов изменения состояния имеет следующую структуру:

 

Запрос Set Hub Descriptor позволяет хосту перезаписать (заменить) дескриптор хаба. Запрос имеет следующие параметры:

 

По запросу Set Hub Descriptor хост передает хабу дескриптор, структура которого описана в табл. 8.9.

Запрос Set Hub Feature используется для того, чтобы установить признак состояния хаба, указанный значением селектора свойств. Запрос имеет следующие параметры:

 

Передача данных по запросу Set Hub Feature не производится. Запрос Set Port Feature используется для того, чтобы перевести порт хаба в состояние, указанное значением селектора свойств. Запрос имеет следующие параметры:

 

 

Передача данных по запросу Set Port Feature не производится. Запрос Set Port Feature допускает использование следующих селек торов: PORT_ENABLE, PORT_SUSPEND,

PORT_POWER, C_PORT_CONNECTION, C_PORT_ENABLE, C_PORT_SUSPEND, C_PORT_OVER_CURRENT, C_PORT_RESET.

После установки свойства PORT_SUSPEND порт и подсоединенное к нему устройство переводятся в состоянии ожидания. После установки свойства PORT_ENABLE работа порта будет разрешена. После установки свойства PORT_POWER будет включено питание порта.

 

Процедура нумерации и конфигурирования устройств на шине USB

 

После включения питания хоста и подачи на шину USB сигнала сброса все устройства, которые подсоединены к шине и включены, находятся в несконфигурированном состоянии, имеют на шине адрес 0 и реагируют только на запросы по Основному каналу сообщений. Хост должен поочередно идентифицировать каждое устройство, присвоить ему индивидуальный адрес и сконфигурировать его. Конфигурирование системы начинается с подачи сигнала глобального сброса. Далее хост идентифицирует и конфигурирует устройства, подключенные непосредственно к портам хост-контроллера.

Для того чтобы определить, подключено ли к порту хост-контроллера какое-либо устройство, нужно разрешить работу порта, записав 1 во второй разряд регистра состояния и управления порта. После этого нужно прочитать регистр состояния порта и проверить значение нулевого разряда слова состояния; если к порту подключено устройство, этот разряд будет установлен в 1. Кроме того, по значению восьмого разряда слова состояния нужно определить тип устройства (0 — полноскоростное устройство, 1 — низкоскоростное). Далее хост выполнит процедуру конфигурирования устройства. Порядок конфигурирования приведен ниже.

 

 

ВНИМАНИЕ

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

 

 


Операционные системы Windows 98 SE, Windows 2000 и Windows ХР используют несколько более сложный порядок конфигурирования [39].

 

Если какое-либо из устройств, подключенных к порту, является хабом, хост продолжает процесс настройки системы, поочередно опрашивая каждый порт хаба. Каждому найденному устройству хост присваивает адрес и задает конфигурацию по описанной выше схеме. Процесс конфигурирования продолжается, пока не будут настроены все хабы и подсоединенные к ним периферийные устройства с включенным питанием (выключенные устройства на запросы
не отвечают, поэтому хост их «не видит»).

В процессе работы некоторые устройства могут быть отсоединены от шины или подсоединены к ней. Хост должен периодически контролировать состояние собственных портов и портов хабов (путем 1 опроса по прерываниям), чтобы контролировать изменения на шине 1 USB. Каждому вновь подключенному устройству должен быть присвоен номер и задана конфигурация.

 

Работа с принтером через интерфейс USB

 

В процессе стандартизации периферийного оборудования с интерфейсом USB постоянно возникают проблемы, связанные с несогласованностью действий разработчиков, а часто — и с явным нежеланием следовать каким-либо стандартам. Некоторые классы устройств описаны настолько расплывчато, что создание для них универсальных драйверов в принципе невозможно: для разработки программного обеспечения требуется запрашивать у изготовителя документацию на конкретное устройство.

Принтеры являются счастливым исключением из общего правила: интерфейс USB для принтеров разработан таким образом, чтобы имитировать работу с принтером через параллельный порт, и полностью стандартизирован. Описание интерфейса принтеров приводится в спецификации Universal Serial Bus Device Class Definition for Printing Devices [93].

Для управления процессом печати используются командные языки фирм-изготовителей принтеров, поэтому создать единый универсальный драйвер практически невозможно. Существуют, однако, достаточно крупные группы изделий, для которых можно создать специфические драйверы, используя открытые (опубликованные) спецификации на командные языки. Например, как уже было указано в главе «Принтеры: печать в растровом режиме», для лазерных принтеров фактическим стандартом является язык HP PCL, а все струйные принтеры EPSON поддерживают язык Epson raster. Многие модели лазерных принтеров поддерживают также язык PostScript.

В обязательном порядке принтер имеет, по крайней мере, одну выходную точку, работающую в режиме передачи массивов данных (Bulk OUT). Эта точка служит для передачи данных (печатаемого текста или изображения) с хоста на принтер. Принтер может иметь также входную точку, работающую в режиме передачи массивов данных (Bulk IN) и предназначенную для передачи хосту информации об устройстве (например, о наличии бумаги в лотке подачи и тонера в картридже) и текущем состоянии процесса печати документа (например, об используемом разрешении, режиме печати, применяемых шрифтах).

Любой принтер с интерфейсом USB должен поддерживать, по крайней мере, один из двух возможных интерфейсов:

 

Обычно используется только двунаправленный интерфейс. Если принтер поддерживает одновременно оба интерфейса, они должны быть реализованы как альтернативные. Тип интерфейса указывается в поле протокола дескриптора интерфейса: однонаправленному интерфейсу соответствует код 01 h, двунаправленному — код 02h.

Принтеры поддерживают все стандартные запросы к устройству USB, а также несколько специфических (для своего класса) запросов:

 

Запрос Get Device ID позволяет получить строку-идентификатор принтера. Запрос имеет следующие параметры:

 

По запросу Get Device ID принтер передает хосту строку-идентификатор (Device ID) в формате, соответствующем стандарту IEEE- 1284: первые два байта содержат 16-разрядное слово, задающее общую длину идентификатора в байтах, а вслед за ними размещается собственно строка-идентификатор в коде ASCII.

 

ПРИМЕЧАНИЕ

При расчете размера идентификатора в байтах учитываются длина поля размера (2 байта) и длина текстовой строки (строка не имеет оконечного огра ничителя и состоит исключительно из символов ASCII).

 

 


Принтеры, имеющие несколько конфигураций, интерфейсов или несколько альтернативных установок для интерфейса, могут выдавать отдельную строку-идентификатор для каждого из возможных вариантов настройки.

Запрос Get Port Status позволяет получить содержимое регистра состояния принтера. Запрос имеет следующие параметры:

 

По запросу Get Port Status принтер передает хосту байт состояния, который имеет формат, аналогичный изображенному на рис. 7.2 формату регистра состояния параллельного порта. Байт состояния имеет следующую структуру:

 

Таким образом, для передачи информации используются только три разряда байта состояния, а остальные разряды зарезервированы.

По запросу Soft Reset производится программный сброс принтера. Запрос имеет следующие параметры:

 

Передача данных при выполнении запроса не производится.

Запрос Soft Reset вызывает очистку всех буферов данных принтера и сброс входного (Bulk IN) и выходного (Bulk OUT) каналов передачи массивов данных; все признаки ошибок и сбоев также сбрасываются. На USB -адрес и конфигурацию устройства программный сброс не влияет.

Устройство, относящееся к классу принтеров, должно поддерживать стандартные дескрипторы устройства, конфигурации, интерфейса и конечных точек.

Поля bDeviceClass, bDeviceSubClass, bDeviceProtocol в дескрипторе Устройства содержат нули и не могут использоваться для проверки принадлежности устройства к классу принтеров. Поля idVendor и idProduct пригодны для идентификации устройства только в том случае, если программисту известно значение этих полей для принтеров данного типа: списки числовых идентификаторов для изделий известных фирм можно найти в Интернете; идентификатор устройства также иногда указывается в фирменной документации по программированию.

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

В дескрипторе интерфейса требуется проверить значение полей класса и подкласса устройства: для принтеров код базового класса имеет значение 07h, код подкласса — 01 h. Тип интерфейса (однонаправленный или двунаправленный) особой роли не играет, так как программист обычно может работать только с Основным каналом сообщений и выходным каналом: структура информации о принтере, которую хост получает от входной точки, известна только фирме-разработчику устройства (открыто не публикуется).

Из дескриптора выходной конечной точки (Bulk OUT) нужно извлечь значение поля bEndpointAddress, содержащего адрес этой конечной точки, и значение поля wMaxPacketSize, задающего максимальный размер пакета при передаче данных на принтер. Опознать дескриптор конечной точки можно по значению полей bLength (поле должно содержать значение 07h), bDescriptorType (поле должно содержать значение 05h), bEndpointAddress (поле должно содержать 0 в старшем разряде) и bmAttributes (поле должно содержать значение 02h).

В листинге 8.3 приведена программа USB_EpsonStylus_Test, осуществляющая печать заштрихованного квадрата на струйном принтере EPSON Stylus в растровом черно-белом режиме с разрешением 360x360 точек/дюйм. Программа использует следующие процедуры:

 

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

 

ПРИМЕЧАНИЕ

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

 

 


Листинг 8.3. Печать заштрихованного квадрата на струйном принтере EPSON Stylus с интерфейсом USB.

 

 

IDEAL

P386

LOCALS

MODEL MEDIUM

 

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

FrameListBaseAddr equ 200000h

 

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

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

include "list1_03.inc"

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

include "list1_04.inc"

 

DATASEG

; Текстовые сообщения

Txt0 DB LIGHTMAGENTA,0,22

DB "ПОИСК И ТЕСТИРОВАНИЕ ПРИНТЕРА EPSON",0

DB YELLOW,11,19

DB "Включите принтер, установите лист бумаги в",0

DB YELLOW,12,13,"приемный лоток и нажмите "

DB "любую клавишу на клавиатуре.",0

Txt1 DB LIGHTGREEN,11,0,"Идентификатор принтера:",0

DB YELLOW,24,9,"Нажмите любую клавишу на "

DB "клавиатуре и ждите завершения печати",0

; Сообщения об ошибках

NoPrn DB 12,22,"Струйный принтер EPSON не обнаружен",0

PrnEr DB 12,27,"Принтер не готов к работе",0

; Номер печатаемой строки изображения

PrintingString DW ?

; Номер печатаемого байта

PrintingByte DW ?

 

; КОМАНДЫ ДЛЯ ПРИНТЕРА

; Выйти из "Packet Mode"

ExitPacketMode DB 1Bh,0,0,0,1Bh,1

DB "@EJL 1284.4",0Ah,"@EJL ",0Ah

; Выйти из "Remote Mode"

TerminateRemoteMode DB 4, 1Bh,0,0,0

; Инициализировать принтер

PrnInitialization DB 2, 1Bh,'@'

; Установить графический режим

SelectGraphicsMode DB 6, 1Bh,'(','G',1,0,1

; Выбор монохромного режима

MonochromeSelection DB 7, 1Bh,'(','K',1,0,0,1

; Печать растровой графики (320 точек в строке)

PrintRasterData DB 8, 1Bh,'.',0,10,10,1,64,1

; Перевод строки

SetRelVertPosition DB 7, 1Bh,'(','v',2,0,1,0

 

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

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

GetDevDesc DB 80h,6

DW 100h,0,8

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

SetAddrDesc DB 0,5

DW 1,0,0

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

GetConfDesc DB 80h,6

DW 200h,0,8

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

SetConfigur DB 00h,9

DW 1,0,0

; Дескриптор команды "Get Port Status"

GetPortStatus DB 0A1h,1

DW 0,0,1

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

GetDeviceID DB 0A1h,0

DW 0,0,8

ENDS

 

; Область памяти для хранения дескрипторов передачи

SEGMENT USB_DESCR para public 'DATA'

; Заголовок очереди дескрипторов

QH_Descriptor DD 00000003h ;единственный заголовок

DD 00000000h ;указатель на первый TD

DD 0,0,0,0,0,0 ;область данных ПО

; Список дескрипторов для одной транзакции

TD_Array DD 8*64 DUP(?)

ENDS

 

SEGMENT sseg para stack 'STACK'

DB 400h DUP(?)

ENDS

 

CODESEG

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

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

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

PROC USB_EpsonStylus_Test

mov AX,DGROUP

mov DS,AX

mov [CS:MainDataSeg],AX

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

mov AX,3

int 10h

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

mov [ScreenString],25

mov [ScreenColumn],0

call SetCursorPosition

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

mov AX,0B101h

int 1Ah

jc @@PCIBIOSNotFound

cmp EDX,20494350h

jne @@PCIBIOSNotFound

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

MShowColorText 3,Txt0

call GetChar

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

call Initialization

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

call InitializeDeascriptors

 

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

mov [SearchResult],0

mov [USB_HostIndex],0

@@NextHost:

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

call FindUSBController

cmp [SearchResult],0

jne @@NoHost

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

mov DX,[USB_BaseAddr]

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

out DX,AX

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

call Wait05s

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

mov AX,0

out DX,AX

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

call Wait05s

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

mov [USB_Device_Number],0

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

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

mov DX,[USB_BaseAddr]

add DX,6

mov AX,0

out DX,AX

add DX,2

mov EAX,FrameListBaseAddr

out DX,EAX

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

mov DX,[USB_BaseAddr]

mov AX,1

out DX,AX

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

mov [USB_PortNum],1

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

mov DX,[USB_BaseAddr]

add DX,10h

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

mov [USB_PortReg],DX

; Проверить наличие устройства

in AX,DX

test AX,000Fh

jz @@TestPort2

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

call Enumeration

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

call GetConfigurationDescriptor

; Устройство является принтером?

cmp [word ptr DataBuffer+9+5],0107h

je @@PrinterFound

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

@@TestPort2:

mov [USB_PortNum],2

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

mov DX,[USB_BaseAddr]

add DX,12h

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

mov [USB_PortReg],DX

; Проверить наличие устройства

in AX,DX

test AX,000Fh

jz @@ContrStop

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

call Enumeration

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

call GetConfigurationDescriptor

; Устройство является принтером?

cmp [word ptr DataBuffer+9+5],0107h

je @@PrinterFound

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

@@ContrStop:

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

jmp @@NextHost

@@PrinterFound:

 

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

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

mov SI,offset SetConfigur

call Setup_Transaction

; Подать команду "Get Port Status"

mov SI,offset GetPortStatus

call StatusIN_Transaction

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

cmp [byte ptr DataBuffer],18h

jne @@PrinterError

 

; ИДЕНТИФИЦИРОВАТЬ УСТРОЙСТВО

; Подать команду "Get Device ID"

mov SI,offset GetDeviceID

call StatusIN_Transaction

; Определить полную длину дескриптора

mov AX,[word ptr DataBuffer]

xchg AL,AH ;переставить байты

mov [word ptr GetDeviceID+6],AX

; Подать команду "Get Device ID" повторно

mov SI,offset GetDeviceID

call StatusIN_Transaction

; Проверить тип принтера по идентификатору

mov SI,offset DataBuffer

mov CX,[SI] ;загрузить длину строки

xchg CL,CH ;переставить байты

add SI,2

cmp CX,4

jbe @@DeviceNotFound

sub CX,4

; Цикл поиска слова "EPSON"

mov EAX,"OSPE"

@@SearchEPSO:

cmp EAX,[SI]

je @@SearchStyl

inc SI

loop @@SearchEPSO

jmp @@DeviceNotFound

; Цикл поиска слова "Stylus"

mov EAX,"lytS"

@@SearchStyl:

cmp EAX,[SI]

je @@ShowDeviceID

inc SI

loop @@SearchStyl

jmp @@DeviceNotFound

; Показать полученный дескриптор

@@ShowDeviceID:

call ClearScreen

MShowColorString Txt0

MShowColorText 2,Txt1

mov [ScreenString],19

mov CX,[word ptr GetDeviceID+6]

call Show_Ident

call GetChar

 

; ПОДГОТОВКА К НАЧАЛУ ПЕЧАТИ ИЗОБРАЖЕНИЯ

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

mov [dword ptr DataTrigger],0

; Выйти из "Packet Mode"

mov SI,offset ExitPacketMode

call OutCommandToPrn

; Инициализировать принтер

mov SI,offset PrnInitialization

call OutCommandToPrn

; Включить графический режим печати

mov SI,offset SelectGraphicsMode

call OutCommandToPrn

; Выборать монохромный режим

mov SI,offset MonochromeSelection

call OutCommandToPrn

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

call BulkOUT_Transaction

 

; ОСНОВНОЙ ЦИКЛ (ПО ПЕЧАТАЕМЫМ СТРОКАМ)

; Сбросить счетчик строк растра

mov [PrintingString],0

; Задать начальное значение байта штриховки

mov DL,80h

@@P0:

; Задать длину строки 40 байт (320/8)

mov SI,offset PrintRasterData

call OutCommandToPrn

; Верхнюю и нижнюю строки закрасить полностью

cmp [PrintingString],0

je @@TopOrBottomLine

cmp [PrintingString],319

jne @@Shade

@@TopOrBottomLine:

mov CX,40

mov AL,0FFh ;сплошная линия

; Цикл по печатаемым байтам

@@P1: call OutCharToPrn

loop @@P1

jmp @@LF

; Заштриховать квадрат

@@Shade:

; Левая граница

mov AL,DL

or AL,80h

call OutCharToPrn

; Внутренняя часть

mov CX,38

mov AL,DL

@@P2: call OutCharToPrn

loop @@P2

; Правая граница

mov AL,DL

or AL,01h

call OutCharToPrn

; Повернуть байт штриховки влево

rol DL,1

; Перейти на следующую строку растра принтера

@@LF: mov SI,offset SetRelVertPosition

call OutCommandToPrn

; Послать на принтер команду возврата каретки

mov AL,0Dh

call OutCharToPrn

; Передать данные на принтер

call BulkOUT_Transaction

; Перейти на следующую строку экранного изображения

inc [PrintingString]

cmp [PrintingString],320

jl @@P0

 

; Послать на принтер коды завершения страницы

mov AL,0Ch ;перевод формата

call OutCharToPrn

; Инициализировать принтер

mov SI,offset PrnInitialization

call OutCommandToPrn

call BulkOUT_Transaction

 

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

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

mov AX,3

int 10h

; Выход в DOS

mov AH,4Ch

int 21h

 

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

@@NoHost:

cmp [USB_HostIndex],0

je @@HostNotFound

jmp short @@DeviceNotFound

; Не поддерживается PCI BIOS

@@PCIBIOSNotFound:

MFatalError NoPCI

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

@@BadRegisterNumber:

MFatalError BadRg

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

@@HostNotFound:

MFatalError NoUSB

; Устройство USB не найдено

@@DeviceNotFound:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError NoPrn

; Принтер не готов к печати

@@PrinterError:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError PrnEr

ENDP USB_EpsonStylus_Test

 

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

;* ПЕРЕДАТЬ МАССИВ ДАННЫХ УСТРОЙСТВУ USB *

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

;* BULK_DataSize - объем передаваемых данных. *

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

PROC BulkOUT_Transaction near

pushad

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

mov ESI,[Addr_TD_Array]

; Загрузить в EBX указатель на буфер данных

mov EBX,[Addr_DataDescr]

; Вычислить количество полных (64-байтных) блоков

mov CX,[BULK_DataSize]

shr CX,6 ;количество 64-байтных блоков

cmp CX,64-1

ja @@TD_Array_Error

cmp CX,0

je @@ShortDataBlock

@@NextDataBlock:

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

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

mov EAX,ESI

add EAX,32

mov [GS:ESI],EAX

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

or EAX,07E000E1h ;передать 64 байта

or EAX,[DataTrigger] ;триггер данных

or EAX,00008000h ;конечная точка 1

mov [GS:ESI+8],EAX

xor [dword ptr DataTrigger],80000h

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

add EBX,64

xor EAX,EAX

mov [GS:ESI+16],EAX

mov [GS:ESI+20],EAX

mov [GS:ESI+24],EAX

mov [GS:ESI+28],EAX

add ESI,32

loop @@NextDataBlock

 

; Формирование неполного блока

@@ShortDataBlock:

; Вычислить размер последнего (неполного) блока

mov DX,[BULK_DataSize]

and EDX,111111b

cmp DX,0 ;размер больше нуля?

je @@NoShortBlock

; Сформировать дескриптор данных короткого блока

mov [dword ptr GS:ESI],1b ;последний TD

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

mov EAX,[ShFuncNum] ;номер функции

dec DX

shl EDX,21

or EAX,EDX ;размер блока

or EAX,[DataTrigger] ;триггер данных

or EAX,00008000h ;конечная точка 1

or EAX,0E1h

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

jmp short @@Start

; Нет короткого блока, пометить последний полный блок

; как конечный

@@NoShortBlock:

sub ESI,32

mov [dword ptr GS:ESI],1b ;последний TD

@@Start:

; Установить указатель на список дескрипторов

; (контроллер начинает передачу данных)

mov EAX,[Addr_TD_Array]

mov ESI,[Addr_QH]

add ESI,4

mov [GS:ESI],EAX

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

@@Wait_OpComplete:

cmp [dword ptr GS:ESI],1b

jne @@Wait_OpComplete

mov [BULK_DataSize],0

popad

ret

; Переполнен массив дескрипторов

@@TD_Array_Error:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError DsErr

ENDP BulkOUT_Transaction

 

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

;* ВЫВЕСТИ СИМВОЛ НА ПРИНТЕР *

;* Параметры: *

;* AL - код символа. *

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

PROC OutCharToPrn near

push BX

cmp [BULK_DataSize],4096

jae @@Data_Buffer_Full

mov BX,offset DataBuffer

add BX,[BULK_DataSize]

mov [BX],AL

inc [BULK_DataSize]

pop BX

ret

; Переполнен буфер данных

@@Data_Buffer_Full:

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

mov DX,[USB_BaseAddr]

mov AX,0

out DX,AX

MFatalError BfErr

ENDP OutCharToPrn

 

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

;* ПОСЛАТЬ КОМАНДУ НА ПРИНТЕР *

;* Параметры: *

;* DS:SI - указатель на строку команды. *

;* Первый байт строки содержит количество *

;* байтов команды, посылаемых на принтер. *

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

PROC OutCommandToPrn near

pusha

cld

; Загрузить счетчик байтов команды в CX

lodsb

xor CX,CX

mov CL,AL

@@OutNextByte:

lodsb

call OutCharToPrn

loop @@OutNextByte

popa

ret

ENDP OutCommandToPrn

 

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

;* ОТОБРАЗИТЬ СОДЕРЖИМОЕ ИДЕНТИФИКАТОРА ПРИНТЕРА *

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

PROC Show_Ident near

pusha

mov [ScreenString],12

mov [ScreenColumn],0

mov SI,offset DataBuffer

mov CX,[SI] ;загрузить длину строки

xchg CL,CH ;переставить байты

add SI,2

@@NextByte:

lodsb

call ShowASCIIChar

loop @@NextByte

popa

ret

ENDP Show_Ident

ENDS

 

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

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

include "list1_02.inc"

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

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

include "list2_01.inc"

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

include "list8_01.inc"

END

 

В приведенном примере используется набор команд Epson raster, описанный в главе 7 «Принтеры: печать в растровом режиме». Следует отметить, что при подключении принтера через интерфейс USB сразу после завершения процесса конфигурирования устройству требуется подать специальную команду «Exit Packet Mode», предназначенную для переключения принтера из некоего «пакетного режима Epson» (в открытой документации этот режим не описан) в обычный режим работы. Командная ESC -последовательность для выхода из пакетного режима очень длинная:

00h, 00h, 00h, 1Bh, 0lh, "@EJL", 20h, "1284.4" , 0Ah, "@EJL", 20h, 20h, 20h, 20h, 20h, 0Ah.

Проверка принадлежности принтера к группе моделей EPSON Stylus осуществляется по полученному от принтера идентификатору устройства: строка должна содержать слова «EPSON» и «Stylus».

 

ВНИМАНИЕ

Программа из листинга 8.3 не предназначена для тестирования принтеров серий С20 и С40, которые используют специфические значения параметров в команде передачи растровой строки.

 

 


Работа с мышью через интерфейс USB

 

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

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

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

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


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

 

 

ПРИМЕЧАНИЕ

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

 


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

 

ПРИМЕЧАНИЕ

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

 

 


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

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

 

 

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

 

 

Листинг 8.4. Работа с мышью через интерфейс USB .

 

 

IDEAL

P386

LOCALS

MODEL MEDIUM

 

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

FrameListBaseAddr equ 200000h

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

ScreenLength equ 80 ;количество символов в строке

ScreenHeigth equ 25 ;количество строк на экране

 

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

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

include "list1_03.inc"

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

include "list1_04.inc"

 

DATASEG

; Старое значение фона символа

OldCharBackground DB 0Fh

; Текущее состояние кнопок

ButtonsStatus DB 0

; Текущие координаты курсора мыши

XCoordinate DW 0

YCoordinate DW 0

; Предыдущая позиция курсора мыши

OldXCoordinate DW 0

OldYCoordinate DW 0

; Текстовые сообщения

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

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

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

DB YELLOW,24,21

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

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

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

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

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

DB 8,21,"Регистр состояния:",0

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

DB 10,27,"Номер кадра:",0

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

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

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

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

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

AnyK DB YELLOW,24,29,"Нажмите любую клавишу",0

; Сообщения об ошибках

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

 

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

; Дескриптор команды "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 USB_DESCR para public 'DATA'

; Заголовок очереди дескрипторов

QH_Descriptor DD 00000003h ;единственный заголовок

DD 00000000h ;указатель на первый TD

DD 0,0,0,0,0,0 ;область данных ПО

; Список дескрипторов для одной транзакции

TD_Array DD 8*16 DUP(0)

ENDS

 

CODESEG

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

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

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

PROC USB_Mouse

mov AX,DGROUP

mov DS,AX

mov [CS:MainDataSeg],AX

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

mov AX,3

int 10h

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

mov [ScreenString],25

mov [ScreenColumn],0

call SetCursorPosition

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

mov AX,0B101h

int 1Ah

jc @@PCIBIOSNotFound

cmp EDX,20494350h

jne @@PCIBIOSNotFound

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

call Initialization

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

call InitializeDeascriptors

 

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

mov [SearchResult],0

mov [USB_HostIndex],0

@@NextHost:

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

call FindUSBController

cmp [SearchResult],0

jne @@NoHost

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

mov DX,[USB_BaseAddr]

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

out DX,AX

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

call Wait05s

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

mov AX,0

out DX,AX

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

call Wait05s

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

mov [USB_Device_Number],0

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

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

mov DX,[USB_BaseAddr]

add DX,6

mov AX,0

out DX,AX

add DX,2

mov EAX,FrameListBaseAddr

out DX,EAX

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

mov DX,[USB_BaseAddr]

mov AX,1

out DX,AX

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

mov [USB_PortNum],1

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

mov DX,[USB_BaseAddr]

add DX,10h

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

mov [USB_PortReg],DX

; Проверить наличие устройства

in AX,DX

test AX,000Fh

jz @@TestPort2

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

call Enumeration

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

call GetConfigurationDescriptor

; Устройство является мышью?

cmp [byte ptr DataBuffer+9+5],03h

jne @@TestPort2

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

je @@MouseFound

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

@@TestPort2:

mov [USB_PortNum],2

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

mov DX,[USB_BaseAddr]

add DX,12h

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

mov [USB_PortReg],DX

; Проверить наличие устройства

in AX,DX

test AX,000Fh

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,0

out DX,AX

jmp @@NextHost

 

@@MouseFound:

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

MShowColorText 3,Txt0

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

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

mov SI,offset SetConfigur

call Setup_Transaction

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

call IntEndpointDescriptor

 

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

call ShowNewMouseCursorPosition

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

mov [dword ptr DataTrigger],0

@@NextInterrupt:

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

call InterruptIN_Transaction

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

mov AL,[DataBuffer+1]

cbw

add AX,[XCoordinate]

js @@X1

cmp AX,ScreenLength

jb @@X2

mov AX,ScreenLength-1

jmp @@X2

@@X1: xor AX,AX

@@X2: mov [XCoordinate],AX

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

mov AL,[DataBuffer+2]

cbw

add AX,[YCoordinate]

js @@Y1

cmp AX,ScreenHeigth

jb @@Y2

mov AX,ScreenHeigth-1

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 AX,3

int 10h

; Выход в DOS

mov AH,4Ch

int 21h

 

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

@@NoHost:

cmp [USB_HostIndex],0

je @@HostNotFound

jmp short @@MouseNotFound

; Не поддерживается PCI BIOS

@@PCIBIOSNotFound:

MFatalError NoPCI

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

@@BadRegisterNumber:

MFatalError BadRg

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

@@HostNotFound:

MFatalError NoUSB

; Мышь USB не найдена

@@MouseNotFound:

MFatalError NoMouse

ENDP USB_Mouse

 

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

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

;* АТРИБУТА СИМВОЛА В ПОЗИЦИИ КУРСОРА *

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

PROC ShowNewMouseCursorPosition NEAR

pusha

push ES

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

mov AX,0B800h

mov ES,AX

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

mov AX,[OldYCoordinate]

mov DX,160

mul DX

add AX,[OldXCoordinate]

add AX,[OldXCoordinate]

inc AX

mov DI,AX

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

mov AL,[OldCharBackground]

mov [ES:DI],AL

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

mov AX,[YCoordinate]

mov DX,160

mul DX

add AX,[XCoordinate]

add AX,[XCoordinate]

inc AX

mov DI,AX

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

mov AL,[ES:DI]

mov [OldCharBackground],AL

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

xor [byte ptr ES:DI],1111111b

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

mov AX,[XCoordinate]

mov [OldXCoordinate],AX

mov AX,[YCoordinate]

mov [OldYCoordinate],AX

pop ES

popa

ret

ENDP ShowNewMouseCursorPosition

 

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

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

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

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

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

PROC InterruptIN_Transaction near

pushad

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

mov ESI,[Addr_TD_Array]

; Загрузить в EBX указатель на буфер данных

mov EBX,[Addr_DataDescr]

 

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

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

mov [dword ptr GS:ESI],1b ;последний TD

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

mov EAX,[ShDevType] ;тип устройства

or EAX,00800000h ;признак активности

mov [GS:ESI+4],EAX

; Маркер

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

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

or EAX,[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],1b

jne @@Wait_OpComplete

popad

ret

ENDP InterruptIN_Transaction

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

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

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

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

PROC IntEndpointDescriptor near

pusha

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

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

@@NextDescriptor:

cmp [word ptr DataBuffer+BX],0507h

je @@Endpoint

@@NextDescOffset:

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

add BL,[DataBuffer+BX]

adc BH,0

; Проверка на превышение длины массива

cmp BX,[word ptr DataBuffer+2]

jb @@NextDescriptor

MFatalError NoDev

@@Endpoint:

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

test [DataBuffer+BX+2],10000000b

jz @@NextDescOffset

cmp [DataBuffer+BX+3],3

jne @@NextDescOffset

; Запомнить адрес конечной точки

xor EAX,EAX

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 "list1_02.inc"

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

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

include "list2_01.inc"

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

include "list8_01.inc"

 

END

 

ПРИМЕЧАНИЕ

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

 

Текст (C) Кулаков В.Г.

(С) ЗАО Издательский дом ПИТЕР , 2003



Назад на список статей       Наверх