Настольная книга компьютерного исследователя


Программирование портов ввода/вывода под Linux

Для начала оценим схему сложнейшего тестера RS-232:

 

 

 

 

 

                                R 1Kom
                           ─────■■■■────────┬────┐
                                             │    │
                                     зел. D1  D2  красн.
                                             │    │
                           ─────────────────┴────┘

Он состоит из одного двухцветного светодиода (или из двух — красный и зеленый соединенные встречно-параллельно), включенного(ых) последновательно с резистором сопротивление которого 1Коm. К свободным концам резистора и диода припаеваем провода и тестер готов. Далее одним концом касаемся к 7-ому пину (у RS-232/DB25s=7, у DB9s это=5), а другим, к проверяемым пинам. (распиновки RS-232 и LPT приведены ниже). Диоды (диод) включены так, что при положительном напряжении загарается красный, а при отрицательном напряжении — зеленый.

Тестер вещь полезная, но, иногда хочется и бесполезного. Возьмем LPT’шный первый пин — strobe, и меняя напряжение на нем в определенный интервал времени заставим включаться/выключаться диод. Бесполезно — но поможет разобраться с программированием портов I/O под Linux.

Как работать с портами под Линей? Для возможности работы с портами нужно получить «разрешение» OS путем вызова ioperm(). Функцию это можно вызвать только от пользователя root:

ioperm (BOOL ToggleOn-Off,long StartingPort#,long #Ports)

Toggle-Off — включает доступ если «правда» (1), или отключает доступ если «ложь» (0)
StartingPort# — определяет номер первого порта для доступа.
#Ports — определяет какое количество портов будет доступно (например StartingPort#=8h и #Ports=5 — даст доступ к портам с 8h по 0dh).

В программе достаточно сделать ioperm() один раз, и использовать порты ввода/вывода, не вызовая ее каждый раз. (OS сама позаботится об этом).

Теперь коснемся инициализации порта при загрузке систем базирующихся на Dos и *nix подобных OS (в данном случае Linux).

Прочтем байт регистра управления после загрузки dos/win32.

;—————————————————————————-
C:>debug io.com
-r
AX=0000 BX=0000 CX=0005 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=1BBC ES=1BBC SS=1BBC CS=1BBC IP=0100 NV UP EI PL NZ NA PO NC
1BBC:0100 BA7A03 MOV DX,037A
-p
AX=0000 BX=0000 CX=0005 DX=037A SP=FFFE BP=0000 SI=0000 DI=0000
DS=1BBC ES=1BBC SS=1BBC CS=1BBC IP=0103 NV UP EI PL NZ NA PO NC
1BBC:0103 ED IN AX,DX
-p
AX=09CC BX=0000 CX=0005 DX=037A SP=0000 BP=0000 SI=0000 DI=0000
DS=1BBC ES=1BBC SS=1BBC CS=1BBC IP=0000 NV UP EI PL NZ NA PO NC
1BBC:0000 CD20 INT 20
;—EOF————————————————————————

Как видим — CC.

Байт регистра состояния (37a):

                            С                  С
    0 - strobe             1100 - резерв      1100  - init,select in
    1 - AutoLf                             важный ascii
    2 - Init
    3 - Select In
    4 - Ack
    5 - Direction
    6,7 - резерв (неважно т.е.)

В таком (ССh) положении у нас положительное напряжение, а следовательно горит красный диод. Поставив к примеру 0dh (как я сказал 7и6 неважны) мы его соответсвенно выключим. Делается цикл по изменению регистра управления и диодик мигает. Теперь прочтем байт регистра управления после загрузки linux.

;—————————————————————————-

# gdb read_37ah
(gdb) break main
Breakpoint 1 at 0x80483d0
(gdb) r
Starting program: /Develop/asm/intel/read_37ah
Breakpoint 1, 0x80483d0 in main ()
(gdb) n
Single stepping until exit from function main,
which has no line number information.
0x4002e1eb in __libc_start_main (main=0x80483d0 , argc=1,
    argv=0xbffffd24, init=0x8048298 , fini=0x804841c ,
    rtld_fini=0x4000a610 , stack_end=0xbffffd1c)
    at ../sysdeps/generic/libc-start.c:90
(gdb) info registers eax
eax            0xc0     192

;—EOF———————————————————————-

C0 — никаких иницилизаций и установок от фонаря. Все так сказать очень чисто. Поставим чистый strobe в 1 — и имея в этом случае отрицательное напряжение включим зеленый диод. Далее соответственно. Это в принципе все. Можно мигать 2-мя диодами однавременно, можно по отдельности, я просто для примера, мигну зеленым на 2-х синтаксисах.

;—diod blinking (Intel Syntax)———————————————-

bits 32
global main
extern ioperm
main:
      push word 1         ; "правда"
      push dword 04h      ; 4 порта
      push dword 0378h    ; начиная с 378
      call ioperm         ; зовем ioperm()
      add ESP, 10         ; наводим порядок в стеке

      mov dx,037ah        ;
      in al,dx            ; Считываем биты регистра управления

      or al,00000001b     ; ВЫКЛючаем диод
;      and al,11111110b     ; ВКЛючаем диод
      out dx,ax            ; Выводим в порт

 ; по здравому смыслу стоило_бы сделать "лживый" ioperm() и навести порядок
 ; в стэке , но суть которая вкладывалась в этот пример уже изложена.

      ret

;—EOF————————————————————————

;—diod blinking (AT&T Syntax)————————————————

.globl main
main:
        pushl $1                # Turn On value
        pushl $4                # to 37a
        pushl $0x378            # Get IOpermission, starting from 378h
        call ioperm
        addw $10,%esp

        movw $0x37a,%dx         #
        inb (%dx),%al           # Считываем биты регистра управления

        orb $1,%al              # ВЫКЛючаем диод
//        andb $0xfe,%al          # ВКЛючаем диод
        outw %ax,(%dx)          # Выводим в порт

        movl $1,%eax           //  Функция 1(Выход) - exit
        movl $0,%ebx           //  параметры выхода
        int $0x80              //  SysCall

;—EOF————————————————————————

Красоты как обычно никто не наводит. Теперь дело за подключением холодильников, вентиляторов и прочего хлама…

     Распиновка RS-232/DB25s                 Распиновка RS-232/DB9s

  1    -    Protect Ground                1    -    Data Carrier Detected
  2    -    Transmit Data                 2    -    Receive Data
  3    -    Receive Data                  3    -    Transmit Data
  4    -    Request To Send               4    -    Data Terminal Ready
  5    -    Clear To Send                 5    -    Signal Ground
  6    -    Data Set Ready                6    -    Data Set Ready
  7    -    Signal Ground                 7    -    Request To Send
  8    -    Data Carrier Detected         8    -    Clear To Send
  20   -    Data Terminal Ready           9    -    Ring Indicator
  22   -    Ring Indicator

Распиновка LPT/DB25s

1 — Strobe
2 — Data 0
3 — Data 1
4 — Data 2
5 — Data 3
6 — Data 4
7 — Data 5
8 — Data 6
9 — Data 7
10 — Ack
11 — Busy
12 — PaperEnd
13 — Select
14 — Auto LF
15 — Error
16 — Init
17 — Select In
18-25 — Ground

(c) MadCr



©2013 Журнал Хакера Entries (RSS) and Comments (RSS)