1/*
2 * PeeCeeI.c: The emerging standard...
3 *
4 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
5 */
6
7#include <linux/module.h>
8
9#include <asm/io.h>
10#include <asm/byteorder.h>
11
12void outsb(unsigned long __addr, const void *src, unsigned long count)
13{
14	void __iomem *addr = (void __iomem *) __addr;
15	const u8 *p = src;
16
17	while (count--)
18		__raw_writeb(*p++, addr);
19}
20EXPORT_SYMBOL(outsb);
21
22void outsw(unsigned long __addr, const void *src, unsigned long count)
23{
24	void __iomem *addr = (void __iomem *) __addr;
25
26	while (count--) {
27		__raw_writew(*(u16 *)src, addr);
28		src += sizeof(u16);
29	}
30}
31EXPORT_SYMBOL(outsw);
32
33void outsl(unsigned long __addr, const void *src, unsigned long count)
34{
35	void __iomem *addr = (void __iomem *) __addr;
36	u32 l, l2;
37
38	if (!count)
39		return;
40
41	switch (((unsigned long)src) & 0x3) {
42	case 0x0:
43		/* src is naturally aligned */
44		while (count--) {
45			__raw_writel(*(u32 *)src, addr);
46			src += sizeof(u32);
47		}
48		break;
49	case 0x2:
50		/* 2-byte alignment */
51		while (count--) {
52			l = (*(u16 *)src) << 16;
53			l |= *(u16 *)(src + sizeof(u16));
54			__raw_writel(l, addr);
55			src += sizeof(u32);
56		}
57		break;
58	case 0x1:
59		/* Hold three bytes in l each time, grab a byte from l2 */
60		l = (*(u8 *)src) << 24;
61		l |= (*(u16 *)(src + sizeof(u8))) << 8;
62		src += sizeof(u8) + sizeof(u16);
63		while (count--) {
64			l2 = *(u32 *)src;
65			l |= (l2 >> 24);
66			__raw_writel(l, addr);
67			l = l2 << 8;
68			src += sizeof(u32);
69		}
70		break;
71	case 0x3:
72		/* Hold a byte in l each time, grab 3 bytes from l2 */
73		l = (*(u8 *)src) << 24;
74		src += sizeof(u8);
75		while (count--) {
76			l2 = *(u32 *)src;
77			l |= (l2 >> 8);
78			__raw_writel(l, addr);
79			l = l2 << 24;
80			src += sizeof(u32);
81		}
82		break;
83	}
84}
85EXPORT_SYMBOL(outsl);
86
87void insb(unsigned long __addr, void *dst, unsigned long count)
88{
89	void __iomem *addr = (void __iomem *) __addr;
90
91	if (count) {
92		u32 *pi;
93		u8 *pb = dst;
94
95		while ((((unsigned long)pb) & 0x3) && count--)
96			*pb++ = __raw_readb(addr);
97		pi = (u32 *)pb;
98		while (count >= 4) {
99			u32 w;
100
101			w  = (__raw_readb(addr) << 24);
102			w |= (__raw_readb(addr) << 16);
103			w |= (__raw_readb(addr) << 8);
104			w |= (__raw_readb(addr) << 0);
105			*pi++ = w;
106			count -= 4;
107		}
108		pb = (u8 *)pi;
109		while (count--)
110			*pb++ = __raw_readb(addr);
111	}
112}
113EXPORT_SYMBOL(insb);
114
115void insw(unsigned long __addr, void *dst, unsigned long count)
116{
117	void __iomem *addr = (void __iomem *) __addr;
118
119	if (count) {
120		u16 *ps = dst;
121		u32 *pi;
122
123		if (((unsigned long)ps) & 0x2) {
124			*ps++ = __raw_readw(addr);
125			count--;
126		}
127		pi = (u32 *)ps;
128		while (count >= 2) {
129			u32 w;
130
131			w  = __raw_readw(addr) << 16;
132			w |= __raw_readw(addr) << 0;
133			*pi++ = w;
134			count -= 2;
135		}
136		ps = (u16 *)pi;
137		if (count)
138			*ps = __raw_readw(addr);
139	}
140}
141EXPORT_SYMBOL(insw);
142
143void insl(unsigned long __addr, void *dst, unsigned long count)
144{
145	void __iomem *addr = (void __iomem *) __addr;
146
147	if (count) {
148		if ((((unsigned long)dst) & 0x3) == 0) {
149			u32 *pi = dst;
150			while (count--)
151				*pi++ = __raw_readl(addr);
152		} else {
153			u32 l = 0, l2, *pi;
154			u16 *ps;
155			u8 *pb;
156
157			switch (((unsigned long)dst) & 3) {
158			case 0x2:
159				ps = dst;
160				count -= 1;
161				l = __raw_readl(addr);
162				*ps++ = l;
163				pi = (u32 *)ps;
164				while (count--) {
165					l2 = __raw_readl(addr);
166					*pi++ = (l << 16) | (l2 >> 16);
167					l = l2;
168				}
169				ps = (u16 *)pi;
170				*ps = l;
171				break;
172
173			case 0x1:
174				pb = dst;
175				count -= 1;
176				l = __raw_readl(addr);
177				*pb++ = l >> 24;
178				ps = (u16 *)pb;
179				*ps++ = ((l >> 8) & 0xffff);
180				pi = (u32 *)ps;
181				while (count--) {
182					l2 = __raw_readl(addr);
183					*pi++ = (l << 24) | (l2 >> 8);
184					l = l2;
185				}
186				pb = (u8 *)pi;
187				*pb = l;
188				break;
189
190			case 0x3:
191				pb = (u8 *)dst;
192				count -= 1;
193				l = __raw_readl(addr);
194				*pb++ = l >> 24;
195				pi = (u32 *)pb;
196				while (count--) {
197					l2 = __raw_readl(addr);
198					*pi++ = (l << 8) | (l2 >> 24);
199					l = l2;
200				}
201				ps = (u16 *)pi;
202				*ps++ = ((l >> 8) & 0xffff);
203				pb = (u8 *)ps;
204				*pb = l;
205				break;
206			}
207		}
208	}
209}
210EXPORT_SYMBOL(insl);
211
212