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$"); 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 93212413Savgppbus_add_child(device_t dev, u_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) { 396187714Sjhb mtx_lock(ppb->ppc_lock); 397187576Sjhb error = BUS_WRITE_IVAR(device_get_parent(dev), dev, 398187576Sjhb PPC_IVAR_INTR_HANDLER, (uintptr_t)&ppbus_intr); 399187714Sjhb mtx_unlock(ppb->ppc_lock); 400187576Sjhb if (error) { 401187576Sjhb device_printf(dev, "Unable to set interrupt handler\n"); 402187576Sjhb return (error); 403187576Sjhb } 404187576Sjhb } 405187576Sjhb 40656455Speter /* Locate our children */ 40756455Speter bus_generic_probe(dev); 40828219Smsmith 40955939Snsouch#ifndef DONTPROBE_1284 41055939Snsouch /* detect IEEE1284 compliant devices */ 411187576Sjhb mtx_lock(ppb->ppc_lock); 41255939Snsouch ppb_scan_bus(dev); 413187576Sjhb mtx_unlock(ppb->ppc_lock); 41455939Snsouch#endif /* !DONTPROBE_1284 */ 41528219Smsmith 416185003Sjhb /* launch attachment of the added children */ 41755939Snsouch bus_generic_attach(dev); 41828219Smsmith 419184130Sjhb return (0); 42028219Smsmith} 42128219Smsmith 42255939Snsouchstatic int 423157774Siwasakippbus_detach(device_t dev) 424157774Siwasaki{ 425229118Shselasky int error; 426157774Siwasaki 427184130Sjhb error = bus_generic_detach(dev); 428184130Sjhb if (error) 429184130Sjhb return (error); 430184130Sjhb 431157774Siwasaki /* detach & delete all children */ 432229118Shselasky device_delete_children(dev); 433157774Siwasaki 434157774Siwasaki return (0); 435157774Siwasaki} 436157774Siwasaki 437157774Siwasakistatic int 438187576Sjhbppbus_intr(void *arg) 439187576Sjhb{ 440187576Sjhb struct ppb_device *ppbdev; 441187576Sjhb struct ppb_data *ppb = arg; 442187576Sjhb 443187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 444187576Sjhb if (ppb->ppb_owner == NULL) 445187576Sjhb return (ENOENT); 446187576Sjhb 447187576Sjhb ppbdev = device_get_ivars(ppb->ppb_owner); 448187576Sjhb if (ppbdev->intr_hook == NULL) 449187576Sjhb return (ENOENT); 450187576Sjhb 451187576Sjhb ppbdev->intr_hook(ppbdev->intr_arg); 452187576Sjhb return (0); 453187576Sjhb} 454187576Sjhb 455187576Sjhbstatic int 45655939Snsouchppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 457166901Spiso driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) 45838061Smsmith{ 459187576Sjhb struct ppb_device *ppbdev = device_get_ivars(child); 46055939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 46138061Smsmith 462187576Sjhb /* We do not support filters. */ 463187576Sjhb if (filt != NULL || ihand == NULL) 46455939Snsouch return (EINVAL); 46538061Smsmith 466187576Sjhb /* Can only attach handlers to the parent device's resource. */ 467187576Sjhb if (ppb->ppc_irq_res != r) 468187576Sjhb return (EINVAL); 46938061Smsmith 470187576Sjhb mtx_lock(ppb->ppc_lock); 471187576Sjhb ppbdev->intr_hook = ihand; 472187576Sjhb ppbdev->intr_arg = arg; 473187576Sjhb *cookiep = ppbdev; 474187576Sjhb mtx_unlock(ppb->ppc_lock); 47528219Smsmith 47628219Smsmith return (0); 47728219Smsmith} 47828219Smsmith 47955939Snsouchstatic int 48055939Snsouchppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 48128219Smsmith{ 482187576Sjhb struct ppb_device *ppbdev = device_get_ivars(child); 48355939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 484185003Sjhb 485187576Sjhb mtx_lock(ppb->ppc_lock); 486187576Sjhb if (ppbdev != ih || ppb->ppc_irq_res != r) { 487187576Sjhb mtx_unlock(ppb->ppc_lock); 48855939Snsouch return (EINVAL); 489187576Sjhb } 49028219Smsmith 491187576Sjhb ppbdev->intr_hook = NULL; 492187576Sjhb mtx_unlock(ppb->ppc_lock); 49328219Smsmith 494187576Sjhb return (0); 49528219Smsmith} 49628219Smsmith 49728219Smsmith/* 49828257Smsmith * ppb_request_bus() 49928219Smsmith * 50028257Smsmith * Allocate the device to perform transfers. 50128257Smsmith * 50228257Smsmith * how : PPB_WAIT or PPB_DONTWAIT 50328219Smsmith */ 50428219Smsmithint 50555939Snsouchppb_request_bus(device_t bus, device_t dev, int how) 50628219Smsmith{ 50755939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 50855939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 509187576Sjhb int error = 0; 51028219Smsmith 511187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 51228257Smsmith while (!error) { 51328257Smsmith if (ppb->ppb_owner) { 51428257Smsmith switch (how) { 515187576Sjhb case PPB_WAIT | PPB_INTR: 516187576Sjhb error = mtx_sleep(ppb, ppb->ppc_lock, 517187576Sjhb PPBPRI | PCATCH, "ppbreq", 0); 51828257Smsmith break; 51928219Smsmith 520187576Sjhb case PPB_WAIT | PPB_NOINTR: 521187576Sjhb error = mtx_sleep(ppb, ppb->ppc_lock, PPBPRI, 522187576Sjhb "ppbreq", 0); 52328257Smsmith break; 52428219Smsmith 52528257Smsmith default: 52628257Smsmith return (EWOULDBLOCK); 52728257Smsmith } 52828219Smsmith 52928257Smsmith } else { 53028257Smsmith ppb->ppb_owner = dev; 53128219Smsmith 53238061Smsmith /* restore the context of the device 53338061Smsmith * The first time, ctx.valid is certainly false 53438061Smsmith * then do not change anything. This is usefull for 535185003Sjhb * drivers that do not set there operating mode 53638061Smsmith * during attachement 53738061Smsmith */ 53855939Snsouch if (ppbdev->ctx.valid) 53955939Snsouch ppb_set_mode(bus, ppbdev->ctx.mode); 54038061Smsmith 54128257Smsmith return (0); 54228257Smsmith } 54328257Smsmith } 54428219Smsmith 54528257Smsmith return (error); 54628219Smsmith} 54728219Smsmith 54828219Smsmith/* 54928257Smsmith * ppb_release_bus() 55028219Smsmith * 55160048Sn_hibma * Release the device allocated with ppb_request_bus() 55228219Smsmith */ 55328219Smsmithint 55455939Snsouchppb_release_bus(device_t bus, device_t dev) 55528219Smsmith{ 55655939Snsouch struct ppb_data *ppb = DEVTOSOFTC(bus); 55755939Snsouch struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 55828219Smsmith 559187576Sjhb mtx_assert(ppb->ppc_lock, MA_OWNED); 560187576Sjhb if (ppb->ppb_owner != dev) 56128219Smsmith return (EACCES); 56228219Smsmith 56338061Smsmith /* save the context of the device */ 56455939Snsouch ppbdev->ctx.mode = ppb_get_mode(bus); 56538061Smsmith 56638061Smsmith /* ok, now the context of the device is valid */ 56755939Snsouch ppbdev->ctx.valid = 1; 56838061Smsmith 569187576Sjhb ppb->ppb_owner = 0; 570187576Sjhb 57128257Smsmith /* wakeup waiting processes */ 57228257Smsmith wakeup(ppb); 57328219Smsmith 57428219Smsmith return (0); 57528219Smsmith} 57655939Snsouch 57756455Speterstatic devclass_t ppbus_devclass; 57856455Speter 57956455Speterstatic device_method_t ppbus_methods[] = { 580185003Sjhb /* device interface */ 581185003Sjhb DEVMETHOD(device_probe, ppbus_probe), 582185003Sjhb DEVMETHOD(device_attach, ppbus_attach), 583185003Sjhb DEVMETHOD(device_detach, ppbus_detach), 584185003Sjhb 585185003Sjhb /* bus interface */ 58656455Speter DEVMETHOD(bus_add_child, ppbus_add_child), 58756455Speter DEVMETHOD(bus_print_child, ppbus_print_child), 588185003Sjhb DEVMETHOD(bus_read_ivar, ppbus_read_ivar), 589185003Sjhb DEVMETHOD(bus_write_ivar, ppbus_write_ivar), 59056455Speter DEVMETHOD(bus_setup_intr, ppbus_setup_intr), 59156455Speter DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), 592183053Sjhb DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 593185003Sjhb DEVMETHOD(bus_release_resource, bus_generic_release_resource), 59456455Speter 595185003Sjhb { 0, 0 } 59656455Speter}; 59756455Speter 59856455Speterstatic driver_t ppbus_driver = { 599185003Sjhb "ppbus", 600185003Sjhb ppbus_methods, 601185003Sjhb sizeof(struct ppb_data), 60256455Speter}; 60355939SnsouchDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0); 604