| 1 | ; **********************************************************************
 | 
|---|
| 2 | ; Copyright (C) 1995 by Holger Veit (Holger.Veit@gmd.de)
 | 
|---|
| 3 | ; Use at your own risk! No Warranty! The author is not responsible for
 | 
|---|
| 4 | ; any damage or loss of data caused by proper or improper use of this
 | 
|---|
| 5 | ; device driver.
 | 
|---|
| 6 | ; **********************************************************************
 | 
|---|
| 7 | ;
 | 
|---|
| 8 | ; compile with ALP
 | 
|---|
| 9 | ;
 | 
|---|
| 10 |   TITLE  ICCIO.ASM
 | 
|---|
| 11 |   .386
 | 
|---|
| 12 |   .387
 | 
|---|
| 13 | CODE32  SEGMENT DWORD USE32 PUBLIC 'CODE'
 | 
|---|
| 14 | CODE32  ENDS
 | 
|---|
| 15 | DATA32  SEGMENT DWORD USE32 PUBLIC 'DATA'
 | 
|---|
| 16 | DATA32  ENDS
 | 
|---|
| 17 | CONST32  SEGMENT DWORD USE32 PUBLIC 'CONST'
 | 
|---|
| 18 | CONST32  ENDS
 | 
|---|
| 19 | BSS32  SEGMENT DWORD USE32 PUBLIC 'BSS'
 | 
|---|
| 20 | BSS32  ENDS
 | 
|---|
| 21 | DGROUP  GROUP CONST32, BSS32, DATA32
 | 
|---|
| 22 |   ASSUME  CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT
 | 
|---|
| 23 | DATA32  SEGMENT
 | 
|---|
| 24 | DATA32  ENDS
 | 
|---|
| 25 | BSS32  SEGMENT
 | 
|---|
| 26 | BSS32  ENDS
 | 
|---|
| 27 | CONST32  SEGMENT
 | 
|---|
| 28 | CONST32  ENDS
 | 
|---|
| 29 | 
 | 
|---|
| 30 | DATA32  SEGMENT
 | 
|---|
| 31 | ioentry   DWORD  0
 | 
|---|
| 32 | gdt    WORD  0
 | 
|---|
| 33 | DATA32  ENDS
 | 
|---|
| 34 | 
 | 
|---|
| 35 | CODE32  SEGMENT
 | 
|---|
| 36 | 
 | 
|---|
| 37 | ; performs fast output of a byte to an I/O port
 | 
|---|
| 38 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 39 | ;
 | 
|---|
| 40 | ; Calling convention:
 | 
|---|
| 41 | ;  void c_outb1(short port,char data)
 | 
|---|
| 42 | ;
 | 
|---|
| 43 | ;
 | 
|---|
| 44 |   PUBLIC  c_outb1
 | 
|---|
| 45 |   ALIGN  04H
 | 
|---|
| 46 | c_outb1  PROC
 | 
|---|
| 47 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 48 |   MOV  AL, [ESP+8]    ; get data
 | 
|---|
| 49 |   OUT  DX,AL
 | 
|---|
| 50 |   RET
 | 
|---|
| 51 | c_outb1  ENDP
 | 
|---|
| 52 | 
 | 
|---|
| 53 | ; performs fast output of a word to an I/O port
 | 
|---|
| 54 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 55 | ;
 | 
|---|
| 56 | ; Calling convention:
 | 
|---|
| 57 | ;  void c_outw1(short port,short data)
 | 
|---|
| 58 | ;
 | 
|---|
| 59 | ;
 | 
|---|
| 60 |   PUBLIC  c_outw1
 | 
|---|
| 61 |   ALIGN  04H
 | 
|---|
| 62 | c_outw1  PROC
 | 
|---|
| 63 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 64 |   MOV  AX, [ESP+8]    ; get data
 | 
|---|
| 65 |   OUT  DX,AX
 | 
|---|
| 66 |   RET
 | 
|---|
| 67 | c_outw1  ENDP
 | 
|---|
| 68 | 
 | 
|---|
| 69 | ; performs fast output of a longword to an I/O port
 | 
|---|
| 70 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 71 | ;
 | 
|---|
| 72 | ; Calling convention:
 | 
|---|
| 73 | ;  void c_outl1(short port,long data)
 | 
|---|
| 74 | ;
 | 
|---|
| 75 | ;
 | 
|---|
| 76 |   PUBLIC  c_outl1
 | 
|---|
| 77 |   ALIGN  04H
 | 
|---|
| 78 | c_outl1  PROC
 | 
|---|
| 79 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 80 |   MOV  EAX, [ESP+8]    ; get data
 | 
