Home | History | Annotate | Line # | Download | only in ppbus
ppbus_base.c revision 1.14
      1  1.14        ad /* $NetBSD: ppbus_base.c,v 1.14 2007/12/05 07:58:31 ad Exp $ */
      2   1.2     bjh21 
      3   1.1  jdolecek /*-
      4   1.1  jdolecek  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
      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  *
     16   1.1  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17   1.1  jdolecek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18   1.1  jdolecek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19   1.1  jdolecek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20   1.1  jdolecek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21   1.1  jdolecek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22   1.1  jdolecek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23   1.1  jdolecek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1  jdolecek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1  jdolecek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1  jdolecek  * SUCH DAMAGE.
     27   1.1  jdolecek  *
     28   1.4     bjh21  * FreeBSD: src/sys/dev/ppbus/ppb_base.c,v 1.10.2.1 2000/08/01 23:26:26 n_hibma Exp
     29   1.1  jdolecek  *
     30   1.1  jdolecek  */
     31   1.4     bjh21 
     32   1.4     bjh21 #include <sys/cdefs.h>
     33  1.14        ad __KERNEL_RCSID(0, "$NetBSD: ppbus_base.c,v 1.14 2007/12/05 07:58:31 ad Exp $");
     34   1.4     bjh21 
     35   1.1  jdolecek #include "opt_ppbus_1284.h"
     36   1.9     perry #include "opt_ppbus.h"
     37   1.1  jdolecek 
     38   1.1  jdolecek #include <sys/param.h>
     39   1.1  jdolecek #include <sys/kernel.h>
     40   1.3     bjh21 #include <sys/malloc.h>
     41   1.1  jdolecek #include <sys/proc.h>
     42   1.1  jdolecek #include <sys/lock.h>
     43   1.1  jdolecek #include <sys/systm.h>
     44   1.1  jdolecek 
     45   1.1  jdolecek #include <dev/ppbus/ppbus_1284.h>
     46   1.1  jdolecek #include <dev/ppbus/ppbus_conf.h>
     47   1.1  jdolecek #include <dev/ppbus/ppbus_base.h>
     48   1.1  jdolecek #include <dev/ppbus/ppbus_device.h>
     49   1.1  jdolecek #include <dev/ppbus/ppbus_io.h>
     50   1.1  jdolecek #include <dev/ppbus/ppbus_var.h>
     51   1.1  jdolecek 
     52   1.6  jdolecek #ifndef DONTPROBE_1284
     53   1.1  jdolecek /* Utility functions */
     54  1.10  drochner static char * search_token(char *, int, const char *);
     55   1.6  jdolecek #endif
     56   1.1  jdolecek 
     57   1.1  jdolecek /* Perform general ppbus I/O request */
     58   1.1  jdolecek int
     59   1.1  jdolecek ppbus_io(struct device * dev, int iop, u_char * addr, int cnt, u_char byte)
     60   1.1  jdolecek {
     61   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     62  1.12   thorpej 	return (bus->ppbus_io(device_parent(dev), iop, addr, cnt, byte));
     63   1.1  jdolecek }
     64   1.1  jdolecek 
     65   1.1  jdolecek /* Execute microsequence */
     66   1.1  jdolecek int
     67   1.1  jdolecek ppbus_exec_microseq(struct device * dev, struct ppbus_microseq ** sequence)
     68   1.1  jdolecek {
     69   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     70  1.12   thorpej 	return (bus->ppbus_exec_microseq(device_parent(dev), sequence));
     71   1.1  jdolecek }
     72   1.1  jdolecek 
     73   1.1  jdolecek /* Read instance variables of ppbus */
     74   1.1  jdolecek int
     75   1.1  jdolecek ppbus_read_ivar(struct device * dev, int index, unsigned int * val)
     76   1.9     perry 
     77   1.1  jdolecek {
     78   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
     79   1.1  jdolecek 
     80   1.1  jdolecek 	switch (index) {
     81   1.1  jdolecek 	case PPBUS_IVAR_INTR:
     82   1.1  jdolecek 	case PPBUS_IVAR_EPP_PROTO:
     83   1.1  jdolecek 	case PPBUS_IVAR_DMA:
     84  1.12   thorpej 		return (bus->ppbus_read_ivar(device_parent(dev), index, val));
     85   1.1  jdolecek 
     86   1.1  jdolecek 	case PPBUS_IVAR_IEEE:
     87   1.1  jdolecek 		*val = (bus->sc_use_ieee == PPBUS_ENABLE_IEEE) ? 1 : 0;
     88   1.1  jdolecek 		break;
     89   1.1  jdolecek 
     90   1.1  jdolecek 	default:
     91   1.1  jdolecek 		return (ENOENT);
     92   1.1  jdolecek 	}
     93   1.9     perry 
     94   1.1  jdolecek 	return 0;
     95   1.1  jdolecek }
     96   1.1  jdolecek 
     97   1.1  jdolecek /* Write an instance variable */
     98   1.1  jdolecek int
     99   1.1  jdolecek ppbus_write_ivar(struct device * dev, int index, unsigned int * val)
    100   1.1  jdolecek {
    101   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    102   1.9     perry 
    103   1.1  jdolecek 	switch (index) {
    104   1.1  jdolecek 	case PPBUS_IVAR_INTR:
    105   1.1  jdolecek 	case PPBUS_IVAR_EPP_PROTO:
    106   1.1  jdolecek 	case PPBUS_IVAR_DMA:
    107  1.12   thorpej 		return (bus->ppbus_write_ivar(device_parent(dev), index, val));
    108   1.1  jdolecek 
    109   1.1  jdolecek 	case PPBUS_IVAR_IEEE:
    110   1.9     perry 		bus->sc_use_ieee = ((*val != 0) ? PPBUS_ENABLE_IEEE :
    111   1.1  jdolecek 			PPBUS_DISABLE_IEEE);
    112   1.1  jdolecek 		break;
    113   1.1  jdolecek 
    114   1.1  jdolecek 	default:
    115   1.1  jdolecek 		return (ENOENT);
    116   1.9     perry 	}
    117   1.9     perry 
    118   1.1  jdolecek 	return 0;
    119   1.1  jdolecek }
    120   1.1  jdolecek 
    121   1.1  jdolecek /* Polls the bus for a max of 10-milliseconds */
    122   1.1  jdolecek int
    123  1.10  drochner ppbus_poll_bus(struct device * dev, int maxp, char mask, char status,
    124   1.1  jdolecek 	int how)
    125   1.1  jdolecek {
    126   1.1  jdolecek 	int i, j, error;
    127   1.1  jdolecek 	char r;
    128   1.1  jdolecek 
    129   1.1  jdolecek 	/* try at least up to 10ms */
    130  1.10  drochner 	for (j = 0; j < ((how & PPBUS_POLL) ? maxp : 1); j++) {
    131   1.1  jdolecek 		for (i = 0; i < 10000; i++) {
    132   1.1  jdolecek 			r = ppbus_rstr(dev);
    133   1.1  jdolecek 			DELAY(1);
    134   1.1  jdolecek 			if ((r & mask) == status)
    135   1.1  jdolecek 				return (0);
    136   1.1  jdolecek 		}
    137   1.1  jdolecek 	}
    138   1.1  jdolecek 
    139   1.1  jdolecek 	if (!(how & PPBUS_POLL)) {
    140  1.10  drochner 	   for (i = 0; maxp == PPBUS_FOREVER || i < maxp-1; i++) {
    141   1.1  jdolecek 		if ((ppbus_rstr(dev) & mask) == status)
    142   1.1  jdolecek 			return (0);
    143   1.1  jdolecek 
    144   1.1  jdolecek 		switch (how) {
    145   1.1  jdolecek 		case PPBUS_NOINTR:
    146   1.1  jdolecek 			/* wait 10 ms */
    147  1.13  christos 			tsleep((void *)dev, PPBUSPRI, "ppbuspoll", hz/100);
    148   1.1  jdolecek 			break;
    149   1.1  jdolecek 
    150   1.1  jdolecek 		case PPBUS_INTR:
    151   1.1  jdolecek 		default:
    152   1.1  jdolecek 			/* wait 10 ms */
    153  1.13  christos 			if (((error = tsleep((void *)dev, PPBUSPRI | PCATCH,
    154   1.1  jdolecek 			    "ppbuspoll", hz/100)) != EWOULDBLOCK) != 0) {
    155   1.1  jdolecek 				return (error);
    156   1.1  jdolecek 			}
    157   1.1  jdolecek 			break;
    158   1.1  jdolecek 		}
    159   1.1  jdolecek 	   }
    160   1.1  jdolecek 	}
    161   1.1  jdolecek 
    162   1.1  jdolecek 	return (EWOULDBLOCK);
    163   1.1  jdolecek }
    164   1.1  jdolecek 
    165   1.1  jdolecek /* Get operating mode of the chipset */
    166   1.1  jdolecek int
    167   1.1  jdolecek ppbus_get_mode(struct device * dev)
    168   1.1  jdolecek {
    169   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    170   1.1  jdolecek 
    171   1.1  jdolecek 	return (bus->sc_mode);
    172   1.1  jdolecek }
    173   1.1  jdolecek 
    174   1.1  jdolecek /* Set the operating mode of the chipset, return 0 on success. */
    175   1.1  jdolecek int
    176   1.1  jdolecek ppbus_set_mode(struct device * dev, int mode, int options)
    177   1.1  jdolecek {
    178   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    179   1.1  jdolecek 	int error = 0;
    180   1.1  jdolecek 
    181   1.1  jdolecek 	/* If no mode change, do nothing */
    182   1.1  jdolecek 	if(bus->sc_mode == mode)
    183   1.1  jdolecek 		return error;
    184   1.1  jdolecek 
    185   1.5     bjh21 	/* Do necessary negotiations */
    186   1.9     perry 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    187   1.5     bjh21 		/* Cannot negotiate standard mode */
    188   1.1  jdolecek 		if(!(mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
    189   1.5     bjh21  			error = ppbus_1284_negotiate(dev, mode, options);
    190   1.1  jdolecek 		}
    191   1.1  jdolecek 		/* Termination is unnecessary for standard<->fast */
    192   1.1  jdolecek 		else if(!(bus->sc_mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
    193   1.1  jdolecek 			ppbus_1284_terminate(dev);
    194   1.1  jdolecek 		}
    195   1.1  jdolecek 	}
    196   1.1  jdolecek 
    197   1.1  jdolecek 	if(!error) {
    198   1.1  jdolecek 		/* Set mode and update mode of ppbus to actual mode */
    199  1.12   thorpej 		error = bus->ppbus_setmode(device_parent(dev), mode);
    200  1.12   thorpej 		bus->sc_mode = bus->ppbus_getmode(device_parent(dev));
    201   1.1  jdolecek 	}
    202   1.1  jdolecek 
    203   1.1  jdolecek 	/* Update host state if necessary */
    204   1.1  jdolecek 	if(!(error) && (bus->sc_use_ieee == PPBUS_ENABLE_IEEE)) {
    205   1.1  jdolecek 		switch(mode) {
    206   1.1  jdolecek 		case PPBUS_COMPATIBLE:
    207   1.1  jdolecek 		case PPBUS_FAST:
    208   1.1  jdolecek 		case PPBUS_EPP:
    209   1.1  jdolecek 		case PPBUS_ECP:
    210   1.1  jdolecek 			ppbus_1284_set_state(dev, PPBUS_FORWARD_IDLE);
    211   1.1  jdolecek 			break;
    212   1.1  jdolecek 
    213   1.1  jdolecek 		case PPBUS_NIBBLE:
    214   1.1  jdolecek 		case PPBUS_PS2:
    215   1.1  jdolecek 			ppbus_1284_set_state(dev, PPBUS_REVERSE_IDLE);
    216   1.1  jdolecek 			break;
    217   1.1  jdolecek 		}
    218   1.1  jdolecek 	}
    219   1.1  jdolecek 
    220   1.1  jdolecek 	return error;
    221   1.1  jdolecek }
    222   1.1  jdolecek 
    223   1.1  jdolecek /* Write charaters to the port */
    224   1.1  jdolecek int
    225   1.1  jdolecek ppbus_write(struct device * dev, char * buf, int len, int how, size_t * cnt)
    226   1.1  jdolecek {
    227   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    228   1.1  jdolecek 
    229   1.1  jdolecek 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    230   1.1  jdolecek 		if(bus->sc_1284_state != PPBUS_FORWARD_IDLE) {
    231   1.9     perry 			printf("%s(%s): bus not in forward idle mode.\n",
    232   1.1  jdolecek 				__func__, dev->dv_xname);
    233   1.1  jdolecek 			return ENODEV;
    234   1.1  jdolecek 		}
    235   1.1  jdolecek 	}
    236   1.1  jdolecek 
    237  1.12   thorpej 	return (bus->ppbus_write(device_parent(&bus->sc_dev), buf, len, how, cnt));
    238   1.1  jdolecek }
    239   1.1  jdolecek 
    240   1.1  jdolecek /* Read charaters from the port */
    241   1.1  jdolecek int
    242   1.1  jdolecek ppbus_read(struct device * dev, char * buf, int len, int how, size_t * cnt)
    243   1.1  jdolecek {
    244   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    245   1.1  jdolecek 
    246   1.1  jdolecek 	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
    247   1.1  jdolecek 		if(bus->sc_1284_state != PPBUS_REVERSE_IDLE) {
    248   1.9     perry 			printf("%s(%s): bus not in reverse idle mode.\n",
    249   1.1  jdolecek 				__func__, dev->dv_xname);
    250   1.1  jdolecek 			return ENODEV;
    251   1.1  jdolecek 		}
    252   1.1  jdolecek 	}
    253   1.1  jdolecek 
    254  1.12   thorpej 	return (bus->ppbus_read(device_parent(dev), buf, len, how, cnt));
    255   1.1  jdolecek }
    256   1.1  jdolecek 
    257   1.1  jdolecek /* Reset the EPP timeout bit in the status register */
    258   1.1  jdolecek int
    259   1.1  jdolecek ppbus_reset_epp_timeout(struct device * dev)
    260   1.1  jdolecek {
    261   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    262   1.1  jdolecek 
    263   1.1  jdolecek 	if(bus->sc_capabilities & PPBUS_HAS_EPP) {
    264  1.12   thorpej 		bus->ppbus_reset_epp_timeout(device_parent(dev));
    265   1.1  jdolecek 		return 0;
    266   1.1  jdolecek 	}
    267   1.1  jdolecek 	else {
    268   1.1  jdolecek 		return ENODEV;
    269   1.1  jdolecek 	}
    270   1.1  jdolecek }
    271   1.1  jdolecek 
    272   1.1  jdolecek /* Wait for the ECP FIFO to be empty */
    273   1.1  jdolecek int
    274   1.1  jdolecek ppbus_ecp_sync(struct device * dev)
    275   1.1  jdolecek {
    276   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    277   1.1  jdolecek 
    278   1.1  jdolecek 	if(bus->sc_capabilities & PPBUS_HAS_ECP) {
    279  1.12   thorpej 		bus->ppbus_ecp_sync(device_parent(dev));
    280   1.1  jdolecek 		return 0;
    281   1.1  jdolecek 	}
    282   1.1  jdolecek 	else {
    283   1.1  jdolecek 		return ENODEV;
    284   1.1  jdolecek 	}
    285   1.1  jdolecek }
    286   1.1  jdolecek 
    287   1.1  jdolecek /* Allocate DMA for use with ppbus */
    288   1.9     perry int
    289  1.13  christos ppbus_dma_malloc(struct device * dev, void ** buf, bus_addr_t * addr,
    290   1.1  jdolecek 	bus_size_t size)
    291   1.1  jdolecek {
    292   1.1  jdolecek 	struct ppbus_softc * ppbus = (struct ppbus_softc *) dev;
    293   1.1  jdolecek 
    294   1.1  jdolecek 	if(ppbus->sc_capabilities & PPBUS_HAS_DMA)
    295  1.12   thorpej 		return (ppbus->ppbus_dma_malloc(device_parent(dev), buf, addr,
    296   1.1  jdolecek 			size));
    297   1.1  jdolecek 	else
    298   1.1  jdolecek 		return ENODEV;
    299   1.1  jdolecek }
    300   1.1  jdolecek 
    301   1.1  jdolecek /* Free memory allocated with ppbus_dma_malloc() */
    302   1.1  jdolecek int
    303  1.13  christos ppbus_dma_free(struct device * dev, void ** buf, bus_addr_t * addr,
    304   1.1  jdolecek 	bus_size_t size)
    305   1.1  jdolecek {
    306   1.1  jdolecek 	struct ppbus_softc * ppbus = (struct ppbus_softc *) dev;
    307   1.1  jdolecek 
    308   1.1  jdolecek 	if(ppbus->sc_capabilities & PPBUS_HAS_DMA) {
    309  1.12   thorpej 		ppbus->ppbus_dma_free(device_parent(dev), buf, addr, size);
    310   1.1  jdolecek 		return 0;
    311   1.1  jdolecek 	}
    312   1.1  jdolecek 	else {
    313   1.1  jdolecek 		return ENODEV;
    314   1.1  jdolecek 	}
    315   1.1  jdolecek }
    316   1.1  jdolecek 
    317   1.1  jdolecek /* Install a handler to be called by hardware interrupt handler */
    318  1.13  christos int ppbus_add_handler(struct device * dev, void (*func)(void *), void *arg)
    319   1.1  jdolecek {
    320   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    321   1.1  jdolecek 
    322   1.1  jdolecek 	if(bus->sc_capabilities & PPBUS_HAS_INTR)
    323  1.12   thorpej 		return bus->ppbus_add_handler(device_parent(dev), func, arg);
    324   1.1  jdolecek 	else
    325   1.1  jdolecek 		return ENODEV;
    326   1.1  jdolecek }
    327   1.1  jdolecek 
    328   1.1  jdolecek /* Remove a handler registered with ppbus_add_handler() */
    329   1.1  jdolecek int ppbus_remove_handler(struct device * dev, void (*func)(void *))
    330   1.1  jdolecek {
    331   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    332   1.1  jdolecek 
    333   1.1  jdolecek 	if(bus->sc_capabilities & PPBUS_HAS_INTR)
    334  1.12   thorpej 		return bus->ppbus_remove_handler(device_parent(dev), func);
    335   1.1  jdolecek 	else
    336   1.1  jdolecek 		return ENODEV;
    337   1.1  jdolecek }
    338   1.1  jdolecek 
    339   1.1  jdolecek /*
    340   1.1  jdolecek  * ppbus_get_status()
    341   1.1  jdolecek  *
    342   1.1  jdolecek  * Read the status register and update the status info
    343   1.1  jdolecek  */
    344   1.1  jdolecek int
    345   1.1  jdolecek ppbus_get_status(struct device * dev, struct ppbus_status * status)
    346   1.1  jdolecek {
    347   1.1  jdolecek 	register char r = status->status = ppbus_rstr(dev);
    348   1.1  jdolecek 
    349   1.1  jdolecek 	status->timeout	= r & TIMEOUT;
    350   1.1  jdolecek 	status->error	= !(r & nFAULT);
    351   1.1  jdolecek 	status->select	= r & SELECT;
    352   1.1  jdolecek 	status->paper_end = r & PERROR;
    353   1.1  jdolecek 	status->ack	= !(r & nACK);
    354   1.1  jdolecek 	status->busy	= !(r & nBUSY);
    355   1.1  jdolecek 
    356   1.1  jdolecek 	return (0);
    357   1.1  jdolecek }
    358   1.1  jdolecek 
    359   1.1  jdolecek /* Allocate the device to perform transfers */
    360   1.1  jdolecek int
    361   1.9     perry ppbus_request_bus(struct device * dev, struct device * busdev, int how,
    362   1.9     perry 	unsigned int timeout)
    363   1.1  jdolecek {
    364   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    365   1.9     perry 	unsigned int counter = timeout;
    366   1.1  jdolecek 	int priority = PPBUSPRI;
    367   1.1  jdolecek 	int error;
    368   1.1  jdolecek 
    369   1.1  jdolecek 	if(how & PPBUS_INTR)
    370   1.1  jdolecek 		priority |= PCATCH;
    371   1.1  jdolecek 
    372   1.1  jdolecek 	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
    373   1.1  jdolecek 	for(;;) {
    374  1.14        ad 		if (mutex_tryenter(&(bus->sc_lock)))
    375   1.1  jdolecek 			break;
    376   1.9     perry 
    377   1.1  jdolecek 		if(how & PPBUS_WAIT) {
    378   1.1  jdolecek 			error = ltsleep(bus, priority, __func__, hz/2, NULL);
    379   1.1  jdolecek 			counter -= (hz/2);
    380   1.1  jdolecek 			if(!(error))
    381   1.1  jdolecek 				continue;
    382   1.1  jdolecek 			else if(error != EWOULDBLOCK)
    383   1.1  jdolecek 				goto end;
    384   1.1  jdolecek 			if(counter == 0) {
    385   1.1  jdolecek 				error = ETIMEDOUT;
    386   1.1  jdolecek 				goto end;
    387   1.1  jdolecek 			}
    388   1.1  jdolecek 		}
    389   1.1  jdolecek 		else {
    390  1.14        ad 			error = EWOULDBLOCK;
    391   1.1  jdolecek 			goto end;
    392   1.1  jdolecek 		}
    393   1.9     perry 	}
    394   1.1  jdolecek 
    395   1.1  jdolecek 	/* Set bus owner or return error if bus is taken */
    396   1.1  jdolecek 	if(bus->ppbus_owner == NULL) {
    397   1.1  jdolecek 		bus->ppbus_owner = busdev;
    398   1.1  jdolecek 		error = 0;
    399   1.1  jdolecek 	}
    400   1.1  jdolecek 	else {
    401   1.1  jdolecek 		error = EBUSY;
    402   1.1  jdolecek 	}
    403   1.9     perry 
    404   1.1  jdolecek 	/* Release lock */
    405  1.14        ad 	mutex_exit(&(bus->sc_lock));
    406   1.9     perry 
    407   1.1  jdolecek end:
    408   1.1  jdolecek 	return error;
    409   1.1  jdolecek }
    410   1.1  jdolecek 
    411   1.1  jdolecek /* Release the device allocated with ppbus_request_bus() */
    412   1.1  jdolecek int
    413   1.9     perry ppbus_release_bus(struct device * dev, struct device * busdev, int how,
    414   1.1  jdolecek 	unsigned int timeout)
    415   1.1  jdolecek {
    416   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    417   1.9     perry 	unsigned int counter = timeout;
    418   1.1  jdolecek 	int priority = PPBUSPRI;
    419   1.1  jdolecek 	int error;
    420   1.1  jdolecek 
    421   1.1  jdolecek 	if(how & PPBUS_INTR)
    422   1.1  jdolecek 		priority |= PCATCH;
    423   1.1  jdolecek 
    424   1.1  jdolecek 	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
    425   1.1  jdolecek 	for(;;) {
    426  1.14        ad 		if (mutex_tryenter(&(bus->sc_lock)))
    427   1.1  jdolecek 			break;
    428   1.9     perry 
    429   1.1  jdolecek 		if(how & PPBUS_WAIT) {
    430   1.1  jdolecek 			error = ltsleep(bus, priority, __func__, hz/2, NULL);
    431   1.1  jdolecek 			counter -= (hz/2);
    432   1.1  jdolecek 			if(!(error))
    433   1.1  jdolecek 				continue;
    434   1.1  jdolecek 			else if(error != EWOULDBLOCK)
    435   1.1  jdolecek 				goto end;
    436   1.1  jdolecek 			if(counter == 0) {
    437   1.1  jdolecek 				error = ETIMEDOUT;
    438   1.1  jdolecek 				goto end;
    439   1.1  jdolecek 			}
    440   1.1  jdolecek 		}
    441   1.1  jdolecek 		else {
    442  1.14        ad 			error = EWOULDBLOCK;
    443   1.1  jdolecek 			goto end;
    444   1.1  jdolecek 		}
    445   1.9     perry 	}
    446   1.9     perry 
    447   1.1  jdolecek 	/* If the device is the owner, release bus */
    448   1.1  jdolecek 	if(bus->ppbus_owner != busdev) {
    449   1.1  jdolecek 		error = EINVAL;
    450   1.1  jdolecek 	}
    451   1.1  jdolecek 	else {
    452   1.1  jdolecek 		bus->ppbus_owner = NULL;
    453   1.1  jdolecek 		error = 0;
    454   1.1  jdolecek 	}
    455   1.1  jdolecek 
    456   1.1  jdolecek 	/* Release lock */
    457  1.14        ad 	mutex_exit(&(bus->sc_lock));
    458   1.1  jdolecek 
    459   1.1  jdolecek end:
    460   1.1  jdolecek 	return error;
    461   1.1  jdolecek }
    462   1.1  jdolecek 
    463   1.1  jdolecek 
    464   1.1  jdolecek /* IEEE 1284-based probes */
    465   1.1  jdolecek 
    466   1.1  jdolecek #ifndef DONTPROBE_1284
    467   1.1  jdolecek 
    468  1.10  drochner static const char *pnp_tokens[] = {
    469   1.1  jdolecek 	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
    470   1.1  jdolecek 	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
    471   1.1  jdolecek 
    472   1.1  jdolecek /* ??? */
    473   1.1  jdolecek #if 0
    474   1.1  jdolecek static char *pnp_classes[] = {
    475   1.1  jdolecek 	"printer", "modem", "network device",
    476   1.1  jdolecek 	"hard disk", "PCMCIA", "multimedia device",
    477   1.1  jdolecek 	"floppy disk", "ports", "scanner",
    478   1.1  jdolecek 	"digital camera", "unknown device", NULL };
    479   1.1  jdolecek #endif
    480   1.1  jdolecek 
    481   1.9     perry /*
    482   1.9     perry  * Search the first occurence of a token within a string
    483   1.1  jdolecek  * XXX should use strxxx() calls
    484   1.9     perry  */
    485   1.1  jdolecek static char *
    486  1.10  drochner search_token(char *str, int slen, const char *token)
    487   1.1  jdolecek {
    488  1.10  drochner 	const char *p;
    489   1.1  jdolecek 	int tlen, i, j;
    490   1.9     perry 
    491   1.1  jdolecek #define UNKNOWN_LENGTH  -1
    492   1.1  jdolecek 
    493   1.1  jdolecek 	if (slen == UNKNOWN_LENGTH)
    494   1.1  jdolecek 	       /* get string's length */
    495   1.1  jdolecek 	       for (slen = 0, p = str; *p != '\0'; p++)
    496   1.8    simonb 		       slen++;
    497   1.1  jdolecek 
    498   1.1  jdolecek        /* get token's length */
    499   1.1  jdolecek        for (tlen = 0, p = token; *p != '\0'; p++)
    500   1.8    simonb 	       tlen++;
    501   1.1  jdolecek 
    502   1.9     perry        if (tlen == 0)
    503   1.1  jdolecek 	       return (str);
    504   1.1  jdolecek 
    505   1.1  jdolecek        for (i = 0; i <= slen-tlen; i++) {
    506   1.1  jdolecek 	       for (j = 0; j < tlen; j++)
    507   1.1  jdolecek 		       if (str[i+j] != token[j])
    508   1.1  jdolecek 			       break;
    509   1.1  jdolecek 	       if (j == tlen)
    510   1.1  jdolecek 		       return (&str[i]);
    511   1.1  jdolecek        }
    512   1.1  jdolecek 
    513   1.9     perry 	return (NULL);
    514   1.1  jdolecek }
    515   1.1  jdolecek 
    516   1.9     perry /* Stores the class ID of the peripherial in soft config data */
    517   1.1  jdolecek void
    518   1.1  jdolecek ppbus_pnp_detect(struct device * dev)
    519   1.9     perry {
    520   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    521   1.1  jdolecek 	int i;
    522   1.1  jdolecek 	int error;
    523   1.1  jdolecek 	size_t len = 0;
    524   1.1  jdolecek 	size_t str_sz = 0;
    525   1.1  jdolecek 	char * str = NULL;
    526   1.1  jdolecek 	char * class = NULL;
    527   1.1  jdolecek 	char * token;
    528   1.1  jdolecek 
    529   1.1  jdolecek #ifdef PPBUS_VERBOSE
    530   1.9     perry 	printf("%s: Probing for PnP devices.\n", dev->dv_xname);
    531   1.1  jdolecek #endif
    532   1.1  jdolecek 
    533   1.1  jdolecek 	error = ppbus_1284_read_id(dev, PPBUS_NIBBLE, &str, &str_sz, &len);
    534   1.1  jdolecek 	if(str_sz != len) {
    535   1.1  jdolecek #ifdef DEBUG_1284
    536   1.9     perry 		printf("%s(%s): device returned less characters than expected "
    537   1.1  jdolecek 			"in device ID.\n", __func__, dev->dv_xname);
    538   1.1  jdolecek #endif
    539   1.1  jdolecek 	}
    540   1.1  jdolecek 	if(error) {
    541   1.9     perry 		printf("%s: Error getting device ID (errno = %d)\n",
    542   1.1  jdolecek 			dev->dv_xname, error);
    543   1.1  jdolecek 		goto end_detect;
    544   1.1  jdolecek 	}
    545   1.1  jdolecek 
    546   1.1  jdolecek #ifdef DEBUG_1284
    547   1.1  jdolecek 	printf("%s: <PnP> %d characters: ", dev->dv_xname, len);
    548   1.1  jdolecek 	for (i = 0; i < len; i++)
    549   1.1  jdolecek 		printf("%c(0x%x) ", str[i], str[i]);
    550   1.1  jdolecek 	printf("\n");
    551   1.1  jdolecek #endif
    552   1.1  jdolecek 
    553   1.1  jdolecek 	/* replace ';' characters by '\0' */
    554   1.1  jdolecek 	for (i = 0; i < len; i++)
    555   1.1  jdolecek 		if(str[i] == ';') str[i] = '\0';
    556   1.1  jdolecek 		/* str[i] = (str[i] == ';') ? '\0' : str[i]; */
    557   1.1  jdolecek 
    558   1.1  jdolecek 	if ((token = search_token(str, len, "MFG")) != NULL ||
    559   1.1  jdolecek 		(token = search_token(str, len, "MANUFACTURER")) != NULL)
    560   1.1  jdolecek 		printf("%s: <%s", dev->dv_xname,
    561   1.1  jdolecek 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    562   1.1  jdolecek 	else
    563   1.1  jdolecek 		printf("%s: <unknown", dev->dv_xname);
    564   1.1  jdolecek 
    565   1.1  jdolecek 	if ((token = search_token(str, len, "MDL")) != NULL ||
    566   1.1  jdolecek 		(token = search_token(str, len, "MODEL")) != NULL)
    567   1.1  jdolecek 		printf(" %s",
    568   1.1  jdolecek 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    569   1.1  jdolecek 
    570   1.1  jdolecek 	if ((token = search_token(str, len, "REV")) != NULL)
    571   1.1  jdolecek 		printf(".%s",
    572   1.1  jdolecek 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    573   1.1  jdolecek 
    574   1.1  jdolecek 	printf(">");
    575   1.1  jdolecek 
    576   1.1  jdolecek 	if ((token = search_token(str, len, "CLS")) != NULL) {
    577   1.1  jdolecek 		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
    578   1.1  jdolecek 		printf(" %s", class);
    579   1.1  jdolecek 	}
    580   1.1  jdolecek 
    581   1.1  jdolecek 	if ((token = search_token(str, len, "CMD")) != NULL ||
    582   1.1  jdolecek 		(token = search_token(str, len, "COMMAND")) != NULL)
    583   1.1  jdolecek 		printf(" %s",
    584   1.1  jdolecek 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
    585   1.1  jdolecek 
    586   1.1  jdolecek 	printf("\n");
    587   1.1  jdolecek 
    588   1.1  jdolecek 	if (class) {
    589   1.1  jdolecek 		/* identify class ident */
    590   1.1  jdolecek 		for (i = 0; pnp_tokens[i] != NULL; i++) {
    591   1.1  jdolecek 			if (search_token(class, len, pnp_tokens[i]) != NULL) {
    592   1.1  jdolecek 				bus->sc_class_id = i;
    593   1.1  jdolecek 				goto end_detect;
    594   1.1  jdolecek 			}
    595   1.1  jdolecek 		}
    596   1.1  jdolecek 	}
    597   1.1  jdolecek 	bus->sc_class_id = PPBUS_PNP_UNKNOWN;
    598   1.1  jdolecek 
    599   1.1  jdolecek end_detect:
    600   1.1  jdolecek 	if(str)
    601   1.1  jdolecek 		free(str, M_DEVBUF);
    602   1.1  jdolecek         return;
    603   1.1  jdolecek }
    604   1.1  jdolecek 
    605   1.1  jdolecek /* Scan the ppbus for IEEE1284 compliant devices */
    606   1.1  jdolecek int
    607   1.1  jdolecek ppbus_scan_bus(struct device * dev)
    608   1.1  jdolecek {
    609   1.1  jdolecek 	struct ppbus_softc * bus = (struct ppbus_softc *) dev;
    610   1.1  jdolecek 	int error;
    611   1.1  jdolecek 
    612   1.1  jdolecek 	/* Try IEEE1284 modes, one device only (no IEEE1284.3 support) */
    613   1.1  jdolecek 
    614   1.5     bjh21 	error = ppbus_1284_negotiate(dev, PPBUS_NIBBLE, 0);
    615   1.7  jdolecek 	if (error && bus->sc_1284_state == PPBUS_ERROR
    616   1.7  jdolecek 	    && bus->sc_1284_error == PPBUS_NOT_IEEE1284)
    617   1.7  jdolecek 		return (error);
    618   1.1  jdolecek 	ppbus_1284_terminate(dev);
    619   1.1  jdolecek 
    620   1.7  jdolecek #if defined(PPBUS_VERBOSE) || defined(PPBUS_DEBUG)
    621   1.7  jdolecek 	/* IEEE1284 supported, print info */
    622   1.7  jdolecek 	printf("%s: IEEE1284 negotiation: modes %s",
    623   1.7  jdolecek 	    dev->dv_xname, "NIBBLE");
    624   1.7  jdolecek 
    625   1.5     bjh21 	error = ppbus_1284_negotiate(dev, PPBUS_PS2, 0);
    626   1.7  jdolecek 	if (!error)
    627   1.1  jdolecek 		printf("/PS2");
    628   1.1  jdolecek 	ppbus_1284_terminate(dev);
    629   1.1  jdolecek 
    630   1.5     bjh21 	error = ppbus_1284_negotiate(dev, PPBUS_ECP, 0);
    631   1.9     perry 	if (!error)
    632   1.1  jdolecek 		printf("/ECP");
    633   1.1  jdolecek 	ppbus_1284_terminate(dev);
    634   1.7  jdolecek 
    635   1.5     bjh21 	error = ppbus_1284_negotiate(dev, PPBUS_ECP, PPBUS_USE_RLE);
    636   1.7  jdolecek 	if (!error)
    637   1.1  jdolecek 		printf("/ECP_RLE");
    638   1.1  jdolecek 	ppbus_1284_terminate(dev);
    639   1.7  jdolecek 
    640   1.5     bjh21 	error = ppbus_1284_negotiate(dev, PPBUS_EPP, 0);
    641   1.7  jdolecek 	if (!error)
    642   1.1  jdolecek 		printf("/EPP");
    643   1.1  jdolecek 	ppbus_1284_terminate(dev);
    644   1.7  jdolecek 
    645   1.1  jdolecek 	printf("\n");
    646   1.7  jdolecek #endif /* PPBUS_VERBOSE || PPBUS_DEBUG */
    647   1.1  jdolecek 
    648   1.1  jdolecek 	return 0;
    649   1.1  jdolecek }
    650   1.1  jdolecek 
    651   1.1  jdolecek #endif /* !DONTPROBE_1284 */
    652   1.1  jdolecek 
    653