ppbconf.c revision 78132
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 78132 2001-06-12 07:01:27Z peter $
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
17628257Smsmith */
17728257Smsmithstatic char *
17828257Smsmithsearch_token(char *str, int slen, char *token)
17928257Smsmith{
18078132Speter	int tlen, i;
18128257Smsmith
18228257Smsmith#define UNKNOWN_LENGTH	-1
18328257Smsmith
18428257Smsmith	if (slen == UNKNOWN_LENGTH)
18528257Smsmith		/* get string's length */
18675061Salfred		slen = strlen(str);
18728257Smsmith
18828257Smsmith	/* get token's length */
18975061Salfred	tlen = strlen(token);
19028257Smsmith	if (tlen == 0)
19128257Smsmith		return (str);
19228257Smsmith
19328257Smsmith	for (i = 0; i <= slen-tlen; i++) {
19475061Salfred		if (strncmp(str + i, token, tlen) == 0)
19528257Smsmith			return (&str[i]);
19628257Smsmith	}
19728257Smsmith
19828257Smsmith	return (NULL);
19928257Smsmith}
20028257Smsmith
20128257Smsmith/*
20228257Smsmith * ppb_pnp_detect()
20328257Smsmith *
20428257Smsmith * Returns the class id. of the peripherial, -1 otherwise
20528257Smsmith */
20628257Smsmithstatic int
20755939Snsouchppb_pnp_detect(device_t bus)
20828257Smsmith{
20942475Snsouch	char *token, *class = 0;
21028257Smsmith	int i, len, error;
21138061Smsmith	int class_id = -1;
21228257Smsmith	char str[PPB_PnP_STRING_SIZE+1];
21355939Snsouch	int unit = device_get_unit(bus);
21428257Smsmith
21555939Snsouch	printf("Probing for PnP devices on ppbus%d:\n", unit);
21642475Snsouch
21755939Snsouch	if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str,
21842475Snsouch					PPB_PnP_STRING_SIZE, &len)))
21938061Smsmith		goto end_detect;
22039134Snsouch
22142475Snsouch#ifdef DEBUG_1284
22242475Snsouch	printf("ppb: <PnP> %d characters: ", len);
22342475Snsouch	for (i = 0; i < len; i++)
22442475Snsouch		printf("%c(0x%x) ", str[i], str[i]);
22542475Snsouch	printf("\n");
22642475Snsouch#endif
22728257Smsmith
22828257Smsmith	/* replace ';' characters by '\0' */
22928257Smsmith	for (i = 0; i < len; i++)
23028257Smsmith		str[i] = (str[i] == ';') ? '\0' : str[i];
23128257Smsmith
23242475Snsouch	if ((token = search_token(str, len, "MFG")) != NULL ||
23342475Snsouch		(token = search_token(str, len, "MANUFACTURER")) != NULL)
23455939Snsouch		printf("ppbus%d: <%s", unit,
23528257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
23628257Smsmith	else
23755939Snsouch		printf("ppbus%d: <unknown", unit);
23828257Smsmith
23942475Snsouch	if ((token = search_token(str, len, "MDL")) != NULL ||
24042475Snsouch		(token = search_token(str, len, "MODEL")) != NULL)
24128257Smsmith		printf(" %s",
24228257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
24328257Smsmith	else
24428257Smsmith		printf(" unknown");
24528257Smsmith
24628257Smsmith	if ((token = search_token(str, len, "VER")) != NULL)
24728257Smsmith		printf("/%s",
24828257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
24928257Smsmith
25028257Smsmith	if ((token = search_token(str, len, "REV")) != NULL)
25128257Smsmith		printf(".%s",
25228257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
25328257Smsmith
25428257Smsmith	printf(">");
25528257Smsmith
25628257Smsmith	if ((token = search_token(str, len, "CLS")) != NULL) {
25728257Smsmith		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
25828257Smsmith		printf(" %s", class);
25928257Smsmith	}
26028257Smsmith
26142475Snsouch	if ((token = search_token(str, len, "CMD")) != NULL ||
26242475Snsouch		(token = search_token(str, len, "COMMAND")) != NULL)
26328257Smsmith		printf(" %s",
26428257Smsmith			search_token(token, UNKNOWN_LENGTH, ":") + 1);
26528257Smsmith
26628257Smsmith	printf("\n");
26728257Smsmith
26828257Smsmith	if (class)
26928257Smsmith		/* identify class ident */
27028257Smsmith		for (i = 0; pnp_tokens[i] != NULL; i++) {
27128257Smsmith			if (search_token(class, len, pnp_tokens[i]) != NULL) {
27238061Smsmith				class_id = i;
27338061Smsmith				goto end_detect;
27428257Smsmith			}
27528257Smsmith		}
27628257Smsmith
27738061Smsmith	class_id = PPB_PnP_UNKNOWN;
27838061Smsmith
27938061Smsmithend_detect:
28042475Snsouch	return (class_id);
28142475Snsouch}
28239134Snsouch
28342475Snsouch/*
28442475Snsouch * ppb_scan_bus()
28542475Snsouch *
28642475Snsouch * Scan the ppbus for IEEE1284 compliant devices
28742475Snsouch */
28842475Snsouchstatic int
28955939Snsouchppb_scan_bus(device_t bus)
29042475Snsouch{
29155939Snsouch	struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus);
29242475Snsouch	int error = 0;
29355939Snsouch	int unit = device_get_unit(bus);
29442475Snsouch
29542475Snsouch	/* try all IEEE1284 modes, for one device only
29642475Snsouch	 *
29742475Snsouch	 * XXX We should implement the IEEE1284.3 standard to detect
29842475Snsouch	 * daisy chained devices
29942475Snsouch	 */
30042475Snsouch
30155939Snsouch	error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID);
30242475Snsouch
30342475Snsouch	if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
30442475Snsouch		goto end_scan;
30542475Snsouch
30655939Snsouch	ppb_1284_terminate(bus);
30742475Snsouch
30855939Snsouch	printf("ppbus%d: IEEE1284 device found ", unit);
30942475Snsouch
31055939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) {
31142475Snsouch		printf("/NIBBLE");
31255939Snsouch		ppb_1284_terminate(bus);
31342475Snsouch	}
31442475Snsouch
31555939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) {
31642475Snsouch		printf("/PS2");
31755939Snsouch		ppb_1284_terminate(bus);
31842475Snsouch	}
31942475Snsouch
32055939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) {
32142475Snsouch		printf("/ECP");
32255939Snsouch		ppb_1284_terminate(bus);
32342475Snsouch	}
32442475Snsouch
32555939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) {
32642475Snsouch		printf("/ECP_RLE");
32755939Snsouch		ppb_1284_terminate(bus);
32842475Snsouch	}
32942475Snsouch
33055939Snsouch	if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) {
33142475Snsouch		printf("/EPP");
33255939Snsouch		ppb_1284_terminate(bus);
33342475Snsouch	}
33442475Snsouch
33542536Snsouch	/* try more IEEE1284 modes */
33642536Snsouch	if (bootverbose) {
33755939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE,
33842536Snsouch				PPB_REQUEST_ID))) {
33942536Snsouch			printf("/NIBBLE_ID");
34055939Snsouch			ppb_1284_terminate(bus);
34142536Snsouch		}
34242475Snsouch
34355939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_PS2,
34442536Snsouch				PPB_REQUEST_ID))) {
34542536Snsouch			printf("/PS2_ID");
34655939Snsouch			ppb_1284_terminate(bus);
34742536Snsouch		}
34842475Snsouch
34955939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
35042536Snsouch				PPB_REQUEST_ID))) {
35142536Snsouch			printf("/ECP_ID");
35255939Snsouch			ppb_1284_terminate(bus);
35342536Snsouch		}
35442475Snsouch
35555939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_ECP,
35642536Snsouch				PPB_REQUEST_ID | PPB_USE_RLE))) {
35742536Snsouch			printf("/ECP_RLE_ID");
35855939Snsouch			ppb_1284_terminate(bus);
35942536Snsouch		}
36042475Snsouch
36155939Snsouch		if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE,
36242475Snsouch				PPB_EXTENSIBILITY_LINK))) {
36342536Snsouch			printf("/Extensibility Link");
36455939Snsouch			ppb_1284_terminate(bus);
36542536Snsouch		}
36642536Snsouch	}
36742475Snsouch
36842536Snsouch	printf("\n");
36942536Snsouch
37042475Snsouch	/* detect PnP devices */
37155939Snsouch	ppb->class_id = ppb_pnp_detect(bus);
37242475Snsouch
37342475Snsouch	return (0);
37442475Snsouch
37542475Snsouchend_scan:
37642475Snsouch	return (error);
37728257Smsmith}
37828257Smsmith
37942475Snsouch#endif /* !DONTPROBE_1284 */
38042475Snsouch
38155939Snsouchstatic int
38255939Snsouchppbus_attach(device_t dev)
38328219Smsmith{
38428257Smsmith
38556455Speter	/* Locate our children */
38656455Speter	bus_generic_probe(dev);
38728219Smsmith
38855939Snsouch#ifndef DONTPROBE_1284
38955939Snsouch	/* detect IEEE1284 compliant devices */
39055939Snsouch	ppb_scan_bus(dev);
39155939Snsouch#endif /* !DONTPROBE_1284 */
39228219Smsmith
39355939Snsouch	/* launch attachement of the added children */
39455939Snsouch	bus_generic_attach(dev);
39528219Smsmith
39655939Snsouch	return 0;
39728219Smsmith}
39828219Smsmith
39955939Snsouchstatic int
40055939Snsouchppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
40155939Snsouch			void (*ihand)(void *), void *arg, void **cookiep)
40238061Smsmith{
40355939Snsouch	int error;
40455939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
40555939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
40638061Smsmith
40755939Snsouch	/* a device driver must own the bus to register an interrupt */
40855939Snsouch	if (ppb->ppb_owner != child)
40955939Snsouch		return (EINVAL);
41038061Smsmith
41155939Snsouch	if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
41255939Snsouch					ihand, arg, cookiep)))
41355939Snsouch		return (error);
41438061Smsmith
41555939Snsouch	/* store the resource and the cookie for eventually forcing
41655939Snsouch	 * handler unregistration
41755939Snsouch	 */
41855939Snsouch	ppbdev->intr_cookie = *cookiep;
41955939Snsouch	ppbdev->intr_resource = r;
42028219Smsmith
42128219Smsmith	return (0);
42228219Smsmith}
42328219Smsmith
42455939Snsouchstatic int
42555939Snsouchppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
42628219Smsmith{
42755939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
42855939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
42955939Snsouch
43055939Snsouch	/* a device driver must own the bus to unregister an interrupt */
43155939Snsouch	if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) ||
43255939Snsouch			(ppbdev->intr_resource != r))
43355939Snsouch		return (EINVAL);
43428219Smsmith
43555939Snsouch	ppbdev->intr_cookie = 0;
43655939Snsouch	ppbdev->intr_resource = 0;
43728219Smsmith
43855939Snsouch	/* pass unregistration to the upper layer */
43955939Snsouch	return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
44028219Smsmith}
44128219Smsmith
44228219Smsmith/*
44328257Smsmith * ppb_request_bus()
44428219Smsmith *
44528257Smsmith * Allocate the device to perform transfers.
44628257Smsmith *
44728257Smsmith * how	: PPB_WAIT or PPB_DONTWAIT
44828219Smsmith */
44928219Smsmithint
45055939Snsouchppb_request_bus(device_t bus, device_t dev, int how)
45128219Smsmith{
45228257Smsmith	int s, error = 0;
45355939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
45455939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
45528219Smsmith
45628257Smsmith	while (!error) {
45728257Smsmith		s = splhigh();
45828257Smsmith		if (ppb->ppb_owner) {
45928257Smsmith			splx(s);
46028219Smsmith
46128257Smsmith			switch (how) {
46228257Smsmith			case (PPB_WAIT | PPB_INTR):
46328257Smsmith				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
46428257Smsmith				break;
46528219Smsmith
46628257Smsmith			case (PPB_WAIT | PPB_NOINTR):
46728257Smsmith				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
46828257Smsmith				break;
46928219Smsmith
47028257Smsmith			default:
47128257Smsmith				return (EWOULDBLOCK);
47228257Smsmith				break;
47328257Smsmith			}
47428219Smsmith
47528257Smsmith		} else {
47628257Smsmith			ppb->ppb_owner = dev;
47728219Smsmith
47838061Smsmith			/* restore the context of the device
47938061Smsmith			 * The first time, ctx.valid is certainly false
48038061Smsmith			 * then do not change anything. This is usefull for
48138061Smsmith			 * drivers that do not set there operating mode
48238061Smsmith			 * during attachement
48338061Smsmith			 */
48455939Snsouch			if (ppbdev->ctx.valid)
48555939Snsouch				ppb_set_mode(bus, ppbdev->ctx.mode);
48638061Smsmith
48728257Smsmith			splx(s);
48828257Smsmith			return (0);
48928257Smsmith		}
49028257Smsmith	}
49128219Smsmith
49228257Smsmith	return (error);
49328219Smsmith}
49428219Smsmith
49528219Smsmith/*
49628257Smsmith * ppb_release_bus()
49728219Smsmith *
49860048Sn_hibma * Release the device allocated with ppb_request_bus()
49928219Smsmith */
50028219Smsmithint
50155939Snsouchppb_release_bus(device_t bus, device_t dev)
50228219Smsmith{
50355939Snsouch	int s, error;
50455939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
50555939Snsouch	struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
50628219Smsmith
50755939Snsouch	if (ppbdev->intr_resource != 0)
50855939Snsouch		/* force interrupt handler unregistration when the ppbus is released */
50955939Snsouch		if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource,
51055939Snsouch					       ppbdev->intr_cookie)))
51155939Snsouch			return (error);
51255939Snsouch
51328257Smsmith	s = splhigh();
51428257Smsmith	if (ppb->ppb_owner != dev) {
51528257Smsmith		splx(s);
51628219Smsmith		return (EACCES);
51728257Smsmith	}
51828219Smsmith
51928257Smsmith	ppb->ppb_owner = 0;
52028257Smsmith	splx(s);
52128219Smsmith
52238061Smsmith	/* save the context of the device */
52355939Snsouch	ppbdev->ctx.mode = ppb_get_mode(bus);
52438061Smsmith
52538061Smsmith	/* ok, now the context of the device is valid */
52655939Snsouch	ppbdev->ctx.valid = 1;
52738061Smsmith
52828257Smsmith	/* wakeup waiting processes */
52928257Smsmith	wakeup(ppb);
53028219Smsmith
53128219Smsmith	return (0);
53228219Smsmith}
53355939Snsouch
53456455Speterstatic devclass_t ppbus_devclass;
53556455Speter
53656455Speterstatic device_method_t ppbus_methods[] = {
53756455Speter        /* device interface */
53856455Speter	DEVMETHOD(device_probe,         ppbus_probe),
53956455Speter	DEVMETHOD(device_attach,        ppbus_attach),
54056455Speter
54156455Speter        /* bus interface */
54256455Speter	DEVMETHOD(bus_add_child,	ppbus_add_child),
54356455Speter	DEVMETHOD(bus_print_child,	ppbus_print_child),
54456455Speter	DEVMETHOD(bus_read_ivar,        ppbus_read_ivar),
54556455Speter	DEVMETHOD(bus_write_ivar,       ppbus_write_ivar),
54656455Speter	DEVMETHOD(bus_setup_intr,	ppbus_setup_intr),
54756455Speter	DEVMETHOD(bus_teardown_intr,	ppbus_teardown_intr),
54856455Speter	DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
54956455Speter
55056455Speter        { 0, 0 }
55156455Speter};
55256455Speter
55356455Speterstatic driver_t ppbus_driver = {
55456455Speter        "ppbus",
55556455Speter        ppbus_methods,
55656455Speter        sizeof(struct ppb_data),
55756455Speter};
55855939SnsouchDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);
559