1 1.12 martin /* $NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $ */ 2 1.2 scw 3 1.2 scw /*- 4 1.2 scw * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 1.2 scw * All rights reserved. 6 1.2 scw * 7 1.2 scw * This code is derived from software contributed to The NetBSD Foundation 8 1.2 scw * by Steve C. Woodford. 9 1.2 scw * 10 1.2 scw * Redistribution and use in source and binary forms, with or without 11 1.2 scw * modification, are permitted provided that the following conditions 12 1.2 scw * are met: 13 1.2 scw * 1. Redistributions of source code must retain the above copyright 14 1.2 scw * notice, this list of conditions and the following disclaimer. 15 1.2 scw * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 scw * notice, this list of conditions and the following disclaimer in the 17 1.2 scw * documentation and/or other materials provided with the distribution. 18 1.2 scw * 19 1.2 scw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 scw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 scw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 scw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 scw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 scw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 scw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 scw * POSSIBILITY OF SUCH DAMAGE. 30 1.2 scw */ 31 1.2 scw 32 1.2 scw /* 33 1.2 scw * Device Driver back-end for the MVME147's parallel printer port 34 1.2 scw */ 35 1.8 lukem 36 1.8 lukem #include <sys/cdefs.h> 37 1.12 martin __KERNEL_RCSID(0, "$NetBSD: lpt_pcc.c,v 1.12 2008/04/28 20:23:29 martin Exp $"); 38 1.2 scw 39 1.2 scw #include <sys/param.h> 40 1.2 scw #include <sys/systm.h> 41 1.2 scw #include <sys/kernel.h> 42 1.2 scw #include <sys/device.h> 43 1.2 scw #include <sys/syslog.h> 44 1.2 scw 45 1.3 scw #include <machine/bus.h> 46 1.2 scw 47 1.5 scw #include <dev/mvme/lptvar.h> 48 1.5 scw 49 1.2 scw #include <mvme68k/dev/lpt_pccreg.h> 50 1.2 scw #include <mvme68k/dev/pccreg.h> 51 1.2 scw #include <mvme68k/dev/pccvar.h> 52 1.2 scw 53 1.10 tsutsui #include "ioconf.h" 54 1.2 scw 55 1.2 scw 56 1.10 tsutsui static int lpt_pcc_intr(void *); 57 1.10 tsutsui static void lpt_pcc_open(struct lpt_softc *, int); 58 1.10 tsutsui static void lpt_pcc_close(struct lpt_softc *); 59 1.10 tsutsui static void lpt_pcc_iprime(struct lpt_softc *); 60 1.10 tsutsui static void lpt_pcc_speed(struct lpt_softc *, int); 61 1.10 tsutsui static int lpt_pcc_notrdy(struct lpt_softc *, int); 62 1.10 tsutsui static void lpt_pcc_wr_data(struct lpt_softc *, u_char); 63 1.2 scw 64 1.2 scw struct lpt_funcs lpt_pcc_funcs = { 65 1.2 scw lpt_pcc_open, 66 1.2 scw lpt_pcc_close, 67 1.2 scw lpt_pcc_iprime, 68 1.2 scw lpt_pcc_speed, 69 1.2 scw lpt_pcc_notrdy, 70 1.2 scw lpt_pcc_wr_data 71 1.2 scw }; 72 1.2 scw 73 1.2 scw /* 74 1.2 scw * Autoconfig stuff 75 1.2 scw */ 76 1.11 cube static int lpt_pcc_match(device_t, cfdata_t , void *); 77 1.11 cube static void lpt_pcc_attach(device_t, device_t, void *); 78 1.2 scw 79 1.11 cube CFATTACH_DECL_NEW(lpt_pcc, sizeof(struct lpt_softc), 80 1.7 thorpej lpt_pcc_match, lpt_pcc_attach, NULL, NULL); 81 1.2 scw 82 1.2 scw 83 1.2 scw /*ARGSUSED*/ 84 1.3 scw static int 85 1.11 cube lpt_pcc_match(device_t parent, cfdata_t cf, void *args) 86 1.2 scw { 87 1.3 scw struct pcc_attach_args *pa; 88 1.3 scw 89 1.3 scw pa = args; 90 1.2 scw 91 1.2 scw if (strcmp(pa->pa_name, lpt_cd.cd_name)) 92 1.10 tsutsui return 0; 93 1.2 scw 94 1.2 scw pa->pa_ipl = cf->pcccf_ipl; 95 1.10 tsutsui return 1; 96 1.2 scw } 97 1.2 scw 98 1.2 scw /*ARGSUSED*/ 99 1.2 scw static void 100 1.11 cube lpt_pcc_attach(device_t parent, device_t self, void *args) 101 1.2 scw { 102 1.3 scw struct lpt_softc *sc; 103 1.3 scw struct pcc_attach_args *pa; 104 1.3 scw 105 1.11 cube sc = device_private(self); 106 1.11 cube sc->sc_dev = self; 107 1.3 scw pa = args; 108 1.3 scw 109 1.3 scw sc->sc_bust = pa->pa_bust; 110 1.3 scw bus_space_map(pa->pa_bust, pa->pa_offset, LPREG_SIZE, 0, &sc->sc_bush); 111 1.2 scw 112 1.2 scw sc->sc_ipl = pa->pa_ipl & PCC_IMASK; 113 1.3 scw sc->sc_funcs = &lpt_pcc_funcs; 114 1.2 scw sc->sc_laststatus = 0; 115 1.2 scw 116 1.11 cube aprint_normal(": PCC Parallel Printer\n"); 117 1.2 scw 118 1.2 scw /* 119 1.2 scw * Disable interrupts until device is opened 120 1.2 scw */ 121 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0); 122 1.2 scw 123 1.2 scw /* 124 1.2 scw * Main attachment code 125 1.2 scw */ 126 1.2 scw lpt_attach_subr(sc); 127 1.2 scw 128 1.4 scw /* Register the event counter */ 129 1.4 scw evcnt_attach_dynamic(&sc->sc_evcnt, EVCNT_TYPE_INTR, 130 1.11 cube pccintr_evcnt(sc->sc_ipl), "printer", device_xname(sc->sc_dev)); 131 1.4 scw 132 1.2 scw /* 133 1.2 scw * Hook into the printer interrupt 134 1.2 scw */ 135 1.4 scw pccintr_establish(PCCV_PRINTER, lpt_pcc_intr, sc->sc_ipl, sc, 136 1.4 scw &sc->sc_evcnt); 137 1.2 scw } 138 1.2 scw 139 1.2 scw /* 140 1.2 scw * Handle printer interrupts which occur when the printer is ready to accept 141 1.2 scw * another char. 142 1.2 scw */ 143 1.2 scw int 144 1.10 tsutsui lpt_pcc_intr(void *arg) 145 1.2 scw { 146 1.3 scw struct lpt_softc *sc; 147 1.2 scw int i; 148 1.2 scw 149 1.3 scw sc = arg; 150 1.3 scw 151 1.2 scw /* is printer online and ready for output */ 152 1.2 scw if (lpt_pcc_notrdy(sc, 0) && lpt_pcc_notrdy(sc, 1)) 153 1.2 scw return 0; 154 1.2 scw 155 1.2 scw i = lpt_intr(sc); 156 1.2 scw 157 1.3 scw if (pcc_reg_read(sys_pcc, PCCREG_PRNT_INTR_CTRL) & LPI_ACKINT) { 158 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 159 1.3 scw sc->sc_icr | LPI_ACKINT); 160 1.3 scw } 161 1.2 scw 162 1.10 tsutsui return i; 163 1.2 scw } 164 1.2 scw 165 1.2 scw 166 1.2 scw static void 167 1.10 tsutsui lpt_pcc_open(struct lpt_softc *sc, int int_ena) 168 1.2 scw { 169 1.2 scw int sps; 170 1.2 scw 171 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 172 1.3 scw LPI_ACKINT | LPI_FAULTINT); 173 1.2 scw 174 1.3 scw if (int_ena == 0) { 175 1.2 scw sps = splhigh(); 176 1.2 scw sc->sc_icr = sc->sc_ipl | LPI_ENABLE; 177 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr); 178 1.2 scw splx(sps); 179 1.2 scw } 180 1.2 scw } 181 1.2 scw 182 1.2 scw static void 183 1.10 tsutsui lpt_pcc_close(struct lpt_softc *sc) 184 1.2 scw { 185 1.3 scw 186 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 0); 187 1.2 scw sc->sc_icr = sc->sc_ipl; 188 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, sc->sc_icr); 189 1.2 scw } 190 1.2 scw 191 1.3 scw /* ARGSUSED */ 192 1.2 scw static void 193 1.10 tsutsui lpt_pcc_iprime(struct lpt_softc *sc) 194 1.2 scw { 195 1.3 scw 196 1.3 scw lpt_control_write(LPC_INPUT_PRIME); 197 1.2 scw delay(100); 198 1.2 scw } 199 1.2 scw 200 1.3 scw /* ARGSUSED */ 201 1.2 scw static void 202 1.10 tsutsui lpt_pcc_speed(struct lpt_softc *sc, int speed) 203 1.2 scw { 204 1.3 scw 205 1.3 scw if (speed == LPT_STROBE_FAST) 206 1.3 scw lpt_control_write(LPC_FAST_STROBE); 207 1.2 scw else 208 1.3 scw lpt_control_write(0); 209 1.2 scw } 210 1.2 scw 211 1.2 scw static int 212 1.10 tsutsui lpt_pcc_notrdy(struct lpt_softc *sc, int err) 213 1.2 scw { 214 1.2 scw u_char status; 215 1.2 scw u_char new; 216 1.2 scw 217 1.2 scw #define LPS_INVERT (LPS_SELECT) 218 1.2 scw #define LPS_MASK (LPS_SELECT|LPS_FAULT|LPS_BUSY|LPS_PAPER_EMPTY) 219 1.2 scw 220 1.3 scw status = (lpt_status_read(sc) ^ LPS_INVERT) & LPS_MASK; 221 1.2 scw 222 1.3 scw if (err) { 223 1.2 scw new = status & ~sc->sc_laststatus; 224 1.2 scw sc->sc_laststatus = status; 225 1.2 scw 226 1.2 scw if (new & LPS_SELECT) 227 1.2 scw log(LOG_NOTICE, "%s: offline\n", 228 1.11 cube device_xname(sc->sc_dev)); 229 1.2 scw else if (new & LPS_PAPER_EMPTY) 230 1.2 scw log(LOG_NOTICE, "%s: out of paper\n", 231 1.11 cube device_xname(sc->sc_dev)); 232 1.2 scw else if (new & LPS_FAULT) 233 1.2 scw log(LOG_NOTICE, "%s: output error\n", 234 1.11 cube device_xname(sc->sc_dev)); 235 1.2 scw } 236 1.2 scw 237 1.3 scw pcc_reg_write(sys_pcc, PCCREG_PRNT_INTR_CTRL, 238 1.3 scw sc->sc_icr | LPI_FAULTINT); 239 1.2 scw 240 1.10 tsutsui return status; 241 1.2 scw } 242 1.2 scw 243 1.2 scw static void 244 1.10 tsutsui lpt_pcc_wr_data(struct lpt_softc *sc, u_char data) 245 1.2 scw { 246 1.2 scw 247 1.3 scw lpt_data_write(sc, data); 248 1.2 scw } 249