io.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
- /*
- * Alpha IO and memory functions.. Just expand the inlines in the header
- * files..
- */
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/string.h>
- #include <asm/io.h>
- u8 _inb(unsigned long addr)
- {
- return __inb(addr);
- }
- u16 _inw(unsigned long addr)
- {
- return __inw(addr);
- }
- u32 _inl(unsigned long addr)
- {
- return __inl(addr);
- }
- void _outb(u8 b, unsigned long addr)
- {
- __outb(b, addr);
- }
- void _outw(u16 b, unsigned long addr)
- {
- __outw(b, addr);
- }
- void _outl(u32 b, unsigned long addr)
- {
- __outl(b, addr);
- }
- u8 ___raw_readb(unsigned long addr)
- {
- return __readb(addr);
- }
- u16 ___raw_readw(unsigned long addr)
- {
- return __readw(addr);
- }
- u32 ___raw_readl(unsigned long addr)
- {
- return __readl(addr);
- }
- u64 ___raw_readq(unsigned long addr)
- {
- return __readq(addr);
- }
- u8 _readb(unsigned long addr)
- {
- unsigned long r = __readb(addr);
- mb();
- return r;
- }
- u16 _readw(unsigned long addr)
- {
- unsigned long r = __readw(addr);
- mb();
- return r;
- }
- u32 _readl(unsigned long addr)
- {
- unsigned long r = __readl(addr);
- mb();
- return r;
- }
- u64 _readq(unsigned long addr)
- {
- unsigned long r = __readq(addr);
- mb();
- return r;
- }
- void ___raw_writeb(u8 b, unsigned long addr)
- {
- __writeb(b, addr);
- }
- void ___raw_writew(u16 b, unsigned long addr)
- {
- __writew(b, addr);
- }
- void ___raw_writel(u32 b, unsigned long addr)
- {
- __writel(b, addr);
- }
- void ___raw_writeq(u64 b, unsigned long addr)
- {
- __writeq(b, addr);
- }
- void _writeb(u8 b, unsigned long addr)
- {
- __writeb(b, addr);
- mb();
- }
- void _writew(u16 b, unsigned long addr)
- {
- __writew(b, addr);
- mb();
- }
- void _writel(u32 b, unsigned long addr)
- {
- __writel(b, addr);
- mb();
- }
- void _writeq(u64 b, unsigned long addr)
- {
- __writeq(b, addr);
- mb();
- }
- /*
- * 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, long count)
- {
- /* Optimize co-aligned transfers. Everything else gets handled
- a byte at a time. */
- if (count >= 8 && ((long)to & 7) == (from & 7)) {
- count -= 8;
- do {
- *(u64 *)to = __raw_readq(from);
- count -= 8;
- to += 8;
- from += 8;
- } while (count >= 0);
- count += 8;
- }
- if (count >= 4 && ((long)to & 3) == (from & 3)) {
- count -= 4;
- do {
- *(u32 *)to = __raw_readl(from);
- count -= 4;
- to += 4;
- from += 4;
- } while (count >= 0);
- count += 4;
- }
-
- if (count >= 2 && ((long)to & 1) == (from & 1)) {
- count -= 2;
- do {
- *(u16 *)to = __raw_readw(from);
- count -= 2;
- to += 2;
- from += 2;
- } while (count >= 0);
- count += 2;
- }
- while (count > 0) {
- *(u8 *) to = __raw_readb(from);
- count--;
- to++;
- from++;
- }
- }
- /*
- * Copy data from "real" memory space to IO memory space.
- * This needs to be optimized.
- */
- void _memcpy_toio(unsigned long to, const void * from, long count)
- {
- /* Optimize co-aligned transfers. Everything else gets handled
- a byte at a time. */
- /* FIXME -- align FROM. */
- if (count >= 8 && (to & 7) == ((long)from & 7)) {
- count -= 8;
- do {
- __raw_writeq(*(const u64 *)from, to);
- count -= 8;
- to += 8;
- from += 8;
- } while (count >= 0);
- count += 8;
- }
- if (count >= 4 && (to & 3) == ((long)from & 3)) {
- count -= 4;
- do {
- __raw_writel(*(const u32 *)from, to);
- count -= 4;
- to += 4;
- from += 4;
- } while (count >= 0);
- count += 4;
- }
-
- if (count >= 2 && (to & 1) == ((long)from & 1)) {
- count -= 2;
- do {
- __raw_writew(*(const u16 *)from, to);
- count -= 2;
- to += 2;
- from += 2;
- } while (count >= 0);
- count += 2;
- }
- while (count > 0) {
- __raw_writeb(*(const u8 *) from, to);
- count--;
- to++;
- from++;
- }
- mb();
- }
- /*
- * "memset" on IO memory space.
- */
- void _memset_c_io(unsigned long to, unsigned long c, long count)
- {
- /* Handle any initial odd byte */
- if (count > 0 && (to & 1)) {
- __raw_writeb(c, to);
- to++;
- count--;
- }
- /* Handle any initial odd halfword */
- if (count >= 2 && (to & 2)) {
- __raw_writew(c, to);
- to += 2;
- count -= 2;
- }
- /* Handle any initial odd word */
- if (count >= 4 && (to & 4)) {
- __raw_writel(c, to);
- to += 4;
- count -= 4;
- }
- /* Handle all full-sized quadwords: we're aligned
- (or have a small count) */
- count -= 8;
- if (count >= 0) {
- do {
- __raw_writeq(c, to);
- to += 8;
- count -= 8;
- } while (count >= 0);
- }
- count += 8;
- /* The tail is word-aligned if we still have count >= 4 */
- if (count >= 4) {
- __raw_writel(c, to);
- to += 4;
- count -= 4;
- }
- /* The tail is half-word aligned if we have count >= 2 */
- if (count >= 2) {
- __raw_writew(c, to);
- to += 2;
- count -= 2;
- }
- /* And finally, one last byte.. */
- if (count) {
- __raw_writeb(c, to);
- }
- mb();
- }
- void
- scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
- {
- if (! __is_ioaddr((unsigned long) s)) {
- /* Source is memory. */
- if (! __is_ioaddr((unsigned long) d))
- memcpy(d, s, count);
- else
- memcpy_toio(d, s, count);
- } else {
- /* Source is screen. */
- if (! __is_ioaddr((unsigned long) d))
- memcpy_fromio(d, s, count);
- else {
- /* FIXME: Should handle unaligned ops and
- operation widening. */
- count /= 2;
- while (count--) {
- u16 tmp = __raw_readw((unsigned long)(s++));
- __raw_writew(tmp, (unsigned long)(d++));
- }
- }
- }
- }