ppbconf.c revision 157774
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 *
2628219Smsmith *
2728219Smsmith */
28119418Sobrien
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ppbus/ppbconf.c 157774 2006-04-15 12:31:34Z iwasaki $");
3155939Snsouch#include "opt_ppb_1284.h"
3255939Snsouch
3328219Smsmith#include <sys/param.h>
3428219Smsmith#include <sys/systm.h>
3555939Snsouch#include <sys/kernel.h>
3655939Snsouch#include <sys/module.h>
3755939Snsouch#include <sys/bus.h>
3828219Smsmith#include <sys/malloc.h>
3928219Smsmith
4028219Smsmith#include <dev/ppbus/ppbconf.h>
4128257Smsmith#include <dev/ppbus/ppb_1284.h>
4228219Smsmith
4355939Snsouch#include "ppbus_if.h"
4455939Snsouch
4555939Snsouch#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev))
4655939Snsouch
4769774Sphkstatic MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device");
4842475Snsouch
4928219Smsmith
5028219Smsmith/*
5155939Snsouch * Device methods
5228219Smsmith */
5328219Smsmith
5455939Snsouchstatic void
5555939Snsouchppbus_print_child(device_t bus, device_t dev)
5655939Snsouch{
5755939Snsouch	struct ppb_device *ppbdev;
5828219Smsmith
5955939Snsouch	bus_print_child_header(bus, dev);
6055939Snsouch
6155939Snsouch	ppbdev = (struct ppb_device *)device_get_ivars(dev);
6255939Snsouch
6355939Snsouch	if (ppbdev->flags != 0)
6455939Snsouch		printf(" flags 0x%x", ppbdev->flags);
6555939Snsouch
6655939Snsouch	printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus));
6755939Snsouch
6855939Snsouch	return;
6955939Snsouch}
7055939Snsouch
7155939Snsouchstatic int
7255939Snsouchppbus_probe(device_t dev)
7355939Snsouch{
7455939Snsouch	device_set_desc(dev, "Parallel port bus");
7555939Snsouch
7655939Snsouch	return (0);
7755939Snsouch}
7855939Snsouch
7928219Smsmith/*
8056455Speter * ppbus_add_child()
8128219Smsmith *
8255939Snsouch * Add a ppbus device, allocate/initialize the ivars
8328219Smsmith */
8456455Speterstatic device_t
8556455Speterppbus_add_child(device_t dev, int order, const char *name, int unit)
8628219Smsmith{
8755939Snsouch	struct ppb_device *ppbdev;
8855939Snsouch	device_t child;
8955939Snsouch
9055939Snsouch	/* allocate ivars for the new ppbus child */
9169781Sdwmalone	ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV,
9269781Sdwmalone		M_NOWAIT | M_ZERO);
9355939Snsouch	if (!ppbdev)
9456455Speter		return NULL;
9528219Smsmith
9655939Snsouch	/* initialize the ivars */
9755939Snsouch	ppbdev->name = name;
9828219Smsmith
9955939Snsouch	/* add the device as a child to the ppbus bus with the allocated
10055939Snsouch	 * ivars */
10156455Speter	child = device_add_child_ordered(dev, order, name, unit);
10255939Snsouch	device_set_ivars(child, ppbdev);
10328219Smsmith
10456455Speter	return child;
10555939Snsouch}
10655939Snsouch
10755939Snsouchstatic int
10855939Snsouchppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val)
10956455Speter{
11055939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
11155939Snsouch
11255939Snsouch	switch (index) {
11355939Snsouch	case PPBUS_IVAR_MODE:
11455939Snsouch		/* XXX yet device mode = ppbus mode = chipset mode */
11555939Snsouch		*val = (u_long)ppb_get_mode(bus);
11655939Snsouch		ppbdev->mode = (u_short)*val;
11755939Snsouch		break;
11855939Snsouch	case PPBUS_IVAR_AVM:
11955939Snsouch		*val = (u_long)ppbdev->avm;
12055939Snsouch		break;
12155939Snsouch	case PPBUS_IVAR_IRQ:
12255939Snsouch		BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val);
12355939Snsouch		break;
12455939Snsouch	default:
12555939Snsouch		return (ENOENT);
12628219Smsmith	}
12755939Snsouch
12855939Snsouch	return (0);
12928219Smsmith}
13055939Snsouch
13155939Snsouchstatic int
13255939Snsouchppbus_write_ivar(device_t bus, device_t dev, int index, u_long val)
13355939Snsouch{
13455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
13528219Smsmith
13655939Snsouch	switch (index) {
13755939Snsouch	case PPBUS_IVAR_MODE:
13855939Snsouch		/* XXX yet device mode = ppbus mode = chipset mode */
13955939Snsouch		ppb_set_mode(bus,val);
14055939Snsouch		ppbdev->mode = ppb_get_mode(bus);
14155939Snsouch		break;
14255939Snsouch	default:
14355939Snsouch		return (ENOENT);
14455939Snsouch  	}
14555939Snsouch
14655939Snsouch	return (0);
14755939Snsouch  }
14855939Snsouch
14942475Snsouch#define PPB_PNP_PRINTER		0
15042475Snsouch#define PPB_PNP_MODEM		1
15142475Snsouch#define PPB_PNP_NET		2
15242475Snsouch#define PPB_PNP_HDC		3
15342475Snsouch#define PPB_PNP_PCMCIA		4
15442475Snsouch#define PPB_PNP_MEDIA		5
15542475Snsouch#define PPB_PNP_FDC		6
15642475Snsouch#define PPB_PNP_PORTS		7
15742475Snsouch#define PPB_PNP_SCANNER		8
15842475Snsouch#define PPB_PNP_DIGICAM		9
15942475Snsouch
16042475Snsouch#ifndef DONTPROBE_1284
16142475Snsouch
16228257Smsmithstatic char *pnp_tokens[] = {
16328257Smsmith	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
16428257Smsmith	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
16528257Smsmith
16642475Snsouch#if 0
16728257Smsmithstatic char *pnp_classes[] = {
16828257Smsmith	"printer", "modem", "network device",
16928257Smsmith	"hard disk", "PCMCIA", "multimedia device",
17028257Smsmith	"floppy disk", "ports", "scanner",
17128257Smsmith	"digital camera", "unknown device", NULL };
17242475Snsouch#endif
17328257Smsmith
17428219Smsmith/*
17528257Smsmith * search_token()
17628257Smsmith *
17728257Smsmith * Search the first occurence of a token within a string
17828257Smsmith */
17928257Smsmithstatic char *
18028257Smsmithsearch_token(char *str, int slen, char *token)
18128257Smsmith{
18278132Speter	int tlen, i;
18328257Smsmith
18428257Smsmith#define UNKNOWN_LENGTH	-1
18528257Smsmith
18628257Smsmith	if (slen == UNKNOWN_LENGTH)
18728257Smsmith		/* get string's length */
18875061Salfred		slen = strlen(str);
18928257Smsmith
19028257Smsmith	/* get token's length */
19175061Salfred	tlen = strlen(token);
19228257Smsmith	if (tlen == 0)
19328257Smsmith		return (str);
19428257Smsmith
19528257Smsmith	for (i = 0; i <= slen-tlen; i++) {
19675061Salfred		if (strncmp(str + i, token, tlen) == 0)
19728257Smsmith			return (&str[i]);
19828257Smsmith	}
19928257Smsmith
20028257Smsmith	return (NULL);
20128257Smsmith}
20228257Smsmith
20328257Smsmith/*
20428257Smsmith * ppb_pnp_detect()
20528257Smsmith *
20628257Smsmith * Returns the class id. of the peripherial, -1 otherwise
20728257Smsmith */
20828257Smsmithstatic int
20955939Snsouchppb_pnp_detect(device_t bus)
21028257Smsmith{
21142475Snsouch	char *token, *class = 0;
21228257Smsmith	int i, len, error;
21338061Smsmith	int class_id = -1;
21428257Smsmith	char str[PPB_PnP_STRING_SIZE+1];
21555939Snsouch	int unit = device_get_unit(bus);
21628257Smsmith
21755939Snsouch	printf("Probing for PnP devices on ppbus%d:\n", unit);
21842475Snsouch
21955939Snsouch	if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str,
22042475Snsouch					PPB_PnP_STRING_SIZE, &len)))
22138061Smsmith		goto end_detect;
22239134Snsouch
22342475Snsouch#ifdef DEBUG_1284
22442475Snsouch	printf("ppb: <PnP> %d characters: ", len);
22542475Snsouch	for (i = 0; i < len; i++)
22642475Snsouch		printf("%c(0x%x) ", str[i], str[i]);
22742475Snsouch	printf("\n");
22842475Snsouch#endif
22928257Smsmith
23028257Smsmith	/* replace ';' characters by '\0' */
23128257Smsmith	for (i = 0; i < len; i++)
23228257Smsmith		str[i] = (str[i] == ';') ? '\0' : str[i];
23328257Smsmith
23442475Snsouch	if ((token = search_token(str, len, "MFG")) != NULL ||
23542475Snsouch		(token = search_token(str, len, "MANUFACTURER")) != NULL)
23655939Snsouch		printf("ppbus%d: <%s", unit,
23728257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
23828257Smsmith	else
23955939Snsouch		printf("ppbus%d: <unknown", unit);
24028257Smsmith
24142475Snsouch	if ((token = search_token(str, len, "MDL")) != NULL ||
24242475Snsouch		(token = search_token(str, len, "MODEL")) != NULL)
24328257Smsmith		printf(" %s",
24428257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
24528257Smsmith	else
24628257Smsmith		printf(" unknown");
24728257Smsmith
24828257Smsmith	if ((token = search_token(str, len, "VER")) != NULL)
24928257Smsmith		printf("/%s",
25028257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
25128257Smsmith
25228257Smsmith	if ((token = search_token(str, len, "REV")) != NULL)
25328257Smsmith		printf(".%s",
25428257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
25528257Smsmith
25628257Smsmith	printf(">");
25728257Smsmith
25828257Smsmith	if ((token = search_token(str, len, "CLS")) != NULL) {
25928257Smsmith		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
26028257Smsmith		printf(" %s", class);
26128257Smsmith	}
26228257Smsmith
26342475Snsouch	if ((token = search_token(str, len, "CMD")) != NULL ||
26442475Snsouch		(token = search_token(str, len, "COMMAND")) != NULL)
26528257Smsmith		printf(" %s",
26628257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
26728257Smsmith
26828257Smsmith	printf("\n");
26928257Smsmith
27028257Smsmith	if (class)
27128257Smsmith		/* identify class ident */
27228257Smsmith		for (i = 0; pnp_tokens[i] != NULL; i++) {
27328257Smsmith			if (search_token(class, len, pnp_tokens[i]) != NULL) {
27438061Smsmith				class_id = i;
27538061Smsmith				goto end_detect;
27628257Smsmith			}
27728257Smsmith		}
27828257Smsmith
27938061Smsmith	class_id = PPB_PnP_UNKNOWN;
28038061Smsmith
28138061Smsmithend_detect:
28242475Snsouch	return (class_id);
28342475Snsouch}
28439134Snsouch
28542475Snsouch/*
28642475Snsouch * ppb_scan_bus()
28742475Snsouch *
28842475Snsouch * Scan the ppbus for IEEE1284 compliant devices
28942475Snsouch */
29042475Snsouchstatic int
29155939Snsouchppb_scan_bus(device_t bus)
29242475Snsouch{
29355939Snsouch	struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus);
29442475Snsouch	int error = 0;
29555939Snsouch	int unit = device_get_unit(bus);
29642475Snsouch
29742475Snsouch	/* try all IEEE1284 modes, for one device only
29842475Snsouch	 *
29942475Snsouch	 * XXX We should implement the IEEE1284.3 standard to detect
30042475Snsouch	 * daisy chained devices
30142475Snsouch	 */
30242475Snsouch
30355939Snsouch	error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID);
30442475Snsouch
30542475Snsouch	if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
30642475Snsouch		goto end_scan;
30742475Snsouch
30855939Snsouch	ppb_1284_terminate(bus);
30942475Snsouch
31055939Snsouch	printf("ppbus%d: IEEE1284 device found ", unit);
31142475Snsouch
31255939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) {
31342475Snsouch		printf("/NIBBLE");
31455939Snsouch		ppb_1284_terminate(bus);
31542475Snsouch	}
31642475Snsouch
31755939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) {
31842475Snsouch		printf("/PS2");
31955939Snsouch		ppb_1284_terminate(bus);
32042475Snsouch	}
32142475Snsouch
32255939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) {
32342475Snsouch		printf("/ECP");
32455939Snsouch		ppb_1284_terminate(bus);
32542475Snsouch	}
32642475Snsouch
32755939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) {
32842475Snsouch		printf("/ECP_RLE");
32955939Snsouch		ppb_1284_terminate(bus);
33042475Snsouch	}
33142475Snsouch
33255939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) {
33342475Snsouch		printf("/EPP");
33455939Snsouch		ppb_1284_terminate(bus);
33542475Snsouch	}
33642475Snsouch
33742536Snsouch	/* try more IEEE1284 modes */
33842536Snsouch	if (bootverbose) {
33955939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE,
34042536Snsouch				PPB_REQUEST_ID))) {
34142536Snsouch			printf("/NIBBLE_ID");
34255939Snsouch			ppb_1284_terminate(bus);
34342536Snsouch		}
34442475Snsouch
34555939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_PS2,
34642536Snsouch				PPB_REQUEST_ID))) {
34742536Snsouch			printf("/PS2_ID");
34855939Snsouch			ppb_1284_terminate(bus);
34942536Snsouch		}
35042475Snsouch
35155939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
35242536Snsouch				PPB_REQUEST_ID))) {
35342536Snsouch			printf("/ECP_ID");
35455939Snsouch			ppb_1284_terminate(bus);
35542536Snsouch		}
35642475Snsouch
35755939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
35842536Snsouch				PPB_REQUEST_ID | PPB_USE_RLE))) {
35942536Snsouch			printf("/ECP_RLE_ID");
36055939Snsouch			ppb_1284_terminate(bus);
36142536Snsouch		}
36242475Snsouch
36355939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE,
36442475Snsouch				PPB_EXTENSIBILITY_LINK))) {
36542536Snsouch			printf("/Extensibility Link");
36655939Snsouch			ppb_1284_terminate(bus);
36742536Snsouch		}
36842536Snsouch	}
36942475Snsouch
37042536Snsouch	printf("\n");
37142536Snsouch
37242475Snsouch	/* detect PnP devices */
37355939Snsouch	ppb->class_id = ppb_pnp_detect(bus);
37442475Snsouch
37542475Snsouch	return (0);
37642475Snsouch
37742475Snsouchend_scan:
37842475Snsouch	return (error);
37928257Smsmith}
38028257Smsmith
38142475Snsouch#endif /* !DONTPROBE_1284 */
38242475Snsouch
38355939Snsouchstatic int
38455939Snsouchppbus_attach(device_t dev)
38528219Smsmith{
38628257Smsmith
38756455Speter	/* Locate our children */
38856455Speter	bus_generic_probe(dev);
38928219Smsmith
39055939Snsouch#ifndef DONTPROBE_1284
39155939Snsouch	/* detect IEEE1284 compliant devices */
39255939Snsouch	ppb_scan_bus(dev);
39355939Snsouch#endif /* !DONTPROBE_1284 */
39428219Smsmith
39555939Snsouch	/* launch attachement of the added children */
39655939Snsouch	bus_generic_attach(dev);
39728219Smsmith
39855939Snsouch	return 0;
39928219Smsmith}
40028219Smsmith
40155939Snsouchstatic int
402157774Siwasakippbus_detach(device_t dev)
403157774Siwasaki{
404157774Siwasaki        device_t *children;
405157774Siwasaki        int nchildren, i;
406157774Siwasaki
407157774Siwasaki	/* detach & delete all children */
408157774Siwasaki	if (!device_get_children(dev, &children, &nchildren)) {
409157774Siwasaki		for (i = 0; i < nchildren; i++)
410157774Siwasaki			if (children[i])
411157774Siwasaki				device_delete_child(dev, children[i]);
412157774Siwasaki		free(children, M_TEMP);
413157774Siwasaki        }
414157774Siwasaki
415157774Siwasaki	return (0);
416157774Siwasaki}
417157774Siwasaki
418157774Siwasakistatic int
41955939Snsouchppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
42055939Snsouch			void (*ihand)(void *), void *arg, void **cookiep)
42138061Smsmith{
42255939Snsouch	int error;
42355939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
42455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
42538061Smsmith
42655939Snsouch	/* a device driver must own the bus to register an interrupt */
42755939Snsouch	if (ppb->ppb_owner != child)
42855939Snsouch		return (EINVAL);
42938061Smsmith
43055939Snsouch	if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
43155939Snsouch					ihand, arg, cookiep)))
43255939Snsouch		return (error);
43338061Smsmith
43455939Snsouch	/* store the resource and the cookie for eventually forcing
43555939Snsouch	 * handler unregistration
43655939Snsouch	 */
43755939Snsouch	ppbdev->intr_cookie = *cookiep;
43855939Snsouch	ppbdev->intr_resource = r;
43928219Smsmith
44028219Smsmith	return (0);
44128219Smsmith}
44228219Smsmith
44355939Snsouchstatic int
44455939Snsouchppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
44528219Smsmith{
44655939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
44755939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
44855939Snsouch
44955939Snsouch	/* a device driver must own the bus to unregister an interrupt */
45055939Snsouch	if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) ||
45155939Snsouch			(ppbdev->intr_resource != r))
45255939Snsouch		return (EINVAL);
45328219Smsmith
45455939Snsouch	ppbdev->intr_cookie = 0;
45555939Snsouch	ppbdev->intr_resource = 0;
45628219Smsmith
45755939Snsouch	/* pass unregistration to the upper layer */
45855939Snsouch	return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
45928219Smsmith}
46028219Smsmith
46128219Smsmith/*
46228257Smsmith * ppb_request_bus()
46328219Smsmith *
46428257Smsmith * Allocate the device to perform transfers.
46528257Smsmith *
46628257Smsmith * how	: PPB_WAIT or PPB_DONTWAIT
46728219Smsmith */
46828219Smsmithint
46955939Snsouchppb_request_bus(device_t bus, device_t dev, int how)
47028219Smsmith{
47128257Smsmith	int s, error = 0;
47255939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
47355939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
47428219Smsmith
47528257Smsmith	while (!error) {
47628257Smsmith		s = splhigh();
47728257Smsmith		if (ppb->ppb_owner) {
47828257Smsmith			splx(s);
47928219Smsmith
48028257Smsmith			switch (how) {
48128257Smsmith			case (PPB_WAIT | PPB_INTR):
48228257Smsmith				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
48328257Smsmith				break;
48428219Smsmith
48528257Smsmith			case (PPB_WAIT | PPB_NOINTR):
48628257Smsmith				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
48728257Smsmith				break;
48828219Smsmith
48928257Smsmith			default:
49028257Smsmith				return (EWOULDBLOCK);
49128257Smsmith				break;
49228257Smsmith			}
49328219Smsmith
49428257Smsmith		} else {
49528257Smsmith			ppb->ppb_owner = dev;
49628219Smsmith
49738061Smsmith			/* restore the context of the device
49838061Smsmith			 * The first time, ctx.valid is certainly false
49938061Smsmith			 * then do not change anything. This is usefull for
50038061Smsmith			 * drivers that do not set there operating mode
50138061Smsmith			 * during attachement
50238061Smsmith			 */
50355939Snsouch			if (ppbdev->ctx.valid)
50455939Snsouch				ppb_set_mode(bus, ppbdev->ctx.mode);
50538061Smsmith
50628257Smsmith			splx(s);
50728257Smsmith			return (0);
50828257Smsmith		}
50928257Smsmith	}
51028219Smsmith
51128257Smsmith	return (error);
51228219Smsmith}
51328219Smsmith
51428219Smsmith/*
51528257Smsmith * ppb_release_bus()
51628219Smsmith *
51760048Sn_hibma * Release the device allocated with ppb_request_bus()
51828219Smsmith */
51928219Smsmithint
52055939Snsouchppb_release_bus(device_t bus, device_t dev)
52128219Smsmith{
52255939Snsouch	int s, error;
52355939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
52455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
52528219Smsmith
52655939Snsouch	if (ppbdev->intr_resource != 0)
52755939Snsouch		/* force interrupt handler unregistration when the ppbus is released */
52855939Snsouch		if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource,
52955939Snsouch					       ppbdev->intr_cookie)))
53055939Snsouch			return (error);
53155939Snsouch
53228257Smsmith	s = splhigh();
53328257Smsmith	if (ppb->ppb_owner != dev) {
53428257Smsmith		splx(s);
53528219Smsmith		return (EACCES);
53628257Smsmith	}
53728219Smsmith
53828257Smsmith	ppb->ppb_owner = 0;
53928257Smsmith	splx(s);
54028219Smsmith
54138061Smsmith	/* save the context of the device */
54255939Snsouch	ppbdev->ctx.mode = ppb_get_mode(bus);
54338061Smsmith
54438061Smsmith	/* ok, now the context of the device is valid */
54555939Snsouch	ppbdev->ctx.valid = 1;
54638061Smsmith
54728257Smsmith	/* wakeup waiting processes */
54828257Smsmith	wakeup(ppb);
54928219Smsmith
55028219Smsmith	return (0);
55128219Smsmith}
55255939Snsouch
55356455Speterstatic devclass_t ppbus_devclass;
55456455Speter
55556455Speterstatic device_method_t ppbus_methods[] = {
55656455Speter        /* device interface */
55756455Speter	DEVMETHOD(device_probe,         ppbus_probe),
55856455Speter	DEVMETHOD(device_attach,        ppbus_attach),
559157774Siwasaki	DEVMETHOD(device_detach,        ppbus_detach),
56056455Speter
56156455Speter        /* bus interface */
56256455Speter	DEVMETHOD(bus_add_child,	ppbus_add_child),
56356455Speter	DEVMETHOD(bus_print_child,	ppbus_print_child),
56456455Speter	DEVMETHOD(bus_read_ivar,        ppbus_read_ivar),
56556455Speter	DEVMETHOD(bus_write_ivar,       ppbus_write_ivar),
56656455Speter	DEVMETHOD(bus_setup_intr,	ppbus_setup_intr),
56756455Speter	DEVMETHOD(bus_teardown_intr,	ppbus_teardown_intr),
56856455Speter	DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
56956455Speter
57056455Speter        { 0, 0 }
57156455Speter};
57256455Speter
57356455Speterstatic driver_t ppbus_driver = {
57456455Speter        "ppbus",
57556455Speter        ppbus_methods,
57656455Speter        sizeof(struct ppb_data),
57756455Speter};
57855939SnsouchDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);
579