Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1999 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 MVME147's parallel printer port
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/kernel.h>
     42 #include <sys/device.h>
     43 #include <sys/syslog.h>
     44 
     45 #include <machine/bus.h>
     46 
     47 #include <dev/mvme/lptvar.h>
     48 
     49 #include <mvme68k/dev/lpt_pccreg.h>
     50 #include <mvme68k/dev/pccreg.h>
     51 #include <mvme68k/dev/pccvar.h>
     52 
     53 #include "ioconf.h"
     54 
     55 
     56 static int lpt_pcc_intr(void *);
     57 static void lpt_pcc_open(struct lpt_softc *, int);
     58 static void lpt_pcc_close(struct lpt_softc *);
     59 static void lpt_pcc_iprime(struct lpt_softc *);
     60 static void lpt_pcc_speed(struct lpt_softc *, int);
     61 static int lpt_pcc_notrdy(struct lpt_softc *, int);
     62 static void lpt_pcc_wr_data(struct lpt_softc *, u_char);
     63 
     64 struct lpt_funcs lpt_pcc_funcs = {
     65 	lpt_pcc_open,
     66 	lpt_pcc_close,
     67 	lpt_pcc_iprime,
     68 	lpt_pcc_speed,
     69 	lpt_pcc_notrdy,
     70 	lpt_pcc_wr_data
     71 };
     72 
     73 /*
     74  * Autoconfig stuff
     75  */
     76 static int lpt_pcc_match(device_t, cfdata_t , void *);
     77 static void lpt_pcc_attach(device_t, device_t, void *);
     78 
     79 CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc),
     80     lpt_pcc_match, lpt_pcc_attach, NULL, NULL);
     81 
     82 
     83 /*ARGSUSED*/
     84 static int
     85 lpt_pcc_match(device_t parent, cfdata_t cf, void *args)
     86 {
     87 	struct pcc_attach_args *pa;
     88 
     89 	pa = args;
     90 
     91 	if (strcmp(pa->pa_name, lpt_cd.cd_name))
     92 		return 0;
     93 
     94 	pa->pa_ipl = cf->pcccf_ipl;
     95 	return 1;
     96 }
     97 
     98 /*ARGSUSED*/
     99 static void
    100 lpt_pcc_attach(device_t parent, device_t self, void *args)
    101 {
    102 	struct lpt_softc *sc;
    103 	struct pcc_attach_args *pa;
    104 
    105 	sc = device_private(self);
    106 	sc->sc_dev = self;
    107 	pa = args;
    108 
    109 	sc->sc_bust = pa->pa_bust;
    110 	bus_space_map(pa->pa_bust, pa->pa_offset, LPREG_SIZE, 0, &sc->sc_bush);
    111 
    112 	sc->sc_ipl = pa->pa_ipl & PCC_IMASK;
    113 	sc->sc_funcs = &lpt_pcc_funcs;
    114 	sc->sc_laststatus = 0;
    115 
    116 	aprint_normal(": PCC Parallel Printer\n");
    117 
    118 	/*
    119 	 * Disable interrupts until device is opened
    120 	 */
    121 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
    122 
    123 	/*
    124 	 * Main attachment code
    125 	 */
    126 	lpt_attach_subr(sc);
    127 
    128 	/* Register the event counter */
    129 	evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR,
    130 	    pccintr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev));
    131 
    132 	/*
    133 	 * Hook into the printer interrupt
    134 	 */
    135 	pccintr_establish(PCCV_PRINTER, lpt_pcc_intr, sc->sc_ipl, sc,
    136 	    &sc->sc_evcnt);
    137 }
    138 
    139 /*
    140  * Handle printer interrupts which occur when the printer is ready to accept
    141  * another char.
    142  */
    143 int
    144 lpt_pcc_intr(void *arg)
    145 {
    146 	struct lpt_softc *sc;
    147 	int i;
    148 
    149 	sc = arg;
    150 
    151 	/* is printer online and ready for output */
    152 	if (lpt_pcc_notrdy(sc, 0) && lpt_pcc_notrdy(sc, 1))
    153 		return 0;
    154 
    155 	i = lpt_intr(sc);
    156 
    157 	if (pcc_reg_read(sys_pcc, PCCREG_PRNT_INTR_CTRL) & LPI_ACKINT) {
    158 		pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
    159 		    sc->sc_icr | LPI_ACKINT);
    160 	}
    161 
    162 	return i;
    163 }
    164 
    165 
    166 static void
    167 lpt_pcc_open(struct lpt_softc *sc, int int_ena)
    168 {
    169 	int sps;
    170 
    171 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
    172 	    LPI_ACKINT | LPI_FAULTINT);
    173 
    174 	if (int_ena == 0) {
    175 		sps = splhigh();
    176 		sc->sc_icr = sc->sc_ipl | LPI_ENABLE;
    177 		pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
    178 		splx(sps);
    179 	}
    180 }
    181 
    182 static void
    183 lpt_pcc_close(struct lpt_softc *sc)
    184 {
    185 
    186 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0);
    187 	sc->sc_icr = sc->sc_ipl;
    188 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr);
    189 }
    190 
    191 /* ARGSUSED */
    192 static void
    193 lpt_pcc_iprime(struct lpt_softc *sc)
    194 {
    195 
    196 	lpt_control_write(LPC_INPUT_PRIME);
    197 	delay(100);
    198 }
    199 
    200 /* ARGSUSED */
    201 static void
    202 lpt_pcc_speed(struct lpt_softc *sc, int speed)
    203 {
    204 
    205 	if (speed == LPT_STROBE_FAST)
    206 		lpt_control_write(LPC_FAST_STROBE);
    207 	else
    208 		lpt_control_write(0);
    209 }
    210 
    211 static int
    212 lpt_pcc_notrdy(struct lpt_softc *sc, int err)
    213 {
    214 	u_char status;
    215 	u_char new;
    216 
    217 #define	LPS_INVERT	(LPS_SELECT)
    218 #define	LPS_MASK	(LPS_SELECT|LPS_FAULT|LPS_BUSY|LPS_PAPER_EMPTY)
    219 
    220 	status = (lpt_status_read(sc) ^ LPS_INVERT) & LPS_MASK;
    221 
    222 	if (err) {
    223 		new = status & ~sc->sc_laststatus;
    224 		sc->sc_laststatus = status;
    225 
    226 		if (new & LPS_SELECT)
    227 			log(LOG_NOTICE, "%s: offline\n",
    228 			    device_xname(sc->sc_dev));
    229 		else if (new & LPS_PAPER_EMPTY)
    230 			log(LOG_NOTICE, "%s: out of paper\n",
    231 			    device_xname(sc->sc_dev));
    232 		else if (new & LPS_FAULT)
    233 			log(LOG_NOTICE, "%s: output error\n",
    234 			    device_xname(sc->sc_dev));
    235 	}
    236 
    237 	pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL,
    238 	    sc->sc_icr | LPI_FAULTINT);
    239 
    240 	return status;
    241 }
    242 
    243 static void
    244 lpt_pcc_wr_data(struct lpt_softc *sc, u_char data)
    245 {
    246 
    247 	lpt_data_write(sc, data);
    248 }
    249