ppbconf.c revision 182014
16059Samurai/*- 26059Samurai * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 36059Samurai * All rights reserved. 46059Samurai * 56059Samurai * Redistribution and use in source and binary forms, with or without 66059Samurai * modification, are permitted provided that the following conditions 76059Samurai * are met: 86059Samurai * 1. Redistributions of source code must retain the above copyright 96059Samurai * notice, this list of conditions and the following disclaimer. 106059Samurai * 2. Redistributions in binary form must reproduce the above copyright 116059Samurai * notice, this list of conditions and the following disclaimer in the 126059Samurai * documentation and/or other materials provided with the distribution. 136059Samurai * 146059Samurai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156059Samurai * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166059Samurai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176059Samurai * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186059Samurai * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198857Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031962Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218857Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226059Samurai * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2330715Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2430715Sbrian * SUCH DAMAGE. 2526031Sbrian * 2630715Sbrian * 2726031Sbrian */ 2830715Sbrian 2926031Sbrian#include <sys/cdefs.h> 3030715Sbrian__FBSDID("$FreeBSD: head/sys/dev/ppbus/ppbconf.c 182014 2008-08-22 18:42:18Z jhb $"); 3130715Sbrian#include "opt_ppb_1284.h" 3231343Sbrian 3326031Sbrian#include <sys/param.h> 3431343Sbrian#include <sys/systm.h> 3530715Sbrian#include <sys/kernel.h> 3630715Sbrian#include <sys/module.h> 3726516Sbrian#include <sys/bus.h> 3830715Sbrian#include <sys/malloc.h> 3930715Sbrian#include <sys/rman.h> 4030715Sbrian 4130715Sbrian#include <machine/resource.h> 4230715Sbrian 4330715Sbrian#include <dev/ppbus/ppbconf.h> 4430715Sbrian#include <dev/ppbus/ppb_1284.h> 4530715Sbrian 4630715Sbrian#include "ppbus_if.h" 4730715Sbrian 4831343Sbrian#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) 4930715Sbrian 5030715Sbrianstatic MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); 5130715Sbrian 5230715Sbrian 536059Samurai/* 546059Samurai * Device methods 556059Samurai */ 5631690Sbrian 576059Samuraistatic void 586059Samuraippbus_print_child(device_t bus, device_t dev) 5913389Sphk{ 6031343Sbrian struct ppb_device *ppbdev; 6126031Sbrian 6231343Sbrian bus_print_child_header(bus, dev); 636059Samurai 6426142Sbrian ppbdev = (struct ppb_device *)device_get_ivars(dev); 656059Samurai 6625630Sbrian if (ppbdev->flags != 0) 6725630Sbrian printf(" flags 0x%x", ppbdev->flags); 686059Samurai 6926940Sbrian printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus)); 7030715Sbrian 7130715Sbrian return; 7230715Sbrian} 7330733Sbrian 7430715Sbrianstatic int 7531080Sbrianppbus_probe(device_t dev) 766059Samurai{ 776059Samurai device_set_desc(dev, "Parallel port bus"); 7831822Sbrian 796059Samurai return (0); 8031343Sbrian} 8131343Sbrian 8231343Sbrian/* 8331343Sbrian * ppbus_add_child() 8431343Sbrian * 8531343Sbrian * Add a ppbus device, allocate/initialize the ivars 8631343Sbrian */ 8731343Sbrianstatic device_t 8831343Sbrianppbus_add_child(device_t dev, int order, const char *name, int unit) 8931343Sbrian{ 9031343Sbrian struct ppb_device *ppbdev; 9131343Sbrian device_t child; 9231343Sbrian 9331343Sbrian /* allocate ivars for the new ppbus child */ 9431343Sbrian ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV, 9531343Sbrian M_NOWAIT | M_ZERO); 9631343Sbrian if (!ppbdev) 976059Samurai return NULL; 986059Samurai 9931343Sbrian /* initialize the ivars */ 1006059Samurai ppbdev->name = name; 10128679Sbrian 10231372Sbrian /* add the device as a child to the ppbus bus with the allocated 1036059Samurai * ivars */ 10426516Sbrian child = device_add_child_ordered(dev, order, name, unit); 10526516Sbrian device_set_ivars(child, ppbdev); 10626516Sbrian 10731343Sbrian return child; 10831343Sbrian} 10931372Sbrian 11031372Sbrianstatic int 11128679Sbrianppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val) 11228679Sbrian{ 1136059Samurai struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 11426516Sbrian 1156059Samurai switch (index) { 11631372Sbrian case PPBUS_IVAR_MODE: 11731372Sbrian /* XXX yet device mode = ppbus mode = chipset mode */ 11831372Sbrian *val = (u_long)ppb_get_mode(bus); 11931372Sbrian ppbdev->mode = (u_short)*val; 12031372Sbrian break; 12131372Sbrian case PPBUS_IVAR_AVM: 12231372Sbrian *val = (u_long)ppbdev->avm; 12331372Sbrian break; 12431372Sbrian case PPBUS_IVAR_IRQ: 12531372Sbrian BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val); 1266059Samurai break; 12731343Sbrian default: 1286764Samurai return (ENOENT); 12931372Sbrian } 13031372Sbrian 13131372Sbrian return (0); 13231372Sbrian} 1336059Samurai 13431372Sbrianstatic int 13526516Sbrianppbus_write_ivar(device_t bus, device_t dev, int index, u_long val) 13626516Sbrian{ 13726516Sbrian struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 1386059Samurai 1396059Samurai switch (index) { 1406059Samurai case PPBUS_IVAR_MODE: 14130913Sbrian /* XXX yet device mode = ppbus mode = chipset mode */ 1426059Samurai ppb_set_mode(bus,val); 14331343Sbrian ppbdev->mode = ppb_get_mode(bus); 1446059Samurai break; 14520120Snate default: 14620120Snate return (ENOENT); 14725908Sbrian } 14825908Sbrian 14920120Snate return (0); 15010528Samurai} 1516059Samurai 15210528Samurai#define PPB_PNP_PRINTER 0 1536059Samurai#define PPB_PNP_MODEM 1 15410528Samurai#define PPB_PNP_NET 2 1556059Samurai#define PPB_PNP_HDC 3 15630913Sbrian#define PPB_PNP_PCMCIA 4 15726516Sbrian#define PPB_PNP_MEDIA 5 15826516Sbrian#define PPB_PNP_FDC 6 1596059Samurai#define PPB_PNP_PORTS 7 16026516Sbrian#define PPB_PNP_SCANNER 8 1616059Samurai#define PPB_PNP_DIGICAM 9 1626059Samurai 1636059Samurai#ifndef DONTPROBE_1284 16431343Sbrian 1656059Samuraistatic char *pnp_tokens[] = { 16611336Samurai "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 16726858Sbrian "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 16811336Samurai 1696059Samurai#if 0 17026516Sbrianstatic char *pnp_classes[] = { 17126516Sbrian "printer", "modem", "network device", 17226516Sbrian "hard disk", "PCMCIA", "multimedia device", 1736059Samurai "floppy disk", "ports", "scanner", 17426516Sbrian "digital camera", "unknown device", NULL }; 17531343Sbrian#endif 17631140Sbrian 17731121Sbrian/* 17811336Samurai * search_token() 17911336Samurai * 18026516Sbrian * Search the first occurence of a token within a string 18126516Sbrian */ 18231034Sbrianstatic char * 18326516Sbriansearch_token(char *str, int slen, char *token) 18428679Sbrian{ 18511336Samurai int tlen, i; 18611336Samurai 18726858Sbrian#define UNKNOWN_LENGTH -1 18830697Sbrian 18931343Sbrian if (slen == UNKNOWN_LENGTH) 19011336Samurai /* get string's length */ 19111336Samurai slen = strlen(str); 19226858Sbrian 19326858Sbrian /* get token's length */ 19411336Samurai tlen = strlen(token); 19526516Sbrian if (tlen == 0) 19626516Sbrian return (str); 1976059Samurai 1986059Samurai for (i = 0; i <= slen-tlen; i++) { 19910528Samurai if (strncmp(str + i, token, tlen) == 0) 20031343Sbrian return (&str[i]); 20128536Sbrian } 20231343Sbrian 20331343Sbrian return (NULL); 20428536Sbrian} 20531141Sbrian 20631141Sbrian/* 20731343Sbrian * ppb_pnp_detect() 20828536Sbrian * 20931141Sbrian * Returns the class id. of the peripherial, -1 otherwise 21031141Sbrian */ 21128536Sbrianstatic int 21228536Sbrianppb_pnp_detect(device_t bus) 21328536Sbrian{ 21428536Sbrian char *token, *class = 0; 21531343Sbrian int i, len, error; 21610528Samurai int class_id = -1; 21710528Samurai char str[PPB_PnP_STRING_SIZE+1]; 21810528Samurai int unit = device_get_unit(bus); 21926516Sbrian 22031343Sbrian printf("Probing for PnP devices on ppbus%d:\n", unit); 22131343Sbrian 22220813Sjkh if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str, 22318856Ssos PPB_PnP_STRING_SIZE, &len))) 22426911Sbrian goto end_detect; 22526516Sbrian 22626516Sbrian#ifdef DEBUG_1284 22726516Sbrian printf("ppb: <PnP> %d characters: ", len); 22810528Samurai for (i = 0; i < len; i++) 22926911Sbrian printf("%c(0x%x) ", str[i], str[i]); 23026911Sbrian printf("\n"); 23128679Sbrian#endif 23226911Sbrian 23328679Sbrian /* replace ';' characters by '\0' */ 23428679Sbrian for (i = 0; i < len; i++) 23526911Sbrian str[i] = (str[i] == ';') ? '\0' : str[i]; 23631121Sbrian 23728679Sbrian if ((token = search_token(str, len, "MFG")) != NULL || 23826516Sbrian (token = search_token(str, len, "MANUFACTURER")) != NULL) 23926516Sbrian printf("ppbus%d: <%s", unit, 24026516Sbrian search_token(token, UNKNOWN_LENGTH, ":") + 1); 24126516Sbrian else 24231343Sbrian printf("ppbus%d: <unknown", unit); 24328381Sbrian 24431121Sbrian if ((token = search_token(str, len, "MDL")) != NULL || 24531121Sbrian (token = search_token(str, len, "MODEL")) != NULL) 24631121Sbrian printf(" %s", 24731121Sbrian search_token(token, UNKNOWN_LENGTH, ":") + 1); 24831121Sbrian else 24931121Sbrian printf(" unknown"); 25028381Sbrian 25128381Sbrian if ((token = search_token(str, len, "VER")) != NULL) 25228381Sbrian printf("/%s", 25328679Sbrian search_token(token, UNKNOWN_LENGTH, ":") + 1); 25428381Sbrian 25528381Sbrian if ((token = search_token(str, len, "REV")) != NULL) 25628679Sbrian printf(".%s", 25726516Sbrian search_token(token, UNKNOWN_LENGTH, ":") + 1); 25826516Sbrian 25928679Sbrian printf(">"); 26028679Sbrian 26118531Sbde if ((token = search_token(str, len, "CLS")) != NULL) { 26228679Sbrian class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 26328679Sbrian printf(" %s", class); 26428679Sbrian } 26528679Sbrian 26628679Sbrian if ((token = search_token(str, len, "CMD")) != NULL || 26728679Sbrian (token = search_token(str, len, "COMMAND")) != NULL) 26828679Sbrian printf(" %s", 26928679Sbrian search_token(token, UNKNOWN_LENGTH, ":") + 1); 27026516Sbrian 27128679Sbrian printf("\n"); 27228679Sbrian 27328679Sbrian if (class) 27428679Sbrian /* identify class ident */ 27528679Sbrian for (i = 0; pnp_tokens[i] != NULL; i++) { 27628679Sbrian if (search_token(class, len, pnp_tokens[i]) != NULL) { 27728679Sbrian class_id = i; 27828679Sbrian goto end_detect; 27926516Sbrian } 28028679Sbrian } 28131343Sbrian 28226516Sbrian class_id = PPB_PnP_UNKNOWN; 28328679Sbrian 28431061Sbrianend_detect: 28531343Sbrian return (class_id); 28628679Sbrian} 28731343Sbrian 28831343Sbrian/* 28931343Sbrian * ppb_scan_bus() 29031343Sbrian * 29131343Sbrian * Scan the ppbus for IEEE1284 compliant devices 29231343Sbrian */ 29331343Sbrianstatic int 29431343Sbrianppb_scan_bus(device_t bus) 29531343Sbrian{ 29631343Sbrian struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus); 29731343Sbrian int error = 0; 29831343Sbrian int unit = device_get_unit(bus); 29928679Sbrian 30028679Sbrian /* try all IEEE1284 modes, for one device only 30110528Samurai * 30228679Sbrian * XXX We should implement the IEEE1284.3 standard to detect 30328679Sbrian * daisy chained devices 30428974Sbrian */ 30528679Sbrian 30628679Sbrian error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID); 30731125Sbrian 30831343Sbrian if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) 30931343Sbrian goto end_scan; 31030316Sbrian 31130316Sbrian ppb_1284_terminate(bus); 31230316Sbrian 31331343Sbrian printf("ppbus%d: IEEE1284 device found ", unit); 31430316Sbrian 31520813Sjkh if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) { 31631343Sbrian printf("/NIBBLE"); 31728679Sbrian ppb_1284_terminate(bus); 31810528Samurai } 31928679Sbrian 32026516Sbrian if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) { 32110528Samurai printf("/PS2"); 32210528Samurai ppb_1284_terminate(bus); 32328679Sbrian } 32431343Sbrian 32510528Samurai if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) { 32620813Sjkh printf("/ECP"); 32710528Samurai ppb_1284_terminate(bus); 32820813Sjkh } 32928679Sbrian 33010528Samurai if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) { 33110528Samurai printf("/ECP_RLE"); 33231343Sbrian ppb_1284_terminate(bus); 33331343Sbrian } 33431343Sbrian 33531343Sbrian if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) { 33631343Sbrian printf("/EPP"); 33731343Sbrian ppb_1284_terminate(bus); 33831343Sbrian } 33931343Sbrian 34031343Sbrian /* try more IEEE1284 modes */ 34131343Sbrian if (bootverbose) { 34231343Sbrian if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 34331343Sbrian PPB_REQUEST_ID))) { 34431343Sbrian printf("/NIBBLE_ID"); 34531343Sbrian ppb_1284_terminate(bus); 34630715Sbrian } 34728679Sbrian 34828679Sbrian if (!(error = ppb_1284_negociate(bus, PPB_PS2, 34928679Sbrian PPB_REQUEST_ID))) { 35028679Sbrian printf("/PS2_ID"); 35131121Sbrian ppb_1284_terminate(bus); 35231121Sbrian } 35328679Sbrian 35431372Sbrian if (!(error = ppb_1284_negociate(bus, PPB_ECP, 35528679Sbrian PPB_REQUEST_ID))) { 35628679Sbrian printf("/ECP_ID"); 35728679Sbrian ppb_1284_terminate(bus); 35831631Sbrian } 35928679Sbrian 36028679Sbrian if (!(error = ppb_1284_negociate(bus, PPB_ECP, 36128679Sbrian PPB_REQUEST_ID | PPB_USE_RLE))) { 36228679Sbrian printf("/ECP_RLE_ID"); 36328679Sbrian ppb_1284_terminate(bus); 36428679Sbrian } 36528679Sbrian 36628679Sbrian if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE, 36728679Sbrian PPB_EXTENSIBILITY_LINK))) { 36828679Sbrian printf("/Extensibility Link"); 36928679Sbrian ppb_1284_terminate(bus); 37029083Sbrian } 37128679Sbrian } 37228679Sbrian 37328679Sbrian printf("\n"); 37428679Sbrian 37528679Sbrian /* detect PnP devices */ 37628679Sbrian ppb->class_id = ppb_pnp_detect(bus); 37728679Sbrian 37828679Sbrian return (0); 37928679Sbrian 38031372Sbrianend_scan: 38128679Sbrian return (error); 38231372Sbrian} 38331343Sbrian 38428679Sbrian#endif /* !DONTPROBE_1284 */ 38528679Sbrian 38631343Sbrianstatic void 38728679Sbrianppbus_dummy_intr(void *arg) 38828679Sbrian{ 38928679Sbrian} 39031343Sbrian 39128679Sbrianstatic int 39228679Sbrianppbus_attach(device_t dev) 39328679Sbrian{ 3946059Samurai struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev); 3956059Samurai uintptr_t irq; 39628536Sbrian int error, rid; 39731343Sbrian 39828536Sbrian /* Attach a dummy interrupt handler to suck up any stray interrupts. */ 39928536Sbrian BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_IRQ, &irq); 40028536Sbrian 40128536Sbrian if (irq > 0) { 40228536Sbrian rid = 0; 40328536Sbrian ppb->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, 40428536Sbrian irq, 1, RF_SHAREABLE); 40528679Sbrian if (ppb->irq_res != NULL) { 40631343Sbrian error = bus_setup_intr(dev, ppb->irq_res, 4076059Samurai INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppbus_dummy_intr, 4086059Samurai ppb, &ppb->intr_cookie); 4096059Samurai if (error) { 41026516Sbrian device_printf(dev, 41126516Sbrian "failed to setup interrupt handler\n"); 41230913Sbrian bus_release_resource(dev, SYS_RES_IRQ, 0, 41330913Sbrian ppb->irq_res); 41430913Sbrian return (error); 41530913Sbrian } 41626516Sbrian } 41730913Sbrian } 41830913Sbrian 41930913Sbrian /* Locate our children */ 42030913Sbrian bus_generic_probe(dev); 42130913Sbrian 42230913Sbrian#ifndef DONTPROBE_1284 42326516Sbrian /* detect IEEE1284 compliant devices */ 42426516Sbrian ppb_scan_bus(dev); 42526516Sbrian#endif /* !DONTPROBE_1284 */ 4266059Samurai 4276059Samurai /* launch attachement of the added children */ 42828679Sbrian bus_generic_attach(dev); 42931343Sbrian 4306059Samurai return 0; 4316059Samurai} 4326059Samurai 43326516Sbrianstatic int 43426516Sbrianppbus_detach(device_t dev) 4356059Samurai{ 43626516Sbrian struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev); 43726516Sbrian device_t *children; 43828679Sbrian int nchildren, i; 43928679Sbrian 44028679Sbrian /* detach & delete all children */ 44126516Sbrian if (!device_get_children(dev, &children, &nchildren)) { 4426059Samurai for (i = 0; i < nchildren; i++) 44331077Sbrian if (children[i]) 4446059Samurai device_delete_child(dev, children[i]); 4456059Samurai free(children, M_TEMP); 44628679Sbrian } 44731343Sbrian 4486059Samurai if (ppb->irq_res != NULL) { 44931077Sbrian bus_teardown_intr(dev, ppb->irq_res, ppb->intr_cookie); 45031077Sbrian bus_release_resource(dev, SYS_RES_IRQ, 0, ppb->irq_res); 45131077Sbrian } 45231077Sbrian return (0); 45331077Sbrian} 4546059Samurai 4556059Samuraistatic int 45628679Sbrianppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 45731343Sbrian driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep) 45828327Sbrian{ 45928327Sbrian int error; 46028327Sbrian struct ppb_data *ppb = DEVTOSOFTC(bus); 46128461Sbrian struct ppb_device *ppbdev = device_get_ivars(child); 46228461Sbrian 46328461Sbrian /* a device driver must own the bus to register an interrupt */ 46428461Sbrian if (ppb->ppb_owner != child) 46528327Sbrian return (EINVAL); 46628461Sbrian 46728461Sbrian if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, 46828461Sbrian filt, ihand, arg, cookiep))) 46928461Sbrian return (error); 47028461Sbrian 47128461Sbrian /* store the resource and the cookie for eventually forcing 47228461Sbrian * handler unregistration 47328461Sbrian */ 47428461Sbrian ppbdev->intr_cookie = *cookiep; 47528461Sbrian ppbdev->intr_resource = r; 47628461Sbrian 47728461Sbrian return (0); 47828461Sbrian} 47928461Sbrian 48028461Sbrianstatic int 48128461Sbrianppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) 48231077Sbrian{ 48328327Sbrian struct ppb_data *ppb = DEVTOSOFTC(bus); 48428327Sbrian struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); 48528679Sbrian 48631343Sbrian /* a device driver must own the bus to unregister an interrupt */ 4876059Samurai if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) || 48826516Sbrian (ppbdev->intr_resource != r)) 48926516Sbrian return (EINVAL); 49026516Sbrian 49131822Sbrian ppbdev->intr_cookie = 0; 49229840Sbrian ppbdev->intr_resource = 0; 49329840Sbrian 49429840Sbrian /* pass unregistration to the upper layer */ 49531077Sbrian return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih)); 4966059Samurai} 4976059Samurai 49828679Sbrian/* 49931343Sbrian * ppb_request_bus() 5006059Samurai * 50131077Sbrian * Allocate the device to perform transfers. 50231077Sbrian * 50331077Sbrian * how : PPB_WAIT or PPB_DONTWAIT 5046059Samurai */ 5056059Samuraiint 50628679Sbrianppb_request_bus(device_t bus, device_t dev, int how) 50731343Sbrian{ 50826326Sbrian int s, error = 0; 50931077Sbrian struct ppb_data *ppb = DEVTOSOFTC(bus); 51031077Sbrian struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 51131077Sbrian 51226326Sbrian while (!error) { 51326326Sbrian s = splhigh(); 51428679Sbrian if (ppb->ppb_owner) { 51531343Sbrian splx(s); 51626326Sbrian 51731077Sbrian switch (how) { 51831077Sbrian case (PPB_WAIT | PPB_INTR): 51931077Sbrian error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 52031077Sbrian break; 52131077Sbrian 52231077Sbrian case (PPB_WAIT | PPB_NOINTR): 52326326Sbrian error = tsleep(ppb, PPBPRI, "ppbreq", 0); 52426326Sbrian break; 52528679Sbrian 52631343Sbrian default: 52725067Sbrian return (EWOULDBLOCK); 52831077Sbrian break; 52931077Sbrian } 53031077Sbrian 53131077Sbrian } else { 53225067Sbrian ppb->ppb_owner = dev; 53325067Sbrian 53428679Sbrian /* restore the context of the device 53531343Sbrian * The first time, ctx.valid is certainly false 53611336Samurai * then do not change anything. This is usefull for 53726516Sbrian * drivers that do not set there operating mode 53826516Sbrian * during attachement 53926516Sbrian */ 54011336Samurai if (ppbdev->ctx.valid) 54111336Samurai ppb_set_mode(bus, ppbdev->ctx.mode); 54226516Sbrian 54328679Sbrian splx(s); 54426516Sbrian return (0); 54511336Samurai } 54611336Samurai } 54726516Sbrian 54824939Sbrian return (error); 54924939Sbrian} 55026516Sbrian 55128679Sbrian/* 55226516Sbrian * ppb_release_bus() 55324939Sbrian * 55424939Sbrian * Release the device allocated with ppb_request_bus() 55511336Samurai */ 55628679Sbrianint 55711336Samuraippb_release_bus(device_t bus, device_t dev) 55826516Sbrian{ 55911336Samurai int s, error; 56031077Sbrian struct ppb_data *ppb = DEVTOSOFTC(bus); 56111336Samurai struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 56211336Samurai 56326516Sbrian if (ppbdev->intr_resource != 0) 56428679Sbrian /* force interrupt handler unregistration when the ppbus is released */ 56531343Sbrian if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource, 56618752Sjkh ppbdev->intr_cookie))) 56731077Sbrian return (error); 56831077Sbrian 56931077Sbrian s = splhigh(); 57031077Sbrian if (ppb->ppb_owner != dev) { 57131077Sbrian splx(s); 57231077Sbrian return (EACCES); 57331077Sbrian } 57431077Sbrian 57518752Sjkh ppb->ppb_owner = 0; 57628679Sbrian splx(s); 57726516Sbrian 57818752Sjkh /* save the context of the device */ 57930715Sbrian ppbdev->ctx.mode = ppb_get_mode(bus); 58028679Sbrian 58131372Sbrian /* ok, now the context of the device is valid */ 58228679Sbrian ppbdev->ctx.valid = 1; 58331372Sbrian 58428679Sbrian /* wakeup waiting processes */ 58528679Sbrian wakeup(ppb); 58628679Sbrian 58731372Sbrian return (0); 58828679Sbrian} 58928679Sbrian 59028679Sbrianstatic devclass_t ppbus_devclass; 59128679Sbrian 59228679Sbrianstatic device_method_t ppbus_methods[] = { 59331372Sbrian /* device interface */ 59428679Sbrian DEVMETHOD(device_probe, ppbus_probe), 59528679Sbrian DEVMETHOD(device_attach, ppbus_attach), 59628679Sbrian DEVMETHOD(device_detach, ppbus_detach), 59728679Sbrian 59828679Sbrian /* bus interface */ 59928679Sbrian DEVMETHOD(bus_add_child, ppbus_add_child), 60028679Sbrian DEVMETHOD(bus_print_child, ppbus_print_child), 60131372Sbrian DEVMETHOD(bus_read_ivar, ppbus_read_ivar), 60228679Sbrian DEVMETHOD(bus_write_ivar, ppbus_write_ivar), 60331372Sbrian DEVMETHOD(bus_setup_intr, ppbus_setup_intr), 60428679Sbrian DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), 60528679Sbrian DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 60628679Sbrian 60728679Sbrian { 0, 0 } 60828679Sbrian}; 60928679Sbrian 61028679Sbrianstatic driver_t ppbus_driver = { 61128679Sbrian "ppbus", 61228679Sbrian ppbus_methods, 61328679Sbrian sizeof(struct ppb_data), 61428679Sbrian}; 61528679SbrianDRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0); 61628679Sbrian