1139749Simp/*- 243989Snsouch * Copyright (c) 1990 William F. Jolitz, TeleMuse 343989Snsouch * All rights reserved. 443989Snsouch * 543989Snsouch * Redistribution and use in source and binary forms, with or without 643989Snsouch * modification, are permitted provided that the following conditions 743989Snsouch * are met: 843989Snsouch * 1. Redistributions of source code must retain the above copyright 943989Snsouch * notice, this list of conditions and the following disclaimer. 1043989Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1143989Snsouch * notice, this list of conditions and the following disclaimer in the 1243989Snsouch * documentation and/or other materials provided with the distribution. 1343989Snsouch * 3. All advertising materials mentioning features or use of this software 1443989Snsouch * must display the following acknowledgement: 1543989Snsouch * This software is a component of "386BSD" developed by 1643989Snsouch * William F. Jolitz, TeleMuse. 1743989Snsouch * 4. Neither the name of the developer nor the name "386BSD" 1843989Snsouch * may be used to endorse or promote products derived from this software 1943989Snsouch * without specific prior written permission. 2043989Snsouch * 2143989Snsouch * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 2243989Snsouch * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 2343989Snsouch * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 2443989Snsouch * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 2543989Snsouch * NOT MAKE USE OF THIS WORK. 2643989Snsouch * 2743989Snsouch * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 2843989Snsouch * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 2943989Snsouch * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 3043989Snsouch * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 3143989Snsouch * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 3243989Snsouch * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 3343989Snsouch * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 3443989Snsouch * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 3543989Snsouch * 3643989Snsouch * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 3743989Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3843989Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3943989Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 4043989Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4143989Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4243989Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4343989Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4443989Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4543989Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4643989Snsouch * SUCH DAMAGE. 4743989Snsouch * 4843989Snsouch * from: unknown origin, 386BSD 0.1 4943989Snsouch * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp 5043989Snsouch * From Id: nlpt.c,v 1.14 1999/02/08 13:55:43 des Exp 5143989Snsouch */ 5243989Snsouch 53119418Sobrien#include <sys/cdefs.h> 54119418Sobrien__FBSDID("$FreeBSD$"); 55119418Sobrien 5643989Snsouch/* 5743989Snsouch * Device Driver for AT parallel printer port 5843989Snsouch * Written by William Jolitz 12/18/90 5943989Snsouch */ 6043989Snsouch 6143989Snsouch/* 6243989Snsouch * Updated for ppbus by Nicolas Souchu 6343989Snsouch * [Mon Jul 28 1997] 6443989Snsouch */ 6543989Snsouch 6655939Snsouch#include "opt_lpt.h" 6755939Snsouch 6843989Snsouch#include <sys/param.h> 6943989Snsouch#include <sys/systm.h> 7055939Snsouch#include <sys/module.h> 7155939Snsouch#include <sys/bus.h> 7243989Snsouch#include <sys/conf.h> 7343989Snsouch#include <sys/kernel.h> 7443989Snsouch#include <sys/uio.h> 7543989Snsouch#include <sys/syslog.h> 7660025Sphk#include <sys/malloc.h> 7743989Snsouch 7855939Snsouch#include <machine/bus.h> 7955939Snsouch#include <machine/resource.h> 8055939Snsouch#include <sys/rman.h> 8155939Snsouch 8260719Sobrien#include <dev/ppbus/lptio.h> 8343989Snsouch#include <dev/ppbus/ppbconf.h> 8443989Snsouch#include <dev/ppbus/ppb_1284.h> 8543989Snsouch#include <dev/ppbus/lpt.h> 8655939Snsouch#include "ppbus_if.h" 8755939Snsouch#include <dev/ppbus/ppbio.h> 8843989Snsouch 8943989Snsouch#ifndef LPT_DEBUG 90185003Sjhb#define lprintf(args) 9143989Snsouch#else 92185003Sjhb#define lprintf(args) \ 9343989Snsouch do { \ 9443989Snsouch if (lptflag) \ 9543989Snsouch printf args; \ 9643989Snsouch } while (0) 9743989Snsouchstatic int volatile lptflag = 1; 9843989Snsouch#endif 9943989Snsouch 10043989Snsouch#define LPINITRDY 4 /* wait up to 4 seconds for a ready */ 10143989Snsouch#define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ 10243989Snsouch#define LPTOUTMAX 1 /* maximal timeout 1 s */ 10343989Snsouch#define LPPRI (PZERO+8) 10443989Snsouch#define BUFSIZE 1024 10543989Snsouch#define BUFSTATSIZE 32 10643989Snsouch 10743999Snsouchstruct lpt_data { 108187576Sjhb device_t sc_dev; 109187576Sjhb struct cdev *sc_cdev; 110187576Sjhb struct cdev *sc_cdev_bypass; 11143999Snsouch short sc_state; 11243999Snsouch /* default case: negative prime, negative ack, handshake strobe, 11343999Snsouch prime once */ 11443999Snsouch u_char sc_control; 11543999Snsouch char sc_flags; 116298955Spfg#define LP_POS_INIT 0x04 /* if we are a positive init signal */ 117185003Sjhb#define LP_POS_ACK 0x08 /* if we are a positive going ack */ 118185003Sjhb#define LP_NO_PRIME 0x10 /* don't prime the printer at all */ 119185003Sjhb#define LP_PRIMEOPEN 0x20 /* prime on every open */ 120185003Sjhb#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ 121185003Sjhb#define LP_BYPASS 0x80 /* bypass printer ready checks */ 12260025Sphk void *sc_inbuf; 12360025Sphk void *sc_statbuf; 12443999Snsouch short sc_xfercnt ; 12543999Snsouch char sc_primed; 12643999Snsouch char *sc_cp ; 12743999Snsouch u_short sc_irq ; /* IRQ status of port */ 128185003Sjhb#define LP_HAS_IRQ 0x01 /* we have an irq available */ 129185003Sjhb#define LP_USE_IRQ 0x02 /* we are using our irq */ 130185003Sjhb#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ 131185003Sjhb#define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */ 13243999Snsouch u_char sc_backoff ; /* time to call lptout() again */ 133187576Sjhb struct callout sc_timer; 13443999Snsouch 135187576Sjhb struct resource *sc_intr_resource; /* interrupt resource */ 136187576Sjhb void *sc_intr_cookie; /* interrupt cookie */ 13743999Snsouch}; 13843999Snsouch 139185003Sjhb#define LPT_NAME "lpt" /* our official name */ 14043989Snsouch 14143989Snsouchstatic timeout_t lptout; 14255939Snsouchstatic int lpt_port_test(device_t dev, u_char data, u_char mask); 14355939Snsouchstatic int lpt_detect(device_t dev); 14443989Snsouch 145185003Sjhb#define DEVTOSOFTC(dev) \ 14655939Snsouch ((struct lpt_data *)device_get_softc(dev)) 14743989Snsouch 148187576Sjhbstatic void lptintr(void *arg); 14943989Snsouch 15055939Snsouchstatic devclass_t lpt_devclass; 15143989Snsouch 15255939Snsouch 15343989Snsouch/* bits for state */ 15443989Snsouch#define OPEN (1<<0) /* device is open */ 15543989Snsouch#define ASLP (1<<1) /* awaiting draining of printer */ 15643989Snsouch#define EERROR (1<<2) /* error was received from printer */ 15743989Snsouch#define OBUSY (1<<3) /* printer is busy doing output */ 158185003Sjhb#define LPTOUT (1<<4) /* timeout while not selected */ 159185003Sjhb#define TOUT (1<<5) /* timeout while not selected */ 160185003Sjhb#define LPTINIT (1<<6) /* waiting to initialize for open */ 161185003Sjhb#define INTERRUPTED (1<<7) /* write call was interrupted */ 162185003Sjhb#define HAVEBUS (1<<8) /* the driver owns the bus */ 16343989Snsouch 16443989Snsouch/* status masks to interrogate printer status */ 165185003Sjhb#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ 166185003Sjhb#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) 16743989Snsouch 16843989Snsouch/* Printer Ready condition - from lpa.c */ 16943989Snsouch/* Only used in polling code */ 17043989Snsouch#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) 17143989Snsouch#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) 17255939Snsouch#define NOT_READY(ppbus) ((ppb_rstr(ppbus)^LPS_INVERT)&LPS_MASK) 17343989Snsouch 17443989Snsouch#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ 17543989Snsouch#define MAX_SPIN 20 /* Max delay for device ready in usecs */ 17643989Snsouch 17743989Snsouch 17843989Snsouchstatic d_open_t lptopen; 17943989Snsouchstatic d_close_t lptclose; 18043989Snsouchstatic d_write_t lptwrite; 18143989Snsouchstatic d_read_t lptread; 18243989Snsouchstatic d_ioctl_t lptioctl; 18343989Snsouch 18447625Sphkstatic struct cdevsw lpt_cdevsw = { 185126080Sphk .d_version = D_VERSION, 186111815Sphk .d_open = lptopen, 187111815Sphk .d_close = lptclose, 188111815Sphk .d_read = lptread, 189111815Sphk .d_write = lptwrite, 190111815Sphk .d_ioctl = lptioctl, 191111815Sphk .d_name = LPT_NAME, 19247625Sphk}; 19343989Snsouch 19443989Snsouchstatic int 19555939Snsouchlpt_request_ppbus(device_t dev, int how) 19643989Snsouch{ 19755939Snsouch device_t ppbus = device_get_parent(dev); 19855939Snsouch struct lpt_data *sc = DEVTOSOFTC(dev); 19943989Snsouch int error; 20043989Snsouch 201187576Sjhb /* 202187576Sjhb * We might already have the bus for a write(2) after an interrupted 203187576Sjhb * write(2) call. 204187576Sjhb */ 205187576Sjhb ppb_assert_locked(ppbus); 20643989Snsouch if (sc->sc_state & HAVEBUS) 20743989Snsouch return (0); 20843989Snsouch 209187576Sjhb error = ppb_request_bus(ppbus, dev, how); 210187576Sjhb if (error == 0) 21143989Snsouch sc->sc_state |= HAVEBUS; 21243989Snsouch return (error); 21343989Snsouch} 21443989Snsouch 21543989Snsouchstatic int 21655939Snsouchlpt_release_ppbus(device_t dev) 21743989Snsouch{ 21855939Snsouch device_t ppbus = device_get_parent(dev); 21955939Snsouch struct lpt_data *sc = DEVTOSOFTC(dev); 22055939Snsouch int error = 0; 22143989Snsouch 222187576Sjhb ppb_assert_locked(ppbus); 223187576Sjhb if (sc->sc_state & HAVEBUS) { 224187576Sjhb error = ppb_release_bus(ppbus, dev); 225187576Sjhb if (error == 0) 226187576Sjhb sc->sc_state &= ~HAVEBUS; 227187576Sjhb } 22855939Snsouch return (error); 22943989Snsouch} 23043989Snsouch 23143989Snsouch/* 23243989Snsouch * Internal routine to lptprobe to do port tests of one byte value 23343989Snsouch */ 23443989Snsouchstatic int 23555939Snsouchlpt_port_test(device_t ppbus, u_char data, u_char mask) 23643989Snsouch{ 23743989Snsouch int temp, timeout; 23843989Snsouch 23943989Snsouch data = data & mask; 24055939Snsouch ppb_wdtr(ppbus, data); 24143989Snsouch timeout = 10000; 24243989Snsouch do { 24343989Snsouch DELAY(10); 24455939Snsouch temp = ppb_rdtr(ppbus) & mask; 24543989Snsouch } 24643989Snsouch while (temp != data && --timeout); 24743989Snsouch lprintf(("out=%x\tin=%x\ttout=%d\n", data, temp, timeout)); 24843989Snsouch return (temp == data); 24943989Snsouch} 25043989Snsouch 25143989Snsouch/* 25243989Snsouch * Probe simplified by replacing multiple loops with a hardcoded 25343989Snsouch * test pattern - 1999/02/08 des@freebsd.org 25443989Snsouch * 25543989Snsouch * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 25643989Snsouch * Based partially on Rod Grimes' printer probe 25743989Snsouch * 25843989Snsouch * Logic: 25943989Snsouch * 1) If no port address was given, use the bios detected ports 26043989Snsouch * and autodetect what ports the printers are on. 26143989Snsouch * 2) Otherwise, probe the data port at the address given, 26243989Snsouch * using the method in Rod Grimes' port probe. 26343989Snsouch * (Much code ripped off directly from Rod's probe.) 26443989Snsouch * 26543989Snsouch * Comments from Rod's probe: 26643989Snsouch * Logic: 26743989Snsouch * 1) You should be able to write to and read back the same value 26843989Snsouch * to the data port. Do an alternating zeros, alternating ones, 26943989Snsouch * walking zero, and walking one test to check for stuck bits. 27043989Snsouch * 27143989Snsouch * 2) You should be able to write to and read back the same value 27243989Snsouch * to the control port lower 5 bits, the upper 3 bits are reserved 27343989Snsouch * per the IBM PC technical reference manauls and different boards 27443989Snsouch * do different things with them. Do an alternating zeros, alternating 27543989Snsouch * ones, walking zero, and walking one test to check for stuck bits. 27643989Snsouch * 27743989Snsouch * Some printers drag the strobe line down when the are powered off 27843989Snsouch * so this bit has been masked out of the control port test. 27943989Snsouch * 28043989Snsouch * XXX Some printers may not like a fast pulse on init or strobe, I 28143989Snsouch * don't know at this point, if that becomes a problem these bits 28243989Snsouch * should be turned off in the mask byte for the control port test. 28343989Snsouch * 28443989Snsouch * We are finally left with a mask of 0x14, due to some printers 28543989Snsouch * being adamant about holding other bits high ........ 28643989Snsouch * 28743989Snsouch * Before probing the control port, we write a 0 to the data port - 28843989Snsouch * If not, some printers chuck out garbage when the strobe line 28943989Snsouch * gets toggled. 29043989Snsouch * 29143989Snsouch * 3) Set the data and control ports to a value of 0 29243989Snsouch * 29343989Snsouch * This probe routine has been tested on Epson Lx-800, HP LJ3P, 29443989Snsouch * Epson FX-1170 and C.Itoh 8510RM 29543989Snsouch * printers. 29643989Snsouch * Quick exit on fail added. 29743989Snsouch */ 29843989Snsouchstatic int 29955939Snsouchlpt_detect(device_t dev) 30043989Snsouch{ 30155939Snsouch device_t ppbus = device_get_parent(dev); 30255939Snsouch 30343989Snsouch static u_char testbyte[18] = { 30443989Snsouch 0x55, /* alternating zeros */ 30543989Snsouch 0xaa, /* alternating ones */ 30643989Snsouch 0xfe, 0xfd, 0xfb, 0xf7, 30743989Snsouch 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 30843989Snsouch 0x01, 0x02, 0x04, 0x08, 30943989Snsouch 0x10, 0x20, 0x40, 0x80 /* walking one */ 31043989Snsouch }; 31143989Snsouch int i, error, status; 31243989Snsouch 31343989Snsouch status = 1; /* assume success */ 31443989Snsouch 315187576Sjhb ppb_lock(ppbus); 31655939Snsouch if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { 317187576Sjhb ppb_unlock(ppbus); 318187576Sjhb device_printf(dev, "cannot alloc ppbus (%d)!\n", error); 319187576Sjhb return (0); 32043989Snsouch } 32143989Snsouch 32243989Snsouch for (i = 0; i < 18 && status; i++) 32355939Snsouch if (!lpt_port_test(ppbus, testbyte[i], 0xff)) { 32443989Snsouch status = 0; 325187576Sjhb break; 32643989Snsouch } 32743989Snsouch 32843989Snsouch /* write 0's to control and data ports */ 32955939Snsouch ppb_wdtr(ppbus, 0); 33055939Snsouch ppb_wctr(ppbus, 0); 33143989Snsouch 33255939Snsouch lpt_release_ppbus(dev); 333187576Sjhb ppb_unlock(ppbus); 33443989Snsouch 33543989Snsouch return (status); 33643989Snsouch} 33743989Snsouch 33856455Speterstatic void 33956455Speterlpt_identify(driver_t *driver, device_t parent) 34056455Speter{ 34156455Speter 342127189Sguido device_t dev; 343127189Sguido 344155921Sjhb dev = device_find_child(parent, LPT_NAME, -1); 345127189Sguido if (!dev) 346127189Sguido BUS_ADD_CHILD(parent, 0, LPT_NAME, -1); 34756455Speter} 34856455Speter 34943989Snsouch/* 35055939Snsouch * lpt_probe() 35143989Snsouch */ 35255939Snsouchstatic int 35355939Snsouchlpt_probe(device_t dev) 35443989Snsouch{ 35543989Snsouch 35655939Snsouch if (!lpt_detect(dev)) 35755939Snsouch return (ENXIO); 35843989Snsouch 35955939Snsouch device_set_desc(dev, "Printer"); 36043989Snsouch 36155939Snsouch return (0); 36243989Snsouch} 36343989Snsouch 36443989Snsouchstatic int 36555939Snsouchlpt_attach(device_t dev) 36643989Snsouch{ 36755939Snsouch device_t ppbus = device_get_parent(dev); 36855939Snsouch struct lpt_data *sc = DEVTOSOFTC(dev); 369183053Sjhb int rid = 0, unit = device_get_unit(dev); 37043989Snsouch int error; 37143989Snsouch 37243989Snsouch sc->sc_primed = 0; /* not primed yet */ 373187576Sjhb ppb_init_callout(ppbus, &sc->sc_timer, 0); 37443989Snsouch 375187576Sjhb ppb_lock(ppbus); 37655939Snsouch if ((error = lpt_request_ppbus(dev, PPB_DONTWAIT))) { 377187576Sjhb ppb_unlock(ppbus); 378187576Sjhb device_printf(dev, "cannot alloc ppbus (%d)!\n", error); 37943989Snsouch return (0); 38043989Snsouch } 38143989Snsouch 38255939Snsouch ppb_wctr(ppbus, LPC_NINIT); 383187740Sjhb lpt_release_ppbus(dev); 384187576Sjhb ppb_unlock(ppbus); 38543989Snsouch 386183053Sjhb /* declare our interrupt handler */ 387187576Sjhb sc->sc_intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 388183053Sjhb RF_SHAREABLE); 389187576Sjhb if (sc->sc_intr_resource) { 390187576Sjhb error = bus_setup_intr(dev, sc->sc_intr_resource, 391187576Sjhb INTR_TYPE_TTY | INTR_MPSAFE, NULL, lptintr, sc, 392187576Sjhb &sc->sc_intr_cookie); 393187576Sjhb if (error) { 394187576Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, 395187576Sjhb sc->sc_intr_resource); 396187576Sjhb device_printf(dev, 397187576Sjhb "Unable to register interrupt handler\n"); 398187576Sjhb return (error); 399187576Sjhb } 40043989Snsouch sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; 40155939Snsouch device_printf(dev, "Interrupt-driven port\n"); 40243989Snsouch } else { 40343989Snsouch sc->sc_irq = 0; 40455939Snsouch device_printf(dev, "Polled port\n"); 40543989Snsouch } 406183053Sjhb lprintf(("irq %x\n", sc->sc_irq)); 40743989Snsouch 408187576Sjhb sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK); 409187576Sjhb sc->sc_statbuf = malloc(BUFSTATSIZE, M_DEVBUF, M_WAITOK); 410187576Sjhb sc->sc_dev = dev; 411187576Sjhb sc->sc_cdev = make_dev(&lpt_cdevsw, unit, 41255939Snsouch UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d", unit); 413187576Sjhb sc->sc_cdev->si_drv1 = sc; 414187576Sjhb sc->sc_cdev->si_drv2 = 0; 415187576Sjhb sc->sc_cdev_bypass = make_dev(&lpt_cdevsw, unit, 41655939Snsouch UID_ROOT, GID_WHEEL, 0600, LPT_NAME "%d.ctl", unit); 417187576Sjhb sc->sc_cdev_bypass->si_drv1 = sc; 418187576Sjhb sc->sc_cdev_bypass->si_drv2 = (void *)LP_BYPASS; 41955939Snsouch return (0); 42043989Snsouch} 42143989Snsouch 422157774Siwasakistatic int 423157774Siwasakilpt_detach(device_t dev) 424157774Siwasaki{ 425157774Siwasaki struct lpt_data *sc = DEVTOSOFTC(dev); 426187576Sjhb device_t ppbus = device_get_parent(dev); 427157774Siwasaki 428187576Sjhb destroy_dev(sc->sc_cdev); 429187576Sjhb destroy_dev(sc->sc_cdev_bypass); 430187576Sjhb ppb_lock(ppbus); 431157774Siwasaki lpt_release_ppbus(dev); 432187576Sjhb ppb_unlock(ppbus); 433187576Sjhb callout_drain(&sc->sc_timer); 434187576Sjhb if (sc->sc_intr_resource != NULL) { 435187576Sjhb bus_teardown_intr(dev, sc->sc_intr_resource, 436187576Sjhb sc->sc_intr_cookie); 437187576Sjhb bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr_resource); 438157774Siwasaki } 439187576Sjhb free(sc->sc_inbuf, M_DEVBUF); 440187576Sjhb free(sc->sc_statbuf, M_DEVBUF); 441157774Siwasaki 442157774Siwasaki return (0); 443157774Siwasaki} 444157774Siwasaki 44543989Snsouchstatic void 44643989Snsouchlptout(void *arg) 44743989Snsouch{ 448187576Sjhb struct lpt_data *sc = arg; 449187576Sjhb device_t dev = sc->sc_dev; 450227814Sattilio device_t ppbus; 45143989Snsouch 452227814Sattilio ppbus = device_get_parent(dev); 453187576Sjhb ppb_assert_locked(ppbus); 45455939Snsouch lprintf(("T %x ", ppb_rstr(ppbus))); 45543989Snsouch if (sc->sc_state & OPEN) { 45643989Snsouch sc->sc_backoff++; 45743989Snsouch if (sc->sc_backoff > hz/LPTOUTMAX) 458197772Sjhb sc->sc_backoff = hz/LPTOUTMAX; 459187576Sjhb callout_reset(&sc->sc_timer, sc->sc_backoff, lptout, sc); 46043989Snsouch } else 46143989Snsouch sc->sc_state &= ~TOUT; 46243989Snsouch 46343989Snsouch if (sc->sc_state & EERROR) 46443989Snsouch sc->sc_state &= ~EERROR; 46543989Snsouch 46643989Snsouch /* 46755939Snsouch * Avoid possible hangs due to missed interrupts 46843989Snsouch */ 46943989Snsouch if (sc->sc_xfercnt) { 470187576Sjhb lptintr(sc); 47143989Snsouch } else { 47243989Snsouch sc->sc_state &= ~OBUSY; 473111748Sdes wakeup(dev); 47443989Snsouch } 47543989Snsouch} 47643989Snsouch 47743989Snsouch/* 47843989Snsouch * lptopen -- reset the printer, then wait until it's selected and not busy. 47943989Snsouch * If LP_BYPASS flag is selected, then we do not try to select the 48043989Snsouch * printer -- this is just used for passing ioctls. 48143989Snsouch */ 48243989Snsouch 48343989Snsouchstatic int 484130585Sphklptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 48543989Snsouch{ 48643989Snsouch int trys, err; 487184130Sjhb struct lpt_data *sc = dev->si_drv1; 488198358Sbrueffer device_t lptdev; 489198358Sbrueffer device_t ppbus; 49043989Snsouch 49155939Snsouch if (!sc) 49243989Snsouch return (ENXIO); 49343989Snsouch 494198358Sbrueffer lptdev = sc->sc_dev; 495198358Sbrueffer ppbus = device_get_parent(lptdev); 496198358Sbrueffer 497187576Sjhb ppb_lock(ppbus); 49843989Snsouch if (sc->sc_state) { 499187576Sjhb lprintf(("%s: still open %x\n", device_get_nameunit(lptdev), 500187576Sjhb sc->sc_state)); 501187576Sjhb ppb_unlock(ppbus); 50243989Snsouch return(EBUSY); 50343989Snsouch } else 50443989Snsouch sc->sc_state |= LPTINIT; 50543989Snsouch 506184164Sjhb sc->sc_flags = (uintptr_t)dev->si_drv2; 50743989Snsouch 50843989Snsouch /* Check for open with BYPASS flag set. */ 50943989Snsouch if (sc->sc_flags & LP_BYPASS) { 51043989Snsouch sc->sc_state = OPEN; 511187576Sjhb ppb_unlock(ppbus); 51243989Snsouch return(0); 51343989Snsouch } 51443989Snsouch 51543989Snsouch /* request the ppbus only if we don't have it already */ 51655939Snsouch if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { 51755939Snsouch /* give it a chance to try later */ 51855939Snsouch sc->sc_state = 0; 519187576Sjhb ppb_unlock(ppbus); 52043989Snsouch return (err); 52155939Snsouch } 52243989Snsouch 523187576Sjhb lprintf(("%s flags 0x%x\n", device_get_nameunit(lptdev), 524187576Sjhb sc->sc_flags)); 52543989Snsouch 52655939Snsouch /* set IRQ status according to ENABLE_IRQ flag 52755939Snsouch */ 52843989Snsouch if (sc->sc_irq & LP_ENABLE_IRQ) 52943989Snsouch sc->sc_irq |= LP_USE_IRQ; 53043989Snsouch else 53143989Snsouch sc->sc_irq &= ~LP_USE_IRQ; 53243989Snsouch 53343989Snsouch /* init printer */ 53443989Snsouch if ((sc->sc_flags & LP_NO_PRIME) == 0) { 535185003Sjhb if ((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { 53655939Snsouch ppb_wctr(ppbus, 0); 53743989Snsouch sc->sc_primed++; 53843989Snsouch DELAY(500); 53943989Snsouch } 54043989Snsouch } 54143989Snsouch 54255939Snsouch ppb_wctr(ppbus, LPC_SEL|LPC_NINIT); 54343989Snsouch 54443989Snsouch /* wait till ready (printer running diagnostics) */ 54543989Snsouch trys = 0; 54643989Snsouch do { 54743989Snsouch /* ran out of waiting for the printer */ 54843989Snsouch if (trys++ >= LPINITRDY*4) { 54955939Snsouch lprintf(("status %x\n", ppb_rstr(ppbus))); 55043989Snsouch 55155939Snsouch lpt_release_ppbus(lptdev); 552188484Sjhb sc->sc_state = 0; 553187576Sjhb ppb_unlock(ppbus); 55443989Snsouch return (EBUSY); 55543989Snsouch } 55643989Snsouch 55743989Snsouch /* wait 1/4 second, give up if we get a signal */ 558187576Sjhb if (ppb_sleep(ppbus, lptdev, LPPRI | PCATCH, "lptinit", 559187576Sjhb hz / 4) != EWOULDBLOCK) { 560188484Sjhb lpt_release_ppbus(lptdev); 56143989Snsouch sc->sc_state = 0; 562187576Sjhb ppb_unlock(ppbus); 56343989Snsouch return (EBUSY); 56443989Snsouch } 56543989Snsouch 56643989Snsouch /* is printer online and ready for output */ 56755939Snsouch } while ((ppb_rstr(ppbus) & 56843989Snsouch (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 56943989Snsouch (LPS_SEL|LPS_NBSY|LPS_NERR)); 57043989Snsouch 57143989Snsouch sc->sc_control = LPC_SEL|LPC_NINIT; 57243989Snsouch if (sc->sc_flags & LP_AUTOLF) 57343989Snsouch sc->sc_control |= LPC_AUTOL; 57443989Snsouch 57543989Snsouch /* enable interrupt if interrupt-driven */ 57643989Snsouch if (sc->sc_irq & LP_USE_IRQ) 57743989Snsouch sc->sc_control |= LPC_ENA; 57843989Snsouch 57955939Snsouch ppb_wctr(ppbus, sc->sc_control); 58043989Snsouch 581188484Sjhb sc->sc_state &= ~LPTINIT; 582188484Sjhb sc->sc_state |= OPEN; 58343989Snsouch sc->sc_xfercnt = 0; 58443989Snsouch 58543989Snsouch /* only use timeout if using interrupt */ 58643989Snsouch lprintf(("irq %x\n", sc->sc_irq)); 58743989Snsouch if (sc->sc_irq & LP_USE_IRQ) { 58843989Snsouch sc->sc_state |= TOUT; 589187576Sjhb sc->sc_backoff = hz / LPTOUTINITIAL; 590187576Sjhb callout_reset(&sc->sc_timer, sc->sc_backoff, lptout, sc); 59143989Snsouch } 59243989Snsouch 593187576Sjhb /* release the ppbus */ 594187576Sjhb lpt_release_ppbus(lptdev); 595187576Sjhb ppb_unlock(ppbus); 596187576Sjhb 59743989Snsouch lprintf(("opened.\n")); 59843989Snsouch return(0); 59943989Snsouch} 60043989Snsouch 60143989Snsouch/* 60243989Snsouch * lptclose -- close the device, free the local line buffer. 60343989Snsouch * 60443989Snsouch * Check for interrupted write call added. 60543989Snsouch */ 60643989Snsouch 60743989Snsouchstatic int 608130585Sphklptclose(struct cdev *dev, int flags, int fmt, struct thread *td) 60943989Snsouch{ 610184130Sjhb struct lpt_data *sc = dev->si_drv1; 611187576Sjhb device_t lptdev = sc->sc_dev; 612185003Sjhb device_t ppbus = device_get_parent(lptdev); 61343989Snsouch int err; 61443989Snsouch 615187576Sjhb ppb_lock(ppbus); 616188484Sjhb if (sc->sc_flags & LP_BYPASS) 61743989Snsouch goto end_close; 61843989Snsouch 619187576Sjhb if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { 620187576Sjhb ppb_unlock(ppbus); 62143989Snsouch return (err); 622187576Sjhb } 62343989Snsouch 62443989Snsouch /* if the last write was interrupted, don't complete it */ 625185003Sjhb if ((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) 62655939Snsouch while ((ppb_rstr(ppbus) & 62743989Snsouch (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 62843989Snsouch (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) 629198028Sjhb /* wait 1 second, give up if we get a signal */ 630187576Sjhb if (ppb_sleep(ppbus, lptdev, LPPRI | PCATCH, "lpclose", 631187576Sjhb hz) != EWOULDBLOCK) 63243989Snsouch break; 63343989Snsouch 634187576Sjhb sc->sc_state &= ~OPEN; 635187576Sjhb callout_stop(&sc->sc_timer); 63655939Snsouch ppb_wctr(ppbus, LPC_NINIT); 63743989Snsouch 638187576Sjhb /* 63955939Snsouch * unregistration of interrupt forced by release 64055939Snsouch */ 64155939Snsouch lpt_release_ppbus(lptdev); 64243989Snsouch 643187576Sjhbend_close: 644188484Sjhb sc->sc_state = 0; 645188484Sjhb sc->sc_xfercnt = 0; 646188484Sjhb ppb_unlock(ppbus); 64743989Snsouch lprintf(("closed.\n")); 64843989Snsouch return(0); 64943989Snsouch} 65043989Snsouch 65143989Snsouch/* 65243989Snsouch * lpt_pushbytes() 65343989Snsouch * Workhorse for actually spinning and writing bytes to printer 65443989Snsouch * Derived from lpa.c 65543989Snsouch * Originally by ? 65643989Snsouch * 65743989Snsouch * This code is only used when we are polling the port 65843989Snsouch */ 65943989Snsouchstatic int 660187576Sjhblpt_pushbytes(struct lpt_data *sc) 66143989Snsouch{ 662187576Sjhb device_t dev = sc->sc_dev; 66355939Snsouch device_t ppbus = device_get_parent(dev); 66443989Snsouch int spin, err, tic; 66543989Snsouch char ch; 66643989Snsouch 667187576Sjhb ppb_assert_locked(ppbus); 66843989Snsouch lprintf(("p")); 66943989Snsouch /* loop for every character .. */ 67043989Snsouch while (sc->sc_xfercnt > 0) { 67143989Snsouch /* printer data */ 67243989Snsouch ch = *(sc->sc_cp); 67343989Snsouch sc->sc_cp++; 67443989Snsouch sc->sc_xfercnt--; 67543989Snsouch 67643989Snsouch /* 67743989Snsouch * Wait for printer ready. 67843989Snsouch * Loop 20 usecs testing BUSY bit, then sleep 67943989Snsouch * for exponentially increasing timeout. (vak) 68043989Snsouch */ 68155939Snsouch for (spin = 0; NOT_READY(ppbus) && spin < MAX_SPIN; ++spin) 68243989Snsouch DELAY(1); /* XXX delay is NOT this accurate! */ 68343989Snsouch if (spin >= MAX_SPIN) { 68443989Snsouch tic = 0; 68555939Snsouch while (NOT_READY(ppbus)) { 68643989Snsouch /* 68743989Snsouch * Now sleep, every cycle a 68843989Snsouch * little longer .. 68943989Snsouch */ 69043989Snsouch tic = tic + tic + 1; 69143989Snsouch /* 69243989Snsouch * But no more than 10 seconds. (vak) 69343989Snsouch */ 69443989Snsouch if (tic > MAX_SLEEP) 69543989Snsouch tic = MAX_SLEEP; 696187576Sjhb err = ppb_sleep(ppbus, dev, LPPRI, 69743989Snsouch LPT_NAME "poll", tic); 69843989Snsouch if (err != EWOULDBLOCK) { 69943989Snsouch return (err); 70043989Snsouch } 70143989Snsouch } 70243989Snsouch } 70343989Snsouch 70443989Snsouch /* output data */ 70555939Snsouch ppb_wdtr(ppbus, ch); 70643989Snsouch /* strobe */ 70755939Snsouch ppb_wctr(ppbus, sc->sc_control|LPC_STB); 70855939Snsouch ppb_wctr(ppbus, sc->sc_control); 70943989Snsouch 71043989Snsouch } 71143989Snsouch return(0); 71243989Snsouch} 71343989Snsouch 71443989Snsouch/* 71543989Snsouch * lptread --retrieve printer status in IEEE1284 NIBBLE mode 71643989Snsouch */ 71743989Snsouch 71843989Snsouchstatic int 719130585Sphklptread(struct cdev *dev, struct uio *uio, int ioflag) 72043989Snsouch{ 721184130Sjhb struct lpt_data *sc = dev->si_drv1; 722187576Sjhb device_t lptdev = sc->sc_dev; 723185003Sjhb device_t ppbus = device_get_parent(lptdev); 72443989Snsouch int error = 0, len; 72543989Snsouch 72658082Sgreen if (sc->sc_flags & LP_BYPASS) { 72758082Sgreen /* we can't do reads in bypass mode */ 72858082Sgreen return (EPERM); 72958082Sgreen } 73058082Sgreen 731187576Sjhb ppb_lock(ppbus); 732187576Sjhb if ((error = ppb_1284_negociate(ppbus, PPB_NIBBLE, 0))) { 733187576Sjhb ppb_unlock(ppbus); 73443989Snsouch return (error); 735187576Sjhb } 73643989Snsouch 73743989Snsouch /* read data in an other buffer, read/write may be simultaneous */ 73843989Snsouch len = 0; 73943989Snsouch while (uio->uio_resid) { 74055939Snsouch if ((error = ppb_1284_read(ppbus, PPB_NIBBLE, 74160025Sphk sc->sc_statbuf, min(BUFSTATSIZE, 74243989Snsouch uio->uio_resid), &len))) { 74343989Snsouch goto error; 74443989Snsouch } 74543989Snsouch 74643989Snsouch if (!len) 74743989Snsouch goto error; /* no more data */ 74843989Snsouch 749187576Sjhb ppb_unlock(ppbus); 750187576Sjhb error = uiomove(sc->sc_statbuf, len, uio); 751187576Sjhb ppb_lock(ppbus); 752187576Sjhb if (error) 75343989Snsouch goto error; 75443989Snsouch } 75543989Snsouch 75643989Snsoucherror: 75755939Snsouch ppb_1284_terminate(ppbus); 758187576Sjhb ppb_unlock(ppbus); 75943989Snsouch return (error); 76043989Snsouch} 76143989Snsouch 76243989Snsouch/* 76343989Snsouch * lptwrite --copy a line from user space to a local buffer, then call 76443989Snsouch * putc to get the chars moved to the output queue. 76543989Snsouch * 76643989Snsouch * Flagging of interrupted write added. 76743989Snsouch */ 76843989Snsouch 76943989Snsouchstatic int 770130585Sphklptwrite(struct cdev *dev, struct uio *uio, int ioflag) 77143989Snsouch{ 77243989Snsouch register unsigned n; 77355939Snsouch int err; 774184130Sjhb struct lpt_data *sc = dev->si_drv1; 775187576Sjhb device_t lptdev = sc->sc_dev; 776185003Sjhb device_t ppbus = device_get_parent(lptdev); 77743989Snsouch 778185003Sjhb if (sc->sc_flags & LP_BYPASS) { 77943989Snsouch /* we can't do writes in bypass mode */ 780187576Sjhb return (EPERM); 78143989Snsouch } 78243989Snsouch 78343989Snsouch /* request the ppbus only if we don't have it already */ 784187576Sjhb ppb_lock(ppbus); 785187576Sjhb if ((err = lpt_request_ppbus(lptdev, PPB_WAIT|PPB_INTR)) != 0) { 786187576Sjhb ppb_unlock(ppbus); 78743989Snsouch return (err); 78855939Snsouch } 78955939Snsouch 79043989Snsouch sc->sc_state &= ~INTERRUPTED; 79143989Snsouch while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { 79260025Sphk sc->sc_cp = sc->sc_inbuf; 793187576Sjhb ppb_unlock(ppbus); 794187576Sjhb err = uiomove(sc->sc_cp, n, uio); 795187576Sjhb ppb_lock(ppbus); 796187576Sjhb if (err) 797187576Sjhb break; 798187576Sjhb sc->sc_xfercnt = n; 79943989Snsouch 80043989Snsouch if (sc->sc_irq & LP_ENABLE_EXT) { 80143989Snsouch /* try any extended mode */ 80255939Snsouch err = ppb_write(ppbus, sc->sc_cp, 80355939Snsouch sc->sc_xfercnt, 0); 80443989Snsouch switch (err) { 80543989Snsouch case 0: 80643989Snsouch /* if not all data was sent, we could rely 80743989Snsouch * on polling for the last bytes */ 80843989Snsouch sc->sc_xfercnt = 0; 80943989Snsouch break; 81043989Snsouch case EINTR: 811185003Sjhb sc->sc_state |= INTERRUPTED; 812187576Sjhb ppb_unlock(ppbus); 813187576Sjhb return (err); 81443989Snsouch case EINVAL: 81543989Snsouch /* advanced mode not avail */ 816184130Sjhb log(LOG_NOTICE, 817184130Sjhb "%s: advanced mode not avail, polling\n", 818187576Sjhb device_get_nameunit(sc->sc_dev)); 81943989Snsouch break; 82043989Snsouch default: 821187576Sjhb ppb_unlock(ppbus); 822187576Sjhb return (err); 82343989Snsouch } 82443989Snsouch } else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { 82543989Snsouch lprintf(("i")); 82643989Snsouch /* if the printer is ready for a char, */ 82743989Snsouch /* give it one */ 82843989Snsouch if ((sc->sc_state & OBUSY) == 0){ 82943989Snsouch lprintf(("\nC %d. ", sc->sc_xfercnt)); 830187576Sjhb lptintr(sc); 83143989Snsouch } 83243989Snsouch lprintf(("W ")); 83343989Snsouch if (sc->sc_state & OBUSY) 834187576Sjhb if ((err = ppb_sleep(ppbus, lptdev, 83543989Snsouch LPPRI|PCATCH, LPT_NAME "write", 0))) { 83643989Snsouch sc->sc_state |= INTERRUPTED; 837187576Sjhb ppb_unlock(ppbus); 83843989Snsouch return(err); 83943989Snsouch } 84043989Snsouch } 84143989Snsouch 84243989Snsouch /* check to see if we must do a polled write */ 843185003Sjhb if (!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { 84443989Snsouch lprintf(("p")); 84543989Snsouch 846187576Sjhb err = lpt_pushbytes(sc); 84743989Snsouch 848187576Sjhb if (err) { 849187576Sjhb ppb_unlock(ppbus); 850187576Sjhb return (err); 851187576Sjhb } 85243989Snsouch } 85343989Snsouch } 85443989Snsouch 85543989Snsouch /* we have not been interrupted, release the ppbus */ 85655939Snsouch lpt_release_ppbus(lptdev); 857187576Sjhb ppb_unlock(ppbus); 85843989Snsouch 859187576Sjhb return (err); 86043989Snsouch} 86143989Snsouch 86243989Snsouch/* 863187576Sjhb * lptintr -- handle printer interrupts which occur when the printer is 86443989Snsouch * ready to accept another char. 86543989Snsouch * 86643989Snsouch * do checking for interrupted write call. 86743989Snsouch */ 86843989Snsouchstatic void 869187576Sjhblptintr(void *arg) 87043989Snsouch{ 871187576Sjhb struct lpt_data *sc = arg; 872187576Sjhb device_t lptdev = sc->sc_dev; 873185003Sjhb device_t ppbus = device_get_parent(lptdev); 87456618Sdfr int sts = 0; 87543989Snsouch int i; 876185003Sjhb 87743989Snsouch /* 87843989Snsouch * Is printer online and ready for output? 87943989Snsouch * 88043989Snsouch * Avoid falling back to lptout() too quickly. First spin-loop 88143989Snsouch * to see if the printer will become ready ``really soon now''. 88243989Snsouch */ 88343989Snsouch for (i = 0; i < 100 && 88455939Snsouch ((sts=ppb_rstr(ppbus)) & RDY_MASK) != LP_READY; i++) ; 88543989Snsouch 88643989Snsouch if ((sts & RDY_MASK) == LP_READY) { 88743989Snsouch sc->sc_state = (sc->sc_state | OBUSY) & ~EERROR; 888185003Sjhb sc->sc_backoff = hz / LPTOUTINITIAL; 88943989Snsouch 89043989Snsouch if (sc->sc_xfercnt) { 89143989Snsouch /* send char */ 89243989Snsouch /*lprintf(("%x ", *sc->sc_cp)); */ 89355939Snsouch ppb_wdtr(ppbus, *sc->sc_cp++) ; 89455939Snsouch ppb_wctr(ppbus, sc->sc_control|LPC_STB); 89543989Snsouch /* DELAY(X) */ 89655939Snsouch ppb_wctr(ppbus, sc->sc_control); 89743989Snsouch 89843989Snsouch /* any more data for printer */ 899185003Sjhb if (--(sc->sc_xfercnt) > 0) 900185003Sjhb return; 90143989Snsouch } 90243989Snsouch 90343989Snsouch /* 90443989Snsouch * No more data waiting for printer. 90557064Snsouch * Wakeup is not done if write call was not interrupted. 90643989Snsouch */ 90743989Snsouch sc->sc_state &= ~OBUSY; 90843989Snsouch 909185003Sjhb if (!(sc->sc_state & INTERRUPTED)) 910111748Sdes wakeup(lptdev); 91143989Snsouch lprintf(("w ")); 91243989Snsouch return; 91343989Snsouch } else { /* check for error */ 914185003Sjhb if (((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && 91543989Snsouch (sc->sc_state & OPEN)) 91643989Snsouch sc->sc_state |= EERROR; 91743989Snsouch /* lptout() will jump in and try to restart. */ 91843989Snsouch } 91943989Snsouch lprintf(("sts %x ", sts)); 92043989Snsouch} 92143989Snsouch 92243989Snsouchstatic int 923130585Sphklptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) 92443989Snsouch{ 92543989Snsouch int error = 0; 926184130Sjhb struct lpt_data *sc = dev->si_drv1; 927187576Sjhb device_t ppbus; 92843989Snsouch u_char old_sc_irq; /* old printer IRQ status */ 92943989Snsouch 93043989Snsouch switch (cmd) { 93143989Snsouch case LPT_IRQ : 932187576Sjhb ppbus = device_get_parent(sc->sc_dev); 933187576Sjhb ppb_lock(ppbus); 934185003Sjhb if (sc->sc_irq & LP_HAS_IRQ) { 93543989Snsouch /* 93643989Snsouch * NOTE: 93743989Snsouch * If the IRQ status is changed, 93843989Snsouch * this will only be visible on the 93943989Snsouch * next open. 94043989Snsouch * 94143989Snsouch * If interrupt status changes, 94243989Snsouch * this gets syslog'd. 94343989Snsouch */ 94443989Snsouch old_sc_irq = sc->sc_irq; 945187576Sjhb switch (*(int*)data) { 94643989Snsouch case 0: 94743989Snsouch sc->sc_irq &= (~LP_ENABLE_IRQ); 94843989Snsouch break; 94943989Snsouch case 1: 95043989Snsouch sc->sc_irq &= (~LP_ENABLE_EXT); 95143989Snsouch sc->sc_irq |= LP_ENABLE_IRQ; 95243989Snsouch break; 95343989Snsouch case 2: 95443989Snsouch /* classic irq based transfer and advanced 95543989Snsouch * modes are in conflict 95643989Snsouch */ 95743989Snsouch sc->sc_irq &= (~LP_ENABLE_IRQ); 95843989Snsouch sc->sc_irq |= LP_ENABLE_EXT; 95943989Snsouch break; 96043989Snsouch case 3: 96143989Snsouch sc->sc_irq &= (~LP_ENABLE_EXT); 96243989Snsouch break; 96343989Snsouch default: 96443989Snsouch break; 96543989Snsouch } 966185003Sjhb 96743989Snsouch if (old_sc_irq != sc->sc_irq ) 968184130Sjhb log(LOG_NOTICE, "%s: switched to %s %s mode\n", 969187576Sjhb device_get_nameunit(sc->sc_dev), 97043989Snsouch (sc->sc_irq & LP_ENABLE_IRQ)? 97143989Snsouch "interrupt-driven":"polled", 97243989Snsouch (sc->sc_irq & LP_ENABLE_EXT)? 97343989Snsouch "extended":"standard"); 97443989Snsouch } else /* polled port */ 97543989Snsouch error = EOPNOTSUPP; 976187576Sjhb ppb_unlock(ppbus); 97743989Snsouch break; 97843989Snsouch default: 97943989Snsouch error = ENODEV; 98043989Snsouch } 98143989Snsouch 98243989Snsouch return(error); 98343989Snsouch} 98455939Snsouch 98556455Speterstatic device_method_t lpt_methods[] = { 98656455Speter /* device interface */ 98756455Speter DEVMETHOD(device_identify, lpt_identify), 98856455Speter DEVMETHOD(device_probe, lpt_probe), 98956455Speter DEVMETHOD(device_attach, lpt_attach), 990157774Siwasaki DEVMETHOD(device_detach, lpt_detach), 99155939Snsouch 99256455Speter { 0, 0 } 99356455Speter}; 99455939Snsouch 99556455Speterstatic driver_t lpt_driver = { 99656455Speter LPT_NAME, 99756455Speter lpt_methods, 99856455Speter sizeof(struct lpt_data), 99956455Speter}; 100056455Speter 100156455SpeterDRIVER_MODULE(lpt, ppbus, lpt_driver, lpt_devclass, 0, 0); 1002153610SruMODULE_DEPEND(lpt, ppbus, 1, 1, 1); 1003