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