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