tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pckb[cd] changes for sparc64



Hi,

I'd like to add support for the keyboard on the Tadpole SPARCle laptops.
This uses a PC (8042) keyboard controller with two main differences.  The
first is that the aux port does't probe until after an initial timeout.
The second is that the keyboard does not do scan code translation, so we
have to translate the sequences in software.

There is already support for this keyboard in OpenBSD, and the attached
patch (sparc64-8042.patch) is based on their sys/dev/pckbc/pckbd.c,
revision 1.15 and sys/dev/ic/pckbc.c, revisions 1.10, 1.16, 1.17.  A new
pckbc at ebus attachment (pckbc_ebus.c) is based on our existing sparc
pckbc_js.c attachment.  Note, that the patch doesn't include the changes
to every other caller of pckbc_cnattach() to add the flags argument.

The keyboard also generates scancodes for the extra keys that appear on
normal Sun keyboards.  I've mapped these to the same codes ones that we
use for these keys in the USB code (see our ukbd.c, revision 1.123).

Any comments (especially on a better/cleaner way to do this)?

Thanks,

J

-- 
   NetBSD: simple; works; documented    /        Sailing at Newbiggin
        http://www.netbsd.org/        /   http://www.newbigginsailingclub.org/
Index: sys/arch/sparc64/conf/files.sparc64
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/conf/files.sparc64,v
retrieving revision 1.138
diff -u -r1.138 files.sparc64
--- sys/arch/sparc64/conf/files.sparc64 3 Mar 2012 03:21:16 -0000       1.138
+++ sys/arch/sparc64/conf/files.sparc64 21 Sep 2012 12:58:58 -0000
@@ -153,6 +153,11 @@
 attach com at ebus with com_ebus
 file   arch/sparc64/dev/com_ebus.c             com_ebus
 
+# ebus PS/2 keyboard attachment for Tadpole SPARCle, etc.
+include "dev/pckbport/files.pckbport"
+attach pckbc at ebus with pckbc_ebus
+file   arch/sparc64/dev/pckbc_ebus.c
+
 device zstty {}: tty
 attach zstty at zs
 file dev/ic/z8530tty.c                 zstty needs-flag
Index: sys/dev/ic/pckbc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/pckbc.c,v
retrieving revision 1.53
diff -u -r1.53 pckbc.c
--- sys/dev/ic/pckbc.c  2 Feb 2012 19:43:03 -0000       1.53
+++ sys/dev/ic/pckbc.c  21 Sep 2012 12:58:59 -0000
@@ -354,6 +354,20 @@
        t->t_haveaux = 1;
        bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
        res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
