| 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 | 
|---|