1 /* $NetBSD: pfckbd.c,v 1.2 2001/03/02 19:21:53 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 #define PFCKBD_DEBUG 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 #include <sys/callout.h> 44 45 #include <machine/bus.h> 46 #include <dev/hpc/hpckbdvar.h> 47 48 #include <sh3/pfcreg.h> 49 50 #include <hpcsh/dev/pfckbdvar.h> 51 52 #ifdef PFCKBD_DEBUG 53 int pfckbd_debug = 0; 54 #define DPRINTF(fmt, args...) \ 55 if (pfckbd_debug) \ 56 printf("%s: " fmt, __FUNCTION__ , ##args) 57 #define DPRINTFN(n, arg) \ 58 if (pfckbd_debug > (n)) \ 59 printf("%s: " fmt, __FUNCTION__ , ##args) 60 #else 61 #define DPRINTF(arg...) ((void)0) 62 #define DPRINTFN(n, arg...) ((void)0) 63 #endif 64 65 static int pfckbd_match(struct device *, struct cfdata *, void *); 66 static void pfckbd_attach(struct device *, struct device *, void *); 67 68 static struct pfckbd_core { 69 int pc_attached; 70 int pc_enabled; 71 struct callout pc_soft_ch; 72 struct hpckbd_ic_if pc_if; 73 struct hpckbd_if *pc_hpckbd; 74 u_int16_t pc_column[8]; 75 } pfckbd_core; 76 77 struct pfckbd_softc { 78 struct device sc_dev; 79 }; 80 81 struct cfattach pfckbd_ca = { 82 sizeof(struct pfckbd_softc), pfckbd_match, pfckbd_attach 83 }; 84 85 static int pfckbd_poll(void *); 86 static void pfckbd_soft(void *); 87 static void pfckbd_ifsetup(struct pfckbd_core *); 88 static int pfckbd_input_establish(void *, struct hpckbd_if *); 89 90 /* 91 * matrix scan keyboard connected to SH3 PFC module. 92 * currently, HP Jornada 690 only. 93 */ 94 void 95 pfckbd_cnattach() 96 { 97 struct pfckbd_core *pc = &pfckbd_core; 98 99 /* initialize interface */ 100 pfckbd_ifsetup(pc); 101 hpckbd_cnattach(&pc->pc_if); 102 } 103 104 static int 105 pfckbd_match(struct device *parent, struct cfdata *cf, void *aux) 106 { 107 108 return !pfckbd_core.pc_attached; 109 } 110 111 static void 112 pfckbd_attach(struct device *parent, struct device *self, void *aux) 113 { 114 struct hpckbd_attach_args haa; 115 116 printf("\n"); 117 118 /* pfckbd is singleton. no more attach */ 119 pfckbd_core.pc_attached = 1; 120 121 pfckbd_ifsetup(&pfckbd_core); 122 123 /* attach hpckbd */ 124 haa.haa_ic = &pfckbd_core.pc_if; /* tell the hpckbd to my interface */ 125 config_found(self, &haa, hpckbd_print); 126 127 /* install callout handler */ 128 callout_init(&pfckbd_core.pc_soft_ch); 129 callout_reset(&pfckbd_core.pc_soft_ch, 1, pfckbd_soft, &pfckbd_core); 130 } 131 132 static int 133 pfckbd_input_establish(void *ic, struct hpckbd_if *kbdif) 134 { 135 struct pfckbd_core *pc = ic; 136 137 /* save hpckbd interface */ 138 pc->pc_hpckbd = kbdif; 139 /* ok to transact hpckbd */ 140 pc->pc_enabled = 1; 141 142 return 0; 143 } 144 145 static int 146 pfckbd_poll(void *arg) 147 { 148 struct pfckbd_core *pc = arg; 149 150 if (pc->pc_enabled) 151 pfckbd_soft(arg); 152 153 return 0; 154 } 155 156 static void 157 pfckbd_ifsetup(struct pfckbd_core *pc) 158 { 159 int i; 160 161 pc->pc_if.hii_ctx = pc; 162 pc->pc_if.hii_establish = pfckbd_input_establish; 163 pc->pc_if.hii_poll = pfckbd_poll; 164 for (i = 0; i < 8; i++) 165 pc->pc_column[i] = 0xdfff; 166 } 167 168 static void 169 pfckbd_soft(void *arg) 170 { 171 static const struct { 172 u_int8_t d, e; 173 } scan[] = { 174 { 0xfd, 0xff }, 175 { 0xdf, 0xff }, 176 { 0xff, 0xfd }, 177 { 0xff, 0xbf }, 178 { 0xff, 0x7f }, 179 { 0xff, 0xf7 }, 180 { 0xff, 0xfe }, 181 { 0x7f, 0xff }, 182 }; 183 struct pfckbd_core *pc = arg; 184 struct hpckbd_if *hpckbd = pc->pc_hpckbd; 185 u_int16_t *buf = pc->pc_column; 186 int row, column, type, val; 187 u_int16_t data, edge, mask; 188 189 if (!pc->pc_enabled) 190 goto reinstall; 191 192 for (column = 0; column < 8; column++) { 193 SHREG_PDDR = scan[column].d; 194 SHREG_PEDR = scan[column].e; 195 delay(50); 196 data = SHREG_PFDR | (SHREG_PCDR << 8); 197 198 if ((edge = (data ^ buf[column]))) { 199 buf[column] = data; 200 201 for (row = 0, mask = 1; row < 16; row++, mask <<= 1) { 202 if (mask & edge) { 203 type = mask & data ? 0 : 1; 204 val = row * 8 + column; 205 DPRINTF("(%2d, %2d) %d \n", 206 row, column, type); 207 hpckbd_input(hpckbd, type, val); 208 } 209 } 210 } 211 } 212 213 SHREG_PDDR = 0xff; 214 SHREG_PEDR = 0xff; 215 data = SHREG_PGDR | (SHREG_PHDR << 8); 216 217 reinstall: 218 callout_reset(&pc->pc_soft_ch, 1, pfckbd_soft, pc); 219 } 220