1 1.32 msaitoh /* $NetBSD: lpt.c,v 1.32 2019/12/27 09:28:41 msaitoh Exp $ */ 2 1.3 bjh21 3 1.1 jdolecek /* 4 1.1 jdolecek * Copyright (c) 1990 William F. Jolitz, TeleMuse 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 8 1.1 jdolecek * modification, are permitted provided that the following conditions 9 1.1 jdolecek * are met: 10 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 11 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 12 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 14 1.1 jdolecek * documentation and/or other materials provided with the distribution. 15 1.1 jdolecek * 3. All advertising materials mentioning features or use of this software 16 1.1 jdolecek * must display the following acknowledgement: 17 1.1 jdolecek * This software is a component of "386BSD" developed by 18 1.1 jdolecek * William F. Jolitz, TeleMuse. 19 1.1 jdolecek * 4. Neither the name of the developer nor the name "386BSD" 20 1.1 jdolecek * may be used to endorse or promote products derived from this software 21 1.1 jdolecek * without specific prior written permission. 22 1.1 jdolecek * 23 1.1 jdolecek * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 24 1.1 jdolecek * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 25 1.1 jdolecek * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 26 1.1 jdolecek * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 27 1.1 jdolecek * NOT MAKE USE OF THIS WORK. 28 1.1 jdolecek * 29 1.1 jdolecek * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 30 1.1 jdolecek * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 31 1.1 jdolecek * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 32 1.1 jdolecek * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 33 1.1 jdolecek * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 34 1.1 jdolecek * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 35 1.1 jdolecek * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 36 1.1 jdolecek * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 37 1.1 jdolecek * 38 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 39 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 42 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 1.1 jdolecek * SUCH DAMAGE. 49 1.1 jdolecek * 50 1.1 jdolecek * from: unknown origin, 386BSD 0.1 51 1.1 jdolecek * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 52 1.1 jdolecek * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp 53 1.5 bjh21 * FreeBSD: src/sys/dev/ppbus/lpt.c,v 1.15.2.3 2000/07/07 00:30:40 obrien Exp 54 1.1 jdolecek */ 55 1.1 jdolecek 56 1.1 jdolecek /* 57 1.1 jdolecek * Device Driver for AT parallel printer port 58 1.1 jdolecek * Written by William Jolitz 12/18/90 59 1.1 jdolecek */ 60 1.1 jdolecek 61 1.1 jdolecek /* 62 1.1 jdolecek * Updated for ppbus by Nicolas Souchu 63 1.1 jdolecek * [Mon Jul 28 1997] 64 1.1 jdolecek */ 65 1.1 jdolecek 66 1.5 bjh21 #include <sys/cdefs.h> 67 1.32 msaitoh __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.32 2019/12/27 09:28:41 msaitoh Exp $"); 68 1.5 bjh21 69 1.1 jdolecek #include "opt_ppbus_lpt.h" 70 1.1 jdolecek 71 1.1 jdolecek #include <sys/param.h> 72 1.1 jdolecek #include <sys/systm.h> 73 1.1 jdolecek #include <sys/conf.h> 74 1.1 jdolecek #include <sys/kernel.h> 75 1.1 jdolecek #include <sys/proc.h> 76 1.1 jdolecek #include <sys/malloc.h> 77 1.1 jdolecek #include <sys/file.h> 78 1.1 jdolecek #include <sys/uio.h> 79 1.1 jdolecek #include <sys/ioctl.h> 80 1.1 jdolecek #include <sys/types.h> 81 1.1 jdolecek #include <sys/syslog.h> 82 1.1 jdolecek 83 1.20 ad #include <sys/bus.h> 84 1.1 jdolecek 85 1.1 jdolecek #include <dev/ppbus/ppbus_1284.h> 86 1.1 jdolecek #include <dev/ppbus/ppbus_base.h> 87 1.1 jdolecek #include <dev/ppbus/ppbus_io.h> 88 1.1 jdolecek #include <dev/ppbus/ppbus_msq.h> 89 1.1 jdolecek #include <dev/ppbus/ppbus_var.h> 90 1.1 jdolecek 91 1.1 jdolecek #include <dev/ppbus/lptvar.h> 92 1.1 jdolecek #include <dev/ppbus/lptreg.h> 93 1.1 jdolecek #include <dev/ppbus/lptio.h> 94 1.1 jdolecek 95 1.1 jdolecek /* Autoconf functions */ 96 1.24 cegger static int lpt_probe(device_t, cfdata_t, void *); 97 1.21 dyoung static void lpt_attach(device_t, device_t, void *); 98 1.21 dyoung static int lpt_detach(device_t, int); 99 1.1 jdolecek 100 1.1 jdolecek /* Autoconf structure */ 101 1.24 cegger CFATTACH_DECL_NEW(lpt_ppbus, sizeof(struct lpt_softc), lpt_probe, lpt_attach, 102 1.1 jdolecek lpt_detach, NULL); 103 1.1 jdolecek 104 1.1 jdolecek extern struct cfdriver lpt_cd; 105 1.1 jdolecek 106 1.1 jdolecek dev_type_open(lptopen); 107 1.1 jdolecek dev_type_close(lptclose); 108 1.1 jdolecek dev_type_read(lptread); 109 1.1 jdolecek dev_type_write(lptwrite); 110 1.1 jdolecek dev_type_ioctl(lptioctl); 111 1.1 jdolecek 112 1.1 jdolecek const struct cdevsw lpt_cdevsw = { 113 1.29 dholland .d_open = lptopen, 114 1.29 dholland .d_close = lptclose, 115 1.29 dholland .d_read = lptread, 116 1.29 dholland .d_write = lptwrite, 117 1.29 dholland .d_ioctl = lptioctl, 118 1.29 dholland .d_stop = nostop, 119 1.29 dholland .d_tty = notty, 120 1.29 dholland .d_poll = nopoll, 121 1.29 dholland .d_mmap = nommap, 122 1.29 dholland .d_kqfilter = nokqfilter, 123 1.30 dholland .d_discard = nodiscard, 124 1.29 dholland .d_flag = D_OTHER 125 1.1 jdolecek }; 126 1.1 jdolecek 127 1.1 jdolecek 128 1.1 jdolecek /* Function prototypes */ 129 1.21 dyoung static int lpt_detect(device_t); 130 1.1 jdolecek static int lpt_request_ppbus(struct lpt_softc *, int); 131 1.1 jdolecek static int lpt_release_ppbus(struct lpt_softc *, int); 132 1.21 dyoung static int lpt_logstatus(const device_t, const unsigned char); 133 1.1 jdolecek 134 1.1 jdolecek /* 135 1.1 jdolecek * lpt_probe() 136 1.1 jdolecek */ 137 1.1 jdolecek static int 138 1.24 cegger lpt_probe(device_t parent, cfdata_t match, void *aux) 139 1.1 jdolecek { 140 1.1 jdolecek /* Test ppbus's capability */ 141 1.13 perry return lpt_detect(parent); 142 1.1 jdolecek } 143 1.1 jdolecek 144 1.1 jdolecek static void 145 1.21 dyoung lpt_attach(device_t parent, device_t self, void *aux) 146 1.1 jdolecek { 147 1.17 thorpej struct lpt_softc * sc = device_private(self); 148 1.1 jdolecek struct ppbus_device_softc * ppbdev = &(sc->ppbus_dev); 149 1.1 jdolecek struct ppbus_attach_args * args = aux; 150 1.1 jdolecek char buf[64]; 151 1.1 jdolecek int error; 152 1.1 jdolecek 153 1.27 cegger ppbdev->sc_dev = self; 154 1.27 cegger 155 1.1 jdolecek error = lpt_request_ppbus(sc, 0); 156 1.1 jdolecek if(error) { 157 1.1 jdolecek printf("%s(%s): error (%d) requesting bus(%s). Device not " 158 1.23 cegger "properly attached.\n", __func__, device_xname(self), 159 1.23 cegger error, device_xname(parent)); 160 1.1 jdolecek return; 161 1.1 jdolecek } 162 1.1 jdolecek 163 1.1 jdolecek /* Record capabilities */ 164 1.1 jdolecek ppbdev->capabilities = args->capabilities; 165 1.1 jdolecek 166 1.1 jdolecek /* Allocate memory buffers */ 167 1.1 jdolecek if(ppbdev->capabilities & PPBUS_HAS_DMA) { 168 1.13 perry if(ppbus_dma_malloc(parent, &(sc->sc_inbuf), 169 1.1 jdolecek &(sc->sc_in_baddr), BUFSIZE)) { 170 1.13 perry 171 1.1 jdolecek printf(" : cannot allocate input DMA buffer. Device " 172 1.1 jdolecek "not properly attached!\n"); 173 1.1 jdolecek return; 174 1.1 jdolecek } 175 1.13 perry if(ppbus_dma_malloc(parent, &(sc->sc_outbuf), 176 1.1 jdolecek &(sc->sc_out_baddr), BUFSIZE)) { 177 1.13 perry 178 1.13 perry ppbus_dma_free(parent, &(sc->sc_inbuf), 179 1.1 jdolecek &(sc->sc_in_baddr), BUFSIZE); 180 1.1 jdolecek printf(" : cannot allocate output DMA buffer. Device " 181 1.1 jdolecek "not properly attached!\n"); 182 1.1 jdolecek return; 183 1.1 jdolecek } 184 1.9 jdolecek } else { 185 1.1 jdolecek sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 186 1.1 jdolecek sc->sc_outbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 187 1.1 jdolecek } 188 1.1 jdolecek 189 1.1 jdolecek /* Print out mode */ 190 1.1 jdolecek ppbdev->ctx.mode = ppbus_get_mode(parent); 191 1.28 christos snprintb(buf, sizeof(buf), 192 1.28 christos "\20\1COMPATIBLE\2NIBBLE\3PS2\4EPP\5ECP\6FAST_CENTR", 193 1.28 christos ppbdev->ctx.mode); 194 1.6 jdolecek printf(": port mode = %s\n", buf); 195 1.1 jdolecek 196 1.12 jdolecek /* Initialize the device on open by default */ 197 1.12 jdolecek sc->sc_flags = LPT_PRIME; 198 1.12 jdolecek 199 1.1 jdolecek lpt_release_ppbus(sc, 0); 200 1.1 jdolecek } 201 1.1 jdolecek 202 1.1 jdolecek static int 203 1.21 dyoung lpt_detach(device_t self, int flags) 204 1.1 jdolecek { 205 1.17 thorpej struct lpt_softc * lpt = device_private(self); 206 1.1 jdolecek struct ppbus_device_softc * ppbdev = (struct ppbus_device_softc *) lpt; 207 1.1 jdolecek int err; 208 1.1 jdolecek 209 1.1 jdolecek if(lpt->sc_state & HAVEBUS) { 210 1.1 jdolecek err = lpt_release_ppbus(lpt, 0); 211 1.1 jdolecek if(err) { 212 1.13 perry printf("%s error (%d) while releasing bus", 213 1.23 cegger device_xname(self), err); 214 1.1 jdolecek if(flags & DETACH_FORCE) { 215 1.13 perry printf(", continuing (DETACH_FORCE)!\n"); 216 1.1 jdolecek } 217 1.1 jdolecek else { 218 1.1 jdolecek printf(", terminating!\n"); 219 1.1 jdolecek return 0; 220 1.1 jdolecek } 221 1.1 jdolecek } 222 1.1 jdolecek lpt->sc_state &= ~HAVEBUS; 223 1.1 jdolecek } 224 1.1 jdolecek 225 1.1 jdolecek ppbdev->ctx.valid = 0; 226 1.1 jdolecek 227 1.1 jdolecek /* Free memory buffers */ 228 1.1 jdolecek if(ppbdev->capabilities & PPBUS_HAS_DMA) { 229 1.16 thorpej ppbus_dma_free(device_parent(self), &(lpt->sc_inbuf), 230 1.13 perry &(lpt->sc_in_baddr), BUFSIZE); 231 1.16 thorpej ppbus_dma_free(device_parent(self), &(lpt->sc_outbuf), 232 1.1 jdolecek &(lpt->sc_out_baddr), BUFSIZE); 233 1.9 jdolecek } else { 234 1.1 jdolecek free(lpt->sc_inbuf, M_DEVBUF); 235 1.1 jdolecek free(lpt->sc_outbuf, M_DEVBUF); 236 1.1 jdolecek } 237 1.1 jdolecek 238 1.1 jdolecek return 1; 239 1.1 jdolecek } 240 1.1 jdolecek 241 1.1 jdolecek /* Grab bus for lpt device */ 242 1.1 jdolecek static int 243 1.1 jdolecek lpt_request_ppbus(struct lpt_softc * lpt, int how) 244 1.1 jdolecek { 245 1.24 cegger device_t dev = lpt->ppbus_dev.sc_dev; 246 1.1 jdolecek int error; 247 1.1 jdolecek 248 1.16 thorpej error = ppbus_request_bus(device_parent(dev), dev, how, (hz)); 249 1.1 jdolecek if (!(error)) { 250 1.1 jdolecek lpt->sc_state |= HAVEBUS; 251 1.1 jdolecek } 252 1.1 jdolecek else { 253 1.13 perry LPT_DPRINTF(("%s(%s): error %d requesting bus.\n", __func__, 254 1.23 cegger device_xname(dev), error)); 255 1.1 jdolecek } 256 1.1 jdolecek 257 1.1 jdolecek return error; 258 1.1 jdolecek } 259 1.1 jdolecek 260 1.1 jdolecek /* Release ppbus to enable other devices to use it. */ 261 1.1 jdolecek static int 262 1.1 jdolecek lpt_release_ppbus(struct lpt_softc * lpt, int how) 263 1.1 jdolecek { 264 1.24 cegger device_t dev = lpt->ppbus_dev.sc_dev; 265 1.1 jdolecek int error; 266 1.1 jdolecek 267 1.1 jdolecek if(lpt->sc_state & HAVEBUS) { 268 1.16 thorpej error = ppbus_release_bus(device_parent(dev), dev, how, (hz)); 269 1.1 jdolecek if(!(error)) 270 1.1 jdolecek lpt->sc_state &= ~HAVEBUS; 271 1.25 cegger else { 272 1.1 jdolecek LPT_DPRINTF(("%s(%s): error releasing bus.\n", __func__, 273 1.23 cegger device_xname(dev))); 274 1.25 cegger } 275 1.1 jdolecek } 276 1.1 jdolecek else { 277 1.1 jdolecek error = EINVAL; 278 1.13 perry LPT_DPRINTF(("%s(%s): device does not own bus.\n", __func__, 279 1.23 cegger device_xname(dev))); 280 1.1 jdolecek } 281 1.1 jdolecek 282 1.1 jdolecek return error; 283 1.1 jdolecek } 284 1.1 jdolecek 285 1.1 jdolecek 286 1.1 jdolecek /* 287 1.1 jdolecek * Probe simplified by replacing multiple loops with a hardcoded 288 1.1 jdolecek * test pattern - 1999/02/08 des (at) freebsd.org 289 1.1 jdolecek * 290 1.1 jdolecek * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 291 1.1 jdolecek * Based partially on Rod Grimes' printer probe 292 1.1 jdolecek * 293 1.1 jdolecek * Logic: 294 1.1 jdolecek * 1) If no port address was given, use the bios detected ports 295 1.1 jdolecek * and autodetect what ports the printers are on. 296 1.1 jdolecek * 2) Otherwise, probe the data port at the address given, 297 1.1 jdolecek * using the method in Rod Grimes' port probe. 298 1.1 jdolecek * (Much code ripped off directly from Rod's probe.) 299 1.1 jdolecek * 300 1.1 jdolecek * Comments from Rod's probe: 301 1.1 jdolecek * Logic: 302 1.1 jdolecek * 1) You should be able to write to and read back the same value 303 1.1 jdolecek * to the data port. Do an alternating zeros, alternating ones, 304 1.1 jdolecek * walking zero, and walking one test to check for stuck bits. 305 1.1 jdolecek * 306 1.1 jdolecek * 2) You should be able to write to and read back the same value 307 1.1 jdolecek * to the control port lower 5 bits, the upper 3 bits are reserved 308 1.32 msaitoh * per the IBM PC technical reference manuals and different boards 309 1.1 jdolecek * do different things with them. Do an alternating zeros, alternating 310 1.1 jdolecek * ones, walking zero, and walking one test to check for stuck bits. 311 1.1 jdolecek * 312 1.1 jdolecek * Some printers drag the strobe line down when the are powered off 313 1.1 jdolecek * so this bit has been masked out of the control port test. 314 1.1 jdolecek * 315 1.1 jdolecek * XXX Some printers may not like a fast pulse on init or strobe, I 316 1.1 jdolecek * don't know at this point, if that becomes a problem these bits 317 1.1 jdolecek * should be turned off in the mask byte for the control port test. 318 1.1 jdolecek * 319 1.1 jdolecek * We are finally left with a mask of 0x14, due to some printers 320 1.1 jdolecek * being adamant about holding other bits high ........ 321 1.1 jdolecek * 322 1.1 jdolecek * Before probing the control port, we write a 0 to the data port - 323 1.1 jdolecek * If not, some printers chuck out garbage when the strobe line 324 1.1 jdolecek * gets toggled. 325 1.1 jdolecek * 326 1.1 jdolecek * 3) Set the data and control ports to a value of 0 327 1.1 jdolecek * 328 1.1 jdolecek * This probe routine has been tested on Epson Lx-800, HP LJ3P, 329 1.1 jdolecek * Epson FX-1170 and C.Itoh 8510RM 330 1.1 jdolecek * printers. 331 1.1 jdolecek * Quick exit on fail added. 332 1.1 jdolecek */ 333 1.1 jdolecek static int 334 1.21 dyoung lpt_detect(device_t dev) 335 1.1 jdolecek { 336 1.8 jdolecek static const u_char testbyte[18] = { 337 1.1 jdolecek 0x55, /* alternating zeros */ 338 1.1 jdolecek 0xaa, /* alternating ones */ 339 1.1 jdolecek 0xfe, 0xfd, 0xfb, 0xf7, 340 1.1 jdolecek 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 341 1.1 jdolecek 0x01, 0x02, 0x04, 0x08, 342 1.1 jdolecek 0x10, 0x20, 0x40, 0x80 /* walking one */ 343 1.1 jdolecek }; 344 1.1 jdolecek int i, status; 345 1.1 jdolecek u_char dtr, ctr, str, var; 346 1.1 jdolecek 347 1.1 jdolecek /* Save register contents */ 348 1.1 jdolecek dtr = ppbus_rdtr(dev); 349 1.1 jdolecek ctr = ppbus_rctr(dev); 350 1.1 jdolecek str = ppbus_rstr(dev); 351 1.1 jdolecek 352 1.1 jdolecek status = 1; /* assume success */ 353 1.1 jdolecek 354 1.1 jdolecek /* Test data port */ 355 1.1 jdolecek for(i = 0; i < 18; i++) { 356 1.1 jdolecek ppbus_wdtr(dev, testbyte[i]); 357 1.1 jdolecek if((var = ppbus_rdtr(dev)) != testbyte[i]) { 358 1.1 jdolecek status = 0; 359 1.1 jdolecek LPT_DPRINTF(("%s(%s): byte value %x cannot be written " 360 1.13 perry "and read from data port (got %x instead).\n", 361 1.23 cegger __func__, device_xname(dev), testbyte[i], var)); 362 1.1 jdolecek goto end; 363 1.1 jdolecek } 364 1.1 jdolecek } 365 1.1 jdolecek 366 1.1 jdolecek /* Test control port */ 367 1.1 jdolecek ppbus_wdtr(dev, 0); 368 1.1 jdolecek for(i = 0; i < 18; i++) { 369 1.1 jdolecek ppbus_wctr(dev, (testbyte[i] & 0x14)); 370 1.1 jdolecek if(((var = ppbus_rctr(dev)) & 0x14) != (testbyte[i] & 0x14)) { 371 1.1 jdolecek status = 0; 372 1.1 jdolecek LPT_DPRINTF(("%s(%s): byte value %x (unmasked value " 373 1.1 jdolecek "%x) cannot be written and read from control " 374 1.13 perry "port (got %x instead).\n", __func__, 375 1.23 cegger device_xname(dev), (testbyte[i] & 0x14), 376 1.13 perry testbyte[i], (var & 0x14))); 377 1.1 jdolecek break; 378 1.1 jdolecek } 379 1.1 jdolecek } 380 1.1 jdolecek 381 1.1 jdolecek end: 382 1.1 jdolecek /* Restore contents of registers */ 383 1.1 jdolecek ppbus_wdtr(dev, dtr); 384 1.1 jdolecek ppbus_wctr(dev, ctr); 385 1.1 jdolecek ppbus_wstr(dev, str); 386 1.1 jdolecek 387 1.1 jdolecek return status; 388 1.1 jdolecek } 389 1.1 jdolecek 390 1.1 jdolecek /* Log status of status register for printer port */ 391 1.13 perry static int 392 1.21 dyoung lpt_logstatus(const device_t dev, const unsigned char status) 393 1.1 jdolecek { 394 1.1 jdolecek int err; 395 1.1 jdolecek 396 1.1 jdolecek err = EIO; 397 1.1 jdolecek if(!(status & LPS_SEL)) { 398 1.23 cegger log(LOG_ERR, "%s: offline.", device_xname(dev)); 399 1.1 jdolecek } 400 1.1 jdolecek else if(!(status & LPS_NBSY)) { 401 1.23 cegger log(LOG_ERR, "%s: busy.", device_xname(dev)); 402 1.1 jdolecek } 403 1.1 jdolecek else if(status & LPS_OUT) { 404 1.23 cegger log(LOG_ERR, "%s: out of paper.", device_xname(dev)); 405 1.1 jdolecek err = EAGAIN; 406 1.1 jdolecek } 407 1.1 jdolecek else if(!(status & LPS_NERR)) { 408 1.23 cegger log(LOG_ERR, "%s: output error.", device_xname(dev)); 409 1.1 jdolecek } 410 1.1 jdolecek else { 411 1.23 cegger log(LOG_ERR, "%s: no error indication.", device_xname(dev)); 412 1.1 jdolecek err = 0; 413 1.1 jdolecek } 414 1.1 jdolecek 415 1.1 jdolecek return err; 416 1.1 jdolecek } 417 1.1 jdolecek 418 1.1 jdolecek /* 419 1.1 jdolecek * lptopen -- reset the printer, then wait until it's selected and not busy. 420 1.1 jdolecek */ 421 1.1 jdolecek int 422 1.15 rpaulo lptopen(dev_t dev_id, int flags, int fmt, struct lwp *l) 423 1.1 jdolecek { 424 1.12 jdolecek int trys, err; 425 1.1 jdolecek u_int8_t status; 426 1.21 dyoung device_t dev; 427 1.1 jdolecek struct lpt_softc * lpt; 428 1.1 jdolecek struct ppbus_device_softc * ppbus_dev; 429 1.21 dyoung device_t ppbus; 430 1.13 perry 431 1.1 jdolecek dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); 432 1.1 jdolecek if(!dev) { 433 1.13 perry LPT_DPRINTF(("%s(): device not configured.\n", __func__)); 434 1.1 jdolecek return ENXIO; 435 1.1 jdolecek } 436 1.13 perry 437 1.24 cegger lpt = device_private(dev); 438 1.13 perry 439 1.16 thorpej ppbus = device_parent(dev); 440 1.1 jdolecek ppbus_dev = &(lpt->ppbus_dev); 441 1.1 jdolecek 442 1.1 jdolecek /* Request the ppbus */ 443 1.1 jdolecek err = lpt_request_ppbus(lpt, PPBUS_WAIT|PPBUS_INTR); 444 1.1 jdolecek if(err) { 445 1.13 perry LPT_DPRINTF(("%s(%s): error (%d) while requesting bus.\n", 446 1.23 cegger __func__, device_xname(dev), err)); 447 1.1 jdolecek return (err); 448 1.1 jdolecek } 449 1.1 jdolecek 450 1.1 jdolecek /* Update bus mode */ 451 1.1 jdolecek ppbus_dev->ctx.mode = ppbus_get_mode(ppbus); 452 1.13 perry 453 1.1 jdolecek /* init printer */ 454 1.12 jdolecek if ((lpt->sc_flags & LPT_PRIME) && !LPTCTL(dev_id)) { 455 1.13 perry LPT_VPRINTF(("%s(%s): initializing printer.\n", __func__, 456 1.23 cegger device_xname(dev))); 457 1.1 jdolecek lpt->sc_state |= LPTINIT; 458 1.1 jdolecek ppbus_wctr(ppbus, LPC_SEL | LPC_NINIT); 459 1.13 perry 460 1.1 jdolecek /* wait till ready (printer running diagnostics) */ 461 1.13 perry for(trys = 0, status = ppbus_rstr(ppbus); (status & RDY_MASK) 462 1.13 perry != LP_READY; trys += LPT_STEP, status = 463 1.1 jdolecek ppbus_rstr(ppbus)) { 464 1.13 perry 465 1.1 jdolecek /* Time up waiting for the printer */ 466 1.1 jdolecek if(trys >= LPT_TIMEOUT) 467 1.1 jdolecek break; 468 1.1 jdolecek /* wait LPT_STEP ticks, give up if we get a signal */ 469 1.1 jdolecek else { 470 1.19 christos err = tsleep((void *)lpt, LPPRI|PCATCH, 471 1.13 perry "lptinit", LPT_STEP); 472 1.13 perry if((err) && (err != EWOULDBLOCK)) { 473 1.1 jdolecek lpt->sc_state &= ~LPTINIT; 474 1.1 jdolecek LPT_DPRINTF(("%s(%s): interrupted " 475 1.13 perry "during initialization.\n", __func__, 476 1.23 cegger device_xname(dev))); 477 1.1 jdolecek lpt_release_ppbus(lpt, PPBUS_WAIT); 478 1.1 jdolecek return (err); 479 1.1 jdolecek } 480 1.1 jdolecek } 481 1.1 jdolecek } 482 1.13 perry 483 1.1 jdolecek lpt->sc_state &= ~LPTINIT; 484 1.1 jdolecek if(trys >= LPT_TIMEOUT) { 485 1.1 jdolecek LPT_DPRINTF(("%s(%s): timed out while initializing " 486 1.13 perry "printer. [status %x]\n", __func__, 487 1.23 cegger device_xname(dev), status)); 488 1.1 jdolecek err = lpt_logstatus(dev, status); 489 1.1 jdolecek lpt_release_ppbus(lpt, PPBUS_WAIT); 490 1.1 jdolecek return (err); 491 1.1 jdolecek } 492 1.25 cegger else { 493 1.13 perry LPT_VPRINTF(("%s(%s): printer ready.\n", __func__, 494 1.23 cegger device_xname(dev))); 495 1.25 cegger } 496 1.1 jdolecek } 497 1.13 perry 498 1.12 jdolecek /* Set autolinefeed if requested */ 499 1.12 jdolecek if (lpt->sc_flags & LPT_AUTOLF) 500 1.12 jdolecek ppbus_wctr(ppbus, LPC_AUTOL); 501 1.12 jdolecek else 502 1.12 jdolecek ppbus_wctr(ppbus, 0); 503 1.1 jdolecek 504 1.12 jdolecek /* ready now */ 505 1.1 jdolecek lpt->sc_state |= OPEN; 506 1.1 jdolecek 507 1.1 jdolecek return 0; 508 1.1 jdolecek } 509 1.1 jdolecek 510 1.1 jdolecek /* 511 1.1 jdolecek * lptclose -- close the device, free the local line buffer. 512 1.1 jdolecek * 513 1.1 jdolecek * Check for interrupted write call added. 514 1.1 jdolecek */ 515 1.1 jdolecek int 516 1.15 rpaulo lptclose(dev_t dev_id, int flags, int fmt, struct lwp *l) 517 1.1 jdolecek { 518 1.21 dyoung device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); 519 1.21 dyoung struct lpt_softc *sc = device_private(dev); 520 1.1 jdolecek int err; 521 1.1 jdolecek 522 1.1 jdolecek err = lpt_release_ppbus(sc, PPBUS_WAIT|PPBUS_INTR); 523 1.1 jdolecek if(err) { 524 1.13 perry LPT_DPRINTF(("%s(%s): error (%d) while releasing ppbus.\n", 525 1.23 cegger __func__, device_xname(dev), err)); 526 1.1 jdolecek } 527 1.1 jdolecek 528 1.1 jdolecek sc->sc_state = 0; 529 1.13 perry 530 1.1 jdolecek return err; 531 1.1 jdolecek } 532 1.1 jdolecek 533 1.1 jdolecek /* 534 1.1 jdolecek * lptread --retrieve printer status in IEEE1284 NIBBLE mode 535 1.1 jdolecek */ 536 1.1 jdolecek int 537 1.1 jdolecek lptread(dev_t dev_id, struct uio *uio, int ioflag) 538 1.1 jdolecek { 539 1.4 bjh21 size_t len = 0; 540 1.1 jdolecek int error = 0; 541 1.21 dyoung device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); 542 1.21 dyoung struct lpt_softc *sc = device_private(dev); 543 1.1 jdolecek 544 1.1 jdolecek if(!(sc->sc_state & HAVEBUS)) { 545 1.1 jdolecek LPT_DPRINTF(("%s(%s): attempt to read using device which does " 546 1.23 cegger "not own the bus(%s).\n", __func__, device_xname(dev), 547 1.23 cegger device_xname(device_parent(dev)))); 548 1.1 jdolecek return (ENODEV); 549 1.1 jdolecek } 550 1.13 perry 551 1.1 jdolecek sc->sc_state &= ~INTERRUPTED; 552 1.1 jdolecek while (uio->uio_resid) { 553 1.16 thorpej error = ppbus_read(device_parent(dev), sc->sc_outbuf, 554 1.31 riastrad uimin(BUFSIZE, uio->uio_resid), 0, &len); 555 1.1 jdolecek 556 1.1 jdolecek /* If error or no more data, stop */ 557 1.9 jdolecek if (error) { 558 1.9 jdolecek if (error != EWOULDBLOCK) 559 1.13 perry sc->sc_state |= INTERRUPTED; 560 1.1 jdolecek break; 561 1.13 perry } 562 1.9 jdolecek if (len == 0) 563 1.1 jdolecek break; 564 1.1 jdolecek 565 1.9 jdolecek if ((error = uiomove(sc->sc_outbuf, len, uio))) 566 1.1 jdolecek break; 567 1.1 jdolecek } 568 1.1 jdolecek 569 1.1 jdolecek return error; 570 1.1 jdolecek } 571 1.1 jdolecek 572 1.1 jdolecek /* 573 1.1 jdolecek * lptwrite --copy a line from user space to a local buffer, then call 574 1.1 jdolecek * putc to get the chars moved to the output queue. 575 1.1 jdolecek * 576 1.1 jdolecek * Flagging of interrupted write added. 577 1.1 jdolecek */ 578 1.1 jdolecek int 579 1.1 jdolecek lptwrite(dev_t dev_id, struct uio * uio, int ioflag) 580 1.1 jdolecek { 581 1.10 jdolecek int error=0; 582 1.10 jdolecek size_t n, cnt; 583 1.21 dyoung device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); 584 1.21 dyoung struct lpt_softc * sc = device_private(dev); 585 1.1 jdolecek 586 1.1 jdolecek /* Check state and flags */ 587 1.1 jdolecek if(!(sc->sc_state & HAVEBUS)) { 588 1.1 jdolecek LPT_DPRINTF(("%s(%s): attempt to write using device which does " 589 1.23 cegger "not own the bus(%s).\n", __func__, device_xname(dev), 590 1.23 cegger device_xname(device_parent(dev)))); 591 1.1 jdolecek return EINVAL; 592 1.1 jdolecek } 593 1.1 jdolecek 594 1.26 cegger LPT_VPRINTF(("%s(%s): writing %zu bytes\n", __func__, 595 1.23 cegger device_xname(dev), uio->uio_resid)); 596 1.10 jdolecek 597 1.1 jdolecek /* Write the data */ 598 1.1 jdolecek sc->sc_state &= ~INTERRUPTED; 599 1.10 jdolecek while (uio->uio_resid) { 600 1.10 jdolecek n = MIN(BUFSIZE, uio->uio_resid); 601 1.10 jdolecek error = uiomove(sc->sc_inbuf, n, uio); 602 1.10 jdolecek if (error) 603 1.1 jdolecek break; 604 1.1 jdolecek 605 1.16 thorpej error = ppbus_write(device_parent(dev), sc->sc_inbuf, n, ioflag, 606 1.1 jdolecek &cnt); 607 1.10 jdolecek if (error) { 608 1.10 jdolecek if (error != EWOULDBLOCK) 609 1.13 perry sc->sc_state |= INTERRUPTED; 610 1.1 jdolecek break; 611 1.10 jdolecek } 612 1.1 jdolecek } 613 1.1 jdolecek 614 1.10 jdolecek LPT_VPRINTF(("%s(%s): transfer finished, error %d.\n", __func__, 615 1.23 cegger device_xname(dev), error)); 616 1.1 jdolecek 617 1.10 jdolecek return error; 618 1.1 jdolecek } 619 1.1 jdolecek 620 1.1 jdolecek /* Printer ioctl */ 621 1.1 jdolecek int 622 1.19 christos lptioctl(dev_t dev_id, u_long cmd, void *data, int flags, struct lwp *l) 623 1.1 jdolecek { 624 1.21 dyoung device_t dev = device_lookup(&lpt_cd, LPTUNIT(dev_id)); 625 1.21 dyoung struct lpt_softc *sc = device_private(dev); 626 1.11 jdolecek int val, fl; 627 1.11 jdolecek int error=0; 628 1.1 jdolecek 629 1.1 jdolecek if(!(sc->sc_state & HAVEBUS)) { 630 1.1 jdolecek LPT_DPRINTF(("%s(%s): attempt to perform ioctl on device which " 631 1.23 cegger "does not own the bus(%s).\n", __func__, device_xname(dev), 632 1.23 cegger device_xname(device_parent(dev)))); 633 1.1 jdolecek return EBUSY; 634 1.1 jdolecek } 635 1.1 jdolecek 636 1.1 jdolecek switch (cmd) { 637 1.11 jdolecek case LPTGMODE: 638 1.16 thorpej switch (ppbus_get_mode(device_parent(dev))) { 639 1.11 jdolecek case PPBUS_COMPATIBLE: 640 1.11 jdolecek val = mode_standard; 641 1.11 jdolecek break; 642 1.11 jdolecek case PPBUS_NIBBLE: 643 1.11 jdolecek val = mode_nibble; 644 1.11 jdolecek break; 645 1.11 jdolecek case PPBUS_PS2: 646 1.11 jdolecek val = mode_ps2; 647 1.11 jdolecek break; 648 1.11 jdolecek case PPBUS_FAST: 649 1.11 jdolecek val = mode_fast; 650 1.11 jdolecek break; 651 1.11 jdolecek case PPBUS_EPP: 652 1.11 jdolecek val = mode_epp; 653 1.11 jdolecek break; 654 1.11 jdolecek case PPBUS_ECP: 655 1.11 jdolecek val = mode_ecp; 656 1.11 jdolecek break; 657 1.11 jdolecek default: 658 1.11 jdolecek error = EINVAL; 659 1.11 jdolecek val = mode_unknown; 660 1.9 jdolecek break; 661 1.1 jdolecek } 662 1.11 jdolecek *(int *)data = val; 663 1.1 jdolecek break; 664 1.1 jdolecek 665 1.11 jdolecek case LPTSMODE: 666 1.11 jdolecek switch (*(int *)data) { 667 1.11 jdolecek case mode_standard: 668 1.11 jdolecek val = PPBUS_COMPATIBLE; 669 1.11 jdolecek break; 670 1.11 jdolecek case mode_nibble: 671 1.11 jdolecek val = PPBUS_NIBBLE; 672 1.11 jdolecek break; 673 1.11 jdolecek case mode_ps2: 674 1.11 jdolecek val = PPBUS_PS2; 675 1.11 jdolecek break; 676 1.11 jdolecek case mode_fast: 677 1.11 jdolecek val = PPBUS_FAST; 678 1.11 jdolecek break; 679 1.11 jdolecek case mode_epp: 680 1.11 jdolecek val = PPBUS_EPP; 681 1.11 jdolecek break; 682 1.11 jdolecek case mode_ecp: 683 1.11 jdolecek val = PPBUS_ECP; 684 1.11 jdolecek break; 685 1.11 jdolecek default: 686 1.11 jdolecek error = EINVAL; 687 1.11 jdolecek val = mode_unknown; 688 1.9 jdolecek break; 689 1.1 jdolecek } 690 1.9 jdolecek 691 1.11 jdolecek if (!error) 692 1.16 thorpej error = ppbus_set_mode(device_parent(dev), val, 0); 693 1.1 jdolecek 694 1.1 jdolecek break; 695 1.1 jdolecek 696 1.11 jdolecek case LPTGFLAGS: 697 1.11 jdolecek fl = 0; 698 1.1 jdolecek 699 1.12 jdolecek /* DMA */ 700 1.16 thorpej error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val); 701 1.7 jdolecek if (error) 702 1.1 jdolecek break; 703 1.11 jdolecek if (val) 704 1.11 jdolecek fl |= LPT_DMA; 705 1.12 jdolecek 706 1.13 perry /* IEEE mode negotiation */ 707 1.16 thorpej error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val); 708 1.7 jdolecek if (error) 709 1.1 jdolecek break; 710 1.11 jdolecek if (val) 711 1.11 jdolecek fl |= LPT_IEEE; 712 1.11 jdolecek 713 1.12 jdolecek /* interrupts */ 714 1.16 thorpej error = ppbus_read_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val); 715 1.12 jdolecek if (error) 716 1.12 jdolecek break; 717 1.12 jdolecek if (val) 718 1.12 jdolecek fl |= LPT_INTR; 719 1.12 jdolecek 720 1.12 jdolecek /* lpt-only flags */ 721 1.12 jdolecek fl |= sc->sc_flags; 722 1.12 jdolecek 723 1.11 jdolecek *(int *)data = fl; 724 1.11 jdolecek break; 725 1.11 jdolecek 726 1.11 jdolecek case LPTSFLAGS: 727 1.11 jdolecek fl = *(int *)data; 728 1.1 jdolecek 729 1.12 jdolecek /* DMA */ 730 1.11 jdolecek val = (fl & LPT_DMA); 731 1.16 thorpej error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_DMA, &val); 732 1.11 jdolecek if (error) 733 1.1 jdolecek break; 734 1.11 jdolecek 735 1.12 jdolecek /* IEEE mode negotiation */ 736 1.11 jdolecek val = (fl & LPT_IEEE); 737 1.16 thorpej error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_IEEE, &val); 738 1.12 jdolecek if (error) 739 1.12 jdolecek break; 740 1.12 jdolecek 741 1.12 jdolecek /* interrupts */ 742 1.12 jdolecek val = (fl & LPT_INTR); 743 1.16 thorpej error = ppbus_write_ivar(device_parent(dev), PPBUS_IVAR_INTR, &val); 744 1.12 jdolecek if (error) 745 1.12 jdolecek break; 746 1.12 jdolecek 747 1.12 jdolecek /* lpt-only flags */ 748 1.12 jdolecek sc->sc_flags = fl & (LPT_PRIME|LPT_AUTOLF); 749 1.12 jdolecek 750 1.1 jdolecek break; 751 1.7 jdolecek 752 1.1 jdolecek default: 753 1.1 jdolecek error = EINVAL; 754 1.11 jdolecek break; 755 1.1 jdolecek } 756 1.1 jdolecek 757 1.1 jdolecek return error; 758 1.1 jdolecek } 759 1.1 jdolecek 760