Home | History | Annotate | Line # | Download | only in mvme
      1 /*	$NetBSD: lpt_pcctwo.c,v 1.12 2009/03/14 15:36:19 dsl Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Steve C. Woodford.
      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  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Device Driver back-end for the PCCChip2's parallel printer port
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: lpt_pcctwo.c,v 1.12 2009/03/14 15:36:19 dsl Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/kernel.h>
     41 #include <sys/systm.h>
     42 #include <sys/device.h>
     43 #include <sys/syslog.h>
     44 
     45 #include <sys/cpu.h>
     46 #include <sys/bus.h>
     47 
     48 #include <dev/mvme/lptvar.h>
     49 #include <dev/mvme/pcctworeg.h>
     50 #include <dev/mvme/pcctwovar.h>
     51 
     52 /*
     53  * Autoconfig stuff
     54  */
     55 int lpt_pcctwo_match(device_t, cfdata_t , void *);
     56 void lpt_pcctwo_attach(device_t, device_t, void *);
     57 
     58 CFATTACH_DECL_NEW(lpt_pcctwo, sizeof(struct lpt_softc),
     59     lpt_pcctwo_match, lpt_pcctwo_attach, NULL, NULL);
     60 
     61 extern struct cfdriver lpt_cd;
     62 
     63 
     64 int lpt_pcctwo_intr(void *);
     65 void lpt_pcctwo_open(struct lpt_softc *, int);
     66 void lpt_pcctwo_close(struct lpt_softc *);
     67 void lpt_pcctwo_iprime(struct lpt_softc *);
     68 void lpt_pcctwo_speed(struct lpt_softc *, int);
     69 int lpt_pcctwo_notrdy(struct lpt_softc *, int);
     70 void lpt_pcctwo_wr_data(struct lpt_softc *, u_char);
     71 
     72 struct lpt_funcs lpt_pcctwo_funcs = {
     73 	lpt_pcctwo_open,
     74 	lpt_pcctwo_close,
     75 	lpt_pcctwo_iprime,
     76 	lpt_pcctwo_speed,
     77 	lpt_pcctwo_notrdy,
     78 	lpt_pcctwo_wr_data
     79 };
     80 
     81 /* ARGSUSED */
     82 int
     83 lpt_pcctwo_match(device_t parent, cfdata_t cf, void *args)
     84 {
     85 	struct pcctwo_attach_args *pa;
     86 
     87 	pa = args;
     88 
     89 	if (strcmp(pa->pa_name, lpt_cd.cd_name))
     90 		return (0);
     91 
     92 #ifdef MVME68K
     93 	if (machineid != MVME_167 && machineid != MVME_177)
     94 		return (0);
     95 #endif
     96 
     97 #ifdef MVME88K
     98 	if (machineid != MVME_187)
     99 		return (0);
    100 #endif
    101 
    102 	pa->pa_ipl = cf->pcctwocf_ipl;
    103 
    104 	return (1);
    105 }
    106 
    107 /* ARGSUSED */
    108 void
    109 lpt_pcctwo_attach(device_t parent, device_t self, void *args)
    110 {
    111 	struct pcctwo_attach_args *pa;
    112 	struct lpt_softc *sc;
    113 
    114 	pa = (struct pcctwo_attach_args *) args;
    115 	sc = device_private(self);
    116 	sc->sc_dev = self;
    117 
    118 	/* The printer registers are part of the PCCChip2's own registers. */
    119 	sc->sc_bust = pa->pa_bust;
    120 	bus_space_map(pa->pa_bust, pa->pa_offset, PCC2REG_SIZE, 0,
    121 	    &sc->sc_bush);
    122 
    123 	sc->sc_ipl = pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK;
    124 	sc->sc_laststatus = 0;
    125 	sc->sc_funcs = &lpt_pcctwo_funcs;
    126 
    127 	aprint_normal(": PCCchip2 Parallel Printer\n");
    128 
    129 	/*
    130 	 * Disable interrupts until device is opened
    131 	 */
    132 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 0);
    133 	pcc2_reg_write(sc, PCC2REG_PRT_FAULT_ICSR, 0);
    134 	pcc2_reg_write(sc, PCC2REG_PRT_SEL_ICSR, 0);
    135 	pcc2_reg_write(sc, PCC2REG_PRT_PE_ICSR, 0);
    136 	pcc2_reg_write(sc, PCC2REG_PRT_BUSY_ICSR, 0);
    137 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
    138 
    139 	/*
    140 	 * Main attachment code
    141 	 */
    142 	lpt_attach_subr(sc);
    143 
    144 	/* Register the event counter */
    145 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
    146 	    pcctwointr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev));
    147 
    148 	/*
    149 	 * Hook into the printer interrupt
    150 	 */
    151 	pcctwointr_establish(PCCTWOV_PRT_ACK, lpt_pcctwo_intr, sc->sc_ipl, sc,
    152 	    &sc->sc_evcnt);
    153 }
    154 
    155 /*
    156  * Handle printer interrupts
    157  */
    158 int
    159 lpt_pcctwo_intr(void *arg)
    160 {
    161 	struct lpt_softc *sc;
    162 	int i;
    163 
    164 	sc = (struct lpt_softc *) arg;
    165 
    166 	/* is printer online and ready for output */
    167 	if (lpt_pcctwo_notrdy(sc, 0) || lpt_pcctwo_notrdy(sc, 1))
    168 		return (0);
    169 
    170 	i = lpt_intr(sc);
    171 
    172 	if (pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) & PCCTWO_PRT_IN_SR_PINT)
    173 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
    174 		    sc->sc_icr | PCCTWO_ICR_ICLR);
    175 
    176 	return (i);
    177 }
    178 
    179 void
    180 lpt_pcctwo_open(struct lpt_softc *sc, int int_ena)
    181 {
    182 	int sps;
    183 
    184 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
    185 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
    186 
    187 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
    188 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_DOEN);
    189 
    190 	if (int_ena == 0) {
    191 		sps = splhigh();
    192 		sc->sc_icr = sc->sc_ipl | PCCTWO_ICR_EDGE;
    193 		pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, sc->sc_icr);
    194 		splx(sps);
    195 	}
    196 }
    197 
    198 void
    199 lpt_pcctwo_close(struct lpt_softc *sc)
    200 {
    201 
    202 	pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR,
    203 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE);
    204 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0);
    205 }
    206 
    207 void
    208 lpt_pcctwo_iprime(struct lpt_softc *sc)
    209 {
    210 
    211 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
    212 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_INP);
    213 
    214 	delay(100);
    215 
    216 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL,
    217 	    pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) & ~PCCTWO_PRT_CTRL_INP);
    218 
    219 	delay(100);
    220 }
    221 
    222 void
    223 lpt_pcctwo_speed(struct lpt_softc *sc, int speed)
    224 {
    225 	u_int8_t reg;
    226 
    227 	reg = pcc2_reg_read(sc, PCC2REG_PRT_CONTROL);
    228 
    229 	if (speed == LPT_STROBE_FAST)
    230 		reg |= PCCTWO_PRT_CTRL_FAST;
    231 	else
    232 		reg &= ~PCCTWO_PRT_CTRL_FAST;
    233 
    234 	pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, reg);
    235 }
    236 
    237 int
    238 lpt_pcctwo_notrdy(struct lpt_softc *sc, int err)
    239 {
    240 	u_int8_t status;
    241 	u_int8_t new;
    242 
    243 #define	LPS_INVERT	(PCCTWO_PRT_IN_SR_SEL)
    244 #define	LPS_MASK	(PCCTWO_PRT_IN_SR_SEL | PCCTWO_PRT_IN_SR_FLT | \
    245 			 PCCTWO_PRT_IN_SR_BSY | PCCTWO_PRT_IN_SR_PE)
    246 
    247 	status = pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) ^ LPS_INVERT;
    248 	status &= LPS_MASK;
    249 
    250 	if (err) {
    251 		new = status & ~sc->sc_laststatus;
    252 		sc->sc_laststatus = status;
    253 
    254 		if (new & PCCTWO_PRT_IN_SR_SEL)
    255 			log(LOG_NOTICE, "%s: offline\n",
    256 			    device_xname(sc->sc_dev));
    257 		else if (new & PCCTWO_PRT_IN_SR_PE)
    258 			log(LOG_NOTICE, "%s: out of paper\n",
    259 			    device_xname(sc->sc_dev));
    260 		else if (new & PCCTWO_PRT_IN_SR_FLT)
    261 			log(LOG_NOTICE, "%s: output error\n",
    262 			    device_xname(sc->sc_dev));
    263 	}
    264 
    265 	return (status);
    266 }
    267 
    268 void
    269 lpt_pcctwo_wr_data(struct lpt_softc *sc, u_char data)
    270 {
    271 
    272 	pcc2_reg_write16(sc, PCC2REG_PRT_DATA, (u_int16_t) data);
    273 }
    274