ppbconf.c revision 69781
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 *
2650477Speter * $FreeBSD: head/sys/dev/ppbus/ppbconf.c 69781 2000-12-08 21:51:06Z dwmalone $
2728219Smsmith *
2828219Smsmith */
2955939Snsouch#include "opt_ppb_1284.h"
3055939Snsouch
3128219Smsmith#include <sys/param.h>
3228219Smsmith#include <sys/systm.h>
3355939Snsouch#include <sys/kernel.h>
3455939Snsouch#include <sys/module.h>
3555939Snsouch#include <sys/bus.h>
3628219Smsmith#include <sys/malloc.h>
3728219Smsmith
3828219Smsmith#include <dev/ppbus/ppbconf.h>
3928257Smsmith#include <dev/ppbus/ppb_1284.h>
4028219Smsmith
4155939Snsouch#include "ppbus_if.h"
4255939Snsouch
4355939Snsouch#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev))
4455939Snsouch
4569774Sphkstatic MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device");
4642475Snsouch
4728219Smsmith
4828219Smsmith/*
4955939Snsouch * Device methods
5028219Smsmith */
5128219Smsmith
5255939Snsouchstatic void
5355939Snsouchppbus_print_child(device_t bus, device_t dev)
5455939Snsouch{
5555939Snsouch	struct ppb_device *ppbdev;
5628219Smsmith
5755939Snsouch	bus_print_child_header(bus, dev);
5855939Snsouch
5955939Snsouch	ppbdev = (struct ppb_device *)device_get_ivars(dev);
6055939Snsouch
6155939Snsouch	if (ppbdev->flags != 0)
6255939Snsouch		printf(" flags 0x%x", ppbdev->flags);
6355939Snsouch
6455939Snsouch	printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus));
6555939Snsouch
6655939Snsouch	return;
6755939Snsouch}
6855939Snsouch
6955939Snsouchstatic int
7055939Snsouchppbus_probe(device_t dev)
7155939Snsouch{
7255939Snsouch	device_set_desc(dev, "Parallel port bus");
7355939Snsouch
7455939Snsouch	return (0);
7555939Snsouch}
7655939Snsouch
7728219Smsmith/*
7856455Speter * ppbus_add_child()
7928219Smsmith *
8055939Snsouch * Add a ppbus device, allocate/initialize the ivars
8128219Smsmith */
8256455Speterstatic device_t
8356455Speterppbus_add_child(device_t dev, int order, const char *name, int unit)
8428219Smsmith{
8555939Snsouch	struct ppb_device *ppbdev;
8655939Snsouch	device_t child;
8755939Snsouch
8855939Snsouch	/* allocate ivars for the new ppbus child */
8969781Sdwmalone	ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV,
9069781Sdwmalone		M_NOWAIT | M_ZERO);
9155939Snsouch	if (!ppbdev)
9256455Speter		return NULL;
9328219Smsmith
9455939Snsouch	/* initialize the ivars */
9555939Snsouch	ppbdev->name = name;
9628219Smsmith
9755939Snsouch	/* add the device as a child to the ppbus bus with the allocated
9855939Snsouch	 * ivars */
9956455Speter	child = device_add_child_ordered(dev, order, name, unit);
10055939Snsouch	device_set_ivars(child, ppbdev);
10128219Smsmith
10256455Speter	return child;
10355939Snsouch}
10455939Snsouch
10555939Snsouchstatic int
10655939Snsouchppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val)
10756455Speter{
10855939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
10955939Snsouch
11055939Snsouch	switch (index) {
11155939Snsouch	case PPBUS_IVAR_MODE:
11255939Snsouch		/* XXX yet device mode = ppbus mode = chipset mode */
11355939Snsouch		*val = (u_long)ppb_get_mode(bus);
11455939Snsouch		ppbdev->mode = (u_short)*val;
11555939Snsouch		break;
11655939Snsouch	case PPBUS_IVAR_AVM:
11755939Snsouch		*val = (u_long)ppbdev->avm;
11855939Snsouch		break;
11955939Snsouch	case PPBUS_IVAR_IRQ:
12055939Snsouch		BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val);
12155939Snsouch		break;
12255939Snsouch	default:
12355939Snsouch		return (ENOENT);
12428219Smsmith	}
12555939Snsouch
12655939Snsouch	return (0);
12728219Smsmith}
12855939Snsouch
12955939Snsouchstatic int
13055939Snsouchppbus_write_ivar(device_t bus, device_t dev, int index, u_long val)
13155939Snsouch{
13255939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
13328219Smsmith
13455939Snsouch	switch (index) {
13555939Snsouch	case PPBUS_IVAR_MODE:
13655939Snsouch		/* XXX yet device mode = ppbus mode = chipset mode */
13755939Snsouch		ppb_set_mode(bus,val);
13855939Snsouch		ppbdev->mode = ppb_get_mode(bus);
13955939Snsouch		break;
14055939Snsouch	default:
14155939Snsouch		return (ENOENT);
14255939Snsouch  	}
14355939Snsouch
14455939Snsouch	return (0);
14555939Snsouch  }
14655939Snsouch
14742475Snsouch#define PPB_PNP_PRINTER		0
14842475Snsouch#define PPB_PNP_MODEM		1
14942475Snsouch#define PPB_PNP_NET		2
15042475Snsouch#define PPB_PNP_HDC		3
15142475Snsouch#define PPB_PNP_PCMCIA		4
15242475Snsouch#define PPB_PNP_MEDIA		5
15342475Snsouch#define PPB_PNP_FDC		6
15442475Snsouch#define PPB_PNP_PORTS		7
15542475Snsouch#define PPB_PNP_SCANNER		8
15642475Snsouch#define PPB_PNP_DIGICAM		9
15742475Snsouch
15842475Snsouch#ifndef DONTPROBE_1284
15942475Snsouch
16028257Smsmithstatic char *pnp_tokens[] = {
16128257Smsmith	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
16228257Smsmith	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
16328257Smsmith
16442475Snsouch#if 0
16528257Smsmithstatic char *pnp_classes[] = {
16628257Smsmith	"printer", "modem", "network device",
16728257Smsmith	"hard disk", "PCMCIA", "multimedia device",
16828257Smsmith	"floppy disk", "ports", "scanner",
16928257Smsmith	"digital camera", "unknown device", NULL };
17042475Snsouch#endif
17128257Smsmith
17228219Smsmith/*
17328257Smsmith * search_token()
17428257Smsmith *
17528257Smsmith * Search the first occurence of a token within a string
17639134Snsouch *
17739134Snsouch * XXX should use strxxx() calls
17828257Smsmith */
17928257Smsmithstatic char *
18028257Smsmithsearch_token(char *str, int slen, char *token)
18128257Smsmith{
18228257Smsmith	char *p;
18328257Smsmith	int tlen, i, j;
18428257Smsmith
18528257Smsmith#define UNKNOWN_LENGTH	-1
18628257Smsmith
18728257Smsmith	if (slen == UNKNOWN_LENGTH)
18828257Smsmith		/* get string's length */
18928257Smsmith		for (slen = 0, p = str; *p != '\0'; p++)
19028257Smsmith			slen ++;
19128257Smsmith
19228257Smsmith	/* get token's length */
19328257Smsmith	for (tlen = 0, p = token; *p != '\0'; p++)
19428257Smsmith		tlen ++;
19528257Smsmith
19628257Smsmith	if (tlen == 0)
19728257Smsmith		return (str);
19828257Smsmith
19928257Smsmith	for (i = 0; i <= slen-tlen; i++) {
20028257Smsmith		for (j = 0; j < tlen; j++)
20128257Smsmith			if (str[i+j] != token[j])
20228257Smsmith				break;
20328257Smsmith		if (j == tlen)
20428257Smsmith			return (&str[i]);
20528257Smsmith	}
20628257Smsmith
20728257Smsmith	return (NULL);
20828257Smsmith}
20928257Smsmith
21028257Smsmith/*
21128257Smsmith * ppb_pnp_detect()
21228257Smsmith *
21328257Smsmith * Returns the class id. of the peripherial, -1 otherwise
21428257Smsmith */
21528257Smsmithstatic int
21655939Snsouchppb_pnp_detect(device_t bus)
21728257Smsmith{
21842475Snsouch	char *token, *class = 0;
21928257Smsmith	int i, len, error;
22038061Smsmith	int class_id = -1;
22128257Smsmith	char str[PPB_PnP_STRING_SIZE+1];
22255939Snsouch	int unit = device_get_unit(bus);
22328257Smsmith
22455939Snsouch	printf("Probing for PnP devices on ppbus%d:\n", unit);
22542475Snsouch
22655939Snsouch	if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str,
22742475Snsouch					PPB_PnP_STRING_SIZE, &len)))
22838061Smsmith		goto end_detect;
22939134Snsouch
23042475Snsouch#ifdef DEBUG_1284
23142475Snsouch	printf("ppb: <PnP> %d characters: ", len);
23242475Snsouch	for (i = 0; i < len; i++)
23342475Snsouch		printf("%c(0x%x) ", str[i], str[i]);
23442475Snsouch	printf("\n");
23542475Snsouch#endif
23628257Smsmith
23728257Smsmith	/* replace ';' characters by '\0' */
23828257Smsmith	for (i = 0; i < len; i++)
23928257Smsmith		str[i] = (str[i] == ';') ? '\0' : str[i];
24028257Smsmith
24142475Snsouch	if ((token = search_token(str, len, "MFG")) != NULL ||
24242475Snsouch		(token = search_token(str, len, "MANUFACTURER")) != NULL)
24355939Snsouch		printf("ppbus%d: <%s", unit,
24428257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
24528257Smsmith	else
24655939Snsouch		printf("ppbus%d: <unknown", unit);
24728257Smsmith
24842475Snsouch	if ((token = search_token(str, len, "MDL")) != NULL ||
24942475Snsouch		(token = search_token(str, len, "MODEL")) != NULL)
25028257Smsmith		printf(" %s",
25128257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
25228257Smsmith	else
25328257Smsmith		printf(" unknown");
25428257Smsmith
25528257Smsmith	if ((token = search_token(str, len, "VER")) != NULL)
25628257Smsmith		printf("/%s",
25728257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
25828257Smsmith
25928257Smsmith	if ((token = search_token(str, len, "REV")) != NULL)
26028257Smsmith		printf(".%s",
26128257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
26228257Smsmith
26328257Smsmith	printf(">");
26428257Smsmith
26528257Smsmith	if ((token = search_token(str, len, "CLS")) != NULL) {
26628257Smsmith		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
26728257Smsmith		printf(" %s", class);
26828257Smsmith	}
26928257Smsmith
27042475Snsouch	if ((token = search_token(str, len, "CMD")) != NULL ||
27142475Snsouch		(token = search_token(str, len, "COMMAND")) != NULL)
27228257Smsmith		printf(" %s",
27328257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
27428257Smsmith
27528257Smsmith	printf("\n");
27628257Smsmith
27728257Smsmith	if (class)
27828257Smsmith		/* identify class ident */
27928257Smsmith		for (i = 0; pnp_tokens[i] != NULL; i++) {
28028257Smsmith			if (search_token(class, len, pnp_tokens[i]) != NULL) {
28138061Smsmith				class_id = i;
28238061Smsmith				goto end_detect;
28328257Smsmith			}
28428257Smsmith		}
28528257Smsmith
28638061Smsmith	class_id = PPB_PnP_UNKNOWN;
28738061Smsmith
28838061Smsmithend_detect:
28942475Snsouch	return (class_id);
29042475Snsouch}
29139134Snsouch
29242475Snsouch/*
29342475Snsouch * ppb_scan_bus()
29442475Snsouch *
29542475Snsouch * Scan the ppbus for IEEE1284 compliant devices
29642475Snsouch */
29742475Snsouchstatic int
29855939Snsouchppb_scan_bus(device_t bus)
29942475Snsouch{
30055939Snsouch	struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus);
30142475Snsouch	int error = 0;
30255939Snsouch	int unit = device_get_unit(bus);
30342475Snsouch
30442475Snsouch	/* try all IEEE1284 modes, for one device only
30542475Snsouch	 *
30642475Snsouch	 * XXX We should implement the IEEE1284.3 standard to detect
30742475Snsouch	 * daisy chained devices
30842475Snsouch	 */
30942475Snsouch
31055939Snsouch	error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID);
31142475Snsouch
31242475Snsouch	if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
31342475Snsouch		goto end_scan;
31442475Snsouch
31555939Snsouch	ppb_1284_terminate(bus);
31642475Snsouch
31755939Snsouch	printf("ppbus%d: IEEE1284 device found ", unit);
31842475Snsouch
31955939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) {
32042475Snsouch		printf("/NIBBLE");
32155939Snsouch		ppb_1284_terminate(bus);
32242475Snsouch	}
32342475Snsouch
32455939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) {
32542475Snsouch		printf("/PS2");
32655939Snsouch		ppb_1284_terminate(bus);
32742475Snsouch	}
32842475Snsouch
32955939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) {
33042475Snsouch		printf("/ECP");
33155939Snsouch		ppb_1284_terminate(bus);
33242475Snsouch	}
33342475Snsouch
33455939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) {
33542475Snsouch		printf("/ECP_RLE");
33655939Snsouch		ppb_1284_terminate(bus);
33742475Snsouch	}
33842475Snsouch
33955939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) {
34042475Snsouch		printf("/EPP");
34155939Snsouch		ppb_1284_terminate(bus);
34242475Snsouch	}
34342475Snsouch
34442536Snsouch	/* try more IEEE1284 modes */
34542536Snsouch	if (bootverbose) {
34655939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE,
34742536Snsouch				PPB_REQUEST_ID))) {
34842536Snsouch			printf("/NIBBLE_ID");
34955939Snsouch			ppb_1284_terminate(bus);
35042536Snsouch		}
35142475Snsouch
35255939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_PS2,
35342536Snsouch				PPB_REQUEST_ID))) {
35442536Snsouch			printf("/PS2_ID");
35555939Snsouch			ppb_1284_terminate(bus);
35642536Snsouch		}
35742475Snsouch
35855939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
35942536Snsouch				PPB_REQUEST_ID))) {
36042536Snsouch			printf("/ECP_ID");
36155939Snsouch			ppb_1284_terminate(bus);
36242536Snsouch		}
36342475Snsouch
36455939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
36542536Snsouch				PPB_REQUEST_ID | PPB_USE_RLE))) {
36642536Snsouch			printf("/ECP_RLE_ID");
36755939Snsouch			ppb_1284_terminate(bus);
36842536Snsouch		}
36942475Snsouch
37055939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE,
37142475Snsouch				PPB_EXTENSIBILITY_LINK))) {
37242536Snsouch			printf("/Extensibility Link");
37355939Snsouch			ppb_1284_terminate(bus);
37442536Snsouch		}
37542536Snsouch	}
37642475Snsouch
37742536Snsouch	printf("\n");
37842536Snsouch
37942475Snsouch	/* detect PnP devices */
38055939Snsouch	ppb->class_id = ppb_pnp_detect(bus);
38142475Snsouch
38242475Snsouch	return (0);
38342475Snsouch
38442475Snsouchend_scan:
38542475Snsouch	return (error);
38628257Smsmith}
38728257Smsmith
38842475Snsouch#endif /* !DONTPROBE_1284 */
38942475Snsouch
39055939Snsouchstatic int
39155939Snsouchppbus_attach(device_t dev)
39228219Smsmith{
39328257Smsmith
39456455Speter	/* Locate our children */
39556455Speter	bus_generic_probe(dev);
39628219Smsmith
39755939Snsouch#ifndef DONTPROBE_1284
39855939Snsouch	/* detect IEEE1284 compliant devices */
39955939Snsouch	ppb_scan_bus(dev);
40055939Snsouch#endif /* !DONTPROBE_1284 */
40128219Smsmith
40255939Snsouch	/* launch attachement of the added children */
40355939Snsouch	bus_generic_attach(dev);
40428219Smsmith
40555939Snsouch	return 0;
40628219Smsmith}
40728219Smsmith
40855939Snsouchstatic int
40955939Snsouchppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
41055939Snsouch			void (*ihand)(void *), void *arg, void **cookiep)
41138061Smsmith{
41255939Snsouch	int error;
41355939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
41455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
41538061Smsmith
41655939Snsouch	/* a device driver must own the bus to register an interrupt */
41755939Snsouch	if (ppb->ppb_owner != child)
41855939Snsouch		return (EINVAL);
41938061Smsmith
42055939Snsouch	if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
42155939Snsouch					ihand, arg, cookiep)))
42255939Snsouch		return (error);
42338061Smsmith
42455939Snsouch	/* store the resource and the cookie for eventually forcing
42555939Snsouch	 * handler unregistration
42655939Snsouch	 */
42755939Snsouch	ppbdev->intr_cookie = *cookiep;
42855939Snsouch	ppbdev->intr_resource = r;
42928219Smsmith
43028219Smsmith	return (0);
43128219Smsmith}
43228219Smsmith
43355939Snsouchstatic int
43455939Snsouchppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
43528219Smsmith{
43655939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
43755939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
43855939Snsouch
43955939Snsouch	/* a device driver must own the bus to unregister an interrupt */
44055939Snsouch	if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) ||
44155939Snsouch			(ppbdev->intr_resource != r))
44255939Snsouch		return (EINVAL);
44328219Smsmith
44455939Snsouch	ppbdev->intr_cookie = 0;
44555939Snsouch	ppbdev->intr_resource = 0;
44628219Smsmith
44755939Snsouch	/* pass unregistration to the upper layer */
44855939Snsouch	return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
44928219Smsmith}
45028219Smsmith
45128219Smsmith/*
45228257Smsmith * ppb_request_bus()
45328219Smsmith *
45428257Smsmith * Allocate the device to perform transfers.
45528257Smsmith *
45628257Smsmith * how	: PPB_WAIT or PPB_DONTWAIT
45728219Smsmith */
45828219Smsmithint
45955939Snsouchppb_request_bus(device_t bus, device_t dev, int how)
46028219Smsmith{
46128257Smsmith	int s, error = 0;
46255939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
46355939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
46428219Smsmith
46528257Smsmith	while (!error) {
46628257Smsmith		s = splhigh();
46728257Smsmith		if (ppb->ppb_owner) {
46828257Smsmith			splx(s);
46928219Smsmith
47028257Smsmith			switch (how) {
47128257Smsmith			case (PPB_WAIT | PPB_INTR):
47228257Smsmith				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
47328257Smsmith				break;
47428219Smsmith
47528257Smsmith			case (PPB_WAIT | PPB_NOINTR):
47628257Smsmith				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
47728257Smsmith				break;
47828219Smsmith
47928257Smsmith			default:
48028257Smsmith				return (EWOULDBLOCK);
48128257Smsmith				break;
48228257Smsmith			}
48328219Smsmith
48428257Smsmith		} else {
48528257Smsmith			ppb->ppb_owner = dev;
48628219Smsmith
48738061Smsmith			/* restore the context of the device
48838061Smsmith			 * The first time, ctx.valid is certainly false
48938061Smsmith			 * then do not change anything. This is usefull for
49038061Smsmith			 * drivers that do not set there operating mode
49138061Smsmith			 * during attachement
49238061Smsmith			 */
49355939Snsouch			if (ppbdev->ctx.valid)
49455939Snsouch				ppb_set_mode(bus, ppbdev->ctx.mode);
49538061Smsmith
49628257Smsmith			splx(s);
49728257Smsmith			return (0);
49828257Smsmith		}
49928257Smsmith	}
50028219Smsmith
50128257Smsmith	return (error);
50228219Smsmith}
50328219Smsmith
50428219Smsmith/*
50528257Smsmith * ppb_release_bus()
50628219Smsmith *
50760048Sn_hibma * Release the device allocated with ppb_request_bus()
50828219Smsmith */
50928219Smsmithint
51055939Snsouchppb_release_bus(device_t bus, device_t dev)
51128219Smsmith{
51255939Snsouch	int s, error;
51355939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
51455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
51528219Smsmith
51655939Snsouch	if (ppbdev->intr_resource != 0)
51755939Snsouch		/* force interrupt handler unregistration when the ppbus is released */
51855939Snsouch		if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource,
51955939Snsouch					       ppbdev->intr_cookie)))
52055939Snsouch			return (error);
52155939Snsouch
52228257Smsmith	s = splhigh();
52328257Smsmith	if (ppb->ppb_owner != dev) {
52428257Smsmith		splx(s);
52528219Smsmith		return (EACCES);
52628257Smsmith	}
52728219Smsmith
52828257Smsmith	ppb->ppb_owner = 0;
52928257Smsmith	splx(s);
53028219Smsmith
53138061Smsmith	/* save the context of the device */
53255939Snsouch	ppbdev->ctx.mode = ppb_get_mode(bus);
53338061Smsmith
53438061Smsmith	/* ok, now the context of the device is valid */
53555939Snsouch	ppbdev->ctx.valid = 1;
53638061Smsmith
53728257Smsmith	/* wakeup waiting processes */
53828257Smsmith	wakeup(ppb);
53928219Smsmith
54028219Smsmith	return (0);
54128219Smsmith}
54255939Snsouch
54356455Speterstatic devclass_t ppbus_devclass;
54456455Speter
54556455Speterstatic device_method_t ppbus_methods[] = {
54656455Speter        /* device interface */
54756455Speter	DEVMETHOD(device_probe,         ppbus_probe),
54856455Speter	DEVMETHOD(device_attach,        ppbus_attach),
54956455Speter
55056455Speter        /* bus interface */
55156455Speter	DEVMETHOD(bus_add_child,	ppbus_add_child),
55256455Speter	DEVMETHOD(bus_print_child,	ppbus_print_child),
55356455Speter	DEVMETHOD(bus_read_ivar,        ppbus_read_ivar),
55456455Speter	DEVMETHOD(bus_write_ivar,       ppbus_write_ivar),
55556455Speter	DEVMETHOD(bus_setup_intr,	ppbus_setup_intr),
55656455Speter	DEVMETHOD(bus_teardown_intr,	ppbus_teardown_intr),
55756455Speter	DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
55856455Speter
55956455Speter        { 0, 0 }
56056455Speter};
56156455Speter
56256455Speterstatic driver_t ppbus_driver = {
56356455Speter        "ppbus",
56456455Speter        ppbus_methods,
56556455Speter        sizeof(struct ppb_data),
56656455Speter};
56755939SnsouchDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);
568