/* (-lgl * Coherent 386 release 4.2 * Copyright (c) 1982, 1993 by Mark Williams Company. * All rights reserved. May not be copied without permission. * For copying permission and licensing info, write licensing@mwc.com -lgl) */ #ifndef __KERNEL_X86IO_H__ #define __KERNEL_X86IO_H__ /* * The system V DDI/DKI for Intel processors defines a C-language interface to * the machine I/O instructions available through <sys/types.h>. * * For simplicity, this has been factored out into a separate file for this * implementation, and <sys/types.h> pulls this file in. */ #include <common/ccompat.h> #include <common/feature.h> #include <common/xdebug.h> #include <common/__types.h> /* * Get these into a useful form in a similar manner to the way the spl... () * functions are defined in <sys/inline.h> */ #if __GNUC__ && _I386 /* 80386 with GNU CC */ /* * It appears that the code GCC produces is sufficiently good that we can * run into problems with I/O recovery times on older boards, especially with * 386's. So, we allow for the possibility of delaying for a brief time. */ #ifndef __IO_RECOVER # if 1 # define __IO_RECOVER "" # else # define __IO_RECOVER ";jmp LIO%=a;LIO%=a:;jmp LIO%=b;LIO%=b:" # endif #endif /* * Similarly to the above, it may be that using the REP instruction prefix * with I/O instructions may cause problems with motherboards or peripheral * failure to meet bus timings. To permit investigation of this problem we * allow either the REP prefix or the LOOP instruction to be used. */ #if _USE_REP_PREFIX # define __REPEAT(instr) ";rep;" instr #else # define __REPEAT(instr) ";LX%=: " instr "; loop LX%=" #endif /* * Note that the definitions for the string-input instructions assume that * ES: is equivalent to DS:. */ __LOCAL__ __INLINE__ __uchar_t __inb (int _port) { __uchar_t _result; __NON_ISO (asm) volatile ("in %1,%0" __IO_RECOVER : "=a" (_result) : "d" ((__ushort_t) _port)); return _result; } __LOCAL__ __INLINE__ __ulong_t __inl (int _port) { __ulong_t _result; __NON_ISO (asm) volatile ("in %1,%0" __IO_RECOVER : "=a" (_result) : "d" ((__ushort_t) _port)); return _result; } __LOCAL__ __INLINE__ __ushort_t __inw (int _port) { __ushort_t _result; __NON_ISO (asm) volatile ("in %1,%0" __IO_RECOVER : "=a" (_result) : "d" ((__ushort_t) _port)); return _result; } __LOCAL__ __INLINE__ void __outb (int _port, __uchar_t value) { __NON_ISO (asm) volatile ("out %1,%0" __IO_RECOVER : : "d" ((__ushort_t) _port), "a" (value)); } __LOCAL__ __INLINE__ void __outl (int _port, __ulong_t value) { __NON_ISO (asm) volatile ("out %1,%0" __IO_RECOVER : : "d" ((__ushort_t) _port), "a" (value)); } __LOCAL__ __INLINE__ void __outw (int _port, __ushort_t value) { __NON_ISO (asm) volatile ("out %1,%0" __IO_RECOVER : : "d" ((__ushort_t) _port), "a" (value)); } __LOCAL__ __INLINE__ void __repinsb (int _port, __uchar_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("mov %1,%%edi" __REPEAT ("insb") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "di"); } __LOCAL__ __INLINE__ void __repinsd (int _port, __ulong_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("mov %1,%%edi" __REPEAT ("insl") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "di"); } __LOCAL__ __INLINE__ void __repinsw (int _port, __ushort_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("mov %1,%%edi" __REPEAT ("insw") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "di"); } __LOCAL__ __INLINE__ void __repoutsb (int _port, __uchar_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("mov %1,%%esi" __REPEAT ("outsb") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "si"); } __LOCAL__ __INLINE__ void __repoutsd (int _port, __ulong_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("movl %1,%%esi" __REPEAT ("outsl") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "si"); } __LOCAL__ __INLINE__ void __repoutsw (int _port, __ushort_t * _addr, int _cnt) { __NON_ISO (asm) volatile ("movl %1,%%esi" __REPEAT ("outsw") : : "d" ((__ushort_t) _port), "g" (_addr), "c" (_cnt) : "si"); } #define __FORWARD_inb__ #define __FORWARD_inl__ #define __FORWARD_inw__ #define __FORWARD_outb__ #define __FORWARD_outl__ #define __FORWARD_outw__ #define __FORWARD_repinsb__ #define __FORWARD_repinsd__ #define __FORWARD_repinsw__ #define __FORWARD_repoutsb__ #define __FORWARD_repoutsd__ #define __FORWARD_repoutsw__ #elif __BORLANDC__ void __emit__ (unsigned char __byte, ...); /* * Note the use of the 0x66 operand-size override prefix below, which is built * on the assumption that Borland generates 16-bit code segments. */ #define __REP__ 0xF3 /* repeat-prefix */ #define __INB__ 0xEC #define __INW__ 0xED #define __INL__ 0x66, __INW__ /* size-override for 32-bit form */ #define __OUTB__ 0xEE #define __OUTW__ 0xEF #define __OUTL__ 0x66, __OUTW__ /* size-override for 32-bit form */ #define __INSB__ 0x6C #define __INSW__ 0x6D #define __INSL__ 0x65, __INSW__ #define __OUTSB__ 0x6E #define __OUTSW__ 0x6F /* word/long depending on CS: */ #define __OUTSL__ 0x66, __OUTSW__ /* * If we are willing to restrict ourselves to i386's, Borland C++ 3.1 allows * support for 32-bit register-pseudovariables if 386 code generation has * been enabled. * * As it turns out, there are all kinds of bugs in the 386 support in BC++ 3.1 * but enough works that we can even get a far pointer into ES:whatever via * a 32-bit register, as long as the intermediate register isn't _ESI or _EDI * since _EAX = _ESI or _EAX = _EDI only moves the low 16 bits. Being able to * load ES:whatever via a 32-bit register allows us to write macros that only * reference each argument exactly once. * * While the 32-bit-pointer version still works in the near models, it's not * exactly optimal, so we use a more straightforward version there. */ #define __inb(port) (_DX = (port), __emit__ (__INB__),\ (__uchar_t) _AL) #define __inl(port) (_DX = (port), __emit__ (__INL__), _EAX) #define __inw(port) (_DX = (port), __emit__ (__INW__), \ (__ushort_t) _AX) #define __outb(port,value) (_DX = (port), _AL = (value), \ __emit__ (__OUTB__)) #define __outl(port,value) (_DX = (port), _EAX = (value), \ __emit__ (__OUTL__)) #define __outw(port,value) (_DX = (port), _AX = (value), \ __emit__ (__OUTW__)) #if defined (__LARGE__) || defined (__HUGE__) || defined (__COMPACT__) #define __repins(p,a,c) (_EDX = (long) (void __far *) (a), _EAX = _EDX,\ _ES = (unsigned) (_EAX >> 16),\ _DI = _DX, _CX = (c), _DX = (p)) #define __repouts(p,a,c) (_EDX = (long) (void _far *) (a), _EAX = _EDX,\ _ES = (unsigned) (_EAX >> 16),\ _SI = _DX, _CX = (c), _DX = (p)) #else /* use simpler small-data versions */ #define __repins(p,a,c) (_ES = _DS, _DI = (unsigned) (a), \ _CX = (c), _DX = (p)) #define __repouts(p,a,c) (_ES = _DS, _SI = (unsigned) (a), \ _CX = (c), _DX = (p)) #endif #define __repinsb(p,a,c) (__repins (p, a, c),\ __emit__ (__REP__, __INSB__)) #define __repinsd(p,a,c) (__repins (p, a, c),\ __emit__ (__REP__, __INSL__)) #define __repinsw(p,a,c) (__repins (p, a, c),\ __emit__ (__REP__, __INSW__)) #define __repoutsb(p,a,c) (__repouts (p, a, c),\ __emit__ (__REP__, __OUTSB__)) #define __repoutsd(p,a,c) (__repouts (p, a, c),\ __emit__ (__REP__, __OUTSL__)) #define __repoutsw(p,a,c) (__repouts (p, a, c),\ __emit__ (__REP__, __OUTSW__)) #define __FORWARD_inb__ #define __FORWARD_inl__ #define __FORWARD_inw__ #define __FORWARD_outb__ #define __FORWARD_outl__ #define __FORWARD_outw__ #define __FORWARD_repinsb__ #define __FORWARD_repinsd__ #define __FORWARD_repinsw__ #define __FORWARD_repoutsb__ #define __FORWARD_repoutsd__ #define __FORWARD_repoutsw__ #endif __EXTERN_C_BEGIN__ __uchar_t inb __PROTO ((int _port)); __ulong_t inl __PROTO ((int _port)); __ushort_t inw __PROTO ((int _port)); void outb __PROTO ((int _port, __uchar_t _value)); void outl __PROTO ((int _port, __ulong_t _value)); void outw __PROTO ((int _port, __ushort_t _value)); void repinsb __PROTO ((int _port, __uchar_t * _addr, int _cnt)); void repinsd __PROTO ((int _port, __ulong_t * _addr, int _cnt)); void repinsw __PROTO ((int _port, __ushort_t * _addr, int _cnt)); void repoutsb __PROTO ((int _port, __uchar_t * _addr, int _cnt)); void repoutsd __PROTO ((int _port, __ulong_t * _addr, int _cnt)); void repoutsw __PROTO ((int _port, __ushort_t * _addr, int _cnt)); __EXTERN_C_END__ #ifdef __FORWARD_inb__ # define inb(port) __inb (port) #endif #ifdef __FORWARD_inl__ # define inl(port) __inl (port) #endif #ifdef __FORWARD_inw__ # define inw(port) __inw (port) #endif #ifdef __FORWARD_outb__ # define outb(port,val) __outb (port, val) #endif #ifdef __FORWARD_outl__ # define outl(port,val) __outl (port, val) #endif #ifdef __FORWARD_outw__ # define outw(port,val) __outw (port, val) #endif #ifdef __FORWARD_repinsb__ # define repinsb(p,a,c) __repinsb (p, a, c) #endif #ifdef __FORWARD_repinsd__ # define repinsd(p,a,c) __repinsd (p, a, c) #endif #ifdef __FORWARD_repinsw__ # define repinsw(p,a,c) __repinsw (p, a, c) #endif #ifdef __FORWARD_repoutsb__ # define repoutsb(p,a,c) __repoutsb (p, a, c) #endif #ifdef __FORWARD_repoutsd__ # define repoutsd(p,a,c) __repoutsd (p, a, c) #endif #ifdef __FORWARD_repoutsw__ # define repoutsw(p,a,c) __repoutsw (p, a, c) #endif #undef __FORWARD_inb__ #undef __FORWARD_inl__ #undef __FORWARD_inw__ #undef __FORWARD_outb__ #undef __FORWARD_outl__ #undef __FORWARD_outw__ #undef __FORWARD_repinsb__ #undef __FORWARD_repinsd__ #undef __FORWARD_repinsw__ #undef __FORWARD_repoutsb__ #undef __FORWARD_repoutsd__ #undef __FORWARD_repoutsw__ #endif /* ! defined (__KERNEL_X86IO_H__) */