Пишу драйвер для UPS под DOS. Прошу совета

Тема в разделе "WASM.ASSEMBLER", создана пользователем senseysensor, 11 мар 2009.

  1. senseysensor

    senseysensor New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2009
    Сообщения:
    17
    Здравствуйте!
    Ситуация следующая. Нужно, чтобы в момент отключения электричества UPS, который подключен к компьютеру через COM-порт, подал сигнал на комп.
    Как правильнее сделать? Повесить резидент на прерывание 14H и ждать прерывания со стороны устройства? Или повеситься на 1CH (таймер) и n раз в секунду проверять состояние порта?
    Вообще сталкиваюсь с такой задачей впервые. Не ясно, нужно ли самому опрашивать устройство или можно повеситься на аппаратное прерывание.

    А также такой вопрос - нужно ли инициализировать порт (функция 00H прерывания 14H)?
    И ещё, туда же: как узнать номер порта, если нужно будет действовать инструкцией OUT?

    Огромное спасибо за помощь!!!!!!!!!


    ps - Не нашёл подходящего раздела форума... пишу сюда
     
  2. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    1. Какой UPS? Совместим ли он по протоколу с Megatec?
    2. Если да, то, на мой взгляд, такая схема действий:
    - a) инициализируем порт (лучше с помощью int 14h) с параметрами как выше по ссылке;
    - b) раз в секунду-две или три делаем опрос состояния UPS (аналогично - int 14h);
    - c) напрямую в порты лучше не соваться, для протокола Megatec хватает и тех возможностей, что дает int 14h;
    - d) обнаружение UPS на каком-либо порту можно сделать простым перебором - выбрали порт, проинициализировали, отправили запрос, если не получили адекватного ответа, тогда опрашиваем следующий порт.
    3. Если протокол не Megatec-совместимый, тогда какова скорость передачи данных и прочие параметры? Если, скажем, скорость 115200 b/s, тогда придется искать другие пути инициализации порта, например, прямым программированием портов.
    4. В любом случае, думается мне, какой бы протокол ни был, наверняка он построен по типу "запрос-ответ". Так что принципиально мало что отличается от п.2. Главное - иметь описание протокола обмена.
     
  3. senseysensor

    senseysensor New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2009
    Сообщения:
    17
    Спасибо!!! мега полезная информация.
    Счас попробую переварить, а пока - первый же вопрос:
    для того, чтобы опрашивать порты раз в n секунд, мне ведь надо будет повесить резидент на прерывание 08H! Так вот, вопрос такой - можно ли из обработчика этого 08H прерывания вызвать прерывание 14H для опроса порта? не возникнет ли проблем с таймером..?

    Спасибо ещё раз!!!
     
  4. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    1. Можно повеситься на int 08h, тогда после своих дел вместо iret необходимо передавать управление старому обработчику, чтобы он мог тикать системные часы.
    2. Можно повеситься на int 1ch - оно вызывается каждый раз, когда стандартный обработчик int 08h сделает все свои дела по тиканью системных часов. Однако это не рекомендуется, ибо не все tsr-проги, могущие занять вектор 1ch, будучи запущенными после твоего драйвера, заботятся о передаче управления старому (а в данном случае твоему) обработчику.
    3. Практически дел с этими функциями не имел. Однако, учитывая, что в любом UART'е есть FIFO, за исключением совсем древних, команды из нескольких байт можно посылать сразу, не испытывая каких-либо затруднений. Даже если FIFO нет или BIOS его не включает, функция передачи вроде сразу возвращает управление, не ожидая готовности, так что это можно делать самостоятельно, анализируя status. То же относится и к функции приема - управление вроде как возвращается сразу, а о том, принято что-нибудь или нет, можно узнать, анализируя тот же status. Таким образом, если правильно организовать обработку прерывания (08h или 1ch) и обработку таймаутов, никаких проблем возникать не должно.
    Если мои измышления неверны, просьба к кому-нибудь - особенно к тем, кто работал с этими функциями - поправить меня.
     
  5. senseysensor

    senseysensor New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2009
    Сообщения:
    17
    Просветите поподробнее плиз... Или дайте наводку что почитать - как работать с этим status'ом?.......
    В одном из случаев мне придётся делать из обработчика 08H прерывания целую кучу операций - и принять с упса сигнал, и передать команду на упс, и создать файл, и с int 10H поработать.... Как тут быть? Можно ли из прерывания передать управление на какую-то большую подпрограмму, но только чтобы не тормозить таймер (и, соответственно, всю аппаратуру)??? и куда в этом случае возвращаться???????
    Может, есть какие-то мехнизмы для подобных случаев?

    help словом...

    ps - Проверил, протокол моего ups совместим с Megatec (некоторые команды, правда, не работают).
     
  6. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    Если я правильно понял задачу, то вот набросок для tasm'а:
    Код (Text):
    1. .386
    2. .model small
    3.  
    4. PING_CONST          equ       18                  ; приблизительно раз в секунду
    5.  
    6. ;*********************************************************************
    7.  
    8. Text                segment   public 'code'
    9.                     assume    cs:Text, ds:Data
    10.  
    11. UPS_EntryPoint:
    12.                     mov       ax, Text
    13.                     mov       ds, ax
    14.                     mov       IsOperatingNow, 0
    15.  
    16.                     ; ??? тут у нас первоначальная инициализация,
    17.                     ; ??? далее проверяем, нужно ли установить резидент,
    18.                     ; ??? либо же удалить существующий.
    19.                     ; ...
    20.  
    21.                     ; если надо установить, тогда
    22.                     jmp       UPS_InstallService
    23.  
    24.                     ; если удалить, то
    25.                     jmp       UPS_RemoveService
    26.  
    27.                     ; ни то, ни се - выход
    28.                     mov       ax, 04C00h
    29.                     int       21h
    30. ;---------------------------------------------------------------------
    31. UPS_InstallService:
    32.                     mov       ax, 03508h
    33.                     int       21h
    34.                     mov       Old08IP, bx
    35.                     mov       Old08CS, es
    36.  
    37.                     push      ds
    38.                     mov       ax, cs
    39.                     mov       ds, ax
    40.                     lea       dx, UPS_Ping
    41.                     mov       ax, 02508h
    42.                     int       21h
    43.                     pop       ds
    44.  
    45.                     ; ??? тут выходим, оставаясь резидентными
    46.                     ; ...
    47. ;---------------------------------------------------------------------
    48. UPS_RemoveService:
    49.                     push      ds
    50.                     lds       dx, Old08Handler
    51.                     mov       ax, 02508h
    52.                     int       21h
    53.                     pop       ds
    54.                     mov       ax, 04C00h
    55.                     int       21h
    56. ;---------------------------------------------------------------------
    57. UPS_Ping:
    58.                     ;-----------------------------------
    59.                     ; Это наш обработчик прерывания 08h
    60.                     ;-----------------------------------
    61.                     push      ax bx ds
    62.                     mov       ax, Data
    63.                     mov       ds, ax
    64.                     xor       al, al
    65.                     cmp       PingCounter, al     ; защита от дурака
    66.                     jnz       Uping_090
    67. Uping_010:
    68.                     mov       PingCounter, PING_CONST
    69.                     cmp       IsOperatingNow, al
    70.                     jnz       Uping_090
    71.  
    72.                     ; о! пора запустить нашу выхухоль!
    73.                     ;----------------------------------
    74.                     ; Содержимое стека:
    75.                     ; |Flags(x)|    |Flags(x)|
    76.                     ; | CS(x)  |    | CS(x)  |
    77.                     ; | IP(x)  |    | IP(x)  |
    78.                     ; |  AX    |    |Flags(x)|
    79.                     ; |  BX    |    | CS(u)  |
    80.                     ; |  DS    |    | IP(u)  |
    81.                     ;     << SP     | CS(o)  |
    82.                     ;               | IP(o)  |
    83.                     ;                   << SP
    84.                     ;  ^имеем^     ^надо сделать^
    85.                     ; (x - параметры прерванного кода,
    86.                     ;  u - параметры UPS_Operate,
    87.                     ;  o - параметры старого обработчика)
    88.  
    89.                     inc       IsOperatingNow
    90.                     ; планируем передачу ей управления после старого обработчика
    91.                     mov       ax, [sp+10]         ; Flags(x)
    92.                     mov       bx, cs              ; CS(u)
    93.                     pop       ds
    94.                     xchg      bx, [sp]
    95.                     xchg      ax, [sp+2]
    96.                     push      offset UPS_Operate  ; IP(u), must be 16-bit!
    97.                     push      ax bx ds
    98.                     mov       ax, Data
    99.                     mov       ds, ax
    100.                     ; далее доделываем преобразование стека
    101. Uping_090:
    102.                     ; передаем управление старому обработчику
    103.                     ;-----------------------------------------
    104.                     ; Содержимое стека:
    105.                     ; |Flags(x)|    |Flags(x)|
    106.                     ; | CS(x)  |    | CS(x)  |
    107.                     ; | IP(x)  |    | IP(x)  |
    108.                     ; |  AX    |    | CS(o)  |
    109.                     ; |  BX    |    | IP(o)  |
    110.                     ; |  DS    |        << SP
    111.                     ;     << SP
    112.                     ;  ^имеем^     ^надо сделать^
    113.                     ; (x - параметры прерванного кода,
    114.                     ;  o - параметры старого обработчика)
    115.  
    116.                     dec       PingCounter
    117.                     mov       bx, Old08IP
    118.                     mov       ax, Old08CS
    119.                     pop       ds
    120.                     xchg      bx, [sp]
    121.                     xchg      ax, [sp+2]
    122.                     retf
    123. ;---------------------------------------------------------------------
    124. UPS_Operate:
    125.                     ;-------------------
    126.                     ; Это наша выхухоль
    127.                     ;-------------------
    128.  
    129.                     ; ??? теперь здесь делаем что хотим и как хотим
    130.                     ; ??? тупим столько, сколько нужно
    131.                     ; ??? дергаем какие угодно функции DOS/BIOS
    132.                     ; ??? и т.д.
    133.                     ; ...
    134.  
    135.                     cli
    136.                     dec       IsOperatingNow
    137.                     iret
    138.  
    139. Text                ends
    140.  
    141. ;*********************************************************************
    142.  
    143. Data                segment public 'data'
    144.  
    145. Old08Handler        label     dword
    146. Old08IP             dw        0
    147. Old08CS             dw        0
    148. PingCounter         db        0
    149. IsOperatingNow      db        0
    150.  
    151. Data                ends
    152.  
    153. ;*********************************************************************
    154.  
    155.                     end       UPS_EntryPoint
    Все ли ясно?
     
  7. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    Суть всей мышиной возни в том, чтобы выполнять UPS_Operate без проблем: если подпрограмма будет выполняться меньше секунды, то она все равно будет запускаться раз в секунду; если же время ее выполнения будет больше секунды, повторных вхождений в нее не будет. При этом, в обоих случаях, прерывания разрешены и старый обработчик получает управление без пропусков, соответственно системные часы будут тикать как надо и контроллер прерываний и что-нибудь еще будет обслуживаться без проблем:
    Случай 1) UPS_Operate не получает управление:
    Int 08h -> UPS_Ping -> старый обработчик -> прерванный код.
    Случай 2) UPS_Operate должен получить управление:
    Int 08h -> UPS_Ping -> старый обработчик -> UPS_Operate -> прерванный код.
     
  8. senseysensor

    senseysensor New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2009
    Сообщения:
    17
    Да... не знаю, как и благодарить.
    Принцип ясен. В коде подробнее разберусь, как будет свободный часок.
    Думаю, проблем не должно возникнуть.
    СПАСИБО!!!
     
  9. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    Кстати, я его не проверял, даже не компилил, так что если обнаружатся ошибки, просьба сообщить - я поправлю. Мало ли кому еще понадобится.
     
  10. senseysensor

    senseysensor New Member

    Публикаций:
    0
    Регистрация:
    11 мар 2009
    Сообщения:
    17
    он мне при обработке tasm'ом выдаёт "Illegal indexing mode" (mov ax, [sp+10]). Ну до этого я пока не добрался (пока пишу остальные подпрограммы, которые потом распихаю по этому скелету). Кроме того, переделываю чуть-чуть под tiny модель. А так больше никаких ошибок (если что найду по сути алгоритма, напишу).
    ps - по-моему, там надо сделать что-то вроде
    Код (Text):
    1. push sp
    2. pop bp
    3. mov       ax, [BP+10]
     
  11. Ykidia

    Ykidia Member

    Публикаций:
    0
    Регистрация:
    21 июн 2005
    Сообщения:
    99
    Адрес:
    Санкт-Петербург
    Код (Text):
    1. push sp
    2. pop bp
    3. mov       ax, [BP+10]
    Ну во-первых вроде ж можно сделать проще и без участия стека:
    Код (Text):
    1.                 mov     bp, sp
    2.                 mov     ax, [bp+10]
    Во-вторых, самое главное (и неприятное) - то, что при вводе в использование еще одного регистра его надо сохранить, желательно там же, на стеке, но тогда все смещения изменятся.
    По поводу illegal indexing mode - я вспонил, надо использовать не sp, а esp, но тогда надо быть уверенным, что старшая половина esp обнулена. Вообще адресация именно по esp для меня кажется удобной, при этом регистр ebp остается свободным для других целей, например:
    Код (Text):
    1. ; ---------------------------------------------------------
    2. ; -=* R-E-A-D---K-E-Y---O-R---E-R-R-O-R---M-E-S-S-A-G-E *=-
    3. ; ---------------------------------------------------------
    4. LifGetKeywordID:
    5.                 ;------------------------------------------
    6.                 ; IN:   EBX - table address
    7.                 ; OUT:  NC  - keyword found
    8.                 ;       and EBX - keyword ID
    9.                 ;       C   - keyword not found
    10.                 ;------------------------------------------
    11.                 ; GKID Workspace
    12. GKIDWS          struc
    13. gkidws_begin = $
    14. GKIDTmpregESI   dd      ?
    15. GKIDTmpregEBX   dd      ?
    16. GKIDSymbolCnr   dd      ?
    17. GKIDKeywordID   dd      ?
    18. GKIDKeywordLen  dd      ?
    19. GKIDSymbolPtr   dd      ?
    20. GKIDTemplatePtr dd      ?
    21. GKIDTemplates   dd      00100h - (GKIDTemplates - gkidws_begin) dup(?)
    22. gkidws_tmplts_size = $ - GKIDTemplates
    23. gkidws_size = $ - GKIDTmpregESI
    24.                 ends
    25.                 ;------------------------------------------
    26.                 ; GKID Subroutine
    27.                 push    eax
    28.                 and     dl, 0FEh
    29.                 call    LifSkipComments
    30.                 ; clean up and init GKIDWS
    31.                 mov     eax, ecx
    32.                 mov     ecx, gkidws_size / 4
    33. LifGKID_005:
    34.                 push    dword ptr 0
    35.                 loopd   LifGKID_005
    36.                 mov     ecx, eax
    37.                 mov     [esp].GKIDTmpregESI, esi
    38.                 ; starting
    39.                 mov     esi, ebx
    40. LifGKID_010:
    41.                 mov     al, [esi]
    42.                 inc     esi
    43.                 mov     ah, [edi]
    44.                 cmp     al, 0FFh
    45.                 jz      LifGKID_120
    46.                 cmp     al, 080h
    47.                 jz      LifGKID_090
    48.                 cmp     al, 0F0h
    49.                 jnz     LifGKID_020
    50.                 ; control code 0F0h - set current keyword ID
    51.                 lea     esi, [esi + 4]
    52.                 mov     eax, [esi - 4]
    53.                 mov     [esp].GKIDTmpregEBX, eax
    54.                 jmp     LifGKID_010
    55. LifGKID_020:
    56.                 cmp     al, 0F1h
    57.                 jnz     LifGKID_022
    58.                 ; control code 0F1h - set template
    59.                 lea     esi, [esi + 8]
    60.                 mov     ebx, [esp].GKIDTemplatePtr
    61.                 cmp     ebx, gkidws_tmplts_size / 8 - 1
    62.                 jnc     LifGKID_Err2
    63.                 mov     eax, [esi - 4]
    64.                 mov     [[esp].GKIDTemplates + ebx*8], eax
    65.                 mov     eax, [esi - 8]
    66.                 mov     [[esp].GKIDTemplates + ebx*8 + 004h], eax
    67.                 inc     ebx
    68.                 mov     [esp].GKIDTemplatePtr, ebx
    69.                 jmp     LifGKID_010
    70. LifGKID_022:
    71.                 cmp     al, "#"
    72.                 jnz     LifGKID_028
    73.                 ; control symbol "#" - use template if next symbol 0..9 or A..Z
    74.                 mov     al, [esi]
    75.                 inc     esi
    76.                 cmp     al, "0"
    77.                 jc      LifGKID_028
    78.                 cmp     al, "Z"
    79.                 ja      LifGKID_028
    80.                 cmp     al, "9"
    81.                 ja      LifGKID_025
    82.                 sub     al, "0"
    83.                 jmp     LifGKID_026
    84. LifGKID_025:
    85.                 cmp     al, "A"
    86.                 jc      LifGKID_028
    87.                 sub     al, "A" - 10
    88. LifGKID_026:
    89.                 movzx   ebx, al
    90.                 mov     eax, [[esp].GKIDTemplates + ebx*8 + 004h]
    91.                 mov     ebx, [[esp].GKIDTemplates + ebx*8]
    92.                 test    ebx, ebx
    93.                 jz      LifGKID_Err3
    94.                 call    LifGetKeywordID
    95.                 cmp     eax, ebx
    96.                 jnz     LifGKID_070
    97.                 jmp     LifGKID_010
    98. LifGKID_028:
    99.                 cmp     al, "%"
    100.                 jnz     LifGKID_050
    101.                 ; control symbol "%" - means " ", "_" or nothing
    102.                 mov     al, [esi]
    103.                 cmp     al, "%"
    104.                 jnz     LifGKID_030
    105.                 ; double control symbol "%%" means single "%"
    106.                 inc     esi
    107.                 jmp     LifGKID_060
    108. LifGKID_030:
    109.                 cmp     ah, "_"
    110.                 jz      LifGKID_040
    111.                 cmp     ah, " "
    112.                 jnz     LifGKID_010
    113. LifGKID_040:
    114.                 xchg    esi, [esp].GKIDTmpregESI
    115.                 call    LifMAIN_7               ; EDI++
    116.                 xchg    esi, [esp].GKIDTmpregESI
    117.                 jmp     LifGKID_010
    118. LifGKID_050:
    119.                 xchg    esi, [esp].GKIDTmpregESI
    120.                 call    LifMAIN_7
    121.                 xchg    esi, [esp].GKIDTmpregESI
    122.                 cmp     ah, "A"
    123.                 jc      LifGKID_060
    124.                 cmp     ah, "Z"
    125.                 ja      LifGKID_060
    126.                 or      ah, 020h
    127. LifGKID_060:
    128.                 cmp     al, ah
    129.                 jnz     LifGKID_070
    130.                 inc     [esp].GKIDSymbolCnr
    131.                 jmp     LifGKID_010
    132. LifGKID_070:
    133.                 ; skip to next keyword
    134.                 mov     al, [esi]
    135.                 inc     esi
    136.                 cmp     al, 0FFh
    137.                 jz      LifGKID_120
    138.                 cmp     al, 080h
    139.                 jnz     LifGKID_070
    140. LifGKID_080:
    141.                 mov     [esp].GKIDSymbolCnr, 0
    142.                 mov     edi, [esp].GKIDTmpregESI
    143.                 jmp     LifGKID_010
    144. LifGKID_090:
    145.                 mov     eax, [esp].GKIDSymbolCnr
    146.                 cmp     eax, [esp].GKIDKeywordLen
    147.                 jc      LifGKID_080
    148.                 jz      LifGKID_Err1
    149. LifGKID_100:
    150.                 mov     [esp].GKIDKeywordLen, eax
    151.                 mov     eax, [esp].GKIDTmpregEBX
    152.                 mov     [esp].GKIDKeywordID, eax
    153.                 mov     [esp].GKIDSymbolPtr, edi
    154.                 jmp     LifGKID_080
    155. LifGKID_120:
    156.                 cmp     [esp].GKIDSymbolPtr, 0
    157.                 stc
    158.                 jz      LifGKID_130
    159.                 mov     edi, [esp].GKIDSymbolPtr
    160.                 mov     ebx, [esp].GKIDKeywordID
    161.                 mov     eax, [esp].GKIDKeywordLen
    162.                 clc
    163. LifGKID_130:
    164.                 mov     esi, [esp].GKIDTmpregESI
    165.                 lea     esp, [esp + gkidws_size]
    166.                 pop     eax
    167.                 ret
    168. LifGKID_Err1:
    169.                 PSTR    TxtIniDuplicateKey
    170.                 mov     eax, [esp].GKIDTmpregEBX
    171.                 PHEXD   eax
    172.                 PCHR    ","
    173.                 PCHR    " "
    174.                 mov     eax, [esp].GKIDKeywordID
    175.                 PHEXD   eax
    176.                 PENT
    177.                 QUIT
    178. LifGKID_Err2:
    179.                 PSTR    TxtIniNoMoreTempls
    180.                 QUIT
    181. LifGKID_Err3:
    182.                 PSTR    TxtIniNoTemplate
    183.                 QUIT
    Подпрограмма находит соответствие ключевому слову по [edi] в таблице по [esi] и возвращает индекс в ebx. И хотя данный пример для модели flat, он все равно иллюстрирует, как можно использовать стек для локальных переменных, как это делается в C/C++, но со свободным ebp.