| Adrian Bunk | b00dc83 | 2008-05-19 16:52:27 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * PeeCeeI.c: The emerging standard... | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | 
|  | 5 | */ | 
|  | 6 |  | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 7 | #include <linux/module.h> | 
|  | 8 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | #include <asm/io.h> | 
|  | 10 | #include <asm/byteorder.h> | 
|  | 11 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 12 | void outsb(unsigned long __addr, const void *src, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 14 | void __iomem *addr = (void __iomem *) __addr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | const u8 *p = src; | 
|  | 16 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 17 | while (count--) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | outb(*p++, addr); | 
|  | 19 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 20 | EXPORT_SYMBOL(outsb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 22 | void outsw(unsigned long __addr, const void *src, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 24 | void __iomem *addr = (void __iomem *) __addr; | 
|  | 25 |  | 
| Harvey Harrison | 1758ef6 | 2008-10-29 15:33:28 -0700 | [diff] [blame] | 26 | while (count--) { | 
|  | 27 | __raw_writew(*(u16 *)src, addr); | 
|  | 28 | src += sizeof(u16); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | } | 
|  | 30 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 31 | EXPORT_SYMBOL(outsw); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 33 | void outsl(unsigned long __addr, const void *src, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 35 | void __iomem *addr = (void __iomem *) __addr; | 
| Harvey Harrison | 1758ef6 | 2008-10-29 15:33:28 -0700 | [diff] [blame] | 36 | u32 l, l2; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 37 |  | 
| Harvey Harrison | 1758ef6 | 2008-10-29 15:33:28 -0700 | [diff] [blame] | 38 | if (!count) | 
|  | 39 | return; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 |  | 
| Harvey Harrison | 1758ef6 | 2008-10-29 15:33:28 -0700 | [diff] [blame] | 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); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | } | 
| Harvey Harrison | 1758ef6 | 2008-10-29 15:33:28 -0700 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | } | 
|  | 84 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 85 | EXPORT_SYMBOL(outsl); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 87 | void insb(unsigned long __addr, void *dst, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 89 | void __iomem *addr = (void __iomem *) __addr; | 
|  | 90 |  | 
|  | 91 | if (count) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | u32 *pi; | 
|  | 93 | u8 *pb = dst; | 
|  | 94 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 95 | while ((((unsigned long)pb) & 0x3) && count--) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | *pb++ = inb(addr); | 
|  | 97 | pi = (u32 *)pb; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 98 | while (count >= 4) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | u32 w; | 
|  | 100 |  | 
|  | 101 | w  = (inb(addr) << 24); | 
|  | 102 | w |= (inb(addr) << 16); | 
|  | 103 | w |= (inb(addr) << 8); | 
|  | 104 | w |= (inb(addr) << 0); | 
|  | 105 | *pi++ = w; | 
|  | 106 | count -= 4; | 
|  | 107 | } | 
|  | 108 | pb = (u8 *)pi; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 109 | while (count--) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | *pb++ = inb(addr); | 
|  | 111 | } | 
|  | 112 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 113 | EXPORT_SYMBOL(insb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 115 | void insw(unsigned long __addr, void *dst, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 117 | void __iomem *addr = (void __iomem *) __addr; | 
|  | 118 |  | 
|  | 119 | if (count) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | u16 *ps = dst; | 
|  | 121 | u32 *pi; | 
|  | 122 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 123 | if (((unsigned long)ps) & 0x2) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 124 | *ps++ = le16_to_cpu(inw(addr)); | 
|  | 125 | count--; | 
|  | 126 | } | 
|  | 127 | pi = (u32 *)ps; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 128 | while (count >= 2) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | u32 w; | 
|  | 130 |  | 
|  | 131 | w  = (le16_to_cpu(inw(addr)) << 16); | 
|  | 132 | w |= (le16_to_cpu(inw(addr)) << 0); | 
|  | 133 | *pi++ = w; | 
|  | 134 | count -= 2; | 
|  | 135 | } | 
|  | 136 | ps = (u16 *)pi; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 137 | if (count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | *ps = le16_to_cpu(inw(addr)); | 
|  | 139 | } | 
|  | 140 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 141 | EXPORT_SYMBOL(insw); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 143 | void insl(unsigned long __addr, void *dst, unsigned long count) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 | { | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 145 | void __iomem *addr = (void __iomem *) __addr; | 
|  | 146 |  | 
|  | 147 | if (count) { | 
|  | 148 | if ((((unsigned long)dst) & 0x3) == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | u32 *pi = dst; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 150 | while (count--) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | *pi++ = le32_to_cpu(inl(addr)); | 
|  | 152 | } else { | 
|  | 153 | u32 l = 0, l2, *pi; | 
|  | 154 | u16 *ps; | 
|  | 155 | u8 *pb; | 
|  | 156 |  | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 157 | switch (((unsigned long)dst) & 3) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 | case 0x2: | 
|  | 159 | ps = dst; | 
|  | 160 | count -= 1; | 
|  | 161 | l = le32_to_cpu(inl(addr)); | 
|  | 162 | *ps++ = l; | 
|  | 163 | pi = (u32 *)ps; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 164 | while (count--) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 165 | l2 = le32_to_cpu(inl(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 = le32_to_cpu(inl(addr)); | 
|  | 177 | *pb++ = l >> 24; | 
|  | 178 | ps = (u16 *)pb; | 
|  | 179 | *ps++ = ((l >> 8) & 0xffff); | 
|  | 180 | pi = (u32 *)ps; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 181 | while (count--) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 | l2 = le32_to_cpu(inl(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 = le32_to_cpu(inl(addr)); | 
|  | 194 | *pb++ = l >> 24; | 
|  | 195 | pi = (u32 *)pb; | 
| David S. Miller | 8a36895 | 2005-08-31 15:01:33 -0700 | [diff] [blame] | 196 | while (count--) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 197 | l2 = le32_to_cpu(inl(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 | } | 
| Sam Ravnborg | 917c366 | 2009-01-08 16:58:20 -0800 | [diff] [blame] | 210 | EXPORT_SYMBOL(insl); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 |  |