summaryrefslogtreecommitdiffstats
path: root/arch/alpha/lib/io.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /arch/alpha/lib/io.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/alpha/lib/io.c')
-rw-r--r--arch/alpha/lib/io.c363
1 files changed, 333 insertions, 30 deletions
diff --git a/arch/alpha/lib/io.c b/arch/alpha/lib/io.c
index b5f7290ab..405a3afa8 100644
--- a/arch/alpha/lib/io.c
+++ b/arch/alpha/lib/io.c
@@ -2,6 +2,8 @@
* Alpha IO and memory functions.. Just expand the inlines in the header
* files..
*/
+#include <linux/kernel.h>
+
#include <asm/io.h>
/*
@@ -9,90 +11,391 @@
* byte-wide IO.
*/
#ifdef __is_local
-#undef __bus_inb
-unsigned int __bus_inb(unsigned long addr)
+
+unsigned int _bus_inb(unsigned long addr)
{
- return ___bus_inb(addr);
+ return __bus_inb(addr);
}
-#undef __bus_outb
-void __bus_outb(unsigned char b, unsigned long addr)
+void _bus_outb(unsigned char b, unsigned long addr)
{
- ___bus_outb(b, addr);
+ __bus_outb(b, addr);
}
#endif
-#undef inb
-unsigned int inb(unsigned long addr)
+unsigned int _inb(unsigned long addr)
{
return __inb(addr);
}
-#undef inw
-unsigned int inw(unsigned long addr)
+unsigned int _inw(unsigned long addr)
{
return __inw(addr);
}
-#undef inl
-unsigned int inl(unsigned long addr)
+unsigned int _inl(unsigned long addr)
{
return __inl(addr);
}
-#undef outb
-void outb(unsigned char b, unsigned long addr)
+void _outb(unsigned char b, unsigned long addr)
{
__outb(b, addr);
}
-#undef outw
-void outw(unsigned short b, unsigned long addr)
+void _outw(unsigned short b, unsigned long addr)
{
__outw(b, addr);
}
-#undef outl
-void outl(unsigned int b, unsigned long addr)
+void _outl(unsigned int b, unsigned long addr)
{
__outl(b, addr);
}
-#undef readb
-unsigned long readb(unsigned long addr)
+unsigned long _readb(unsigned long addr)
{
return __readb(addr);
}
-#undef readw
-unsigned long readw(unsigned long addr)
+unsigned long _readw(unsigned long addr)
{
return __readw(addr);
}
-#undef readl
-unsigned long readl(unsigned long addr)
+unsigned long _readl(unsigned long addr)
{
return __readl(addr);
}
-#undef writeb
-void writeb(unsigned short b, unsigned long addr)
+void _writeb(unsigned char b, unsigned long addr)
{
__writeb(b, addr);
}
-#undef writew
-void writew(unsigned short b, unsigned long addr)
+void _writew(unsigned short b, unsigned long addr)
{
__writew(b, addr);
}
-#undef writel
-void writel(unsigned int b, unsigned long addr)
+void _writel(unsigned int b, unsigned long addr)
{
__writel(b, addr);
}
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+ while (((unsigned long)dst) & 0x3) {
+ if (!count)
+ return;
+ count--;
+ *(unsigned char *) dst = inb(port);
+ ((unsigned char *) dst)++;
+ }
+
+ while (count >= 4) {
+ unsigned int w;
+ count -= 4;
+ w = inb(port);
+ w |= inb(port) << 8;
+ w |= inb(port) << 16;
+ w |= inb(port) << 24;
+ *(unsigned int *) dst = w;
+ ((unsigned int *) dst)++;
+ }
+
+ while (count) {
+ --count;
+ *(unsigned char *) dst = inb(port);
+ ((unsigned char *) dst)++;
+ }
+}
+
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC. SRC must be at least short aligned. This is used by the
+ * IDE driver to read disk sectors. Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void insw (unsigned long port, void *dst, unsigned long count)
+{
+ if (((unsigned long)dst) & 0x3) {
+ if (((unsigned long)dst) & 0x1) {
+ panic("insw: memory not short aligned");
+ }
+ if (!count)
+ return;
+ count--;
+ *(unsigned short* ) dst = inw(port);
+ ((unsigned short *) dst)++;
+ }
+
+ while (count >= 2) {
+ unsigned int w;
+ count -= 2;
+ w = inw(port);
+ w |= inw(port) << 16;
+ *(unsigned int *) dst = w;
+ ((unsigned int *) dst)++;
+ }
+
+ if (count) {
+ *(unsigned short*) dst = inw(port);
+ }
+}
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void insl (unsigned long port, void *dst, unsigned long count)
+{
+ unsigned int l = 0, l2;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long) dst) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count--)
+ {
+ *(unsigned int *) dst = inl(port);
+ ((unsigned int *) dst)++;
+ }
+ break;
+
+ /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */
+
+ case 0x02: /* Buffer 16-bit aligned */
+ --count;
+
+ l = inl(port);
+ *(unsigned short *) dst = l;
+ ((unsigned short *) dst)++;
+
+ while (count--)
+ {
+ l2 = inl(port);
+ *(unsigned int *) dst = l >> 16 | l2 << 16;
+ ((unsigned int *) dst)++;
+ l = l2;
+ }
+ *(unsigned short *) dst = l >> 16;
+ break;
+ case 0x01: /* Buffer 8-bit aligned */
+ --count;
+
+ l = inl(port);
+ *(unsigned char *) dst = l;
+ ((unsigned char *) dst)++;
+ *(unsigned short *) dst = l >> 8;
+ ((unsigned short *) dst)++;
+ while (count--)
+ {
+ l2 = inl(port);
+ *(unsigned int *) dst = l >> 24 | l2 << 8;
+ ((unsigned int *) dst)++;
+ l = l2;
+ }
+ *(unsigned char *) dst = l >> 24;
+ break;
+ case 0x03: /* Buffer 8-bit aligned */
+ --count;
+
+ l = inl(port);
+ *(unsigned char *) dst = l;
+ ((unsigned char *) dst)++;
+ while (count--)
+ {
+ l2 = inl(port);
+ *(unsigned int *) dst = l << 24 | l2 >> 8;
+ ((unsigned int *) dst)++;
+ l = l2;
+ }
+ *(unsigned short *) dst = l >> 8;
+ ((unsigned short *) dst)++;
+ *(unsigned char *) dst = l >> 24;
+ break;
+ }
+}
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void outsb(unsigned long port, const void * src, unsigned long count)
+{
+ while (count) {
+ count--;
+ outb(*(char *)src, port);
+ ((char *) src)++;
+ }
+}
+
+/*
+ * Like insw but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void outsw (unsigned long port, const void *src, unsigned long count)
+{
+ if (((unsigned long)src) & 0x3) {
+ if (((unsigned long)src) & 0x1) {
+ panic("outsw: memory not short aligned");
+ }
+ outw(*(unsigned short*)src, port);
+ ((unsigned short *) src)++;
+ --count;
+ }
+
+ while (count >= 2) {
+ unsigned int w;
+ count -= 2;
+ w = *(unsigned int *) src;
+ ((unsigned int *) src)++;
+ outw(w >> 0, port);
+ outw(w >> 16, port);
+ }
+
+ if (count) {
+ outw(*(unsigned short *) src, port);
+ }
+}
+
+
+/*
+ * Like insl but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Works with any alignment in SRC.
+ * Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void outsl (unsigned long port, const void *src, unsigned long count)
+{
+ unsigned int l = 0, l2;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long) src) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count--)
+ {
+ outl(*(unsigned int *) src, port);
+ ((unsigned int *) src)++;
+ }
+ break;
+
+ /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */
+
+ case 0x02: /* Buffer 16-bit aligned */
+ --count;
+
+ l = *(unsigned short *) src << 16;
+ ((unsigned short *) src)++;
+
+ while (count--)
+ {
+ l2 = *(unsigned int *) src;
+ ((unsigned int *) src)++;
+ outl (l >> 16 | l2 << 16, port);
+ l = l2;
+ }
+ l2 = *(unsigned short *) src;
+ outl (l >> 16 | l2 << 16, port);
+ break;
+ case 0x01: /* Buffer 8-bit aligned */
+ --count;
+
+ l = *(unsigned char *) src << 8;
+ ((unsigned char *) src)++;
+ l |= *(unsigned short *) src << 16;
+ ((unsigned short *) src)++;
+ while (count--)
+ {
+ l2 = *(unsigned int *) src;
+ ((unsigned int *) src)++;
+ outl (l >> 8 | l2 << 24, port);
+ l = l2;
+ }
+ l2 = *(unsigned char *) src;
+ outl (l >> 8 | l2 << 24, port);
+ break;
+ case 0x03: /* Buffer 8-bit aligned */
+ --count;
+
+ l = *(unsigned char *) src << 24;
+ ((unsigned char *) src)++;
+ while (count--)
+ {
+ l2 = *(unsigned int *) src;
+ ((unsigned int *) src)++;
+ outl (l >> 24 | l2 << 8, port);
+ l = l2;
+ }
+ l2 = *(unsigned short *) src;
+ ((unsigned short *) src)++;
+ l2 |= *(unsigned char *) src << 16;
+ outl (l >> 24 | l2 << 8, port);
+ break;
+ }
+}
+
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void _memcpy_fromio(void * to, unsigned long from, unsigned long count)
+{
+ while (count) {
+ count--;
+ *(char *) to = readb(from);
+ ((char *) to)++;
+ from++;
+ }
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void _memcpy_toio(unsigned long to, void * from, unsigned long count)
+{
+ while (count) {
+ count--;
+ writeb(*(char *) from, to);
+ ((char *) from)++;
+ to++;
+ }
+}
+
+/*
+ * "memset" on IO memory space.
+ * This needs to be optimized.
+ */
+void _memset_io(unsigned long dst, int c, unsigned long count)
+{
+ while (count) {
+ count--;
+ writeb(c, dst);
+ dst++;
+ }
+}