Home | History | Annotate | Line # | Download | only in ppbus
lpt.c revision 1.28.24.1
      1  1.28.24.1       tls /* $NetBSD: lpt.c,v 1.28.24.1 2014/08/20 00:03:49 tls 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.28.24.1       tls __KERNEL_RCSID(0, "$NetBSD: lpt.c,v 1.28.24.1 2014/08/20 00:03:49 tls 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.28.24.1       tls         .d_open = lptopen,
    114  1.28.24.1       tls 	.d_close = lptclose,
    115  1.28.24.1       tls 	.d_read = lptread,
    116  1.28.24.1       tls 	.d_write = lptwrite,
    117  1.28.24.1       tls 	.d_ioctl = lptioctl,
    118  1.28.24.1       tls 	.d_stop = nostop,
    119  1.28.24.1       tls 	.d_tty = notty,
    120  1.28.24.1       tls 	.d_poll = nopoll,
    121  1.28.24.1       tls 	.d_mmap = nommap,
    122  1.28.24.1       tls 	.d_kqfilter = nokqfilter,
    123  1.28.24.1       tls 	.d_discard = nodiscard,
    124  1.28.24.1       tls 	.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.1  jdolecek  *	   per the IBM PC technical reference manauls 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.1  jdolecek 			min(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