+
+       /*
+        * The following is needed to find the aux port on the Tadpole
+        * SPARCle.
+        */
+       if (res == -1 && ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
+               /* Read of aux echo timed out, try again */
+               if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
+                       goto nomouse;
+               if (!pckbc_wait_output(iot, ioh_c))
+                       goto nomouse;
+               bus_space_write_1(iot, ioh_d, 0, 0x5a);
+               res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
+       }
        if (res != -1) {
                /*
                 * In most cases, the 0x5a gets echoed.
@@ -365,6 +379,7 @@
                if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
                        cmdbits |= KC8_MENABLE;
        } else {
+
 #ifdef PCKBCDEBUG
                printf("pckbc: aux echo test failed\n");
 #endif
@@ -395,6 +410,9 @@
        struct pckbc_internal *t = self;
        int ison;
 
+       if (ISSET(t->t_flags, PCKBC_CANT_TRANSLATE))
+               return (-1);
+
        if (slot != PCKBC_KBD_SLOT) {
                /* translation only for kbd slot */
                if (on)
@@ -602,7 +620,7 @@
 
 int
 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr,
-       bus_size_t cmd_offset, pckbc_slot_t slot)
+       bus_size_t cmd_offset, pckbc_slot_t slot, int flags)
 {
        bus_space_handle_t ioh_d, ioh_c;
 #ifdef PCKBC_CNATTACH_SELFTEST
@@ -622,6 +640,7 @@
        pckbc_consdata.t_ioh_d = ioh_d;
        pckbc_consdata.t_ioh_c = ioh_c;
        pckbc_consdata.t_addr = addr;
+       pckbc_consdata.t_flags = flags;
        callout_init(&pckbc_consdata.t_cleanup, 0);
 
        /* flush */
Index: sys/dev/ic/pckbcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/pckbcvar.h,v
retrieving revision 1.19
diff -u -r1.19 pckbcvar.h
--- sys/dev/ic/pckbcvar.h       2 Feb 2012 19:43:03 -0000       1.19
+++ sys/dev/ic/pckbcvar.h       21 Sep 2012 12:58:59 -0000
@@ -62,6 +62,9 @@
        bus_space_handle_t t_ioh_d, t_ioh_c; /* data port, cmd port */
        bus_addr_t t_addr;
        u_char t_cmdbyte; /* shadow */
+       int t_flags;
+#define        PCKBC_CANT_TRANSLATE    0x0001  /* can't translate to XT 
scancodes */
+#define        PCKBC_NEED_AUXWRITE     0x0002  /* need auxwrite command to 
find aux */
 
        int t_haveaux; /* controller has an aux port */
        struct pckbc_slotdata *t_slotdata[PCKBC_NSLOTS];
@@ -102,7 +105,7 @@
 
 /* More normal calls from attach routines */
 void pckbc_attach(struct pckbc_softc *);
-int pckbc_cnattach(bus_space_tag_t, bus_addr_t, bus_size_t, pckbc_slot_t);
+int pckbc_cnattach(bus_space_tag_t, bus_addr_t, bus_size_t, pckbc_slot_t, int);
 int pckbc_is_console(bus_space_tag_t, bus_addr_t);
 int pckbcintr(void *);
 int pckbcintr_hard(void *);
Index: sys/dev/pckbport/pckbd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pckbport/pckbd.c,v
retrieving revision 1.29
diff -u -r1.29 pckbd.c
--- sys/dev/pckbport/pckbd.c    24 Feb 2010 22:38:08 -0000      1.29
+++ sys/dev/pckbport/pckbd.c    21 Sep 2012 12:58:59 -0000
@@ -100,9 +100,12 @@
        pckbport_tag_t t_kbctag;
        pckbport_slot_t t_kbcslot;
 
+       int t_translating;
+
        int t_lastchar;
        int t_extended0;
        int t_extended1;
+       int t_releasing;
 
        struct pckbd_softc *t_sc; /* back pointer */
 };
@@ -167,7 +170,9 @@
 
 void   pckbd_bell(u_int, u_int, u_int, int);
 
-int    pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t);
+int    pckbd_scancode_translate(struct pckbd_internal *, int);
+int    pckbd_set_xtscancode(pckbport_tag_t, pckbport_slot_t,
+           struct pckbd_internal *);
 int    pckbd_init(struct pckbd_internal *, pckbport_tag_t, pckbport_slot_t,
                        int);
 void   pckbd_input(void *, int);
@@ -179,9 +184,10 @@
 struct pckbd_internal pckbd_consdata;
 
 int
-pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot)
+pckbd_set_xtscancode(pckbport_tag_t kbctag, pckbport_slot_t kbcslot,
+    struct pckbd_internal *id)
 {
-       int res;
+       int xt, res = 0;
        u_char cmd[2];
 
        /*
@@ -192,12 +198,14 @@
         * known to not work on some PS/2 machines.  We try desperately to deal
         * with this by checking the (lack of a) translate bit in the 8042 and
         * attempting to set the keyboard to XT mode.  If this all fails, well,
-        * tough luck.
+        * tough luck.  If the PCKBC_CANT_TRANSLATE pckbc flag was set, we
+        * enable software translation.
         *
         * XXX It would perhaps be a better choice to just use AT scan codes
         * and not bother with this.
         */
-       if (pckbport_xt_translation(kbctag, kbcslot, 1)) {
+       xt = pckbport_xt_translation(kbctag, kbcslot, 1);
+       if (xt == 1) {
                /* The 8042 is translating for us; use AT codes. */
                cmd[0] = KBC_SETTABLE;
                cmd[1] = 2;
@@ -216,6 +224,12 @@
                        pckbport_flush(kbctag, kbcslot);
                        res = 0;
                }
+               if (id != NULL)
+                       id->t_translating = 1;
+       } else if (xt == -1) {
+               /* Software translation required */
+               if (id != NULL)
+                       id->t_translating = 0;
        } else {
                /* Stupid 8042; set keyboard to XT codes. */
                cmd[0] = KBC_SETTABLE;
@@ -223,6 +237,8 @@
                res = pckbport_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
                if (res)
                        aprint_debug("pckbd: error setting scanset 1\n");
+               if (id != NULL)
+                       id->t_translating = 1;
        }
        return res;
 }
