ppbconf.c revision 42475
128219Smsmith/*-
242475Snsouch * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
328219Smsmith * All rights reserved.
428219Smsmith *
528219Smsmith * Redistribution and use in source and binary forms, with or without
628219Smsmith * modification, are permitted provided that the following conditions
728219Smsmith * are met:
828219Smsmith * 1. Redistributions of source code must retain the above copyright
928219Smsmith *    notice, this list of conditions and the following disclaimer.
1028219Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1128219Smsmith *    notice, this list of conditions and the following disclaimer in the
1228219Smsmith *    documentation and/or other materials provided with the distribution.
1328219Smsmith *
1428219Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1528219Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1628219Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1728219Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1828219Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1928219Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2028219Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2128219Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2228219Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2328219Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2428219Smsmith * SUCH DAMAGE.
2528219Smsmith *
2642475Snsouch *	$Id: ppbconf.c,v 1.9 1998/12/07 21:58:16 archie Exp $
2728219Smsmith *
2828219Smsmith */
2928219Smsmith#include <sys/param.h>
3028219Smsmith#include <sys/systm.h>
3128219Smsmith#include <sys/kernel.h>
3228219Smsmith#include <sys/malloc.h>
3328219Smsmith
3428219Smsmith#include <vm/vm.h>
3528219Smsmith#include <vm/pmap.h>
3628219Smsmith
3728219Smsmith#include <dev/ppbus/ppbconf.h>
3828257Smsmith#include <dev/ppbus/ppb_1284.h>
3928219Smsmith
4042475Snsouch#include "opt_ppb_1284.h"
4142475Snsouch
4238061SmsmithLIST_HEAD(, ppb_data)	ppbdata;	/* list of existing ppbus */
4328219Smsmith
4428219Smsmith/*
4528219Smsmith * Add a null driver so that the linker set always exists.
4628219Smsmith */
4728219Smsmith
4828219Smsmithstatic struct ppb_driver nulldriver = {
4928219Smsmith    NULL, NULL, "null"
5028219Smsmith};
5128219SmsmithDATA_SET(ppbdriver_set, nulldriver);
5228219Smsmith
5328219Smsmith
5428219Smsmith/*
5528219Smsmith * ppb_alloc_bus()
5628219Smsmith *
5728219Smsmith * Allocate area to store the ppbus description.
5828219Smsmith */
5928219Smsmithstruct ppb_data *
6028219Smsmithppb_alloc_bus(void)
6128219Smsmith{
6228219Smsmith	struct ppb_data *ppb;
6328219Smsmith	static int ppbdata_initted = 0;		/* done-init flag */
6428219Smsmith
6528219Smsmith	ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data),
6628219Smsmith		M_TEMP, M_NOWAIT);
6728219Smsmith
6828219Smsmith	/*
6928219Smsmith	 * Add the new parallel port bus to the list of existing ppbus.
7028219Smsmith	 */
7128219Smsmith	if (ppb) {
7228219Smsmith		bzero(ppb, sizeof(struct ppb_data));
7328219Smsmith
7428219Smsmith		if (!ppbdata_initted) {		/* list not initialised */
7528219Smsmith		    LIST_INIT(&ppbdata);
7628219Smsmith		    ppbdata_initted = 1;
7728219Smsmith		}
7828219Smsmith		LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain);
7928219Smsmith	} else {
8028219Smsmith		printf("ppb_alloc_bus: cannot malloc!\n");
8128219Smsmith	}
8228219Smsmith	return(ppb);
8328219Smsmith}
8428219Smsmith
8542475Snsouch#define PPB_PNP_PRINTER		0
8642475Snsouch#define PPB_PNP_MODEM		1
8742475Snsouch#define PPB_PNP_NET		2
8842475Snsouch#define PPB_PNP_HDC		3
8942475Snsouch#define PPB_PNP_PCMCIA		4
9042475Snsouch#define PPB_PNP_MEDIA		5
9142475Snsouch#define PPB_PNP_FDC		6
9242475Snsouch#define PPB_PNP_PORTS		7
9342475Snsouch#define PPB_PNP_SCANNER		8
9442475Snsouch#define PPB_PNP_DIGICAM		9
9542475Snsouch
9642475Snsouch#ifndef DONTPROBE_1284
9742475Snsouch
9828257Smsmithstatic char *pnp_tokens[] = {
9928257Smsmith	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
10028257Smsmith	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
10128257Smsmith
10242475Snsouch#if 0
10328257Smsmithstatic char *pnp_classes[] = {
10428257Smsmith	"printer", "modem", "network device",
10528257Smsmith	"hard disk", "PCMCIA", "multimedia device",
10628257Smsmith	"floppy disk", "ports", "scanner",
10728257Smsmith	"digital camera", "unknown device", NULL };
10842475Snsouch#endif
10928257Smsmith
11028219Smsmith/*
11128257Smsmith * search_token()
11228257Smsmith *
11328257Smsmith * Search the first occurence of a token within a string
11439134Snsouch *
11539134Snsouch * XXX should use strxxx() calls
11628257Smsmith */
11728257Smsmithstatic char *
11828257Smsmithsearch_token(char *str, int slen, char *token)
11928257Smsmith{
12028257Smsmith	char *p;
12128257Smsmith	int tlen, i, j;
12228257Smsmith
12328257Smsmith#define UNKNOWN_LENGTH	-1
12428257Smsmith
12528257Smsmith	if (slen == UNKNOWN_LENGTH)
12628257Smsmith		/* get string's length */
12728257Smsmith		for (slen = 0, p = str; *p != '\0'; p++)
12828257Smsmith			slen ++;
12928257Smsmith
13028257Smsmith	/* get token's length */
13128257Smsmith	for (tlen = 0, p = token; *p != '\0'; p++)
13228257Smsmith		tlen ++;
13328257Smsmith
13428257Smsmith	if (tlen == 0)
13528257Smsmith		return (str);
13628257Smsmith
13728257Smsmith	for (i = 0; i <= slen-tlen; i++) {
13828257Smsmith		for (j = 0; j < tlen; j++)
13928257Smsmith			if (str[i+j] != token[j])
14028257Smsmith				break;
14128257Smsmith		if (j == tlen)
14228257Smsmith			return (&str[i]);
14328257Smsmith	}
14428257Smsmith
14528257Smsmith	return (NULL);
14628257Smsmith}
14728257Smsmith
14828257Smsmith/*
14928257Smsmith * ppb_pnp_detect()
15028257Smsmith *
15128257Smsmith * Returns the class id. of the peripherial, -1 otherwise
15228257Smsmith */
15328257Smsmithstatic int
15442475Snsouchppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev)
15528257Smsmith{
15642475Snsouch	char *token, *class = 0;
15728257Smsmith	int i, len, error;
15838061Smsmith	int class_id = -1;
15928257Smsmith	char str[PPB_PnP_STRING_SIZE+1];
16028257Smsmith
16142475Snsouch	printf("Probing for PnP devices on ppbus%d:\n",
16238061Smsmith			ppb->ppb_link->adapter_unit);
16342475Snsouch
16442475Snsouch	if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str,
16542475Snsouch					PPB_PnP_STRING_SIZE, &len)))
16638061Smsmith		goto end_detect;
16739134Snsouch
16842475Snsouch#ifdef DEBUG_1284
16942475Snsouch	printf("ppb: <PnP> %d characters: ", len);
17042475Snsouch	for (i = 0; i < len; i++)
17142475Snsouch		printf("%c(0x%x) ", str[i], str[i]);
17242475Snsouch	printf("\n");
17342475Snsouch#endif
17428257Smsmith
17528257Smsmith	/* replace ';' characters by '\0' */
17628257Smsmith	for (i = 0; i < len; i++)
17728257Smsmith		str[i] = (str[i] == ';') ? '\0' : str[i];
17828257Smsmith
17942475Snsouch	if ((token = search_token(str, len, "MFG")) != NULL ||
18042475Snsouch		(token = search_token(str, len, "MANUFACTURER")) != NULL)
18128257Smsmith		printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
18228257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
18328257Smsmith	else
18428257Smsmith		printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
18528257Smsmith
18642475Snsouch	if ((token = search_token(str, len, "MDL")) != NULL ||
18742475Snsouch		(token = search_token(str, len, "MODEL")) != NULL)
18828257Smsmith		printf(" %s",
18928257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
19028257Smsmith	else
19128257Smsmith		printf(" unknown");
19228257Smsmith
19328257Smsmith	if ((token = search_token(str, len, "VER")) != NULL)
19428257Smsmith		printf("/%s",
19528257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
19628257Smsmith
19728257Smsmith	if ((token = search_token(str, len, "REV")) != NULL)
19828257Smsmith		printf(".%s",
19928257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
20028257Smsmith
20128257Smsmith	printf(">");
20228257Smsmith
20328257Smsmith	if ((token = search_token(str, len, "CLS")) != NULL) {
20428257Smsmith		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
20528257Smsmith		printf(" %s", class);
20628257Smsmith	}
20728257Smsmith
20842475Snsouch	if ((token = search_token(str, len, "CMD")) != NULL ||
20942475Snsouch		(token = search_token(str, len, "COMMAND")) != NULL)
21028257Smsmith		printf(" %s",
21128257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
21228257Smsmith
21328257Smsmith	printf("\n");
21428257Smsmith
21528257Smsmith	if (class)
21628257Smsmith		/* identify class ident */
21728257Smsmith		for (i = 0; pnp_tokens[i] != NULL; i++) {
21828257Smsmith			if (search_token(class, len, pnp_tokens[i]) != NULL) {
21938061Smsmith				class_id = i;
22038061Smsmith				goto end_detect;
22128257Smsmith			}
22228257Smsmith		}
22328257Smsmith
22438061Smsmith	class_id = PPB_PnP_UNKNOWN;
22538061Smsmith
22638061Smsmithend_detect:
22742475Snsouch	return (class_id);
22842475Snsouch}
22939134Snsouch
23042475Snsouch/*
23142475Snsouch * ppb_scan_bus()
23242475Snsouch *
23342475Snsouch * Scan the ppbus for IEEE1284 compliant devices
23442475Snsouch */
23542475Snsouchstatic int
23642475Snsouchppb_scan_bus(struct ppb_data *ppb)
23742475Snsouch{
23842475Snsouch	struct ppb_device pnpdev;	/* temporary device to perform I/O */
23942475Snsouch	int error = 0;
24042475Snsouch
24142475Snsouch	/* initialize the pnpdev structure for future use */
24242475Snsouch	bzero(&pnpdev, sizeof(pnpdev));
24342475Snsouch	pnpdev.ppb = ppb;
24442475Snsouch
24542475Snsouch	if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) {
24642475Snsouch		if (bootverbose)
24742475Snsouch			printf("ppb: cannot allocate ppbus!\n");
24842475Snsouch
24942475Snsouch		return (error);
25042475Snsouch	}
25142475Snsouch
25242475Snsouch	/* try all IEEE1284 modes, for one device only
25342475Snsouch	 *
25442475Snsouch	 * XXX We should implement the IEEE1284.3 standard to detect
25542475Snsouch	 * daisy chained devices
25642475Snsouch	 */
25742475Snsouch
25842475Snsouch	error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID);
25942475Snsouch
26042475Snsouch	if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
26142475Snsouch		goto end_scan;
26242475Snsouch
26342475Snsouch	ppb_1284_terminate(&pnpdev);
26442475Snsouch
26542475Snsouch	printf("ppc%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit);
26642475Snsouch
26742475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) {
26842475Snsouch		printf("/NIBBLE");
26942475Snsouch		ppb_1284_terminate(&pnpdev);
27042475Snsouch	}
27142475Snsouch
27242475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) {
27342475Snsouch		printf("/PS2");
27442475Snsouch		ppb_1284_terminate(&pnpdev);
27542475Snsouch	}
27642475Snsouch
27742475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) {
27842475Snsouch		printf("/ECP");
27942475Snsouch		ppb_1284_terminate(&pnpdev);
28042475Snsouch	}
28142475Snsouch
28242475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) {
28342475Snsouch		printf("/ECP_RLE");
28442475Snsouch		ppb_1284_terminate(&pnpdev);
28542475Snsouch	}
28642475Snsouch
28742475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) {
28842475Snsouch		printf("/EPP");
28942475Snsouch		ppb_1284_terminate(&pnpdev);
29042475Snsouch	}
29142475Snsouch
29242475Snsouch#if 0
29342475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID))) {
29442475Snsouch		printf("/NIBBLE_ID");
29542475Snsouch		ppb_1284_terminate(&pnpdev);
29642475Snsouch	}
29742475Snsouch
29842475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, PPB_REQUEST_ID))) {
29942475Snsouch		printf("/PS2_ID");
30042475Snsouch		ppb_1284_terminate(&pnpdev);
30142475Snsouch	}
30242475Snsouch
30342475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_REQUEST_ID))) {
30442475Snsouch		printf("/ECP_ID");
30542475Snsouch		ppb_1284_terminate(&pnpdev);
30642475Snsouch	}
30742475Snsouch
30842475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
30942475Snsouch					PPB_REQUEST_ID | PPB_USE_RLE))) {
31042475Snsouch		printf("/ECP_RLE_ID");
31142475Snsouch		ppb_1284_terminate(&pnpdev);
31242475Snsouch	}
31342475Snsouch#endif
31442475Snsouch
31542475Snsouch	if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
31642475Snsouch				PPB_EXTENSIBILITY_LINK))) {
31742475Snsouch                printf("/Extensibility Link");
31842475Snsouch		ppb_1284_terminate(&pnpdev);
31942475Snsouch        }
32042475Snsouch
32142475Snsouch	printf(" in FORWARD_IDLE state\n");
32242475Snsouch
32342475Snsouch	/* detect PnP devices */
32442475Snsouch	ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
32542475Snsouch
32638061Smsmith	ppb_release_bus(&pnpdev);
32742475Snsouch
32842475Snsouch	return (0);
32942475Snsouch
33042475Snsouchend_scan:
33142475Snsouch	ppb_release_bus(&pnpdev);
33242475Snsouch	return (error);
33328257Smsmith}
33428257Smsmith
33542475Snsouch#endif /* !DONTPROBE_1284 */
33642475Snsouch
33728257Smsmith/*
33828219Smsmith * ppb_attachdevs()
33928219Smsmith *
34028219Smsmith * Called by ppcattach(), this function probes the ppbus and
34128219Smsmith * attaches found devices.
34228219Smsmith */
34328219Smsmithint
34428219Smsmithppb_attachdevs(struct ppb_data *ppb)
34528219Smsmith{
34628219Smsmith	struct ppb_device *dev;
34728219Smsmith	struct ppb_driver **p_drvpp, *p_drvp;
34828257Smsmith
34928219Smsmith	LIST_INIT(&ppb->ppb_devs);	/* initialise device/driver list */
35028219Smsmith	p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
35128257Smsmith
35242475Snsouch#ifndef DONTPROBE_1284
35342475Snsouch	/* detect IEEE1284 compliant devices */
35442475Snsouch	ppb_scan_bus(ppb);
35542475Snsouch#endif /* !DONTPROBE_1284 */
35628219Smsmith
35728219Smsmith	/*
35828219Smsmith	 * Blindly try all probes here.  Later we should look at
35928219Smsmith	 * the parallel-port PnP standard, and intelligently seek
36028219Smsmith	 * drivers based on configuration first.
36128219Smsmith	 */
36228219Smsmith	while ((p_drvp = *p_drvpp++) != NULL) {
36328219Smsmith	    if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) {
36428219Smsmith		/*
36528219Smsmith		 * Add the device to the list of probed devices.
36628219Smsmith		 */
36728219Smsmith		LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
36828219Smsmith
36928219Smsmith		/* Call the device's attach routine */
37028219Smsmith		(void)p_drvp->attach(dev);
37128219Smsmith	    }
37228219Smsmith	}
37328219Smsmith	return (0);
37428219Smsmith}
37528219Smsmith
37628219Smsmith/*
37728257Smsmith * ppb_next_bus()
37828219Smsmith *
37928257Smsmith * Return the next bus in ppbus queue
38028219Smsmith */
38128257Smsmithstruct ppb_data *
38228257Smsmithppb_next_bus(struct ppb_data *ppb)
38328219Smsmith{
38428219Smsmith
38528257Smsmith	if (ppb == NULL)
38628257Smsmith		return (ppbdata.lh_first);
38728219Smsmith
38828257Smsmith	return (ppb->ppb_chain.le_next);
38928257Smsmith}
39028219Smsmith
39128257Smsmith/*
39228257Smsmith * ppb_lookup_bus()
39328257Smsmith *
39428257Smsmith * Get ppb_data structure pointer according to the base address of the ppbus
39528257Smsmith */
39628257Smsmithstruct ppb_data *
39728257Smsmithppb_lookup_bus(int base_port)
39828257Smsmith{
39928257Smsmith	struct ppb_data *ppb;
40028219Smsmith
40128257Smsmith	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
40228257Smsmith		if (ppb->ppb_link->base == base_port)
40328257Smsmith			break;
40428219Smsmith
40528257Smsmith	return (ppb);
40628219Smsmith}
40728219Smsmith
40828219Smsmith/*
40938061Smsmith * ppb_lookup_link()
41038061Smsmith *
41138061Smsmith * Get ppb_data structure pointer according to the unit value
41238061Smsmith * of the corresponding link structure
41338061Smsmith */
41438061Smsmithstruct ppb_data *
41538061Smsmithppb_lookup_link(int unit)
41638061Smsmith{
41738061Smsmith	struct ppb_data *ppb;
41838061Smsmith
41938061Smsmith	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
42038061Smsmith		if (ppb->ppb_link->adapter_unit == unit)
42138061Smsmith			break;
42238061Smsmith
42338061Smsmith	return (ppb);
42438061Smsmith}
42538061Smsmith
42638061Smsmith/*
42728257Smsmith * ppb_attach_device()
42828219Smsmith *
42928257Smsmith * Called by loadable kernel modules to add a device
43028219Smsmith */
43128219Smsmithint
43228257Smsmithppb_attach_device(struct ppb_device *dev)
43328219Smsmith{
43428219Smsmith	struct ppb_data *ppb = dev->ppb;
43528219Smsmith
43628257Smsmith	/* add the device to the list of probed devices */
43728257Smsmith	LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
43828219Smsmith
43928219Smsmith	return (0);
44028219Smsmith}
44128219Smsmith
44228219Smsmith/*
44328257Smsmith * ppb_remove_device()
44428219Smsmith *
44528257Smsmith * Called by loadable kernel modules to remove a device
44628219Smsmith */
44728219Smsmithvoid
44828257Smsmithppb_remove_device(struct ppb_device *dev)
44928219Smsmith{
45028219Smsmith
45128257Smsmith	/* remove the device from the list of probed devices */
45228257Smsmith	LIST_REMOVE(dev, chain);
45328219Smsmith
45428219Smsmith	return;
45528219Smsmith}
45628219Smsmith
45728219Smsmith/*
45828257Smsmith * ppb_request_bus()
45928219Smsmith *
46028257Smsmith * Allocate the device to perform transfers.
46128257Smsmith *
46228257Smsmith * how	: PPB_WAIT or PPB_DONTWAIT
46328219Smsmith */
46428219Smsmithint
46528257Smsmithppb_request_bus(struct ppb_device *dev, int how)
46628219Smsmith{
46728257Smsmith	int s, error = 0;
46828219Smsmith	struct ppb_data *ppb = dev->ppb;
46928219Smsmith
47028257Smsmith	while (!error) {
47128257Smsmith		s = splhigh();
47228257Smsmith		if (ppb->ppb_owner) {
47328257Smsmith			splx(s);
47428219Smsmith
47528257Smsmith			switch (how) {
47628257Smsmith			case (PPB_WAIT | PPB_INTR):
47728257Smsmith				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
47828257Smsmith				break;
47928219Smsmith
48028257Smsmith			case (PPB_WAIT | PPB_NOINTR):
48128257Smsmith				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
48228257Smsmith				break;
48328219Smsmith
48428257Smsmith			default:
48528257Smsmith				return (EWOULDBLOCK);
48628257Smsmith				break;
48728257Smsmith			}
48828219Smsmith
48928257Smsmith		} else {
49028257Smsmith			ppb->ppb_owner = dev;
49128219Smsmith
49238061Smsmith			/* restore the context of the device
49338061Smsmith			 * The first time, ctx.valid is certainly false
49438061Smsmith			 * then do not change anything. This is usefull for
49538061Smsmith			 * drivers that do not set there operating mode
49638061Smsmith			 * during attachement
49738061Smsmith			 */
49838061Smsmith			if (dev->ctx.valid)
49938061Smsmith				ppb_set_mode(dev, dev->ctx.mode);
50038061Smsmith
50128257Smsmith			splx(s);
50228257Smsmith			return (0);
50328257Smsmith		}
50428257Smsmith	}
50528219Smsmith
50628257Smsmith	return (error);
50728219Smsmith}
50828219Smsmith
50928219Smsmith/*
51028257Smsmith * ppb_release_bus()
51128219Smsmith *
51228257Smsmith * Release the device allocated with ppb_request_dev()
51328219Smsmith */
51428219Smsmithint
51528257Smsmithppb_release_bus(struct ppb_device *dev)
51628219Smsmith{
51728257Smsmith	int s;
51828219Smsmith	struct ppb_data *ppb = dev->ppb;
51928219Smsmith
52028257Smsmith	s = splhigh();
52128257Smsmith	if (ppb->ppb_owner != dev) {
52228257Smsmith		splx(s);
52328219Smsmith		return (EACCES);
52428257Smsmith	}
52528219Smsmith
52628257Smsmith	ppb->ppb_owner = 0;
52728257Smsmith	splx(s);
52828219Smsmith
52938061Smsmith	/* save the context of the device */
53038061Smsmith	dev->ctx.mode = ppb_get_mode(dev);
53138061Smsmith
53238061Smsmith	/* ok, now the context of the device is valid */
53338061Smsmith	dev->ctx.valid = 1;
53438061Smsmith
53528257Smsmith	/* wakeup waiting processes */
53628257Smsmith	wakeup(ppb);
53728219Smsmith
53828219Smsmith	return (0);
53928219Smsmith}
540