Martin Roth | 9b1b335 | 2016-02-24 12:27:06 -0800 | [diff] [blame] | 1 | #ifndef _ASM_IO_H |
| 2 | #define _ASM_IO_H |
| 3 | |
| 4 | /* |
| 5 | * This file contains the definitions for the x86 IO instructions |
| 6 | * inb/inw/inl/outb/outw/outl and the "string versions" of the same |
| 7 | * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing" |
| 8 | * versions of the single-IO instructions (inb_p/inw_p/..). |
| 9 | * |
| 10 | * This file is not meant to be obfuscating: it's just complicated |
| 11 | * to (a) handle it all in a way that makes gcc able to optimize it |
| 12 | * as well as possible and (b) trying to avoid writing the same thing |
| 13 | * over and over again with slight variations and possibly making a |
| 14 | * mistake somewhere. |
| 15 | */ |
| 16 | |
| 17 | #ifdef SLOW_IO_BY_JUMPING |
| 18 | #define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") |
| 19 | #else |
| 20 | #define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") |
| 21 | #endif |
| 22 | |
| 23 | #ifdef REALLY_SLOW_IO |
| 24 | #define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } |
| 25 | #else |
| 26 | #define SLOW_DOWN_IO __SLOW_DOWN_IO |
| 27 | #endif |
| 28 | |
| 29 | /* |
| 30 | * Talk about misusing macros.. |
| 31 | */ |
| 32 | |
| 33 | #define __OUT1(s,x) \ |
Martin Roth | 3325fc4 | 2016-02-24 13:15:19 -0800 | [diff] [blame] | 34 | static inline void __out##s(unsigned x value, unsigned short port) { |
Martin Roth | 9b1b335 | 2016-02-24 12:27:06 -0800 | [diff] [blame] | 35 | |
| 36 | #define __OUT2(s,s1,s2) \ |
| 37 | __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" |
| 38 | |
| 39 | #define __OUT(s,s1,x) \ |
| 40 | __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ |
| 41 | __OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ |
| 42 | __OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ |
| 43 | __OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } |
| 44 | |
| 45 | #define __IN1(s) \ |
Martin Roth | 3325fc4 | 2016-02-24 13:15:19 -0800 | [diff] [blame] | 46 | static inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v; |
Martin Roth | 9b1b335 | 2016-02-24 12:27:06 -0800 | [diff] [blame] | 47 | |
| 48 | #define __IN2(s,s1,s2) \ |
| 49 | __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" |
| 50 | |
| 51 | #define __IN(s,s1,i...) \ |
| 52 | __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ |
| 53 | __IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ |
| 54 | __IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ |
| 55 | __IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } |
| 56 | |
| 57 | #define __OUTS(s) \ |
| 58 | extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ |
| 59 | { __asm__ __volatile__ ("cld ; rep ; outs" #s \ |
| 60 | : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } |
| 61 | |
| 62 | #define RETURN_TYPE unsigned char |
| 63 | /* __IN(b,"b","0" (0)) */ |
| 64 | __IN(b,"") |
| 65 | #undef RETURN_TYPE |
| 66 | #define RETURN_TYPE unsigned short |
| 67 | /* __IN(w,"w","0" (0)) */ |
| 68 | __IN(w,"") |
| 69 | #undef RETURN_TYPE |
| 70 | #define RETURN_TYPE unsigned int |
| 71 | __IN(l,"") |
| 72 | #undef RETURN_TYPE |
| 73 | |
| 74 | __OUT(b,"b",char) |
| 75 | __OUT(w,"w",short) |
| 76 | __OUT(l,,int) |
| 77 | |
| 78 | __OUTS(b) |
| 79 | __OUTS(w) |
| 80 | __OUTS(l) |
| 81 | |
| 82 | /* |
| 83 | * Note that due to the way __builtin_constant_p() works, you |
| 84 | * - can't use it inside a inline function (it will never be true) |
| 85 | * - you don't have to worry about side effects within the __builtin.. |
| 86 | */ |
| 87 | #define outb(val,port) \ |
| 88 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 89 | __outbc((val),(port)) : \ |
| 90 | __outb((val),(port))) |
| 91 | |
| 92 | #define inb(port) \ |
| 93 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 94 | __inbc(port) : \ |
| 95 | __inb(port)) |
| 96 | |
| 97 | |
| 98 | #define outw(val,port) \ |
| 99 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 100 | __outwc((val),(port)) : \ |
| 101 | __outw((val),(port))) |
| 102 | |
| 103 | #define inw(port) \ |
| 104 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 105 | __inwc(port) : \ |
| 106 | __inw(port)) |
| 107 | |
| 108 | |
| 109 | #define outl(val,port) \ |
| 110 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 111 | __outlc((val),(port)) : \ |
| 112 | __outl((val),(port))) |
| 113 | |
| 114 | #define inl(port) \ |
| 115 | ((__builtin_constant_p((port)) && (port) < 256) ? \ |
| 116 | __inlc(port) : \ |
| 117 | __inl(port)) |
| 118 | #endif |