ppbconf.c revision 187576
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 187576 2009-01-21 23:10:06Z jhb $"); 3155939Snsouch#include "opt_ppb_1284.h" 3255939Snsouch 3328219Smsmith#include <sys/param.h> 3428219Smsmith#include <sys/systm.h> 3555939Snsouch#include <sys/kernel.h> 36187576Sjhb#include <sys/lock.h> 3755939Snsouch#include <sys/module.h> 38187576Sjhb#include <sys/mutex.h> 3955939Snsouch#include <sys/bus.h> 4028219Smsmith#include <sys/malloc.h> 41175222Sjhb#include <sys/rman.h> 4228219Smsmith 43175222Sjhb#include <machine/resource.h> 44175222Sjhb 4528219Smsmith#include <dev/ppbus/ppbconf.h> 4628257Smsmith#include <dev/ppbus/ppb_1284.h> 4728219Smsmith 4855939Snsouch#include "ppbus_if.h" 49185003Sjhb 5055939Snsouch#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) 51185003Sjhb 5269774Sphkstatic MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); 5342475Snsouch 5428219Smsmith 55187576Sjhbstatic int ppbus_intr(void *arg); 56187576Sjhb 5728219Smsmith/* 5855939Snsouch * Device methods 5928219Smsmith */ 6028219Smsmith 61184130Sjhbstatic int 6255939Snsouchppbus_print_child(device_t bus, device_t dev) 6355939Snsouch{ 6455939Snsouch struct ppb_device *ppbdev; 65184130Sjhb int retval; 6628219Smsmith 67184130Sjhb retval = bus_print_child_header(bus, dev); 6855939Snsouch 6955939Snsouch ppbdev = (struct ppb_device *)device_get_ivars(dev); 7055939Snsouch 7155939Snsouch if (ppbdev->flags != 0) 72184130Sjhb retval += printf(" flags 0x%x", ppbdev->flags); 7355939Snsouch 74184130Sjhb retval += bus_print_child_footer(bus, dev); 7555939Snsouch 76184130Sjhb return (retval); 7755939Snsouch} 7855939Snsouch 7955939Snsouchstatic int 8055939Snsouchppbus_probe(device_t dev) 8155939Snsouch{ 8255939Snsouch device_set_desc(dev, "Parallel port bus"); 8355939Snsouch 8455939Snsouch return (0); 8555939Snsouch} 8655939Snsouch 8728219Smsmith/* 8856455Speter * ppbus_add_child() 8928219Smsmith * 9055939Snsouch * Add a ppbus device, allocate/initialize the ivars 9128219Smsmith */ 9256455Speterstatic device_t 9356455Speterppbus_add_child(device_t dev, int order, const char *name, int unit) 9428219Smsmith{ 9555939Snsouch struct ppb_device *ppbdev; 9655939Snsouch device_t child; 97185003Sjhb 9855939Snsouch /* allocate ivars for the new ppbus child */ 9969781Sdwmalone ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV, 10069781Sdwmalone M_NOWAIT | M_ZERO); 10155939Snsouch if (!ppbdev) 102185003Sjhb return (NULL); 10328219Smsmith 10455939Snsouch /* initialize the ivars */ 10555939Snsouch ppbdev->name = name; 10628219Smsmith 10755939Snsouch /* add the device as a child to the ppbus bus with the allocated 10855939Snsouch * ivars */ 10956455Speter child = device_add_child_ordered(dev, order, name, unit); 11055939Snsouch device_set_ivars(child, ppbdev); 11128219Smsmith 112185003Sjhb return (child); 11355939Snsouch} 11455939Snsouch 11555939Snsouchstatic int 11655939Snsouchppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val) 11756455Speter{ 118185003Sjhb 11955939Snsouch switch (index) { 12055939Snsouch case PPBUS_IVAR_MODE: 12155939Snsouch /* XXX yet device mode = ppbus mode = chipset mode */ 12255939Snsouch *val = (u_long)ppb_get_mode(bus); 12355939Snsouch break; 12455939Snsouch default: 12555939Snsouch return (ENOENT); 12628219Smsmith } 127185003Sjhb 12855939Snsouch return (0); 12928219Smsmith} 130185003Sjhb 13155939Snsouchstatic int 132185003Sjhbppbus_write_ivar(device_t bus, device_t dev, int index, uintptr_t val) 13355939Snsouch{ 13428219Smsmith 13555939Snsouch switch (index) { 13655939Snsouch case PPBUS_IVAR_MODE: 13755939Snsouch /* XXX yet device mode = ppbus mode = chipset mode */ 138184130Sjhb ppb_set_mode(bus, val); 13955939Snsouch break; 14055939Snsouch default: 14155939Snsouch return (ENOENT); 14255939Snsouch } 14355939Snsouch 14455939Snsouch return (0); 145182014Sjhb} 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]; 21328257Smsmith 214184130Sjhb device_printf(bus, "Probing for PnP devices:\n"); 215185003Sjhb 21655939Snsouch if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str, 21742475Snsouch PPB_PnP_STRING_SIZE, &len))) 21838061Smsmith goto end_detect; 21939134Snsouch 22042475Snsouch#ifdef DEBUG_1284 221184130Sjhb device_printf(bus, "<PnP> %d characters: ", len); 22242475Snsouch for (i = 0; i < len; i++) 22342475Snsouch printf("%c(0x%x) ", str[i], str[i]); 22442475Snsouch printf("\n"); 22542475Snsouch#endif 22628257Smsmith 22728257Smsmith /* replace ';' characters by '\0' */ 22828257Smsmith for (i = 0; i < len; i++) 22928257Smsmith str[i] = (str[i] == ';') ? '\0' : str[i]; 23028257Smsmith 23142475Snsouch if ((token = search_token(str, len, "MFG")) != NULL || 23242475Snsouch (token = search_token(str, len, "MANUFACTURER")) != NULL) 233184130Sjhb device_printf(bus, "<%s", 23428257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 23528257Smsmith else 236184130Sjhb device_printf(bus, "<unknown"); 23728257Smsmith 23842475Snsouch if ((token = search_token(str, len, "MDL")) != NULL || 23942475Snsouch (token = search_token(str, len, "MODEL")) != NULL) 24028257Smsmith printf(" %s", 24128257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 24228257Smsmith else 24328257Smsmith printf(" unknown"); 24428257Smsmith 24528257Smsmith if ((token = search_token(str, len, "VER")) != NULL) 24628257Smsmith printf("/%s", 24728257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 24828257Smsmith 24928257Smsmith if ((token = search_token(str, len, "REV")) != NULL) 25028257Smsmith printf(".%s", 25128257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 25228257Smsmith 25328257Smsmith printf(">"); 25428257Smsmith 25528257Smsmith if ((token = search_token(str, len, "CLS")) != NULL) { 25628257Smsmith class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 25728257Smsmith printf(" %s", class); 25828257Smsmith } 25928257Smsmith 26042475Snsouch if ((token = search_token(str, len, "CMD")) != NULL || 26142475Snsouch (token = search_token(str, len, "COMMAND")) != NULL) 26228257Smsmith printf(" %s", 26328257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 26428257Smsmith 26528257Smsmith printf("\n"); 26628257Smsmith 26728257Smsmith if (class) 26828257Smsmith /* identify class ident */ 26928257Smsmith for (i = 0; pnp_tokens[i] != NULL; i++) { 27028257Smsmith if (search_token(class, len, pnp_tokens[i]) != NULL) { 27138061Smsmith class_id = i; 27238061Smsmith goto end_detect; 27328257Smsmith } 27428257Smsmith } 27528257Smsmith 27638061Smsmith class_id = PPB_PnP_UNKNOWN; 27738061Smsmith 27838061Smsmithend_detect: 27942475Snsouch return (class_id); 28042475Snsouch} 28139134Snsouch 28242475Snsouch/* 28342475Snsouch * ppb_scan_bus() 28442475Snsouch * 28542475Snsouch * Scan the ppbus for IEEE1284 compliant devices 28642475Snsouch */ 28742475Snsouchstatic int 28855939Snsouchppb_scan_bus(device_t bus) 28942475Snsouch{ 29055939Snsouch struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus); 29142475Snsouch int error = 0; 29242475Snsouch 29342475Snsouch /* try all IEEE1284 modes, for one device only 294185003Sjhb * 29542475Snsouch * XXX We should implement the IEEE1284.3 standard to detect 29642475Snsouch * daisy chained devices 29742475Snsouch */ 29842475Snsouch 29955939Snsouch error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID); 30042475Snsouch 30142475Snsouch if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) 30242475Snsouch goto end_scan; 30342475Snsouch 30455939Snsouch ppb_1284_terminate(bus); 30542475Snsouch 306184130Sjhb device_printf(bus, "IEEE1284 device found "); 30742475Snsouch 30855939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) { 30942475Snsouch printf("/NIBBLE"); 31055939Snsouch ppb_1284_terminate(bus); 31142475Snsouch } 31242475Snsouch 31355939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) { 31442475Snsouch printf("/PS2"); 31555939Snsouch ppb_1284_terminate(bus); 31642475Snsouch } 31742475Snsouch 31855939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) { 31942475Snsouch printf("/ECP"); 32055939Snsouch ppb_1284_terminate(bus); 32142475Snsouch } 32242475Snsouch 32355939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) { 32442475Snsouch printf("/ECP_RLE"); 32555939Snsouch ppb_1284_terminate(bus); 32642475Snsouch } 32742475Snsouch 32855939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) { 32942475Snsouch printf("/EPP"); 33055939Snsouch ppb_1284_terminate(bus); 33142475Snsouch } 33242475Snsouch 33342536Snsouch /* try more IEEE1284 modes */ 33442536Snsouch if (bootverbose) { 33555939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 33642536Snsouch PPB_REQUEST_ID))) { 33742536Snsouch printf("/NIBBLE_ID"); 33855939Snsouch ppb_1284_terminate(bus); 33942536Snsouch } 34042475Snsouch 34155939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_PS2, 34242536Snsouch PPB_REQUEST_ID))) { 34342536Snsouch printf("/PS2_ID"); 34455939Snsouch ppb_1284_terminate(bus); 34542536Snsouch } 34642475Snsouch 34755939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_ECP, 34842536Snsouch PPB_REQUEST_ID))) { 34942536Snsouch printf("/ECP_ID"); 35055939Snsouch ppb_1284_terminate(bus); 35142536Snsouch } 35242475Snsouch 35355939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_ECP, 35442536Snsouch PPB_REQUEST_ID | PPB_USE_RLE))) { 35542536Snsouch printf("/ECP_RLE_ID"); 35655939Snsouch ppb_1284_terminate(bus); 35742536Snsouch } 35842475Snsouch 35955939Snsouch if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE, 36042475Snsouch PPB_EXTENSIBILITY_LINK))) { 36142536Snsouch printf("/Extensibility Link"); 36255939Snsouch ppb_1284_terminate(bus); 36342536Snsouch } 36442536Snsouch } 36542475Snsouch 36642536Snsouch printf("\n"); 36742536Snsouch 36842475Snsouch /* detect PnP devices */ 36955939Snsouch ppb->class_id = ppb_pnp_detect(bus); 37042475Snsouch 37142475Snsouch return (0); 37242475Snsouch 37342475Snsouchend_scan: 37442475Snsouch return (error); 37528257Smsmith} 37628257Smsmith 37742475Snsouch#endif /* !DONTPROBE_1284 */ 37842475Snsouch 37955939Snsouchstatic int 38055939Snsouchppbus_attach(device_t dev) 38128219Smsmith{ 382187576Sjhb struct ppb_data *ppb = device_get_softc(dev); 383187576Sjhb int error, rid; 38428257Smsmith 385187576Sjhb error = BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_LOCK, 386187576Sjhb (uintptr_t *)&ppb->ppc_lock); 387187576Sjhb if (error) { 388187576Sjhb device_printf(dev, "Unable to fetch parent's lock\n"); 389187576Sjhb return (error); 390187576Sjhb } 391187576Sjhb 392187576Sjhb rid = 0; 393187576Sjhb ppb->ppc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 394187576Sjhb RF_SHAREABLE); 395187576Sjhb if (ppb->ppc_irq_res != NULL) { 396187576Sjhb error = BUS_WRITE_IVAR(device_get_parent(dev), dev, 397187576Sjhb PPC_IVAR_INTR_HANDLER, (uintptr_t)&ppbus_intr); 398187576Sjhb if (error) { 399187576Sjhb device_printf(dev, "Unable to set interrupt handler\n"); 400187576Sjhb return (error); 401187576Sjhb } 402187576Sjhb } 403187576Sjhb 40456455Speter /* Locate our children */ 40556455Speter bus_generic_probe(dev); 40628219Smsmith 40755939Snsouch#ifndef DONTPROBE_1284 40855939Snsouch /* detect IEEE1284 compliant devices */ 409187576Sjhb mtx_lock(ppb->ppc_lock); 41055939Snsouch ppb_scan_bus(dev); 411187576Sjhb mtx_unlock(ppb->ppc_lock); 41255939Snsouch#endif /* !DONTPROBE_1284 */ 41328219Smsmith 414185003Sjhb /* launch attachment of the added children */ 41555939Snsouch bus_generic_attach(dev); 41628219Smsmith 417184130Sjhb return (0); 41828219Smsmith} 41928219Smsmith 42055939Snsouchstatic int 421157774Siwasakippbus_detach(device_t dev) 422157774Siwasaki{ 423185003Sjhb device_t *children; 424185003Sjhb int error, nchildren, i; 425157774Siwasaki 426184130Sjhb error = bus_generic_detach(dev); 427184130Sjhb if (error) 428184130Sjhb return (error); 429184130Sjhb 430157774Siwasaki /* detach & delete all children */ 431157774Siwasaki if (!device_get_children(dev, &children, &nchildren)) { 432157774Siwasaki for (i = 0; i < nchildren; i++) 433157774Siwasaki if (children[i]) 434157774Siwasaki device_delete_child(dev, children[i]); 435157774Siwasaki free(children, M_TEMP); 436185003Sjhb } 437157774Siwasaki 438157774Siwasaki return (0); 439157774Siwasaki} 440157774Siwasaki 441157774Siwasakistatic int 442187576Sjhbppbus_intr(void *arg) 443187576Sjhb{ 444187576Sjhb struct ppb_device *ppbdev; 445187576Sjhb struct ppb_data *ppb = arg; 446187576Sjhb 447187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 448187576Sjhb if (ppb->ppb_owner == NULL) 449187576Sjhb return (ENOENT); 450187576Sjhb 451187576Sjhb ppbdev = device_get_ivars(ppb->ppb_owner); 452187576Sjhb if (ppbdev->intr_hook == NULL) 453187576Sjhb return (ENOENT); 454187576Sjhb 455187576Sjhb ppbdev->intr_hook(ppbdev->intr_arg); 456187576Sjhb return (0); 457187576Sjhb} 458187576Sjhb 459187576Sjhbstatic int 46055939Snsouchppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 461166901Spiso driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) 46238061Smsmith{ 463187576Sjhb struct ppb_device *ppbdev = device_get_ivars(child); 46455939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 46538061Smsmith 466187576Sjhb /* We do not support filters. */ 467187576Sjhb if (filt != NULL || ihand == NULL) 46855939Snsouch return (EINVAL); 46938061Smsmith 470187576Sjhb /* Can only attach handlers to the parent device's resource. */ 471187576Sjhb if (ppb->ppc_irq_res != r) 472187576Sjhb return (EINVAL); 47338061Smsmith 474187576Sjhb mtx_lock(ppb->ppc_lock); 475187576Sjhb ppbdev->intr_hook = ihand; 476187576Sjhb ppbdev->intr_arg = arg; 477187576Sjhb *cookiep = ppbdev; 478187576Sjhb mtx_unlock(ppb->ppc_lock); 47928219Smsmith 48028219Smsmith return (0); 48128219Smsmith} 48228219Smsmith 48355939Snsouchstatic int 48455939Snsouchppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 48528219Smsmith{ 486187576Sjhb struct ppb_device *ppbdev = device_get_ivars(child); 48755939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 488185003Sjhb 489187576Sjhb mtx_lock(ppb->ppc_lock); 490187576Sjhb if (ppbdev != ih || ppb->ppc_irq_res != r) { 491187576Sjhb mtx_unlock(ppb->ppc_lock); 49255939Snsouch return (EINVAL); 493187576Sjhb } 49428219Smsmith 495187576Sjhb ppbdev->intr_hook = NULL; 496187576Sjhb mtx_unlock(ppb->ppc_lock); 49728219Smsmith 498187576Sjhb return (0); 49928219Smsmith} 50028219Smsmith 50128219Smsmith/* 50228257Smsmith * ppb_request_bus() 50328219Smsmith * 50428257Smsmith * Allocate the device to perform transfers. 50528257Smsmith * 50628257Smsmith * how : PPB_WAIT or PPB_DONTWAIT 50728219Smsmith */ 50828219Smsmithint 50955939Snsouchppb_request_bus(device_t bus, device_t dev, int how) 51028219Smsmith{ 51155939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 51255939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 513187576Sjhb int error = 0; 51428219Smsmith 515187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 51628257Smsmith while (!error) { 51728257Smsmith if (ppb->ppb_owner) { 51828257Smsmith switch (how) { 519187576Sjhb case PPB_WAIT | PPB_INTR: 520187576Sjhb error = mtx_sleep(ppb, ppb->ppc_lock, 521187576Sjhb PPBPRI | PCATCH, "ppbreq", 0); 52228257Smsmith break; 52328219Smsmith 524187576Sjhb case PPB_WAIT | PPB_NOINTR: 525187576Sjhb error = mtx_sleep(ppb, ppb->ppc_lock, PPBPRI, 526187576Sjhb "ppbreq", 0); 52728257Smsmith break; 52828219Smsmith 52928257Smsmith default: 53028257Smsmith return (EWOULDBLOCK); 53128257Smsmith } 53228219Smsmith 53328257Smsmith } else { 53428257Smsmith ppb->ppb_owner = dev; 53528219Smsmith 53638061Smsmith /* restore the context of the device 53738061Smsmith * The first time, ctx.valid is certainly false 53838061Smsmith * then do not change anything. This is usefull for 539185003Sjhb * drivers that do not set there operating mode 54038061Smsmith * during attachement 54138061Smsmith */ 54255939Snsouch if (ppbdev->ctx.valid) 54355939Snsouch ppb_set_mode(bus, ppbdev->ctx.mode); 54438061Smsmith 54528257Smsmith return (0); 54628257Smsmith } 54728257Smsmith } 54828219Smsmith 54928257Smsmith return (error); 55028219Smsmith} 55128219Smsmith 55228219Smsmith/* 55328257Smsmith * ppb_release_bus() 55428219Smsmith * 55560048Sn_hibma * Release the device allocated with ppb_request_bus() 55628219Smsmith */ 55728219Smsmithint 55855939Snsouchppb_release_bus(device_t bus, device_t dev) 55928219Smsmith{ 56055939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 56155939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 56228219Smsmith 563187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 564187576Sjhb if (ppb->ppb_owner != dev) 56528219Smsmith return (EACCES); 56628219Smsmith 56738061Smsmith /* save the context of the device */ 56855939Snsouch ppbdev->ctx.mode = ppb_get_mode(bus); 56938061Smsmith 57038061Smsmith /* ok, now the context of the device is valid */ 57155939Snsouch ppbdev->ctx.valid = 1; 57238061Smsmith 573187576Sjhb ppb->ppb_owner = 0; 574187576Sjhb 57528257Smsmith /* wakeup waiting processes */ 57628257Smsmith wakeup(ppb); 57728219Smsmith 57828219Smsmith return (0); 57928219Smsmith} 58055939Snsouch 58156455Speterstatic devclass_t ppbus_devclass; 58256455Speter 58356455Speterstatic device_method_t ppbus_methods[] = { 584185003Sjhb /* device interface */ 585185003Sjhb DEVMETHOD(device_probe, ppbus_probe), 586185003Sjhb DEVMETHOD(device_attach, ppbus_attach), 587185003Sjhb DEVMETHOD(device_detach, ppbus_detach), 588185003Sjhb 589185003Sjhb /* bus interface */ 59056455Speter DEVMETHOD(bus_add_child, ppbus_add_child), 59156455Speter DEVMETHOD(bus_print_child, ppbus_print_child), 592185003Sjhb DEVMETHOD(bus_read_ivar, ppbus_read_ivar), 593185003Sjhb DEVMETHOD(bus_write_ivar, ppbus_write_ivar), 59456455Speter DEVMETHOD(bus_setup_intr, ppbus_setup_intr), 59556455Speter DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), 596183053Sjhb DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 597185003Sjhb DEVMETHOD(bus_release_resource, bus_generic_release_resource), 59856455Speter 599185003Sjhb { 0, 0 } 60056455Speter}; 60156455Speter 60256455Speterstatic driver_t ppbus_driver = { 603185003Sjhb "ppbus", 604185003Sjhb ppbus_methods, 605185003Sjhb sizeof(struct ppb_data), 60656455Speter}; 60755939SnsouchDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0); 608