Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > как управлять через lptwdmio.sys


Автор: Dias2004 17.5.2006, 09:49
Помогите поуправлять внешними устройствами через 2 LPT порта одновременно!

Имеется драйвер lptwdmio.sys и модуль обращения к его функциям (http://valery-us4leh.narod.ru/XpCoding/Shablon_XP.html).
Все блестяще работает, если LPT-порты имеют адреса из стандартного диапазона.

Однако если порты установлены на мультикарте, они имеют "верхние" адреса, например на моем экземпляре железа после установки базовые адреса второго и третьего портов оказались равными $D000 и $B400 соответственно.

Явным образом адреса портов в тексте программы управления (модуль lptio.pas из упомянутого источника) не прописаны - они вытягиваются системными функциями.

Если кто знает или разбирается, подскажите, как научить модуль правильно распознавать нестандартные адреса, или хотя бы прописать их явным образом в виде констант?

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

Автор: Romikgy 17.5.2006, 11:59
надо смотреть исходники lptwdmio.sys,
обращение к нему имхо какое то кривоеsmile 

Автор: Mechanic 18.5.2006, 01:57
Не получится снаружи навязать свои адреса.. smile

Но всегда есть путь в обход..  smile  Дровишко сам мал, и адреса портов 0х378 0х3BC .. прописаны в его теле лишь дважды..
Ход мысли понятен?  Просто патчим 2*2*2 = 8 байт, и пользуемся! smile 

Цитата(Rules said)
2. Обсуждать взлом компонентов и делится вскрытыми компонентами

Ой..  smile 
Ну.. Ить это не вскрытие же. Просто беспокоить автора по таким пустякам..   smile  И это даже не компонент.   smile  

Автор: Dias2004 18.5.2006, 08:45
Если я не ошибаюсь, драйвер - это lptwdmio.sys.
В его теле я не обнаружил ни одного адреса.
Где и как искать?

Явно адреса встречаются (и действительно дваждый) в тексте модуля LPTIO.pas (см. фрагмент ниже), но это относится к коду, предназначенному для исполнения под Win9x. Под XP работает вызов вида
Код
...
const
 {номера портов LPT}
 LPT1 : byte = $10; // $3BC
 LPT2 : byte = $20; // $378
 LPT3 : byte = $30; // $278

 { смещения регистров порта }
 LPT_DATA_REG    : byte = 0; // регистр данных
 LPT_STATE_REG   : byte = 1; // регистр состояния
 LPT_CONTROL_REG : byte = 2; // регистр управления
 LPT_EPP_ADDRESS : byte = 3; // регистр адреса EPP
 LPT_EPP_DATA    : byte = 4; // регистр данных EPP
...
 type
 { Структура адрес-данные }
 ADRDATASTRUCT = record
  Adr  : byte; { адрес == <номер порта> or <смещение регистра> }
  Data : byte; { данные для вывода или место для прочитанного байта }
                 end;
 PADRDATASTRUCT = ^ADRDATASTRUCT;
...

// функция для чтения регистров LPT. Возвращает true, если чтение прошло успешно.
function    TLptPortConnection.ReadPorts (PairArray : PADRDATASTRUCT; PairCount : cardinal) : boolean;
var
 cb   : cardinal;
 Pair : PADRDATASTRUCT;
 ct   : cardinal;
 adr  : WORD;
begin
 if Ready() then
  begin
   if hdrv <> INVALID_HANDLE_VALUE then
   begin // чтение через драйвер
    cb:=0; SetLastError(NO_ERROR);
    DeviceIoControl( hdrv,
                     IOCTL_READ_PORTS,
                     PairArray,PairCount*2,
                     PairArray,PairCount*2,
                     cb,
                     nil );
    ReadPorts := (NO_ERROR = GetLastError());

Судя по тексту, через структуру PairArray в драйвер передается некий условный адрес.
Я не вижу, где и как условный адрес (который == <номер порта> or <> смещение регистра) преобразуется в абсолютный адрес опрашиваемого регистра. Могу только еще раз констатировать, что механизм преобразования работает только если базовый адрес порта - один из трех "стандартных" - $278, $378 или $3BC.
Может, для работы с адресами в диапазоне $B000 и выше не хватает разрядности каких-нибудь переменных?
Помогите разобраться. 

Автор: Mechanic 18.5.2006, 09:25
Плохо искал, видно.. smile Просто байты хранятся в порядке Младший, Старший.
В аттаче прицепил исходный и пропатченный вариант.
В пропатченном поменял 378 -> D000;  278 -> B400.
Можно воспользоваться любым бинарным файловым компаратором, и посмотреть. 

Автор: Dias2004 18.5.2006, 11:07
Цитата
Плохо искал, видно..  Просто байты хранятся в порядке Младший, Старший.

Нет, про обратный порядок младший/старший даже я знаю... просто я искал строку вместо hex...  smile 

Спасибо, еще не проверял, но оптимизма прибавилось! 

Автор: Dias2004 29.5.2006, 14:42
Наконец приступил к испытаниям.
Адреса портов на тестовом железе оказались EF80 и EFA0.
Записал эти адреса в LPTWDMIO.SYS на место 03BC и 0278.
Запустил тестовую программу. Программа запускается, драйвер загружается, но управляется только порт 0378 (в демонстрационной программе это - порт LPT2).

Кому близка тема - можете что-либо сказать или посоветовать? 

Автор: Mechanic 29.5.2006, 20:15
А запиши их вместо $378 - не промахнешься.. smile

Да, и в 2х местах каждый адрес прописывал? 

Автор: Dias2004 30.5.2006, 13:13
Подробно описываю эксперимент.

Исходный код тех двух мест, где в драйвере lptwdmio.sys встречаются известные адреса, идентичен и выглядит (после дизасемблера) так:
Код
...
      mov dx,03BC
      add byte ptr [bx+si], al
      cmp al,01
      jz P1
      mov dx,0378
      add byte ptr [bx+si], al
      cmp al,02
      jz P1
      mov dx,0278
      add byte ptr [bx+si], al
P1:   mov al,ah
...


Если в компьютере установить адрес LPT-порта равным 03BC, то вызов из программы вида
Код
...
Const
 LPT1 : byte = $10;
 LPT2 : byte = $20;
 LPT3 : byte = $30;
...

  Lpt.WritePort(LPT1,LPT_DATA_REG,(Lpt.ReadPort(LPT1,LPT_DATA_REG) xor D0));

переключает бит D0 этого порта.
Если параметром указана константа LPT2, то реагирует порт с адресом 0378, а на LPT3 откликается порт с адресом 0278, все как бы согласуется с асемблерным кодом.

Теперь меняем в теле драйвера адреса 0378 и 0278 на адреса LPT-портов мультикарты (в моем случае они оказались EF80 и EFA0). Порт материнской платы компьютера (03BC) продолжает работать, как и раньше. Порты мультикарты не откликаются.  smile

Что можно было бы попробовать сделать? 

Автор: Dias2004 31.5.2006, 15:23
Может, кто знает, как связаться с автором драйвера lptwdmio.sys?
В теле указано: Автор: Гречко Ю.Б., http://progrex.narod.ru, 2003г. Статус: freeware.
На сегодняшний день указанный URL мертв.
 

Автор: Romikgy 31.5.2006, 16:31
У меня такой исходный код получился 
Код

        mov    edx,000003BCh
        cmp    al,01h
        jz    L000103DE
        mov    edx,00000378h
        cmp    al,02h
        jz    L000103DE
        mov    edx,00000278h
 L000103DE:
        mov    al,ah
        mov    ah,00h
        and    al,07h
        add    edx,eax
        mov    [ebp-10h],edx
        pop    edx
        pop    ebx
        push    [ebp-10h]
        call    jmp_HAL.DLL!READ_PORT_UCHAR


Может те не дает эта строка 
call    jmp_HAL.DLL!READ_PORT_UCHAR
нормально общатся с твоим портом? 

Автор: Mechanic 31.5.2006, 22:54
А дровишку после патчинга переустанавливал? Может быть срабатывает именно старая версия?
И ещё: а под ДОСом порт читается \ пишется?  

Автор: Dias2004 1.6.2006, 08:16
Я не знаю, как может мешать строка call jmp_HAL.DLL. Библиотека такая есть, может она не умеет обращаться к мультикарте, но маловероятно - ОС ведь видит все порты, их адреса, и даже работает с портами штатным образом, например управляет принтером. Как проверить, мешает ли вызов HAL.DLL, а если мешает, то что написать взамен?

Драйвер под XP загружается динамически, поэтому понятия "старая версия" просто не существует. Я не знаю, работает ли порт под DOS - это для меня вообще не важно.  smile

Важно то, что (как я упоминал в самом первом сообщении) все работает, если использовать компонент Small Port.
С ним получается примерно так:
Код
const
// ВНИМАНИЕ!
// адреса портов - аппаратно-зависимые параметры
  LPT1_ADDRESS = $0378;     // базовый адрес порта (варианты: $0278; $03BC;)
  LPT2_ADDRESS = $D000;
  LPT3_ADDRESS = $B400;

...

// ************ LPT2 ************
  { регистр ДАННЫХ }
  DATA2 = LPT2_ADDRESS;
  D2_CW = $01;    {D0 pin 2}

  { регистр СОСТОЯНИЯ }
  STATE2 = LPT2_ADDRESS+1;

  { регистр УПРАВЛЕНИЯ }
  CONTROL2 = LPT2_ADDRESS+2;

...
  SmallPort.Port[DATA2]:=SmallPort.Port[DATA2] or D2_CW;     // Set Bit On


И все работает... но в несколько раз медленнее, чем через lptwdmio... 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)