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