/* * linux/arch/sh/edosk7760/io.c * * Copyright (C) 2001 Ian da Silva, Jeremy Siegel * Based largely on io_se.c. * * I/O routine for Hitachi EDOSK7760. * */ #include #include #include #include #include #define SMC_IOADDR 0xA2000300 #define maybebadio24(name,port) \ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \ #name, (port), (__u32) __builtin_return_address(0)) static inline void delay(void) { ctrl_inw(0xa0000000); } /* Map the Ethernet addresses as if it is at 0x300 - 0x320 */ static inline unsigned long __port2addr(unsigned long port) { if (port >= 0x300 && port < 0x320) { /* SMC91C96 registers are 4 byte aligned rather than the * usual 2 byte! */ return SMC_IOADDR + ( (port - 0x300) * 2); } maybebadio24(__port2addr, port); return port; } unsigned short sh_edosk7760_inw(unsigned long port) { return *(volatile unsigned short *)__port2addr(port); } void sh_edosk7760_outw(unsigned short value, unsigned long port) { *(volatile unsigned short *)__port2addr(port) = value; } unsigned char sh_edosk7760_inb(unsigned long port) { if (port >= 0x300 && port < 0x320 && port & 0x01) { return (volatile unsigned char)(sh_edosk7760_inw(port -1) >> 8); } return *(volatile unsigned char *)__port2addr(port); } unsigned char sh_edosk7760_inb_p(unsigned long port) { unsigned char v; v = *(volatile unsigned char *)__port2addr(port); return v; } unsigned int sh_edosk7760_inl(unsigned long port) { return *(volatile unsigned long *)port; } void sh_edosk7760_outb(unsigned char value, unsigned long port) { if (port >= 0x300 && port < 0x320 && port & 0x01) { sh_edosk7760_outw(((unsigned short)value << 8), port -1); return; } *(volatile unsigned char *)__port2addr(port) = value; } void sh_edosk7760_outb_p(unsigned char value, unsigned long port) { *(volatile unsigned char *)__port2addr(port) = value; } void sh_edosk7760_outl(unsigned int value, unsigned long port) { *(volatile unsigned long *)port = value; } void sh_edosk7760_insb(unsigned long port, void *addr, unsigned long count) { unsigned char *p = addr; while (count--) *p++ = sh_edosk7760_inb(port); } void sh_edosk7760_insw(unsigned long port, void *addr, unsigned long count) { unsigned short *p = (unsigned short*)addr; while (count--) *p++ = sh_edosk7760_inw(port); } void sh_edosk7760_insl(unsigned long port, void *addr, unsigned long count) { unsigned long *p = (unsigned long*)addr; while (count--) *p++ = sh_edosk7760_inl(port); } void sh_edosk7760_outsb(unsigned long port, const void *addr, unsigned long count) { unsigned char *p = (unsigned char*)addr; while (count--) sh_edosk7760_outb(*p++, port); } void sh_edosk7760_outsw(unsigned long port, const void *addr, unsigned long count) { unsigned short *p = (unsigned short*)addr; while (count--) sh_edosk7760_outw(*p++, port); } void sh_edosk7760_outsl(unsigned long port, const void *addr, unsigned long count) { unsigned long *p = (unsigned long*)addr; while (count--) sh_edosk7760_outl(*p++, port); } /* For read/write calls, just copy generic (pass-thru); PCIMBR is */ /* already set up. For a larger memory space, these would need to */ /* reset PCIMBR as needed on a per-call basis... */ unsigned char sh_edosk7760_readb(unsigned long addr) { return *(volatile unsigned char*)addr; } unsigned short sh_edosk7760_readw(unsigned long addr) { return *(volatile unsigned short*)addr; } unsigned int sh_edosk7760_readl(unsigned long addr) { return *(volatile unsigned long*)addr; } void sh_edosk7760_writeb(unsigned char b, unsigned long addr) { *(volatile unsigned char*)addr = b; } void sh_edosk7760_writew(unsigned short b, unsigned long addr) { *(volatile unsigned short*)addr = b; } void sh_edosk7760_writel(unsigned int b, unsigned long addr) { *(volatile unsigned long*)addr = b; } unsigned long sh_edosk7760_isa_port2addr(unsigned long offset) { return __port2addr(offset); }