sa1111_kbc.c revision 1.3 1 /* $NetBSD: sa1111_kbc.c,v 1.3 2004/03/13 17:31:33 bjh21 Exp $ */
2
3 /*
4 * Copyright (c) 2004 Ben Harris.
5 * Copyright (c) 2002 Genetec Corporation. All rights reserved.
6 * Written by Hiroyuki Bessho for Genetec Corporation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of Genetec Corporation may not be used to endorse or
17 * promote products derived from this software without specific prior
18 * written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Driver for keyboard controller in SA-1111 companion chip.
33 */
34 /*
35 * Copyright (c) 1998
36 * Matthias Drochner. All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed for the NetBSD Project
49 * by Matthias Drochner.
50 * 4. The name of the author may not be used to endorse or promote products
51 * derived from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
58 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
62 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 */
64
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: sa1111_kbc.c,v 1.3 2004/03/13 17:31:33 bjh21 Exp $");
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/types.h>
71 #include <sys/callout.h>
72 #include <sys/kernel.h>
73 #include <sys/proc.h>
74 #include <sys/conf.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/errno.h>
78 #include <sys/queue.h>
79 #include <sys/lock.h>
80
81 #include <machine/bus.h>
82 #include <arm/sa11x0/sa1111_reg.h>
83 #include <arm/sa11x0/sa1111_var.h>
84
85 #include <dev/pckbport/pckbportvar.h> /* for prototypes */
86
87 #include "pckbd.h"
88 #include "rnd.h"
89 #include "locators.h"
90
91 struct sackbc_softc {
92 struct device dev;
93
94 bus_space_tag_t iot;
95 bus_space_handle_t ioh;
96
97 void *ih_rx; /* receive interrupt */
98 int intr; /* interrupt number */
99
100 int polling; /* don't process data in interrupt handler */
101 int poll_stat; /* data read from inr handler if polling */
102 int poll_data; /* status read from intr handler if polling */
103
104 pckbport_tag_t pt;
105 };
106
107 static int sackbc_match(struct device *, struct cfdata *, void *);
108 static void sackbc_attach(struct device *, struct device *, void *);
109
110 static int sackbc_xt_translation(void *, pckbport_slot_t, int);
111 #define sackbc_send_devcmd sackbc_send_cmd
112 static int sackbc_send_devcmd(void *, pckbport_slot_t, u_char);
113 static int sackbc_poll_data1(void *, pckbport_slot_t);
114 static void sackbc_slot_enable(void *, pckbport_slot_t, int);
115 static void sackbc_intr_establish(void *, pckbport_slot_t);
116 static void sackbc_set_poll(void *, pckbport_slot_t, int);
117
118 CFATTACH_DECL(sackbc, sizeof(struct sackbc_softc), sackbc_match,
119 sackbc_attach, NULL, NULL);
120
121 static struct pckbport_accessops const sackbc_ops = {
122 sackbc_xt_translation,
123 sackbc_send_devcmd,
124 sackbc_poll_data1,
125 sackbc_slot_enable,
126 sackbc_intr_establish,
127 sackbc_set_poll
128 };
129
130 #define KBD_DELAY DELAY(8)
131
132 /*#define SACKBCDEBUG*/
133
134 #ifdef SACKBCDEBUG
135 #define DPRINTF(arg) printf arg
136 #else
137 #define DPRINTF(arg)
138 #endif
139
140
141 static int
142 sackbc_match(struct device *parent, struct cfdata *cf, void *aux)
143 {
144 struct sa1111_attach_args *aa = (struct sa1111_attach_args *)aux;
145
146 switch( aa->sa_addr ){
147 case SACC_KBD0: case SACC_KBD1:
148 return 1;
149 }
150 return 0;
151 }
152
153 #if 0
154 static int
155 sackbc_txint( void *cookie )
156 {
157 struct sackbc_softc *sc = cookie;
158
159 bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
160
161 return 0;
162 }
163 #endif
164
165 static int
166 sackbc_rxint( void *cookie )
167 {
168 struct sackbc_softc *sc = cookie;
169 int stat, code=-1;
170
171 stat = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
172 DPRINTF(( "sackbc_rxint stat=%x\n", stat ));
173 if( stat & KBDSTAT_RXF ){
174 code = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_DATA );
175
176 if( sc->polling ){
177 sc->poll_data = code;
178 sc->poll_stat = stat;
179 }
180 else
181 pckbportintr(sc->pt, PCKBPORT_KBD_SLOT, code);
182 return 1;
183 }
184
185 return 0;
186 }
187
188 static void
189 sackbc_intr_establish(void *cookie, pckbport_slot_t slot)
190 {
191 struct sackbc_softc *sc = cookie;
192
193 if( !(sc->polling) && sc->ih_rx==NULL ){
194 sc->ih_rx = sacc_intr_establish(
195 (sacc_chipset_tag_t *)(sc->dev.dv_parent),
196 sc->intr+1, IST_EDGE_RAISE, IPL_TTY, sackbc_rxint, sc );
197 if( sc->ih_rx == NULL ){
198 printf( "%s: can't establish interrupt\n",
199 sc->dev.dv_xname );
200 }
201 }
202 }
203
204 static void
205 sackbc_disable_intrhandler( struct sackbc_softc *sc )
206 {
207 if( sc->polling && sc->ih_rx ){
208 sacc_intr_disestablish(
209 (sacc_chipset_tag_t *)(sc->dev.dv_parent),
210 sc->ih_rx );
211 sc->ih_rx = NULL;
212 }
213 }
214
215 static void
216 sackbc_attach(struct device *parent, struct device *self, void *aux)
217 {
218 struct sackbc_softc *sc = (struct sackbc_softc *)self;
219 struct sacc_softc *psc = (struct sacc_softc *)parent;
220 struct sa1111_attach_args *aa = (struct sa1111_attach_args *)aux;
221 struct device *child;
222 uint32_t tmp, clock_bit;
223 int intr;
224
225 switch( aa->sa_addr ){
226 case SACC_KBD0: clock_bit = (1<<6); intr = 21; break;
227 case SACC_KBD1: clock_bit = (1<<5); intr = 18; break;
228 default:
229 return;
230 }
231
232 if( aa->sa_size <= 0 )
233 aa->sa_size = SACCKBD_SIZE;
234 if( aa->sa_intr == SACCCF_INTR_DEFAULT )
235 aa->sa_intr = intr;
236
237 sc->iot = psc->sc_iot;
238 if( bus_space_subregion( psc->sc_iot, psc->sc_ioh,
239 aa->sa_addr, aa->sa_size, &sc->ioh ) ){
240 printf( ": can't map subregion\n" );
241 return;
242 }
243
244 /* enable clock for PS/2 kbd or mouse */
245 tmp = bus_space_read_4( psc->sc_iot, psc->sc_ioh, SACCSC_SKPCR );
246 bus_space_write_4( psc->sc_iot, psc->sc_ioh, SACCSC_SKPCR,
247 tmp | clock_bit );
248
249 sc->ih_rx = NULL;
250 sc->intr = aa->sa_intr;
251 sc->polling = 0;
252
253 tmp = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_CR );
254 bus_space_write_4( sc->iot, sc->ioh, SACCKBD_CR, tmp | KBDCR_ENA );
255
256 /* XXX: this is necessary to get keyboard working. but I don't know why */
257 bus_space_write_4( sc->iot, sc->ioh, SACCKBD_CLKDIV, 2 );
258
259 tmp = bus_space_read_4( sc->iot, sc->ioh, SACCKBD_STAT );
260 if( (tmp & KBDSTAT_ENA) == 0 ){
261 printf("??? can't enable KBD controller\n");
262 return;
263 }
264
265 printf("\n");
266
267 sc->pt = pckbport_attach(sc, &sackbc_ops);
268
269 child = pckbport_attach_slot(self, sc->pt, PCKBPORT_KBD_SLOT);
270
271 #if 0 && NRND > 0 /* XXX: not yet */
272 if (child != NULL && (t->t_slotdata[slot] != NULL))
273 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
274 child->dv_xname, RND_TYPE_TTY, 0);
275 #endif
276 }
277
278
279 static inline int
280 sackbc_wait_output( struct sackbc_softc *sc )
281 {
282 u_int i, stat;
283
284 for (i = 100000; i; i--){
285 stat = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_STAT);
286 delay(100);
287 if( stat & KBDSTAT_TXE)
288 return 1;
289 }
290 return 0;
291 }
292
293 static int
294 sackbc_poll_data1( void *cookie, pckbport_slot_t slot )
295 {
296 struct sackbc_softc *sc = cookie;
297 int i, s, stat, c = -1;
298
299 s = spltty();
300
301 if (sc->polling){
302 stat = sc->poll_stat;
303 c = sc->poll_data;
304 sc->poll_data = -1;
305 sc->poll_stat = -1;
306 if( stat >= 0 &&
307 (stat & (KBDSTAT_RXF|KBDSTAT_STP)) == KBDSTAT_RXF ){
308 splx(s);
309 return c;
310 }
311 }
312
313 /* if 1 port read takes 1us (?), this polls for 100ms */
314 for (i = 100000; i; i--) {
315 stat = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_STAT);
316 if( (stat & (KBDSTAT_RXF|KBDSTAT_STP)) == KBDSTAT_RXF ){
317 KBD_DELAY;
318 c = bus_space_read_4(sc->iot, sc->ioh, SACCKBD_DATA);
319 break;
320 }
321 }
322
323 splx(s);
324 return (c);
325 }
326
327 static int
328 sackbc_send_cmd( void *cookie, pckbport_slot_t slot, u_char val )
329 {
330 struct sackbc_softc *sc = cookie;
331
332 if ( !sackbc_wait_output(sc) )
333 return (0);
334 bus_space_write_1( sc->iot, sc->ioh, SACCKBD_DATA, val );
335 return (1);
336 }
337
338
339 /*
340 * Glue functions for pckbd on sackbc.
341 * These functions emulate those in dev/ic/pckbc.c.
342 *
343 */
344
345 /*
346 * switch scancode translation on / off
347 * return nonzero on success
348 */
349 static int
350 sackbc_xt_translation(void *self, pckbport_slot_t slot, int on)
351 {
352 /* KBD/Mouse controller doesn't have scancode translation */
353 return !on;
354 }
355
356 static void
357 sackbc_slot_enable(void *self, pckbport_slot_t slot, int on)
358 {
359 #if 0
360 struct sackbc_softc *sc = (struct sackbc_softc *) self;
361 int cmd;
362
363 cmd = on ? KBC_KBDENABLE : KBC_KBDDISABLE;
364 if ( !sackbc_send_cmd(sc, cmd ) )
365 printf("sackbc_slot_enable(%d) failed\n", on);
366 #endif
367 }
368
369
370 static void
371 sackbc_set_poll(void *self, pckbport_slot_t slot, int on)
372 {
373 struct sackbc_softc *sc = (struct sackbc_softc *)self;
374 int s;
375
376 s = spltty();
377
378 if( sc->polling != on ){
379
380 sc->polling = on;
381
382 if( on ){
383 sc->poll_data = sc->poll_stat = -1;
384 sackbc_disable_intrhandler(sc);
385 }
386 else {
387 /*
388 * If disabling polling on a device that's
389 * been configured, make sure there are no
390 * bytes left in the FIFO, holding up the
391 * interrupt line. Otherwise we won't get any
392 * further interrupts.
393 */
394 sackbc_rxint(sc);
395 sackbc_intr_establish(sc, PCKBPORT_KBD_SLOT);
396 }
397 }
398 splx(s);
399 }
400