
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.52] |
![]() |
|
Страницы: (51) « Первая ... 26 27 [28] 29 30 ... 50 51 ( Перейти к последнему сообщению ) |
Сообщ.
#406
,
|
|
|
Вот, еще вспомнил (прочитал) про бит CONFIGURED - после установки его в 1 все порты переходят к EHCI (биты 13 PORT_OWNER в регистрах PORTSC устанавливаются в 0).
Потом просматриваем все PORTSC и делаем такие действия: 1. Если бит 0 (Current Connect Status) стоит в 1, значит, что-то подключено. Если нет - пропускаем этот порт. 2. Если биты 10,11 (Line Status) установлены в 01, значит, подключено low speed устройство, мы с ним не работаем. Выставляем бит 13 (Port Owner) в 1 и переходим к следующему порту. 3. Делаем EHCI_RESET. Выставляем бит 8 (Port Reset) в 1 и одновременно бит 2 (Port Enable) в 0 и выдерживаем как минимум 10 миллисекунд (я держу 12). Потом устанавливаем Port Reset в 0, и дожидаемся, когда он действительно сбросится в 0. Если после этого бит 2 (Port Enable) установился в 1, то устройство поддерживает high speed, и мы можем с ним работать. Если Port Enable остается в 0, то устройство не поддерживает high speed, и мы должны отдать его компаньону (ставим Port Owner в 1). Дальше начинается работа непосредственно с устройством. Первое, что мы должны сделать - это пронумеровать устройство. Для этого надо послать пакет типа SETUP, содержащий стандартный Request. Структура всех request'ов на языке Си выглядит так: { unsigned char bmRequestType; // 1 байт unsigned char bRequest; // 1 байт unsigned short wValue; // 2 байта unsigned short wIndex; // 2 байта unsigned short wLength; // 2 байта }; Общая длина - 8 байт. Значения полей для SET_ADDRESS : {0,5,адрес_устройства,0,0} в порядке little-endian, т.е. младшими байтами вперед. Если расписать в байтах, то при адресе устройства, например, 1, будет такая последовательность байтов: 0,5,1,0,0,0,0,0. Для посылки этого запроса через EHCI мы должны разместить этот запрос так, чтобы он не пересекал границу страницы физической памяти, записать его физический адрес в qTD, заполнить все остальные нужные поля qTD, выстроить очередь qTD и запустить контроллер на выполнение этой очереди. Очередь qTD должна состоять из двух qTD - на этот запрос устройство отвечает пакетом нулевой длины, и этот пакет надо принять. |
Сообщ.
#407
,
|
|
|
У qTD размер 32 байта, в
Next qTD Pointer мы занесём адрес стедующего qTD и Т=0, Alternate Next qTD Pointer ставим 0 dt=0 Total Bytes to Transfer=8 ioc=0 C_Page=0 Cerr=0 PID Code=10b(SETUP) Status=0 Buffer Pointer (page 0)=адрес на пакет SET_ADDRESS из 8 байт Current Offset=? Buffer Pointer (page 1)=0 Buffer Pointer (page 2)=0 Buffer Pointer (page 3)=0 Buffer Pointer (page 4)=0 Следующий Next qTD Pointer=0 Т=1, Alternate Next qTD Pointer ставим 0 dt=0 Total Bytes to Transfer=0 ioc=0 C_Page=0 Cerr=0 PID Code=? Status=0 Buffer Pointer (page 0)=0 Current Offset=? Buffer Pointer (page 1)=0 Buffer Pointer (page 2)=0 Buffer Pointer (page 3)=0 Buffer Pointer (page 4)=0 А куда записывать адрес самого qTD и как понять что нам ответили и где будет этот ответ? |
Сообщ.
#408
,
|
|
|
Адрес первого qTD записывается в QH. Адрес QH - в соответствующщий регистр контроллера.
Ответом будет факт приема пакета нулевой длины от устройства. |
Сообщ.
#409
,
|
|
|
Ответом будет факт приема пакета нулевой длины от устройства.
![]() А как понять что у нас факт приема пакета нулевой длины от устройства. |
Сообщ.
#410
,
|
|
|
В qTD будет сброшен бит активности. И еще контроллер даст прерывание, если они не запрещены.
|
Сообщ.
#411
,
|
|
|
Понял спасибо.
Во втором нулевом? |
Сообщ.
#412
,
|
|
|
В каждом. Каждая транзакция приводит к сбросу бита активности соответствующего qTD. Я в своей программе пользуюсь этим для определения того, что транзакция произошла. Просто проверяю биты активности каждого qTD из очереди в цикле с таймаутом. Но мне спешить некуда, а вообще-то правильнее было бы работать с прерываниями.
Добавлено Кстати, при построении qTD бит активности (бит 7 поля Status) надо взводить. В твоих терминах это будет записываться Status = 80h. Для второго qTD (прием пакета нулевой длины) PID Code будет 01b (пакет типа IN). |
Сообщ.
#413
,
|
|
|
Понял, нужно проверять статус на изменения, и там будет либо ошибка либа выполнено. Мы отправим qTD в QH, а где в нём будет инфа о самом порте, которому мы номер посылать собрались, нашему порту с включеным битом enable.
Queue Head Horizontal Link Pointer= Т= RL= C= Maximum Packet= Length= H= EndPt= Device Address= Mult= Port Number*= Hub Addr*= μFrame C-mask*= μFrame S-mask= А после всех заполнений Asynchronous Schedule Enable поставить 1, и кто его выключать должен. С прерываниями кстати тоже проблемы, т.к. после их вызова нужно чтото делать с контроллером, иначе комп виснет. |
Сообщ.
#414
,
|
|
|
Номер порта при транзакциях не используется вообще. Все транзакции однозначно определяются номером устройтсва на шине и номером конечной точки (endpoint) в устройстве.
При первой транзакции (нумерации) логика такая: мы дали ресет на конкретный порт. Устройство (если оно есть) после ресета имеет адрес 0, на этот адрес мы и посылаем пакет SET_ADDRESS. Все предудыщие порты уже обработаны - если там есть high-speed устройства, то им уже присвоены адреса, отличные от 0, если нет - то там нет бита Port Enable, т.е. порт недоступен из EHCI (либо уже отдан компаньону, либо просто пустой). Все последующие порты еще не обработаны, и там тоже нет бита Port Enable. То есть в каждый конкретный момент в системе может быть только одно устройство с адресом 0, именно ему и посылается пакет SET_ADDRESS. На конечную точку номер 0 (control endpoint). Asynchronous Schedule Enable выключаешь сам, когда кончается очередь. В серьезных системах типа Windows или Linux очередь может пополняться динамически, и этот бит скорее всего вообще не выключается. Я в своей программе выключаю, поскольку работаю только с одним QH, и если я начну модифицировать очередь при включенном Asynchronous Schedule Enable, контроллер может начать ее выполнять раньше, чем я ее сформирую, а этого мне не надо. Поэтому я включаю этот бит тогда, когда очередь уже сформирована, и выключаю тогда, когда выполнены все qTD (проверяю по биту активности). Поля Port Number и Hub Address нужно заполнять только тогда, когда используется хаб USB 2.0, к которому подключено устройство USB 1.1. С прерываниями я не работаю, а в принципе, обработка прерываний должна быть стандартная - определить причину прерывания и сделать нужные действия, в т.ч. и с контроллером прерываний. |
Сообщ.
#415
,
|
|
|
После номерации в Queue Head мы заносим этот номер в Device Address для посылки запроса на это устройство? Седьмой бит стоит какойто флаг I, значит номеров 128?
|
Сообщ.
#416
,
|
|
|
Что значит после нумерации в Queue Head?
Все наоборот. В QH ставится номер устройства, которому адресован пакет. Если оно еще не пронумеровано, его номер - 0. После того, как оно будет пронумеровано, мы для дальнейших транзакций будем ставить в QH его номер. 7-й бит в Queue Head DWord 1 - флаг I, да.. This field is only valid when the queue head is in the Periodic Schedule, т.е. для асинхронных транзакций значения не имеет. Адрес устройства занимает младшие 7 бит, т.е. может быть не более 127. |
Сообщ.
#417
,
|
|
|
При начальной загрузке захожу в bios и вижу названия устройств, подключенных через USB, например: JetFlash Trancend, WDC WD1001FALS-00J7B0. Интересно узнать, откуда bios эти названия берет? А если взял, то куда помещает, чтобы их можно было считать.
|
Сообщ.
#418
,
|
|
|
BIOS их берет из устройств. После того, как проделает все операции по инициализации и пр. Первой командой на уровне SCSI идет Inquiry, в ответ на которую устройство и возвращает свое название.
А куда помещает - фиг знает.. В какие-то свои буферы. |
Сообщ.
#419
,
|
|
|
Цитата zakharo @ Первой командой на уровне SCSI идет Inquiry, в ответ на которую устройство и возвращает свое название. У меня UHC и EHC контроллеры. Может где есть ассемблерный пример с использованием Inquiry? А вообще, я пишу не программы, а батники, исполняемые в реальном режиме на уровне биоса, путем запуска специального загрузчика, позволяющего работать с памятью, прерываниями и портами ввода-вывода. Ассемблерный код переделываю под батник. |
Сообщ.
#420
,
|
|
|
Боюсь, что только Inquiry не обойтись. Придется полностью брать на себя управление контроллером.
Может быть, легче в BIOSе найти эти имена? Если тебе доступна вся память, то и просканируй ее. Хотя не исключено, что BIOS хранит их где-нибудь в невидимой области. |