root/arch/sparc/lib/PeeCeeI.c
// SPDX-License-Identifier: GPL-2.0
/*
 * PeeCeeI.c: The emerging standard...
 *
 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 */

#include <linux/module.h>

#include <asm/io.h>
#include <asm/byteorder.h>

void outsb(unsigned long __addr, const void *src, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;
        const u8 *p = src;

        while (count--)
                __raw_writeb(*p++, addr);
}
EXPORT_SYMBOL(outsb);

void outsw(unsigned long __addr, const void *src, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;

        while (count--) {
                __raw_writew(*(u16 *)src, addr);
                src += sizeof(u16);
        }
}
EXPORT_SYMBOL(outsw);

void outsl(unsigned long __addr, const void *src, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;
        u32 l, l2;

        if (!count)
                return;

        switch (((unsigned long)src) & 0x3) {
        case 0x0:
                /* src is naturally aligned */
                while (count--) {
                        __raw_writel(*(u32 *)src, addr);
                        src += sizeof(u32);
                }
                break;
        case 0x2:
                /* 2-byte alignment */
                while (count--) {
                        l = (*(u16 *)src) << 16;
                        l |= *(u16 *)(src + sizeof(u16));
                        __raw_writel(l, addr);
                        src += sizeof(u32);
                }
                break;
        case 0x1:
                /* Hold three bytes in l each time, grab a byte from l2 */
                l = (*(u8 *)src) << 24;
                l |= (*(u16 *)(src + sizeof(u8))) << 8;
                src += sizeof(u8) + sizeof(u16);
                while (count--) {
                        l2 = *(u32 *)src;
                        l |= (l2 >> 24);
                        __raw_writel(l, addr);
                        l = l2 << 8;
                        src += sizeof(u32);
                }
                break;
        case 0x3:
                /* Hold a byte in l each time, grab 3 bytes from l2 */
                l = (*(u8 *)src) << 24;
                src += sizeof(u8);
                while (count--) {
                        l2 = *(u32 *)src;
                        l |= (l2 >> 8);
                        __raw_writel(l, addr);
                        l = l2 << 24;
                        src += sizeof(u32);
                }
                break;
        }
}
EXPORT_SYMBOL(outsl);

void insb(unsigned long __addr, void *dst, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;

        if (count) {
                u32 *pi;
                u8 *pb = dst;

                while ((((unsigned long)pb) & 0x3) && count--)
                        *pb++ = __raw_readb(addr);
                pi = (u32 *)pb;
                while (count >= 4) {
                        u32 w;

                        w  = (__raw_readb(addr) << 24);
                        w |= (__raw_readb(addr) << 16);
                        w |= (__raw_readb(addr) << 8);
                        w |= (__raw_readb(addr) << 0);
                        *pi++ = w;
                        count -= 4;
                }
                pb = (u8 *)pi;
                while (count--)
                        *pb++ = __raw_readb(addr);
        }
}
EXPORT_SYMBOL(insb);

void insw(unsigned long __addr, void *dst, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;

        if (count) {
                u16 *ps = dst;
                u32 *pi;

                if (((unsigned long)ps) & 0x2) {
                        *ps++ = __raw_readw(addr);
                        count--;
                }
                pi = (u32 *)ps;
                while (count >= 2) {
                        u32 w;

                        w  = __raw_readw(addr) << 16;
                        w |= __raw_readw(addr) << 0;
                        *pi++ = w;
                        count -= 2;
                }
                ps = (u16 *)pi;
                if (count)
                        *ps = __raw_readw(addr);
        }
}
EXPORT_SYMBOL(insw);

void insl(unsigned long __addr, void *dst, unsigned long count)
{
        void __iomem *addr = (void __iomem *) __addr;

        if (count) {
                if ((((unsigned long)dst) & 0x3) == 0) {
                        u32 *pi = dst;
                        while (count--)
                                *pi++ = __raw_readl(addr);
                } else {
                        u32 l = 0, l2, *pi;
                        u16 *ps;
                        u8 *pb;

                        switch (((unsigned long)dst) & 3) {
                        case 0x2:
                                ps = dst;
                                count -= 1;
                                l = __raw_readl(addr);
                                *ps++ = l;
                                pi = (u32 *)ps;
                                while (count--) {
                                        l2 = __raw_readl(addr);
                                        *pi++ = (l << 16) | (l2 >> 16);
                                        l = l2;
                                }
                                ps = (u16 *)pi;
                                *ps = l;
                                break;

                        case 0x1:
                                pb = dst;
                                count -= 1;
                                l = __raw_readl(addr);
                                *pb++ = l >> 24;
                                ps = (u16 *)pb;
                                *ps++ = ((l >> 8) & 0xffff);
                                pi = (u32 *)ps;
                                while (count--) {
                                        l2 = __raw_readl(addr);
                                        *pi++ = (l << 24) | (l2 >> 8);
                                        l = l2;
                                }
                                pb = (u8 *)pi;
                                *pb = l;
                                break;

                        case 0x3:
                                pb = (u8 *)dst;
                                count -= 1;
                                l = __raw_readl(addr);
                                *pb++ = l >> 24;
                                pi = (u32 *)pb;
                                while (count--) {
                                        l2 = __raw_readl(addr);
                                        *pi++ = (l << 8) | (l2 >> 24);
                                        l = l2;
                                }
                                ps = (u16 *)pi;
                                *ps++ = ((l >> 8) & 0xffff);
                                pb = (u8 *)ps;
                                *pb = l;
                                break;
                        }
                }
        }
}
EXPORT_SYMBOL(insl);