linux/arch/powerpc/platforms/powermac/udbg_adb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/string.h>
   3#include <linux/kernel.h>
   4#include <linux/errno.h>
   5#include <linux/bitops.h>
   6#include <linux/ptrace.h>
   7#include <linux/adb.h>
   8#include <linux/pmu.h>
   9#include <linux/cuda.h>
  10#include <asm/machdep.h>
  11#include <asm/io.h>
  12#include <asm/page.h>
  13#include <asm/xmon.h>
  14#include <asm/prom.h>
  15#include <asm/bootx.h>
  16#include <asm/errno.h>
  17#include <asm/pmac_feature.h>
  18#include <asm/processor.h>
  19#include <asm/delay.h>
  20#include <asm/btext.h>
  21#include <asm/time.h>
  22#include <asm/udbg.h>
  23
  24/*
  25 * This implementation is "special", it can "patch" the current
  26 * udbg implementation and work on top of it. It must thus be
  27 * initialized last
  28 */
  29
  30static void (*udbg_adb_old_putc)(char c);
  31static int (*udbg_adb_old_getc)(void);
  32static int (*udbg_adb_old_getc_poll)(void);
  33
  34static enum {
  35        input_adb_none,
  36        input_adb_pmu,
  37        input_adb_cuda,
  38} input_type = input_adb_none;
  39
  40int xmon_wants_key, xmon_adb_keycode;
  41
  42static inline void udbg_adb_poll(void)
  43{
  44#ifdef CONFIG_ADB_PMU
  45        if (input_type == input_adb_pmu)
  46                pmu_poll_adb();
  47#endif /* CONFIG_ADB_PMU */
  48#ifdef CONFIG_ADB_CUDA
  49        if (input_type == input_adb_cuda)
  50                cuda_poll();
  51#endif /* CONFIG_ADB_CUDA */
  52}
  53
  54#ifdef CONFIG_BOOTX_TEXT
  55
  56static int udbg_adb_use_btext;
  57static int xmon_adb_shiftstate;
  58
  59static unsigned char xmon_keytab[128] =
  60        "asdfhgzxcv\000bqwer"                           /* 0x00 - 0x0f */
  61        "yt123465=97-80]o"                              /* 0x10 - 0x1f */
  62        "u[ip\rlj'k;\\,/nm."                            /* 0x20 - 0x2f */
  63        "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
  64        "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
  65        "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
  66
  67static unsigned char xmon_shift_keytab[128] =
  68        "ASDFHGZXCV\000BQWER"                           /* 0x00 - 0x0f */
  69        "YT!@#$^%+(&_*)}O"                              /* 0x10 - 0x1f */
  70        "U{IP\rLJ\"K:|<?NM>"                            /* 0x20 - 0x2f */
  71        "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"            /* 0x30 - 0x3f */
  72        "\0.\0*\0+\0\0\0\0\0/\r\0-\0"                   /* 0x40 - 0x4f */
  73        "\0\0000123456789\0\0\0";                       /* 0x50 - 0x5f */
  74
  75static int udbg_adb_local_getc(void)
  76{
  77        int k, t, on;
  78
  79        xmon_wants_key = 1;
  80        for (;;) {
  81                xmon_adb_keycode = -1;
  82                t = 0;
  83                on = 0;
  84                k = -1;
  85                do {
  86                        if (--t < 0) {
  87                                on = 1 - on;
  88                                btext_drawchar(on? 0xdb: 0x20);
  89                                btext_drawchar('\b');
  90                                t = 200000;
  91                        }
  92                        udbg_adb_poll();
  93                        if (udbg_adb_old_getc_poll)
  94                                k = udbg_adb_old_getc_poll();
  95                } while (k == -1 && xmon_adb_keycode == -1);
  96                if (on)
  97                        btext_drawstring(" \b");
  98                if (k != -1)
  99                        return k;
 100                k = xmon_adb_keycode;
 101
 102                /* test for shift keys */
 103                if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
 104                        xmon_adb_shiftstate = (k & 0x80) == 0;
 105                        continue;
 106                }
 107                if (k >= 0x80)
 108                        continue;       /* ignore up transitions */
 109                k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
 110                if (k != 0)
 111                        break;
 112        }
 113        xmon_wants_key = 0;
 114        return k;
 115}
 116#endif /* CONFIG_BOOTX_TEXT */
 117
 118static int udbg_adb_getc(void)
 119{
 120#ifdef CONFIG_BOOTX_TEXT
 121        if (udbg_adb_use_btext && input_type != input_adb_none)
 122                return udbg_adb_local_getc();
 123#endif
 124        if (udbg_adb_old_getc)
 125                return udbg_adb_old_getc();
 126        return -1;
 127}
 128
 129/* getc_poll() is not really used, unless you have the xmon-over modem
 130 * hack that doesn't quite concern us here, thus we just poll the low level
 131 * ADB driver to prevent it from timing out and call back the original poll
 132 * routine.
 133 */
 134static int udbg_adb_getc_poll(void)
 135{
 136        udbg_adb_poll();
 137
 138        if (udbg_adb_old_getc_poll)
 139                return udbg_adb_old_getc_poll();
 140        return -1;
 141}
 142
 143static void udbg_adb_putc(char c)
 144{
 145#ifdef CONFIG_BOOTX_TEXT
 146        if (udbg_adb_use_btext)
 147                btext_drawchar(c);
 148#endif
 149        if (udbg_adb_old_putc)
 150                return udbg_adb_old_putc(c);
 151}
 152
 153void __init udbg_adb_init_early(void)
 154{
 155#ifdef CONFIG_BOOTX_TEXT
 156        if (btext_find_display(1) == 0) {
 157                udbg_adb_use_btext = 1;
 158                udbg_putc = udbg_adb_putc;
 159        }
 160#endif
 161}
 162
 163int __init udbg_adb_init(int force_btext)
 164{
 165        struct device_node *np;
 166
 167        /* Capture existing callbacks */
 168        udbg_adb_old_putc = udbg_putc;
 169        udbg_adb_old_getc = udbg_getc;
 170        udbg_adb_old_getc_poll = udbg_getc_poll;
 171
 172        /* Check if our early init was already called */
 173        if (udbg_adb_old_putc == udbg_adb_putc)
 174                udbg_adb_old_putc = NULL;
 175#ifdef CONFIG_BOOTX_TEXT
 176        if (udbg_adb_old_putc == btext_drawchar)
 177                udbg_adb_old_putc = NULL;
 178#endif
 179
 180        /* Set ours as output */
 181        udbg_putc = udbg_adb_putc;
 182        udbg_getc = udbg_adb_getc;
 183        udbg_getc_poll = udbg_adb_getc_poll;
 184
 185#ifdef CONFIG_BOOTX_TEXT
 186        /* Check if we should use btext output */
 187        if (btext_find_display(force_btext) == 0)
 188                udbg_adb_use_btext = 1;
 189#endif
 190
 191        /* See if there is a keyboard in the device tree with a parent
 192         * of type "adb". If not, we return a failure, but we keep the
 193         * bext output set for now
 194         */
 195        for_each_node_by_name(np, "keyboard") {
 196                struct device_node *parent = of_get_parent(np);
 197                int found = of_node_is_type(parent, "adb");
 198                of_node_put(parent);
 199                if (found)
 200                        break;
 201        }
 202        if (np == NULL)
 203                return -ENODEV;
 204        of_node_put(np);
 205
 206#ifdef CONFIG_ADB_PMU
 207        if (find_via_pmu())
 208                input_type = input_adb_pmu;
 209#endif
 210#ifdef CONFIG_ADB_CUDA
 211        if (find_via_cuda())
 212                input_type = input_adb_cuda;
 213#endif
 214
 215        /* Same as above: nothing found, keep btext set for output */
 216        if (input_type == input_adb_none)
 217                return -ENODEV;
 218
 219        return 0;
 220}
 221