aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm/io.h
blob: c0cbcd16137c749988dc05cfda0c45ab629f6d36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#ifndef _ASM_IO_H
#define _ASM_IO_H

/*
 * Thanks to James van Artsdalen for a better timing-fix than
 * the two short jumps: using outb's to a nonexistent port seems
 * to guarantee better timings even on fast machines.
 *
 * On the other hand, I'd like to be sure of a non-existent port:
 * I feel a bit unsafe about using 0x80.
 *
 *		Linus
 */

#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
#else
#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
#endif

#ifdef REALLY_SLOW_IO
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
#else
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif

/* This is the more general version of outb.. */
extern inline void __outb(unsigned char value, unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%w1"
		: /* no outputs */
		:"a" (value),"d" (port));
}

/* this is used for constant port numbers < 256.. */
extern inline void __outbc(unsigned char value, unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%1"
		: /* no outputs */
		:"a" (value),"i" (port));
}

/* general version of inb */
extern inline unsigned int __inb(unsigned short port)
{
	unsigned int _v;
__asm__ __volatile__ ("inb %w1,%b0"
		:"=a" (_v):"d" (port),"0" (0));
	return _v;
}

/* inb with constant port nr 0-255 */
extern inline unsigned int __inbc(unsigned short port)
{
	unsigned int _v;
__asm__ __volatile__ ("inb %1,%b0"
		:"=a" (_v):"i" (port),"0" (0));
	return _v;
}

extern inline void __outb_p(unsigned char value, unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%w1"
		: /* no outputs */
		:"a" (value),"d" (port));
	SLOW_DOWN_IO;
}

extern inline void __outbc_p(unsigned char value, unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%1"
		: /* no outputs */
		:"a" (value),"i" (port));
	SLOW_DOWN_IO;
}

extern inline unsigned int __inb_p(unsigned short port)
{
	unsigned int _v;
__asm__ __volatile__ ("inb %w1,%b0"
		:"=a" (_v):"d" (port),"0" (0));
	SLOW_DOWN_IO;
	return _v;
}

extern inline unsigned int __inbc_p(unsigned short port)
{
	unsigned int _v;
__asm__ __volatile__ ("inb %1,%b0"
		:"=a" (_v):"i" (port),"0" (0));
	SLOW_DOWN_IO;
	return _v;
}

/*
 * Note that due to the way __builtin_constant_p() works, you
 *  - can't use it inside a inline function (it will never be true)
 *  - you don't have to worry about side effects within the __builtin..
 */
#define outb(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
	__outbc((val),(port)) : \
	__outb((val),(port)))

#define inb(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
	__inbc(port) : \
	__inb(port))

#define outb_p(val,port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
	__outbc_p((val),(port)) : \
	__outb_p((val),(port)))

#define inb_p(port) \
((__builtin_constant_p((port)) && (port) < 256) ? \
	__inbc_p(port) : \
	__inb_p(port))

#endif