|---|
| 81 |   OUT  DX, EAX
 | 
|---|
| 82 |   RET
 | 
|---|
| 83 | c_outl1  ENDP
 | 
|---|
| 84 | 
 | 
|---|
| 85 | ; performs fast input of a byte from an I/O port
 | 
|---|
| 86 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 87 | ;
 | 
|---|
| 88 | ; Calling convention:
 | 
|---|
| 89 | ;  char c_inb1(short port)
 | 
|---|
| 90 | ;
 | 
|---|
| 91 | ;
 | 
|---|
| 92 |   PUBLIC c_inb1
 | 
|---|
| 93 |   ALIGN  04H
 | 
|---|
| 94 | c_inb1  PROC
 | 
|---|
| 95 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 96 |   IN  AL,DX
 | 
|---|
| 97 |   AND  EAX, 000000FFh
 | 
|---|
| 98 |   RET
 | 
|---|
| 99 | c_inb1  ENDP
 | 
|---|
| 100 | 
 | 
|---|
| 101 | ; performs fast input of a word from an I/O port
 | 
|---|
| 102 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 103 | ;
 | 
|---|
| 104 | ; Calling convention:
 | 
|---|
| 105 | ;  short c_inw1(short port)
 | 
|---|
| 106 | ;
 | 
|---|
| 107 | ;
 | 
|---|
| 108 |   PUBLIC c_inw1
 | 
|---|
| 109 |   ALIGN  04H
 | 
|---|
| 110 | c_inw1  PROC
 | 
|---|
| 111 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 112 |   IN  AX, DX
 | 
|---|
| 113 |   AND  EAX, 0000FFFFh    ; mask out word
 | 
|---|
| 114 |   RET
 | 
|---|
| 115 | c_inw1  ENDP
 | 
|---|
| 116 | 
 | 
|---|
| 117 | ; performs fast input of a longword from an I/O port
 | 
|---|
| 118 | ; this routine is intended to be called from gcc C code
 | 
|---|
| 119 | ;
 | 
|---|
| 120 | ; Calling convention:
 | 
|---|
| 121 | ;  lomg c_inl1(short port)
 | 
|---|
| 122 | ;
 | 
|---|
| 123 | ;
 | 
|---|
| 124 |   PUBLIC c_inl1
 | 
|---|
| 125 |   ALIGN  04H
 | 
|---|
| 126 | c_inl1  PROC
 | 
|---|
| 127 |   MOV  EDX, [ESP+4]    ; get port
 | 
|---|
| 128 |   IN  EAX, DX
 | 
|---|
| 129 |   RET
 | 
|---|
| 130 | c_inl1  ENDP
 | 
|---|
| 131 | 
 | 
|---|
| 132 | CODE32  ENDS
 | 
|---|
| 133 | 
 | 
|---|
| 134 | ;------------------------------------------------------------------------------
 | 
|---|
| 135 | 
 | 
|---|
| 136 | ; Initialize I/O access via the driver.
 | 
|---|
| 137 | ; You *must* call this routine once for each *thread* that wants to do
 | 
|---|
| 138 | ; I/O.
 | 
|---|
| 139 | ;
 | 
|---|
| 140 | ; The routine is mainly equivalent to a C routine performing the
 | 
|---|
| 141 | ; following (but no need to add another file):
 | 
|---|
| 142 | ;  DosOpen("/dev/fastio$", read, nonexclusive)
 | 
|---|
| 143 | ;  DosDevIOCtl(device, XFREE86IO, IOGETSEL32)
 | 
|---|
| 144 | ;  selector -> ioentry+4
 | 
|---|
| 145 | ;  DosClose(device)
 | 
|---|
| 146 | ;
 | 
|---|
| 147 | ; Calling convention:
 | 
|---|
| 148 | ;  int io_init1(void)
 | 
|---|
| 149 | ; Return:
 | 
|---|
| 150 | ;  0 if successful
 | 
|---|
| 151 | ;  standard APIRET RETurn code if error
 | 
|---|
| 152 | ;
 | 
|---|
| 153 | 
 | 
|---|
| 154 | CONST32  SEGMENT
 | 
|---|
| 155 |   ALIGN  04H
 | 
|---|
| 156 | devname:
 | 
|---|
| 157 |   DB  "/dev/fastio$",0
 | 
|---|
| 158 | CONST32  ENDS
 | 
|---|
| 159 | 
 | 
|---|
| 160 | 
 | 
|---|
| 161 | CODE32  SEGMENT
 | 
|---|
| 162 |   PUBLIC  io_init1
 | 
|---|
| 163 |   EXTRN  DosOpen:PROC
 | 
|---|
| 164 |   EXTRN  DosClose:PROC
 | 