@@ -331,7 +347,7 @@
         */
        pckbport_flush(pa->pa_tag, pa->pa_slot);
 
-       if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot))
+       if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot, NULL))
                return 0;
 
        return 2;
@@ -421,7 +437,7 @@
                }
 
                res = pckbd_set_xtscancode(sc->id->t_kbctag,
-                                          sc->id->t_kbcslot);
+                                          sc->id->t_kbcslot, sc->id);
                if (res)
                        return res;
 
@@ -446,21 +462,379 @@
        return 0;
 }
 
+const u_int8_t pckbd_xtbl[] = {
+/* 0x00 */
+       0,
+       0x43,           /* F9 */
+       0x89,           /* SunStop */
+       0x3f,           /* F5 */
+       0x3d,           /* F3 */
+       0x3b,           /* F1 */
+       0x3c,           /* F2 */
+       0x58,           /* F12 */
+       0x40,           /* F6 according to documentation */
+       0x44,           /* F10 */
+       0x42,           /* F8 */
+       0x40,           /* F6 according to experimentation */
+       0x3e,           /* F4 */
+       0x0f,           /* Tab */
+       0x29,           /* ` ~ */
+       0,
+/* 0x10 */
+       0,
+       0x38,           /* Left Alt */
+       0x2a,           /* Left Shift */
+       0,
+       0x1d,           /* Left Ctrl */
+       0x10,           /* q */
+       0x02,           /* 1 ! */
+       0,
+       0,
+       0,
+       0x2c,           /* z */
+       0x1f,           /* s */
+       0x1e,           /* a */
+       0x11,           /* w */
+       0x03,           /* 2 @ */
+       0,
+/* 0x20 */     
+       0,
+       0x2e,           /* c */
+       0x2d,           /* x */
+       0x20,           /* d */
+       0x12,           /* e */
+       0x05,           /* 4 $ */
+       0x04,           /* 3 # */
+       0,
+       0,
+       0x39,           /* Space */
+       0x2f,           /* v */
+       0x21,           /* f */
+       0x14,           /* t */
+       0x13,           /* r */
+       0x06,           /* 5 % */
+       0,
+/* 0x30 */
+       0,
+       0x31,           /* n */
+       0x30,           /* b */
+       0x23,           /* h */
+       0x22,           /* g */
+       0x15,           /* y */
+       0x07,           /* 6 ^ */
+       0,
+       0,
+       0,
+       0x32,           /* m */
+       0x24,           /* j */
+       0x16,           /* u */
+       0x08,           /* 7 & */
+       0x09,           /* 8 * */
+       0,
+/* 0x40 */
+       0,
+       0x33,           /* , < */
+       0x25,           /* k */
+       0x17,           /* i */
+       0x18,           /* o */
+       0x0b,           /* 0 ) */
+       0x0a,           /* 9 ( */
+       0,
+       0,
+       0x34,           /* . > */
+       0x35,           /* / ? */
+       0x26,           /* l */
+       0x27,           /* ; : */
+       0x19,           /* p */
+       0x0c,           /* - _ */
+       0,
+/* 0x50 */
+       0,
+       0,
+       0x28,           /* ' " */
+       0,
+       0x1a,           /* [ { */
+       0x0d,           /* = + */
+       0,
+       0,
+       0x3a,           /* Caps Lock */
+       0x36,           /* Right Shift */
+       0x1c,           /* Return */
+       0x1b,           /* ] } */
+       0,
+       0x2b,           /* \ | */
+       0,
+       0,
+/* 0x60 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x0e,           /* Back Space */
+       0,
+       0,
+       0x4f,           /* KP 1 */
+       0,
+       0x4b,           /* KP 4 */
+       0x47,           /* KP 7 */
+       0,
+       0,
+       0,
+/* 0x70 */
+       0x52,           /* KP 0 */
+       0x53,           /* KP . */
+       0x50,           /* KP 2 */
+       0x4c,           /* KP 5 */
+       0x4d,           /* KP 6 */
+       0x48,           /* KP 8 */
+       0x01,           /* Escape */
+       0x45,           /* Num Lock */
+       0x57,           /* F11 */
+       0x4e,           /* KP + */
+       0x51,           /* KP 3 */
+       0x4a,           /* KP - */
+       0x37,           /* KP * */
+       0x49,           /* KP 9 */
+       0x46,           /* Scroll Lock */
+       0,
+/* 0x80 */
+       0,
+       0,
+       0,
+       0x41,           /* F7 (produced as an actual 8 bit code) */
+       0,              /* Alt-Print Screen */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x90 */
+       0x1f,           /* Meta (mapped to L GUI) */
+       0x85,           /* osfHelp */
+       0x8a,           /* SunAgain */
+       0x8b,           /* SunUndo */
+       0x8d,           /* SunCopy */
+       0x8e,           /* SunPaste */
+       0x8c,           /* SunCut */
+       0x87,           /* SunProps */
+       0x88,           /* SunFront */
+       0x84,           /* SunOpen */
+       0x8f            /* SunFind */
+};
+
+const u_int8_t pckbd_xtbl_ext[] = {
+/* 0x00 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x10 */
+       0,
+       0x38,           /* Right Alt */
+       0,              /* E0 12, to be ignored */
+       0,
+       0x1d,           /* Right Ctrl */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x20 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0xdf,           /* Sun Compose */
+/* 0x30 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x40 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x55,           /* KP / */
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x50 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x1c,           /* KP Return */
+       0,
+       0,
+       0,
+       0,
+       0,
+/* 0x60 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0x4f,           /* End */
+       0,
+       0x4b,           /* Left */
+       0x47,           /* Home */
+       0,
+       0,
+       0,
+/* 0x70 */
+       0x52,           /* Insert */
+       0x53,           /* Delete */
+       0x50,           /* Down */
+       0,
+       0x4d,           /* Right */
+       0x48,           /* Up */
+       0,
+       0,
+       0,
+       0,
+       0x51,           /* Page Down */
+       0,
+       0x37,           /* Print Screen */
+       0x49,           /* Page Up */
+       0x46,           /* Ctrl-Break */
+       0
+};
+
+/*
+ * Translate scan codes from set 2 to set 1
+ */
+int
+pckbd_scancode_translate(struct pckbd_internal *id, int datain)
+{
+       if (id->t_translating != 0)
+               return datain;
+
+       if (datain == KBR_BREAK) {
+               id->t_releasing = 0x80; /* next keycode is a release */
+               return 0;       /* consume scancode */
+       }
+
+       /*
+        * Convert BREAK sequence (14 77 -> 1D 45)
+        */
+       if (id->t_extended1 == 2 && datain == 0x14)
+               return 0x1d | id->t_releasing;
+       else if (id->t_extended1 == 1 && datain == 0x77)
+               return 0x45 | id->t_releasing;
+
+       if (id->t_extended0 != 0) {
+               if (datain >= sizeof pckbd_xtbl_ext)
+                       datain = 0;
+               else
+                       datain = pckbd_xtbl_ext[datain];
+       } else {
+               if (datain >= sizeof pckbd_xtbl)
+                       datain = 0;
+               else
+                       datain = pckbd_xtbl[datain];
+       }
+
+       if (datain == 0) {
+               /*
+                * We don't know how to translate this scan code, but
+                * we can't silently eat it either (because there might
+                * have been an extended byte transmitted already).
+                * Hopefully this value will be harmless to the upper
+                * layers.
+                */
+               return 0xff;
+       }
+
+       return datain | id->t_releasing;
+}
+
 static int
 pckbd_decode(struct pckbd_internal *id, int datain, u_int *type, int *dataout)
 {
        int key;
+       int releasing;
 
        if (datain == KBR_EXTENDED0) {
-               id->t_extended0 = 1;
+               id->t_extended0 = 0x80;
                return 0;
        } else if (datain == KBR_EXTENDED1) {
                id->t_extended1 = 2;
                return 0;
        }
 
-       if (id->t_extended0 == 1) {
-               switch (datain & 0x7f) {
+       releasing = datain & 0x80;
+       datain &= 0x7f;
+
+       if (id->t_extended0 == 0x80) {
+               switch (datain) {
                case 0x2a:
                case 0x36:
                        id->t_extended0 = 0;
@@ -470,10 +844,6 @@
                }
        }
 
-       /* map extended keys to (unused) codes 128-254 */
-       key = (datain & 0x7f) | (id->t_extended0 ? 0x80 : 0);
-       id->t_extended0 = 0;
-
        /*
         * process PAUSE (also break) key (EXT1 1D 45  EXT1 9D C5):
         * map to (unused) code 7F
@@ -489,7 +859,18 @@
                id->t_extended1 = 0;
        }
 
-       if (datain & 0x80) {
+       if (id->t_translating != 0) {
+               id->t_releasing = releasing;
+       } else {
+               /* id->t_releasing computed in pckbd_scancode_translate() */
+       }
+
+       /* map extended keys to (unused) codes 128-254 */
+       key = datain | id->t_extended0;
+       id->t_extended0 = 0;
+
+       if (id->t_releasing) {
+               id->t_releasing = 0;
                id->t_lastchar = 0;
                *type = WSCONS_EVENT_KEY_UP;
        } else {
@@ -515,7 +896,7 @@
        t->t_kbctag = kbctag;
        t->t_kbcslot = kbcslot;
 
-       return pckbd_set_xtscancode(kbctag, kbcslot);
+       return pckbd_set_xtscancode(kbctag, kbcslot, t);
 }
 
 static int
@@ -574,6 +955,10 @@
        int key;
        u_int type;
 
+       data = pckbd_scancode_translate(sc->id, data);
+       if (data == 0)
+               return;
+
 #ifdef WSDISPLAY_COMPAT_RAWKBD
        if (sc->rawkbd) {
                u_char d = data;
@@ -692,7 +1077,14 @@
 
        for (;;) {
                val = pckbport_poll_data(t->t_kbctag, t->t_kbcslot);
-               if ((val != -1) && pckbd_decode(t, val, type, data))
+               if (val == -1)
+                       continue;
+
+               val = pckbd_scancode_translate(t, val);
+               if (val == 0)
+                       continue;
+
+               if (pckbd_decode(t, val, type, data))
                        return;
        }
 }
/*      $NetBSD$ */

/*
 * Copyright (c) 2002 Valeriy E. Ushakov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pckbc_js.c,v 1.18 2008/03/18 05:05:35 dogcow Exp 
$");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <sys/intr.h>

#include <machine/autoconf.h>

#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pckbport/pckbportvar.h>

#include <dev/ebus/ebusreg.h>
#include <dev/ebus/ebusvar.h>

struct pckbc_ebus_softc {
        struct pckbc_softc psc_pckbc;   /* real "pckbc" softc */
        uint32_t psc_intr[PCKBC_NSLOTS];
};

static int      pckbc_ebus_match(device_t, cfdata_t, void *);
static void     pckbc_ebus_attach(device_t, device_t, void *);

static void     pckbc_ebus_intr_establish(struct pckbc_softc *, 
pckbport_slot_t);

#define PCKBC_PROM_DEVICE_NAME "8042"

CFATTACH_DECL_NEW(pckbc_ebus, sizeof(struct pckbc_ebus_softc),
    pckbc_ebus_match, pckbc_ebus_attach, NULL, NULL);


static int
pckbc_ebus_match(device_t parent, cfdata_t cf, void *aux)
{
        struct ebus_attach_args *ea = aux;

        return (strcmp(ea->ea_name, PCKBC_PROM_DEVICE_NAME) == 0);
}

static void
pckbc_ebus_attach(device_t parent, device_t self, void *aux)
{
        struct pckbc_ebus_softc *sc = device_private(self);
        struct pckbc_softc *psc = (struct pckbc_softc *) sc;
        struct ebus_attach_args *ea = aux;
        struct pckbc_internal *t;
        bus_space_tag_t iot;
        bus_addr_t ioaddr;
        int stdin_node, node;
        int isconsole, i;

        psc->sc_dv = self;
        iot = ea->ea_bustag;
        ioaddr = EBUS_ADDR_FROM_REG(&ea->ea_reg[0]);

        stdin_node = prom_instance_to_package(prom_stdin());
        isconsole = 0;
        for (node = prom_firstchild(ea->ea_node);
             node != 0; node = prom_nextsibling(node))
                if (node == stdin_node) {
                        isconsole = 1;
                        break;
                }

        psc->intr_establish = pckbc_ebus_intr_establish;

        for (i = 0; i < PCKBC_NSLOTS; i++)
                sc->psc_intr[i] = ea->ea_intr[i];

        if (isconsole) {
                int status;

                status = pckbc_cnattach(iot, ioaddr, KBCMDP, 0,
                    PCKBC_NEED_AUXWRITE | PCKBC_CANT_TRANSLATE);
                if (status == 0)
                        aprint_normal(": cnattach ok");
                else
                        aprint_error(": cnattach %d", status);
        }

        if (pckbc_is_console(iot, ioaddr)) {
                t = &pckbc_consdata;
                pckbc_console_attached = 1;
        } else {
                bus_space_handle_t ioh_d, ioh_c;

                if (bus_space_map(iot, ioaddr + KBDATAP, 1, 0, &ioh_d) != 0) {
                        aprint_error(": unable to map data register\n");
                        return;
                }

                if (bus_space_map(iot, ioaddr + KBCMDP,  1, 0, &ioh_c) != 0) {
                        bus_space_unmap(iot, ioh_d, 1);
                        aprint_error(": unable to map cmd register\n");
                        return;
                }

                t = malloc(sizeof(struct pckbc_internal), M_DEVBUF, M_WAITOK);
                memset(t, 0, sizeof(struct pckbc_internal));
                t->t_iot = iot;
                t->t_ioh_d = ioh_d;
                t->t_ioh_c = ioh_c;
                t->t_addr = ioaddr;
                t->t_cmdbyte = KC8_CPU; /* initial command: enable ports */
                callout_init(&t->t_cleanup, 0);

                (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT); /* flush */

                if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0)
                        aprint_error(": unable to request self test");
                else {
                        int response;

                        response = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
                        if (response == 0x55)
                                aprint_normal(": selftest ok");
                        else
                                aprint_error(": selftest failed (0x%02x)",
                                    response);
                }
        }

        /* crosslink */
        t->t_sc = psc;
        psc->id = t;

        /* finish off the attach */
        aprint_normal("\n");
        pckbc_attach(psc);
}


static void
pckbc_ebus_intr_establish(struct pckbc_softc *sc, pckbport_slot_t slot)
{
        struct pckbc_ebus_softc *psc = (struct pckbc_ebus_softc *)sc;
        void *res;

        /* We assume that interrupt order is the same as slot order. */
        res = bus_intr_establish(sc->id->t_iot, psc->psc_intr[slot],
                                 IPL_TTY, pckbcintr, sc);
        if (res == NULL)
                aprint_error_dev(sc->sc_dv,
                    "unable to establish %s slot interrupt\n",
                    pckbc_slot_names[slot]);

        return;
}


Home | Main Index | Thread Index | Old Index