Home | History | Annotate | Line # | Download | only in sa11x0
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