|---|
| 165 |   EXTRN  DosDevIOCtl:PROC
 | 
|---|
| 166 |   ALIGN  04H
 | 
|---|
| 167 | io_init1  PROC
 | 
|---|
| 168 |   PUSH  EBP
 | 
|---|
| 169 |   MOV  EBP, ESP  ; standard stack frame
 | 
|---|
| 170 |   SUB  ESP, 16    ; reserve memory
 | 
|---|
| 171 |         ; -16 = len arg of DosDevIOCtl
 | 
|---|
| 172 |         ; -12 = action arg of DosOpen
 | 
|---|
| 173 |         ; -8 = fd arg of DosOpen
 | 
|---|
| 174 |         ; -2 = short GDT selector arg
 | 
|---|
| 175 |   PUSH  0    ; (PEAOP2)NULL
 | 
|---|
| 176 |   PUSH  66    ; OPENACCESSREADWRITE|OPENSHAREDENYNONE
 | 
|---|
| 177 |   PUSH  1    ; FILEOPEN
 | 
|---|
| 178 |   PUSH  0    ; FILENORMAL
 | 
|---|
| 179 |   PUSH  0    ; initial size
 | 
|---|
| 180 |   LEA  EAX, [EBP-12]  ; Adress of 'action' arg
 | 
|---|
| 181 |   PUSH  EAX
 | 
|---|
| 182 |   LEA  EAX, [EBP-8]  ; Address of 'fd' arg
 | 
|---|
| 183 |   PUSH  EAX
 | 
|---|
| 184 |   PUSH  OFFSET FLAT:devname
 | 
|---|
| 185 |   CALL  DosOpen    ; call DosOpen
 | 
|---|
| 186 |   ADD  ESP, 32    ; cleanup stack frame
 | 
|---|
| 187 |   CMP  EAX, 0    ; is return code zero?
 | 
|---|
| 188 |   JE  goon    ; yes, proceed
 | 
|---|
| 189 |   LEAVE      ; no RETurn error
 | 
|---|
| 190 |   RET
 | 
|---|
| 191 |   ALIGN  04H
 | 
|---|
| 192 | goon:
 | 
|---|
| 193 |   LEA  EAX, [EBP-16]  ; address of 'len' arg of DosDevIOCtl
 | 
|---|
| 194 |   PUSH  EAX
 | 
|---|
| 195 |   PUSH  2    ; sizeof(short)
 | 
|---|
| 196 |   LEA  EAX, [EBP-2]  ; address to return the GDT selector
 | 
|---|
| 197 |   PUSH  EAX
 | 
|---|
| 198 |   PUSH  0    ; no parameter len
 | 
|---|
| 199 |   PUSH  0    ; no parameter size
 | 
|---|
| 200 |   PUSH  0    ; no parameter address
 | 
|---|
| 201 |   PUSH  100    ; function code IOGETSEL32
 | 
|---|
| 202 |   PUSH  118    ; category code XFREE6IO
 | 
|---|
| 203 |   MOV  EAX,[EBP-8]  ; file handle
 | 
|---|
| 204 |   PUSH  EAX
 | 
|---|
| 205 |   CALL  DosDevIOCtl  ; perform ioctl
 | 
|---|
| 206 |   ADD  ESP, 36    ; cleanup stack
 | 
|---|
| 207 |   CMP  EAX, 0    ; is return code = 0?
 | 
|---|
| 208 |   JE  ok    ; yes, proceed
 | 
|---|
| 209 |   PUSH  EAX    ; was error, save error code
 | 
|---|
| 210 |   MOV  EAX, [EBP-8]  ; file handle
 | 
|---|
| 211 |   PUSH  EAX
 | 
|---|
| 212 |   CALL  DosClose  ; close device
 | 
|---|
| 213 |   ADD  ESP,4    ; clean stack
 | 
|---|
| 214 |   POP  EAX    ; get error code
 | 
|---|
| 215 |   LEAVE      ; return error
 | 
|---|
| 216 |   RET
 | 
|---|
| 217 | 
 | 
|---|
| 218 |   ALIGN  04H
 | 
|---|
| 219 | ok:
 | 
|---|
| 220 |   MOV  EAX, [EBP-8]  ; file handle
 | 
|---|
| 221 |   PUSH  EAX    ; do normal close
 | 
|---|
| 222 |   CALL  DosClose
 | 
|---|
| 223 |   ADD  ESP,4    ; clean stack
 | 
|---|
| 224 | 
 | 
|---|
| 225 |   MOV  AX, [EBP-2]  ; load gdt selector
 | 
|---|
| 226 |   MOV  gdt, AX    ; store in ioentry address selector part
 | 
