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