uboot/drivers/misc/swap_case.c
<<
>>
Prefs
   1/*
   2 * PCI emulation device which swaps the case of text
   3 *
   4 * Copyright (c) 2014 Google, Inc
   5 * Written by Simon Glass <sjg@chromium.org>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <errno.h>
  13#include <pci.h>
  14#include <asm/test.h>
  15#include <linux/ctype.h>
  16
  17/**
  18 * struct swap_case_platdata - platform data for this device
  19 *
  20 * @command:    Current PCI command value
  21 * @bar:        Current base address values
  22 */
  23struct swap_case_platdata {
  24        u16 command;
  25        u32 bar[2];
  26};
  27
  28#define offset_to_barnum(offset)        \
  29                (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32))
  30
  31enum {
  32        MEM_TEXT_SIZE   = 0x100,
  33};
  34
  35enum swap_case_op {
  36        OP_TO_LOWER,
  37        OP_TO_UPPER,
  38        OP_SWAP,
  39};
  40
  41static struct pci_bar {
  42        int type;
  43        u32 size;
  44} barinfo[] = {
  45        { PCI_BASE_ADDRESS_SPACE_IO, 1 },
  46        { PCI_BASE_ADDRESS_MEM_TYPE_32, MEM_TEXT_SIZE },
  47        { 0, 0 },
  48        { 0, 0 },
  49        { 0, 0 },
  50        { 0, 0 },
  51};
  52
  53struct swap_case_priv {
  54        enum swap_case_op op;
  55        char mem_text[MEM_TEXT_SIZE];
  56};
  57
  58static int sandbox_swap_case_get_devfn(struct udevice *dev)
  59{
  60        struct pci_child_platdata *plat = dev_get_parent_platdata(dev);
  61
  62        return plat->devfn;
  63}
  64
  65static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
  66                                         ulong *valuep, enum pci_size_t size)
  67{
  68        struct swap_case_platdata *plat = dev_get_platdata(emul);
  69
  70        switch (offset) {
  71        case PCI_COMMAND:
  72                *valuep = plat->command;
  73                break;
  74        case PCI_HEADER_TYPE:
  75                *valuep = 0;
  76                break;
  77        case PCI_VENDOR_ID:
  78                *valuep = SANDBOX_PCI_VENDOR_ID;
  79                break;
  80        case PCI_DEVICE_ID:
  81                *valuep = SANDBOX_PCI_DEVICE_ID;
  82                break;
  83        case PCI_CLASS_DEVICE:
  84                if (size == PCI_SIZE_8) {
  85                        *valuep = SANDBOX_PCI_CLASS_SUB_CODE;
  86                } else {
  87                        *valuep = (SANDBOX_PCI_CLASS_CODE << 8) |
  88                                        SANDBOX_PCI_CLASS_SUB_CODE;
  89                }
  90                break;
  91        case PCI_CLASS_CODE:
  92                *valuep = SANDBOX_PCI_CLASS_CODE;
  93                break;
  94        case PCI_BASE_ADDRESS_0:
  95        case PCI_BASE_ADDRESS_1:
  96        case PCI_BASE_ADDRESS_2:
  97        case PCI_BASE_ADDRESS_3:
  98        case PCI_BASE_ADDRESS_4:
  99        case PCI_BASE_ADDRESS_5: {
 100                int barnum;
 101                u32 *bar, result;
 102
 103                barnum = offset_to_barnum(offset);
 104                bar = &plat->bar[barnum];
 105
 106                result = *bar;
 107                if (*bar == 0xffffffff) {
 108                        if (barinfo[barnum].type) {
 109                                result = (~(barinfo[barnum].size - 1) &
 110                                        PCI_BASE_ADDRESS_IO_MASK) |
 111                                        PCI_BASE_ADDRESS_SPACE_IO;
 112                        } else {
 113                                result = (~(barinfo[barnum].size - 1) &
 114                                        PCI_BASE_ADDRESS_MEM_MASK) |
 115                                        PCI_BASE_ADDRESS_MEM_TYPE_32;
 116                        }
 117                }
 118                debug("r bar %d=%x\n", barnum, result);
 119                *valuep = result;
 120                break;
 121        }
 122        }
 123
 124        return 0;
 125}
 126
 127static int sandbox_swap_case_write_config(struct udevice *emul, uint offset,
 128                                          ulong value, enum pci_size_t size)
 129{
 130        struct swap_case_platdata *plat = dev_get_platdata(emul);
 131
 132        switch (offset) {
 133        case PCI_COMMAND:
 134                plat->command = value;
 135                break;
 136        case PCI_BASE_ADDRESS_0:
 137        case PCI_BASE_ADDRESS_1: {
 138                int barnum;
 139                u32 *bar;
 140
 141                barnum = offset_to_barnum(offset);
 142                bar = &plat->bar[barnum];
 143
 144                debug("w bar %d=%lx\n", barnum, value);
 145                *bar = value;
 146                break;
 147        }
 148        }
 149
 150        return 0;
 151}
 152
 153static int sandbox_swap_case_find_bar(struct udevice *emul, unsigned int addr,
 154                                      int *barnump, unsigned int *offsetp)
 155{
 156        struct swap_case_platdata *plat = dev_get_platdata(emul);
 157        int barnum;
 158
 159        for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) {
 160                unsigned int size = barinfo[barnum].size;
 161
 162                if (addr >= plat->bar[barnum] &&
 163                    addr < plat->bar[barnum] + size) {
 164                        *barnump = barnum;
 165                        *offsetp = addr - plat->bar[barnum];
 166                        return 0;
 167                }
 168        }
 169        *barnump = -1;
 170
 171        return -ENOENT;
 172}
 173
 174static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len)
 175{
 176        for (; len > 0; len--, str++) {
 177                switch (op) {
 178                case OP_TO_UPPER:
 179                        *str = toupper(*str);
 180                        break;
 181                case OP_TO_LOWER:
 182                        *str = tolower(*str);
 183                        break;
 184                case OP_SWAP:
 185                        if (isupper(*str))
 186                                *str = tolower(*str);
 187                        else
 188                                *str = toupper(*str);
 189                        break;
 190                }
 191        }
 192}
 193
 194int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr,
 195                              ulong *valuep, enum pci_size_t size)
 196{
 197        struct swap_case_priv *priv = dev_get_priv(dev);
 198        unsigned int offset;
 199        int barnum;
 200        int ret;
 201
 202        ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
 203        if (ret)
 204                return ret;
 205
 206        if (barnum == 0 && offset == 0)
 207                *valuep = (*valuep & ~0xff) | priv->op;
 208
 209        return 0;
 210}
 211
 212int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr,
 213                               ulong value, enum pci_size_t size)
 214{
 215        struct swap_case_priv *priv = dev_get_priv(dev);
 216        unsigned int offset;
 217        int barnum;
 218        int ret;
 219
 220        ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
 221        if (ret)
 222                return ret;
 223        if (barnum == 0 && offset == 0)
 224                priv->op = value;
 225
 226        return 0;
 227}
 228
 229static int sandbox_swap_case_map_physmem(struct udevice *dev,
 230                phys_addr_t addr, unsigned long *lenp, void **ptrp)
 231{
 232        struct swap_case_priv *priv = dev_get_priv(dev);
 233        unsigned int offset, avail;
 234        int barnum;
 235        int ret;
 236
 237        ret = sandbox_swap_case_find_bar(dev, addr, &barnum, &offset);
 238        if (ret)
 239                return ret;
 240        if (barnum == 1) {
 241                *ptrp = priv->mem_text + offset;
 242                avail = barinfo[1].size - offset;
 243                if (avail > barinfo[1].size)
 244                        *lenp = 0;
 245                else
 246                        *lenp = min(*lenp, (ulong)avail);
 247
 248                return 0;
 249        }
 250
 251        return -ENOENT;
 252}
 253
 254static int sandbox_swap_case_unmap_physmem(struct udevice *dev,
 255                                           const void *vaddr, unsigned long len)
 256{
 257        struct swap_case_priv *priv = dev_get_priv(dev);
 258
 259        sandbox_swap_case_do_op(priv->op, (void *)vaddr, len);
 260
 261        return 0;
 262}
 263
 264struct dm_pci_emul_ops sandbox_swap_case_emul_ops = {
 265        .get_devfn = sandbox_swap_case_get_devfn,
 266        .read_config = sandbox_swap_case_read_config,
 267        .write_config = sandbox_swap_case_write_config,
 268        .read_io = sandbox_swap_case_read_io,
 269        .write_io = sandbox_swap_case_write_io,
 270        .map_physmem = sandbox_swap_case_map_physmem,
 271        .unmap_physmem = sandbox_swap_case_unmap_physmem,
 272};
 273
 274static const struct udevice_id sandbox_swap_case_ids[] = {
 275        { .compatible = "sandbox,swap-case" },
 276        { }
 277};
 278
 279U_BOOT_DRIVER(sandbox_swap_case_emul) = {
 280        .name           = "sandbox_swap_case_emul",
 281        .id             = UCLASS_PCI_EMUL,
 282        .of_match       = sandbox_swap_case_ids,
 283        .ops            = &sandbox_swap_case_emul_ops,
 284        .priv_auto_alloc_size = sizeof(struct swap_case_priv),
 285        .platdata_auto_alloc_size = sizeof(struct swap_case_platdata),
 286};
 287