|---|
| 227 |   XOR  EAX, EAX  ; EAX = 0
 | 
|---|
| 228 |   MOV  DWORD PTR [ioentry], EAX ; clear ioentry offset part
 | 
|---|
| 229 |         ; return code = 0 (in EAX)
 | 
|---|
| 230 | 
 | 
|---|
| 231 |         ; now use this function to raise the IOPL
 | 
|---|
| 232 |   MOV  EBX,13    ; special function code
 | 
|---|
| 233 |   CALL  FWORD PTR [ioentry]  ; CALL intersegment indirect 16:32
 | 
|---|
| 234 | 
 | 
|---|
| 235 |   ; thread should now be running at IOPL=3
 | 
|---|
| 236 | 
 | 
|---|
| 237 |   XOR  EAX, EAX  ; return code = 0
 | 
|---|
| 238 |   LEAVE      ; clean stack frame
 | 
|---|
| 239 |   RET      ; exit
 | 
|---|
| 240 | io_init1 ENDP
 | 
|---|
| 241 | 
 | 
|---|
| 242 | ; void in_init(short)
 | 
|---|
| 243 | PUBLIC  io_init2
 | 
|---|
| 244 |   ALIGN  04H
 | 
|---|
| 245 | io_init2  PROC
 | 
|---|
| 246 | 
 | 
|---|
| 247 |   MOV  gdt, AX    ; store in ioentry address selector part
 | 
|---|
| 248 |   XOR  EAX, EAX  ; EAX = 0
 | 
|---|
| 249 |   MOV  DWORD PTR [ioentry], EAX ; clear ioentry offset part
 | 
|---|
| 250 |         ; return code = 0 (in EAX)
 | 
|---|
| 251 | 
 | 
|---|
| 252 |         ; now use this function to raise the IOPL
 | 
|---|
| 253 |   MOV  EBX,13    ; special function code
 | 
|---|
| 254 |   CALL  FWORD PTR [ioentry]  ; CALL intersegment indirect 16:32
 | 
|---|
| 255 | 
 | 
|---|
| 256 |   XOR  EAX, EAX  ; return code = 0
 | 
|---|
| 257 |   ret
 | 
|---|
| 258 | io_init2  ENDP
 | 
|---|
| 259 | 
 | 
|---|
| 260 |   PUBLIC  io_exit1
 | 
|---|
| 261 |   ALIGN  04H
 | 
|---|
| 262 | io_exit1  PROC
 | 
|---|
| 263 |   push  EBP
 | 
|---|
| 264 |   MOV  EBP, ESP  ; stackframe, I am accustomed to this :-)
 | 
|---|
| 265 | 
 | 
|---|
| 266 |   MOV  AX, gdt    ; check if ioinit was called once
 | 
|---|
| 267 |   OR  AX, AX
 | 
|---|
| 268 |   JZ  exerr    ; no gdt entry, so process cannot be at IOPL=3
 | 
|---|
| 269 |         ; through this mechanism
 | 
|---|
| 270 | 
 | 
|---|
| 271 |   MOV  EBX, 14    ; function code to disable iopl
 | 
|---|
| 272 |   CALL  FWORD PTR [ioentry]  ; call intersegment indirect 16:32
 | 
|---|
| 273 | 
 | 
|---|
| 274 |   ; process should now be at IOPL=3 again
 | 
|---|
| 275 |   XOR  EAX, EAX  ; ok, RETurn code = 0
 | 
|---|
| 276 |   LEAVE
 | 
|---|
| 277 |   RET
 | 
|---|
| 278 | exerr:  XOR  EAX, EAX  ; not ok, RETurn code = ffffffff
 | 
|---|
| 279 |   DEC  EAX
 | 
|---|
| 280 |   LEAVE
 | 
|---|
| 281 |   RET
 | 
|---|
| 282 | io_exit1  ENDP
 | 
|---|
| 283 | 
 | 
|---|
| 284 | 
 | 
|---|
| 285 | 
 | 
|---|
| 286 | ; for diagnostic only
 | 
|---|
| 287 | 
 | 
|---|
| 288 |   PUBLIC  psw
 | 
|---|
| 289 |   ALIGN  04H
 | 
|---|
| 290 | psw  PROC
 | 
|---|
| 291 |   PUSHF      ; get the current PSW
 | 
|---|
| 292 |   POP  EAX    ; into EAX
 | 
|---|
| 293 |   RET
 | 
|---|
| 294 | psw  ENDP
 | 
|---|
| 295 | 
 | 
|---|
| 296 | CODE32  ENDS
 | 
|---|
| 297 |   END
 | 
|---|