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