1 /* $NetBSD: lpt_pcctwo.c,v 1.11 2008/04/28 20:23:54 martin 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.11 2008/04/28 20:23:54 martin 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(parent, cf, args) 84 device_t parent; 85 cfdata_t cf; 86 void *args; 87 { 88 struct pcctwo_attach_args *pa; 89 90 pa = args; 91 92 if (strcmp(pa->pa_name, lpt_cd.cd_name)) 93 return (0); 94 95 #ifdef MVME68K 96 if (machineid != MVME_167 && machineid != MVME_177) 97 return (0); 98 #endif 99 100 #ifdef MVME88K 101 if (machineid != MVME_187) 102 return (0); 103 #endif 104 105 pa->pa_ipl = cf->pcctwocf_ipl; 106 107 return (1); 108 } 109 110 /* ARGSUSED */ 111 void 112 lpt_pcctwo_attach(parent, self, args) 113 device_t parent; 114 device_t self; 115 void *args; 116 { 117 struct pcctwo_attach_args *pa; 118 struct lpt_softc *sc; 119 120 pa = (struct pcctwo_attach_args *) args; 121 sc = device_private(self); 122 sc->sc_dev = self; 123 124 /* The printer registers are part of the PCCChip2's own registers. */ 125 sc->sc_bust = pa->pa_bust; 126 bus_space_map(pa->pa_bust, pa->pa_offset, PCC2REG_SIZE, 0, 127 &sc->sc_bush); 128 129 sc->sc_ipl = pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK; 130 sc->sc_laststatus = 0; 131 sc->sc_funcs = &lpt_pcctwo_funcs; 132 133 aprint_normal(": PCCchip2 Parallel Printer\n"); 134 135 /* 136 * Disable interrupts until device is opened 137 */ 138 pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 0); 139 pcc2_reg_write(sc, PCC2REG_PRT_FAULT_ICSR, 0); 140 pcc2_reg_write(sc, PCC2REG_PRT_SEL_ICSR, 0); 141 pcc2_reg_write(sc, PCC2REG_PRT_PE_ICSR, 0); 142 pcc2_reg_write(sc, PCC2REG_PRT_BUSY_ICSR, 0); 143 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0); 144 145 /* 146 * Main attachment code 147 */ 148 lpt_attach_subr(sc); 149 150 /* Register the event counter */ 151 evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR, 152 pcctwointr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev)); 153 154 /* 155 * Hook into the printer interrupt 156 */ 157 pcctwointr_establish(PCCTWOV_PRT_ACK, lpt_pcctwo_intr, sc->sc_ipl, sc, 158 &sc->sc_evcnt); 159 } 160 161 /* 162 * Handle printer interrupts 163 */ 164 int 165 lpt_pcctwo_intr(arg) 166 void *arg; 167 { 168 struct lpt_softc *sc; 169 int i; 170 171 sc = (struct lpt_softc *) arg; 172 173 /* is printer online and ready for output */ 174 if (lpt_pcctwo_notrdy(sc, 0) || lpt_pcctwo_notrdy(sc, 1)) 175 return (0); 176 177 i = lpt_intr(sc); 178 179 if (pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) & PCCTWO_PRT_IN_SR_PINT) 180 pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 181 sc->sc_icr | PCCTWO_ICR_ICLR); 182 183 return (i); 184 } 185 186 void 187 lpt_pcctwo_open(sc, int_ena) 188 struct lpt_softc *sc; 189 int int_ena; 190 { 191 int sps; 192 193 pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 194 PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE); 195 196 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 197 pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_DOEN); 198 199 if (int_ena == 0) { 200 sps = splhigh(); 201 sc->sc_icr = sc->sc_ipl | PCCTWO_ICR_EDGE; 202 pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, sc->sc_icr); 203 splx(sps); 204 } 205 } 206 207 void 208 lpt_pcctwo_close(sc) 209 struct lpt_softc *sc; 210 { 211 212 pcc2_reg_write(sc, PCC2REG_PRT_ACK_ICSR, 213 PCCTWO_ICR_ICLR | PCCTWO_ICR_EDGE); 214 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 0); 215 } 216 217 void 218 lpt_pcctwo_iprime(sc) 219 struct lpt_softc *sc; 220 { 221 222 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 223 pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) | PCCTWO_PRT_CTRL_INP); 224 225 delay(100); 226 227 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, 228 pcc2_reg_read(sc, PCC2REG_PRT_CONTROL) & ~PCCTWO_PRT_CTRL_INP); 229 230 delay(100); 231 } 232 233 void 234 lpt_pcctwo_speed(sc, speed) 235 struct lpt_softc *sc; 236 int speed; 237 { 238 u_int8_t reg; 239 240 reg = pcc2_reg_read(sc, PCC2REG_PRT_CONTROL); 241 242 if (speed == LPT_STROBE_FAST) 243 reg |= PCCTWO_PRT_CTRL_FAST; 244 else 245 reg &= ~PCCTWO_PRT_CTRL_FAST; 246 247 pcc2_reg_write(sc, PCC2REG_PRT_CONTROL, reg); 248 } 249 250 int 251 lpt_pcctwo_notrdy(sc, err) 252 struct lpt_softc *sc; 253 int err; 254 { 255 u_int8_t status; 256 u_int8_t new; 257 258 #define LPS_INVERT (PCCTWO_PRT_IN_SR_SEL) 259 #define LPS_MASK (PCCTWO_PRT_IN_SR_SEL | PCCTWO_PRT_IN_SR_FLT | \ 260 PCCTWO_PRT_IN_SR_BSY | PCCTWO_PRT_IN_SR_PE) 261 262 status = pcc2_reg_read(sc, PCC2REG_PRT_INPUT_STATUS) ^ LPS_INVERT; 263 status &= LPS_MASK; 264 265 if (err) { 266 new = status & ~sc->sc_laststatus; 267 sc->sc_laststatus = status; 268 269 if (new & PCCTWO_PRT_IN_SR_SEL) 270 log(LOG_NOTICE, "%s: offline\n", 271 device_xname(sc->sc_dev)); 272 else if (new & PCCTWO_PRT_IN_SR_PE) 273 log(LOG_NOTICE, "%s: out of paper\n", 274 device_xname(sc->sc_dev)); 275 else if (new & PCCTWO_PRT_IN_SR_FLT) 276 log(LOG_NOTICE, "%s: output error\n", 277 device_xname(sc->sc_dev)); 278 } 279 280 return (status); 281 } 282 283 void 284 lpt_pcctwo_wr_data(sc, data) 285 struct lpt_softc *sc; 286 u_char data; 287 { 288 289 pcc2_reg_write16(sc, PCC2REG_PRT_DATA, (u_int16_t) data); 290 } 291