| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1990 William F. Jolitz, TeleMuse | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This software is a component of "386BSD" developed by | |
| 16 | * William F. Jolitz, TeleMuse. | |
| 17 | * 4. Neither the name of the developer nor the name "386BSD" | |
| 18 | * may be used to endorse or promote products derived from this software | |
| 19 | * without specific prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ | |
| 22 | * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS | |
| 23 | * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. | |
| 24 | * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT | |
| 25 | * NOT MAKE USE OF THIS WORK. | |
| 26 | * | |
| 27 | * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED | |
| 28 | * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN | |
| 29 | * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES | |
| 30 | * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING | |
| 31 | * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND | |
| 32 | * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE | |
| 33 | * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS | |
| 34 | * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. | |
| 35 | * | |
| 36 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND | |
| 37 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 39 | * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE | |
| 40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 42 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 43 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 44 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 45 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 46 | * SUCH DAMAGE. | |
| 47 | * | |
| 48 | * from: unknown origin, 386BSD 0.1 | |
| 49 | * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp | |
| 50 | * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp | |
| 51 | * $FreeBSD: src/sys/dev/ppbus/lpt.c,v 1.15.2.3 2000/07/07 00:30:40 obrien Exp $ | |
| e3869ec7 | 52 | * $DragonFly: src/sys/dev/misc/lpt/lpt.c,v 1.19 2006/12/22 23:26:17 swildner Exp $ |
| 984263bc MD |
53 | */ |
| 54 | ||
| 55 | /* | |
| 56 | * Device Driver for AT parallel printer port | |
| 57 | * Written by William Jolitz 12/18/90 | |
| 58 | */ | |
| 59 | ||
| 60 | /* | |
| 61 | * Updated for ppbus by Nicolas Souchu | |
| 62 | * [Mon Jul 28 1997] | |
| 63 | */ | |
| 64 | ||
| 65 | #include "opt_lpt.h" | |
| 66 | ||
| 67 | #include <sys/param.h> | |
| 68 | #include <sys/systm.h> | |
| 69 | #include <sys/module.h> | |
| 70 | #include <sys/bus.h> | |
| 71 | #include <sys/conf.h> | |
| fef8985e | 72 | #include <sys/device.h> |
| 984263bc MD |
73 | #include <sys/kernel.h> |
| 74 | #include <sys/uio.h> | |
| 75 | #include <sys/syslog.h> | |
| b28b340f | 76 | #include <sys/thread2.h> |
| 984263bc | 77 | #include <sys/malloc.h> |
| 1f7ab7c9 | 78 | #include <sys/rman.h> |
| 984263bc MD |
79 | |
| 80 | #include <machine/clock.h> | |
| 984263bc | 81 | |
| 1f2de5d4 MD |
82 | #include "lptio.h" |
| 83 | #include <bus/ppbus/ppbconf.h> | |
| 84 | #include <bus/ppbus/ppb_1284.h> | |
| 85 | #include "lpt.h" | |
| 984263bc | 86 | #include "ppbus_if.h" |
| 1f2de5d4 | 87 | #include <bus/ppbus/ppbio.h> |
| 984263bc MD |
88 | |
| 89 | MALLOC_DEFINE(M_LPT, "lpt", "LPT buffers"); | |
| 90 | ||
| 91 | #ifndef LPT_DEBUG | |
| 92 | #define lprintf(args) | |
| 93 | #else | |
| 94 | #define lprintf(args) \ | |
| 95 | do { \ | |
| 96 | if (lptflag) \ | |
| e3869ec7 | 97 | kprintf args; \ |
| 984263bc MD |
98 | } while (0) |
| 99 | static int volatile lptflag = 1; | |
| 100 | #endif | |
| 101 | ||
| 102 | #define LPINITRDY 4 /* wait up to 4 seconds for a ready */ | |
| 103 | #define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ | |
| 104 | #define LPTOUTMAX 1 /* maximal timeout 1 s */ | |
| 984263bc MD |
105 | #define BUFSIZE 1024 |
| 106 | #define BUFSTATSIZE 32 | |
| 107 | ||
| 108 | #define LPTUNIT(s) ((s)&0x03) | |
| 109 | #define LPTFLAGS(s) ((s)&0xfc) | |
| 110 | ||
| 111 | struct lpt_data { | |
| 984263bc MD |
112 | short sc_state; |
| 113 | /* default case: negative prime, negative ack, handshake strobe, | |
| 114 | prime once */ | |
| 115 | u_char sc_control; | |
| 116 | char sc_flags; | |
| e4c9c0c8 | 117 | #define LP_UNITMASK 0x03 /* up to 4 units */ |
| 984263bc MD |
118 | #define LP_POS_INIT 0x04 /* if we are a postive init signal */ |
| 119 | #define LP_POS_ACK 0x08 /* if we are a positive going ack */ | |
| 120 | #define LP_NO_PRIME 0x10 /* don't prime the printer at all */ | |
| 121 | #define LP_PRIMEOPEN 0x20 /* prime on every open */ | |
| 122 | #define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ | |
| 123 | #define LP_BYPASS 0x80 /* bypass printer ready checks */ | |
| 124 | void *sc_inbuf; | |
| 125 | void *sc_statbuf; | |
| 126 | short sc_xfercnt ; | |
| 127 | char sc_primed; | |
| 128 | char *sc_cp ; | |
| 129 | u_short sc_irq ; /* IRQ status of port */ | |
| 130 | #define LP_HAS_IRQ 0x01 /* we have an irq available */ | |
| 131 | #define LP_USE_IRQ 0x02 /* we are using our irq */ | |
| 132 | #define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ | |
| 133 | #define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */ | |
| 134 | u_char sc_backoff ; /* time to call lptout() again */ | |
| 135 | ||
| 136 | struct resource *intr_resource; /* interrupt resource */ | |
| 137 | void *intr_cookie; /* interrupt registration cookie */ | |
| 6aed8a5b | 138 | struct callout sc_callout; |
| 984263bc MD |
139 | }; |
| 140 | ||
| 141 | #define LPT_NAME "lpt" /* our official name */ | |
| 142 | ||
| 143 | static timeout_t lptout; | |
| 144 | static int lpt_port_test(device_t dev, u_char data, u_char mask); | |
| 145 | static int lpt_detect(device_t dev); | |
| 146 | ||
| 147 | #define DEVTOSOFTC(dev) \ | |
| 148 | ((struct lpt_data *)device_get_softc(dev)) | |
| 149 | #define UNITOSOFTC(unit) \ | |
| 150 | ((struct lpt_data *)devclass_get_softc(lpt_devclass, (unit))) | |
| 151 | #define UNITODEVICE(unit) \ | |
| 152 | (devclass_get_device(lpt_devclass, (unit))) | |
| 153 | ||
| 154 | static void lptintr(device_t dev); | |
| 155 | static void lpt_intr(void *arg); /* without spls */ | |
| 156 | ||
| 157 | static devclass_t lpt_devclass; | |
| 158 | ||
| 159 | ||
| 160 | /* bits for state */ | |
| 161 | #define OPEN (1<<0) /* device is open */ | |
| 162 | #define ASLP (1<<1) /* awaiting draining of printer */ | |
| 163 | #define EERROR (1<<2) /* error was received from printer */ | |
| 164 | #define OBUSY (1<<3) /* printer is busy doing output */ | |
| 165 | #define LPTOUT (1<<4) /* timeout while not selected */ | |
| 166 | #define TOUT (1<<5) /* timeout while not selected */ | |
| 167 | #define LPTINIT (1<<6) /* waiting to initialize for open */ | |
| 168 | #define INTERRUPTED (1<<7) /* write call was interrupted */ | |
| 169 | ||
| 170 | #define HAVEBUS (1<<8) /* the driver owns the bus */ | |
| 171 | ||
| 172 | ||
| 173 | /* status masks to interrogate printer status */ | |
| 174 | #define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ | |
| 175 | #define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) | |
| 176 | ||
| 177 | /* Printer Ready condition - from lpa.c */ | |
| 178 | /* Only used in polling code */ | |
| 179 | #define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) | |
| 180 | #define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) | |
| 181 | #define NOT_READY(ppbus) ((ppb_rstr(ppbus)^LPS_INVERT)&LPS_MASK) | |
| 182 | ||
| 183 | #define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ | |
| 184 | #define MAX_SPIN 20 /* Max delay for device ready in usecs */ | |
| 185 | ||
| 186 | ||
| 187 | static d_open_t lptopen; | |
| 188 | static d_close_t lptclose; | |
| 189 | static d_write_t lptwrite; | |
| 190 | static d_read_t lptread; | |
| 191 | static d_ioctl_t lptioctl; | |
| 192 | ||
| 193 | #define CDEV_MAJOR 16 | |
| fef8985e MD |
194 | static struct dev_ops lpt_ops = { |
| 195 | { LPT_NAME, CDEV_MAJOR, 0 }, | |
| 196 | .d_open = lptopen, | |
| 197 | .d_close = lptclose, | |
| 198 | .d_read = lptread, | |
| 199 | .d_write = lptwrite, | |
| 200 | .d_ioctl = lptioctl, | |
| 984263bc MD |
201 | }; |
| 202 | ||
| 203 | static int | |
| 204 | lpt_request_ppbus(device_t dev, int how) | |
| 205 | { | |
| 206 | device_t ppbus = device_get_parent(dev); | |
| 207 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
| 208 | int error; | |
| 209 | ||
| 210 | if (sc->sc_state & HAVEBUS) | |
| 211 | return (0); | |
| 212 | ||
| 213 | /* we have the bus only if the request succeded */ | |
| 214 | if ((error = ppb_request_bus(ppbus, dev, how)) == 0) | |
| 215 | sc->sc_state |= HAVEBUS; | |
| 216 | ||
| 217 | return (error); | |
| 218 | } | |
| 219 | ||
| 220 | static int | |
| 221 | lpt_release_ppbus(device_t dev) | |
| 222 | { | |
| 223 | device_t ppbus = device_get_parent(dev); | |
| 224 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
| 225 | int error = 0; | |
| 226 | ||
| 227 | if ((error = ppb_release_bus(ppbus, dev)) == 0) | |
| 228 | sc->sc_state &= ~HAVEBUS; | |
| 229 | ||
| 230 | return (error); | |
| 231 | } | |
| 232 | ||
| 233 | /* | |
| 234 | * Internal routine to lptprobe to do port tests of one byte value | |
| 235 | */ | |
| 236 | static int | |
| 237 | lpt_port_test(device_t ppbus, u_char data, u_char mask) | |
| 238 | { | |
| 239 | int temp, timeout; | |
| 240 | ||
| 241 | data = data & mask; | |
| 242 | ppb_wdtr(ppbus, data); | |
| 243 | timeout = 10000; | |
| 244 | do { | |
| 245 | DELAY(10); | |
| 246 | temp = ppb_rdtr(ppbus) & mask; | |
| 247 | } | |
| 248 | while (temp != data && --timeout); | |
| 249 | lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout)); | |
| 250 | return (temp == data); | |
| 251 | } | |
| 252 | ||
| 253 | /* | |
| 254 | * Probe simplified by replacing multiple loops with a hardcoded | |
| 255 | * test pattern - 1999/02/08 des@freebsd.org | |
| 256 | * | |
| 257 | * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 | |
| 258 | * Based partially on Rod Grimes' printer probe | |
| 259 | * | |
| 260 | * Logic: | |
| 261 | * 1) If no port address was given, use the bios detected ports | |
| 262 | * and autodetect what ports the printers are on. | |
| 263 | * 2) Otherwise, probe the data port at the address given, | |
| 264 | * using the method in Rod Grimes' port probe. | |
| 265 | * (Much code ripped off directly from Rod's probe.) | |
| 266 | * | |
| 267 | * Comments from Rod's probe: | |
| 268 | * Logic: | |
| 269 | * 1) You should be able to write to and read back the same value | |
| 270 | * to the data port. Do an alternating zeros, alternating ones, | |
| 271 | * walking zero, and walking one test to check for stuck bits. | |
| 272 | * | |
| 273 | * 2) You should be able to write to and read back the same value | |
| 274 | * to the control port lower 5 bits, the upper 3 bits are reserved | |
| 275 | * per the IBM PC technical reference manauls and different boards | |
| 276 | * do different things with them. Do an alternating zeros, alternating | |
| 277 | * ones, walking zero, and walking one test to check for stuck bits. | |
| 278 | * | |
| 279 | * Some printers drag the strobe line down when the are powered off | |
| 280 | * so this bit has been masked out of the control port test. | |
| 281 | * | |
| 282 | * XXX Some printers may not like a fast pulse on init or strobe, I | |
| 283 | * don't know at this point, if that becomes a problem these bits | |
| 284 | * should be turned off in the mask byte for the control port test. | |
| 285 | * | |
| 286 | * We are finally left with a mask of 0x14, due to some printers | |
| 287 | * being adamant about holding other bits high ........ | |
| 288 | * | |
| 289 | * Before probing the control port, we write a 0 to the data port - | |
| 290 | * If not, some printers chuck out garbage when the strobe line | |
| 291 | * gets toggled. | |
| 292 | * | |
| 293 | * 3) Set the data and control ports to a value of 0 | |
| 294 | * | |
| 295 | * This probe routine has been tested on Epson Lx-800, HP LJ3P, | |
| 296 | * Epson FX-1170 and C.Itoh 8510RM | |
| 297 | * printers. | |
| 298 | * Quick exit on fail added. | |
| 299 | */ | |
| 300 | static int | |
| 301 | lpt_detect(device_t dev) | |
| 302 | { | |
| 303 | device_t ppbus = device_get_parent(dev); | |
| 304 | ||
| 305 | static u_char testbyte[18] = { | |
| 306 | 0x55, /* alternating zeros */ | |
| 307 | 0xaa, /* alternating ones */ | |
| 308 | 0xfe, 0xfd, 0xfb, 0xf7, | |
| 309 | 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ | |
| 310 | 0x01, 0x02, 0x04, 0x08, | |
| 311 | 0x10, 0x20, 0x40, 0x80 /* walking one */ | |
| 312 | }; | |
| 313 | int i, error, status; | |
| 314 | ||
| 315 | status = 1; /* assume success */ | |
| 316 | ||
| 317 | if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { | |
| e3869ec7 | 318 | kprintf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); |
| 984263bc MD |
319 | status = 0; |
| 320 | goto end_probe; | |
| 321 | } | |
| 322 | ||
| 323 | for (i = 0; i < 18 && status; i++) | |
| 324 | if (!lpt_port_test(ppbus, testbyte[i], 0xff)) { | |
| 325 | status = 0; | |
| 326 | goto end_probe; | |
| 327 | } | |
| 328 | ||
| 329 | end_probe: | |
| 330 | /* write 0's to control and data ports */ | |
| 331 | ppb_wdtr(ppbus, 0); | |
| 332 | ppb_wctr(ppbus, 0); | |
| 333 | ||
| 334 | lpt_release_ppbus(dev); | |
| 335 | ||
| 336 | return (status); | |
| 337 | } | |
| 338 | ||
| 984263bc MD |
339 | /* |
| 340 | * lpt_probe() | |
| 341 | */ | |
| 342 | static int | |
| 343 | lpt_probe(device_t dev) | |
| 344 | { | |
| 345 | struct lpt_data *sc; | |
| 346 | ||
| 347 | sc = DEVTOSOFTC(dev); | |
| 348 | bzero(sc, sizeof(struct lpt_data)); | |
| 349 | ||
| 350 | /* | |
| 351 | * Now, try to detect the printer. | |
| 352 | */ | |
| 353 | if (!lpt_detect(dev)) | |
| 354 | return (ENXIO); | |
| 355 | ||
| 356 | device_set_desc(dev, "Printer"); | |
| 357 | ||
| 358 | return (0); | |
| 359 | } | |
| 360 | ||
| 361 | static int | |
| 362 | lpt_attach(device_t dev) | |
| 363 | { | |
| 364 | device_t ppbus = device_get_parent(dev); | |
| 365 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
| 366 | int zero = 0, unit = device_get_unit(dev); | |
| 367 | int error; | |
| 368 | uintptr_t irq; | |
| 369 | ||
| 370 | sc->sc_primed = 0; /* not primed yet */ | |
| 6aed8a5b | 371 | callout_init(&sc->sc_callout); |
| 984263bc MD |
372 | |
| 373 | if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { | |
| e3869ec7 | 374 | kprintf(LPT_NAME ": cannot alloc ppbus (%d)!\n", error); |
| 984263bc MD |
375 | return (0); |
| 376 | } | |
| 377 | ||
| 378 | ppb_wctr(ppbus, LPC_NINIT); | |
| 379 | ||
| 380 | /* check if we can use interrupt, should be done by ppc stuff */ | |
| 381 | lprintf(("oldirq %x\n", sc->sc_irq)); | |
| 382 | ||
| 383 | /* retrieve the ppbus irq */ | |
| 384 | BUS_READ_IVAR(ppbus, dev, PPBUS_IVAR_IRQ, &irq); | |
| 385 | ||
| 386 | if (irq > 0) { | |
| 387 | /* declare our interrupt handler */ | |
| 388 | sc->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ, | |
| 389 | &zero, irq, irq, 1, RF_SHAREABLE); | |
| 390 | } | |
| 391 | if (sc->intr_resource) { | |
| 392 | sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; | |
| 393 | device_printf(dev, "Interrupt-driven port\n"); | |
| 394 | } else { | |
| 395 | sc->sc_irq = 0; | |
| 396 | device_printf(dev, "Polled port\n"); | |
| 397 | } | |
| 398 | lprintf(("irq %x %x\n", irq, sc->sc_irq)); | |
| 399 | ||
| 400 | lpt_release_ppbus(dev); | |
| 401 | ||
| 3e82b46c MD |
402 | make_dev(&lpt_ops, unit, UID_ROOT, GID_WHEEL, |
| 403 | 0600, LPT_NAME "%d", unit); | |
| 404 | make_dev(&lpt_ops, unit | LP_BYPASS, UID_ROOT, GID_WHEEL, | |
| 405 | 0600, LPT_NAME "%d.ctl", unit); | |
| 984263bc MD |
406 | return (0); |
| 407 | } | |
| 408 | ||
| 409 | static void | |
| 410 | lptout(void *arg) | |
| 411 | { | |
| 412 | device_t dev = (device_t)arg; | |
| 413 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
| 414 | #ifdef LPT_DEBUG | |
| 415 | device_t ppbus = device_get_parent(dev); | |
| 416 | #endif | |
| 417 | ||
| 418 | lprintf(("T %x ", ppb_rstr(ppbus))); | |
| 419 | if (sc->sc_state & OPEN) { | |
| 420 | sc->sc_backoff++; | |
| 421 | if (sc->sc_backoff > hz/LPTOUTMAX) | |
| 422 | sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; | |
| 6aed8a5b MD |
423 | callout_reset(&sc->sc_callout, sc->sc_backoff, lptout, dev); |
| 424 | } else { | |
| 984263bc | 425 | sc->sc_state &= ~TOUT; |
| 6aed8a5b | 426 | } |
| 984263bc MD |
427 | |
| 428 | if (sc->sc_state & EERROR) | |
| 429 | sc->sc_state &= ~EERROR; | |
| 430 | ||
| 431 | /* | |
| 432 | * Avoid possible hangs due to missed interrupts | |
| 433 | */ | |
| 434 | if (sc->sc_xfercnt) { | |
| 435 | lptintr(dev); | |
| 436 | } else { | |
| 437 | sc->sc_state &= ~OBUSY; | |
| 438 | wakeup((caddr_t)dev); | |
| 439 | } | |
| 440 | } | |
| 441 | ||
| 442 | /* | |
| 443 | * lptopen -- reset the printer, then wait until it's selected and not busy. | |
| 444 | * If LP_BYPASS flag is selected, then we do not try to select the | |
| 445 | * printer -- this is just used for passing ioctls. | |
| 446 | */ | |
| 447 | ||
| 448 | static int | |
| fef8985e | 449 | lptopen(struct dev_open_args *ap) |
| 984263bc | 450 | { |
| b13267a5 | 451 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
452 | int trys, err; |
| 453 | u_int unit = LPTUNIT(minor(dev)); | |
| 454 | struct lpt_data *sc = UNITOSOFTC(unit); | |
| 455 | device_t lptdev = UNITODEVICE(unit); | |
| 456 | device_t ppbus = device_get_parent(lptdev); | |
| 457 | ||
| 458 | if (!sc) | |
| 459 | return (ENXIO); | |
| 460 | ||
| 461 | if (sc->sc_state) { | |
| 462 | lprintf((LPT_NAME ": still open %x\n", sc->sc_state)); | |
| 463 | return(EBUSY); | |
| 464 | } else | |
| 465 | sc->sc_state |= LPTINIT; | |
| 466 | ||
| 467 | sc->sc_flags = LPTFLAGS(minor(dev)); | |
| 468 | ||
| 469 | /* Check for open with BYPASS flag set. */ | |
| 470 | if (sc->sc_flags & LP_BYPASS) { | |
| 471 | sc->sc_state = OPEN; | |
| 472 | return(0); | |
| 473 | } | |
| 474 | ||
| 475 | /* request the ppbus only if we don't have it already */ | |
| 476 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { | |
| 477 | /* give it a chance to try later */ | |
| 478 | sc->sc_state = 0; | |
| 479 | return (err); | |
| 480 | } | |
| 481 | ||
| b28b340f | 482 | crit_enter(); |
| 984263bc MD |
483 | lprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags)); |
| 484 | ||
| 485 | /* set IRQ status according to ENABLE_IRQ flag | |
| 486 | */ | |
| 487 | if (sc->sc_irq & LP_ENABLE_IRQ) | |
| 488 | sc->sc_irq |= LP_USE_IRQ; | |
| 489 | else | |
| 490 | sc->sc_irq &= ~LP_USE_IRQ; | |
| 491 | ||
| 492 | /* init printer */ | |
| 493 | if ((sc->sc_flags & LP_NO_PRIME) == 0) { | |
| 494 | if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { | |
| 495 | ppb_wctr(ppbus, 0); | |
| 496 | sc->sc_primed++; | |
| 497 | DELAY(500); | |
| 498 | } | |
| 499 | } | |
| 500 | ||
| 501 | ppb_wctr(ppbus, LPC_SEL|LPC_NINIT); | |
| 502 | ||
| 503 | /* wait till ready (printer running diagnostics) */ | |
| 504 | trys = 0; | |
| 505 | do { | |
| 506 | /* ran out of waiting for the printer */ | |
| 507 | if (trys++ >= LPINITRDY*4) { | |
| b28b340f | 508 | crit_exit(); |
| 984263bc MD |
509 | sc->sc_state = 0; |
| 510 | lprintf(("status %x\n", ppb_rstr(ppbus))); | |
| 511 | ||
| 512 | lpt_release_ppbus(lptdev); | |
| 513 | return (EBUSY); | |
| 514 | } | |
| 515 | ||
| 516 | /* wait 1/4 second, give up if we get a signal */ | |
| 377d4740 | 517 | if (tsleep((caddr_t)lptdev, PCATCH, "lptinit", hz/4) != |
| 984263bc MD |
518 | EWOULDBLOCK) { |
| 519 | sc->sc_state = 0; | |
| b28b340f | 520 | crit_exit(); |
| 984263bc MD |
521 | |
| 522 | lpt_release_ppbus(lptdev); | |
| 523 | return (EBUSY); | |
| 524 | } | |
| 525 | ||
| 526 | /* is printer online and ready for output */ | |
| 527 | } while ((ppb_rstr(ppbus) & | |
| 528 | (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != | |
| 529 | (LPS_SEL|LPS_NBSY|LPS_NERR)); | |
| 530 | ||
| 531 | sc->sc_control = LPC_SEL|LPC_NINIT; | |
| 532 | if (sc->sc_flags & LP_AUTOLF) | |
| 533 | sc->sc_control |= LPC_AUTOL; | |
| 534 | ||
| 535 | /* enable interrupt if interrupt-driven */ | |
| 536 | if (sc->sc_irq & LP_USE_IRQ) | |
| 537 | sc->sc_control |= LPC_ENA; | |
| 538 | ||
| 539 | ppb_wctr(ppbus, sc->sc_control); | |
| 540 | ||
| 541 | sc->sc_state = OPEN; | |
| efda3bd0 MD |
542 | sc->sc_inbuf = kmalloc(BUFSIZE, M_LPT, M_WAITOK); |
| 543 | sc->sc_statbuf = kmalloc(BUFSTATSIZE, M_LPT, M_WAITOK); | |
| 984263bc | 544 | sc->sc_xfercnt = 0; |
| b28b340f JS |
545 | |
| 546 | crit_exit(); | |
| 984263bc MD |
547 | |
| 548 | /* release the ppbus */ | |
| 549 | lpt_release_ppbus(lptdev); | |
| 550 | ||
| 551 | /* only use timeout if using interrupt */ | |
| 552 | lprintf(("irq %x\n", sc->sc_irq)); | |
| 553 | if (sc->sc_irq & LP_USE_IRQ) { | |
| 554 | sc->sc_state |= TOUT; | |
| 6aed8a5b MD |
555 | sc->sc_backoff = hz / LPTOUTINITIAL; |
| 556 | callout_reset(&sc->sc_callout, sc->sc_backoff, lptout, lptdev); | |
| 984263bc MD |
557 | } |
| 558 | ||
| 559 | lprintf(("opened.\n")); | |
| 560 | return(0); | |
| 561 | } | |
| 562 | ||
| 563 | /* | |
| 564 | * lptclose -- close the device, free the local line buffer. | |
| 565 | * | |
| 566 | * Check for interrupted write call added. | |
| 567 | */ | |
| 568 | ||
| 569 | static int | |
| fef8985e | 570 | lptclose(struct dev_close_args *ap) |
| 984263bc | 571 | { |
| b13267a5 | 572 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
573 | u_int unit = LPTUNIT(minor(dev)); |
| 574 | struct lpt_data *sc = UNITOSOFTC(unit); | |
| 575 | device_t lptdev = UNITODEVICE(unit); | |
| 576 | device_t ppbus = device_get_parent(lptdev); | |
| 577 | int err; | |
| 578 | ||
| 579 | if(sc->sc_flags & LP_BYPASS) | |
| 580 | goto end_close; | |
| 581 | ||
| 582 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) | |
| 583 | return (err); | |
| 584 | ||
| 585 | sc->sc_state &= ~OPEN; | |
| 586 | ||
| 587 | /* if the last write was interrupted, don't complete it */ | |
| 6aed8a5b | 588 | if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) { |
| 984263bc | 589 | while ((ppb_rstr(ppbus) & |
| 6aed8a5b MD |
590 | (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != |
| 591 | (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) { | |
| 984263bc | 592 | /* wait 1/4 second, give up if we get a signal */ |
| 377d4740 | 593 | if (tsleep((caddr_t)lptdev, PCATCH, |
| 6aed8a5b | 594 | "lpclose", hz) != EWOULDBLOCK) { |
| 984263bc | 595 | break; |
| 6aed8a5b MD |
596 | } |
| 597 | } | |
| 598 | } | |
| 599 | callout_stop(&sc->sc_callout); | |
| 984263bc | 600 | ppb_wctr(ppbus, LPC_NINIT); |
| efda3bd0 MD |
601 | kfree(sc->sc_inbuf, M_LPT); |
| 602 | kfree(sc->sc_statbuf, M_LPT); | |
| 984263bc MD |
603 | |
| 604 | end_close: | |
| 605 | /* release the bus anyway | |
| 606 | * unregistration of interrupt forced by release | |
| 607 | */ | |
| 608 | lpt_release_ppbus(lptdev); | |
| 609 | ||
| 610 | sc->sc_state = 0; | |
| 611 | sc->sc_xfercnt = 0; | |
| 612 | lprintf(("closed.\n")); | |
| 613 | return(0); | |
| 614 | } | |
| 615 | ||
| 616 | /* | |
| 617 | * lpt_pushbytes() | |
| 618 | * Workhorse for actually spinning and writing bytes to printer | |
| 619 | * Derived from lpa.c | |
| 620 | * Originally by ? | |
| 621 | * | |
| 622 | * This code is only used when we are polling the port | |
| 623 | */ | |
| 624 | static int | |
| 625 | lpt_pushbytes(device_t dev) | |
| 626 | { | |
| 627 | struct lpt_data *sc = DEVTOSOFTC(dev); | |
| 628 | device_t ppbus = device_get_parent(dev); | |
| 629 | int spin, err, tic; | |
| 630 | char ch; | |
| 631 | ||
| 632 | lprintf(("p")); | |
| 633 | /* loop for every character .. */ | |
| 634 | while (sc->sc_xfercnt > 0) { | |
| 635 | /* printer data */ | |
| 636 | ch = *(sc->sc_cp); | |
| 637 | sc->sc_cp++; | |
| 638 | sc->sc_xfercnt--; | |
| 639 | ||
| 640 | /* | |
| 641 | * Wait for printer ready. | |
| 642 | * Loop 20 usecs testing BUSY bit, then sleep | |
| 643 | * for exponentially increasing timeout. (vak) | |
| 644 | */ | |
| 645 | for (spin = 0; NOT_READY(ppbus) && spin < MAX_SPIN; ++spin) | |
| 646 | DELAY(1); /* XXX delay is NOT this accurate! */ | |
| 647 | if (spin >= MAX_SPIN) { | |
| 648 | tic = 0; | |
| 649 | while (NOT_READY(ppbus)) { | |
| 650 | /* | |
| 651 | * Now sleep, every cycle a | |
| 652 | * little longer .. | |
| 653 | */ | |
| 654 | tic = tic + tic + 1; | |
| 655 | /* | |
| 656 | * But no more than 10 seconds. (vak) | |
| 657 | */ | |
| 658 | if (tic > MAX_SLEEP) | |
| 659 | tic = MAX_SLEEP; | |
| 377d4740 | 660 | err = tsleep((caddr_t)dev, 0, |
| 984263bc MD |
661 | LPT_NAME "poll", tic); |
| 662 | if (err != EWOULDBLOCK) { | |
| 663 | return (err); | |
| 664 | } | |
| 665 | } | |
| 666 | } | |
| 667 | ||
| 668 | /* output data */ | |
| 669 | ppb_wdtr(ppbus, ch); | |
| 670 | /* strobe */ | |
| 671 | ppb_wctr(ppbus, sc->sc_control|LPC_STB); | |
| 672 | ppb_wctr(ppbus, sc->sc_control); | |
| 673 | ||
| 674 | } | |
| 675 | return(0); | |
| 676 | } | |
| 677 | ||
| 678 | /* | |
| 679 | * lptread --retrieve printer status in IEEE1284 NIBBLE mode | |
| 680 | */ | |
| 681 | ||
| 682 | static int | |
| fef8985e | 683 | lptread(struct dev_read_args *ap) |
| 984263bc | 684 | { |
| b13267a5 | 685 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 686 | struct uio *uio = ap->a_uio; |
| 984263bc MD |
687 | u_int unit = LPTUNIT(minor(dev)); |
| 688 | struct lpt_data *sc = UNITOSOFTC(unit); | |
| 689 | device_t lptdev = UNITODEVICE(unit); | |
| 690 | device_t ppbus = device_get_parent(lptdev); | |
| 691 | int error = 0, len; | |
| 692 | ||
| 693 | if (sc->sc_flags & LP_BYPASS) { | |
| 694 | /* we can't do reads in bypass mode */ | |
| 695 | return (EPERM); | |
| 696 | } | |
| 697 | ||
| 698 | if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) | |
| 699 | return (error); | |
| 700 | ||
| 701 | /* read data in an other buffer, read/write may be simultaneous */ | |
| 702 | len = 0; | |
| 703 | while (uio->uio_resid) { | |
| 704 | if ((error = ppb_1284_read(ppbus, PPB_NIBBLE, | |
| 705 | sc->sc_statbuf, min(BUFSTATSIZE, | |
| 706 | uio->uio_resid), &len))) { | |
| 707 | goto error; | |
| 708 | } | |
| 709 | ||
| 710 | if (!len) | |
| 711 | goto error; /* no more data */ | |
| 712 | ||
| 713 | if ((error = uiomove(sc->sc_statbuf, len, uio))) | |
| 714 | goto error; | |
| 715 | } | |
| 716 | ||
| 717 | error: | |
| 718 | ppb_1284_terminate(ppbus); | |
| 719 | return (error); | |
| 720 | } | |
| 721 | ||
| 722 | /* | |
| 723 | * lptwrite --copy a line from user space to a local buffer, then call | |
| 724 | * putc to get the chars moved to the output queue. | |
| 725 | * | |
| 726 | * Flagging of interrupted write added. | |
| 727 | */ | |
| 728 | ||
| 729 | static int | |
| fef8985e | 730 | lptwrite(struct dev_write_args *ap) |
| 984263bc | 731 | { |
| b13267a5 | 732 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 733 | struct uio *uio = ap->a_uio; |
| f96d6c88 | 734 | unsigned n; |
| 984263bc MD |
735 | int err; |
| 736 | u_int unit = LPTUNIT(minor(dev)); | |
| 737 | struct lpt_data *sc = UNITOSOFTC(unit); | |
| 738 | device_t lptdev = UNITODEVICE(unit); | |
| 739 | device_t ppbus = device_get_parent(lptdev); | |
| 740 | ||
| 741 | if(sc->sc_flags & LP_BYPASS) { | |
| 742 | /* we can't do writes in bypass mode */ | |
| 743 | return(EPERM); | |
| 744 | } | |
| 745 | ||
| 746 | /* request the ppbus only if we don't have it already */ | |
| 747 | /* XXX interrupt registration?! */ | |
| 748 | if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) | |
| 749 | return (err); | |
| 750 | ||
| 751 | /* if interrupts are working, register the handler */ | |
| 752 | if (sc->sc_irq & LP_USE_IRQ) { | |
| 753 | /* register our interrupt handler */ | |
| 754 | err = BUS_SETUP_INTR(ppbus, lptdev, sc->intr_resource, | |
| ee61f228 | 755 | 0, lpt_intr, lptdev, |
| e9cb6d99 | 756 | &sc->intr_cookie, NULL); |
| 984263bc MD |
757 | if (err) { |
| 758 | device_printf(lptdev, "handler registration failed, polled mode.\n"); | |
| 759 | sc->sc_irq &= ~LP_USE_IRQ; | |
| 760 | } | |
| 761 | } | |
| 762 | ||
| 763 | sc->sc_state &= ~INTERRUPTED; | |
| 764 | while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { | |
| 765 | sc->sc_cp = sc->sc_inbuf; | |
| 766 | uiomove(sc->sc_cp, n, uio); | |
| 767 | sc->sc_xfercnt = n ; | |
| 768 | ||
| 769 | if (sc->sc_irq & LP_ENABLE_EXT) { | |
| 770 | /* try any extended mode */ | |
| 771 | err = ppb_write(ppbus, sc->sc_cp, | |
| 772 | sc->sc_xfercnt, 0); | |
| 773 | switch (err) { | |
| 774 | case 0: | |
| 775 | /* if not all data was sent, we could rely | |
| 776 | * on polling for the last bytes */ | |
| 777 | sc->sc_xfercnt = 0; | |
| 778 | break; | |
| 779 | case EINTR: | |
| 780 | sc->sc_state |= INTERRUPTED; | |
| 781 | return(err); | |
| 782 | case EINVAL: | |
| 783 | /* advanced mode not avail */ | |
| 784 | log(LOG_NOTICE, LPT_NAME "%d: advanced mode not avail, polling\n", unit); | |
| 785 | break; | |
| 786 | default: | |
| 787 | return(err); | |
| 788 | } | |
| 789 | } else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { | |
| 790 | lprintf(("i")); | |
| 791 | /* if the printer is ready for a char, */ | |
| 792 | /* give it one */ | |
| 793 | if ((sc->sc_state & OBUSY) == 0){ | |
| 794 | lprintf(("\nC %d. ", sc->sc_xfercnt)); | |
| 795 | lptintr(lptdev); | |
| 796 | } | |
| 797 | lprintf(("W ")); | |
| 798 | if (sc->sc_state & OBUSY) | |
| 799 | if ((err = tsleep((caddr_t)lptdev, | |
| 377d4740 | 800 | PCATCH, LPT_NAME "write", 0))) { |
| 984263bc MD |
801 | sc->sc_state |= INTERRUPTED; |
| 802 | return(err); | |
| 803 | } | |
| 804 | } | |
| 805 | ||
| 806 | /* check to see if we must do a polled write */ | |
| 807 | if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { | |
| 808 | lprintf(("p")); | |
| 809 | ||
| 810 | err = lpt_pushbytes(lptdev); | |
| 811 | ||
| 812 | if (err) | |
| 813 | return(err); | |
| 814 | } | |
| 815 | } | |
| 816 | ||
| 817 | /* we have not been interrupted, release the ppbus */ | |
| 818 | lpt_release_ppbus(lptdev); | |
| 819 | ||
| 820 | return(0); | |
| 821 | } | |
| 822 | ||
| 823 | /* | |
| 824 | * lpt_intr -- handle printer interrupts which occur when the printer is | |
| 825 | * ready to accept another char. | |
| 826 | * | |
| 827 | * do checking for interrupted write call. | |
| 828 | */ | |
| 829 | ||
| 830 | static void | |
| 831 | lpt_intr(void *arg) | |
| 832 | { | |
| 833 | device_t lptdev = (device_t)arg; | |
| 834 | device_t ppbus = device_get_parent(lptdev); | |
| 835 | struct lpt_data *sc = DEVTOSOFTC(lptdev); | |
| 836 | int sts = 0; | |
| 837 | int i; | |
| 838 | ||
| 839 | /* we must own the bus to use it */ | |
| 840 | if ((sc->sc_state & HAVEBUS) == 0) | |
| 841 | return; | |
| 842 | ||
| 843 | /* | |
| 844 | * Is printer online and ready for output? | |
| 845 | * | |
| 846 | * Avoid falling back to lptout() too quickly. First spin-loop | |
| 847 | * to see if the printer will become ready ``really soon now''. | |
| 848 | */ | |
| 849 | for (i = 0; i < 100 && | |
| 850 | ((sts=ppb_rstr(ppbus)) & RDY_MASK) != LP_READY; i++) ; | |
| 851 | ||
| 852 | if ((sts & RDY_MASK) == LP_READY) { | |
| 853 | sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR; | |
| 854 | sc->sc_backoff = hz/LPTOUTINITIAL; | |
| 855 | ||
| 856 | if (sc->sc_xfercnt) { | |
| 857 | /* send char */ | |
| 858 | /*lprintf(("%x ", *sc->sc_cp)); */ | |
| 859 | ppb_wdtr(ppbus, *sc->sc_cp++) ; | |
| 860 | ppb_wctr(ppbus, sc->sc_control|LPC_STB); | |
| 861 | /* DELAY(X) */ | |
| 862 | ppb_wctr(ppbus, sc->sc_control); | |
| 863 | ||
| 864 | /* any more data for printer */ | |
| 865 | if(--(sc->sc_xfercnt) > 0) return; | |
| 866 | } | |
| 867 | ||
| 868 | /* | |
| 869 | * No more data waiting for printer. | |
| 870 | * Wakeup is not done if write call was not interrupted. | |
| 871 | */ | |
| 872 | sc->sc_state &= ~OBUSY; | |
| 873 | ||
| 874 | if(!(sc->sc_state & INTERRUPTED)) | |
| 875 | wakeup((caddr_t)lptdev); | |
| 876 | lprintf(("w ")); | |
| 877 | return; | |
| 878 | } else { /* check for error */ | |
| 879 | if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && | |
| 880 | (sc->sc_state & OPEN)) | |
| 881 | sc->sc_state |= EERROR; | |
| 882 | /* lptout() will jump in and try to restart. */ | |
| 883 | } | |
| 884 | lprintf(("sts %x ", sts)); | |
| 885 | } | |
| 886 | ||
| 887 | static void | |
| 888 | lptintr(device_t dev) | |
| 889 | { | |
| 890 | /* call the interrupt at required spl level */ | |
| b28b340f | 891 | crit_enter(); |
| 984263bc MD |
892 | |
| 893 | lpt_intr(dev); | |
| 894 | ||
| b28b340f | 895 | crit_exit(); |
| 984263bc MD |
896 | } |
| 897 | ||
| 898 | static int | |
| fef8985e | 899 | lptioctl(struct dev_ioctl_args *ap) |
| 984263bc | 900 | { |
| b13267a5 | 901 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
902 | int error = 0; |
| 903 | u_int unit = LPTUNIT(minor(dev)); | |
| 904 | struct lpt_data *sc = UNITOSOFTC(unit); | |
| 905 | u_char old_sc_irq; /* old printer IRQ status */ | |
| 906 | ||
| fef8985e | 907 | switch (ap->a_cmd) { |
| 984263bc MD |
908 | case LPT_IRQ : |
| 909 | if(sc->sc_irq & LP_HAS_IRQ) { | |
| 910 | /* | |
| 911 | * NOTE: | |
| 912 | * If the IRQ status is changed, | |
| 913 | * this will only be visible on the | |
| 914 | * next open. | |
| 915 | * | |
| 916 | * If interrupt status changes, | |
| 917 | * this gets syslog'd. | |
| 918 | */ | |
| 919 | old_sc_irq = sc->sc_irq; | |
| fef8985e | 920 | switch(*(int*)ap->a_data) { |
| 984263bc MD |
921 | case 0: |
| 922 | sc->sc_irq &= (~LP_ENABLE_IRQ); | |
| 923 | break; | |
| 924 | case 1: | |
| 925 | sc->sc_irq &= (~LP_ENABLE_EXT); | |
| 926 | sc->sc_irq |= LP_ENABLE_IRQ; | |
| 927 | break; | |
| 928 | case 2: | |
| 929 | /* classic irq based transfer and advanced | |
| 930 | * modes are in conflict | |
| 931 | */ | |
| 932 | sc->sc_irq &= (~LP_ENABLE_IRQ); | |
| 933 | sc->sc_irq |= LP_ENABLE_EXT; | |
| 934 | break; | |
| 935 | case 3: | |
| 936 | sc->sc_irq &= (~LP_ENABLE_EXT); | |
| 937 | break; | |
| 938 | default: | |
| 939 | break; | |
| 940 | } | |
| 941 | ||
| 942 | if (old_sc_irq != sc->sc_irq ) | |
| 943 | log(LOG_NOTICE, LPT_NAME "%d: switched to %s %s mode\n", | |
| 944 | unit, | |
| 945 | (sc->sc_irq & LP_ENABLE_IRQ)? | |
| 946 | "interrupt-driven":"polled", | |
| 947 | (sc->sc_irq & LP_ENABLE_EXT)? | |
| 948 | "extended":"standard"); | |
| 949 | } else /* polled port */ | |
| 950 | error = EOPNOTSUPP; | |
| 951 | break; | |
| 952 | default: | |
| 953 | error = ENODEV; | |
| 954 | } | |
| 955 | ||
| 956 | return(error); | |
| 957 | } | |
| 958 | ||
| 39b5d600 MD |
959 | /* |
| 960 | * Because lpt is a static device that always exists under a ppbus device, | |
| 961 | * and not scanned by the ppbus device, we need an identify function to | |
| 962 | * install its device. | |
| 963 | */ | |
| 984263bc MD |
964 | static device_method_t lpt_methods[] = { |
| 965 | /* device interface */ | |
| 39b5d600 | 966 | DEVMETHOD(device_identify, bus_generic_identify), |
| 984263bc MD |
967 | DEVMETHOD(device_probe, lpt_probe), |
| 968 | DEVMETHOD(device_attach, lpt_attach), | |
| 969 | ||
| 970 | { 0, 0 } | |
| 971 | }; | |
| 972 | ||
| 973 | static driver_t lpt_driver = { | |
| 974 | LPT_NAME, | |
| 975 | lpt_methods, | |
| 976 | sizeof(struct lpt_data), | |
| 977 | }; | |
| 978 | ||
| 979 | DRIVER_MODULE(lpt, ppbus, lpt_driver, lpt_devclass, 0, 0); | |
| 39b5d600 | 980 |