ppbconf.c revision 28863
1138627Stakawata/*- 2138627Stakawata * Copyright (c) 1997 Nicolas Souchu 3138627Stakawata * All rights reserved. 4138627Stakawata * 5138627Stakawata * Redistribution and use in source and binary forms, with or without 6138627Stakawata * modification, are permitted provided that the following conditions 7138627Stakawata * are met: 8138627Stakawata * 1. Redistributions of source code must retain the above copyright 9138627Stakawata * notice, this list of conditions and the following disclaimer. 10138627Stakawata * 2. Redistributions in binary form must reproduce the above copyright 11138627Stakawata * notice, this list of conditions and the following disclaimer in the 12138627Stakawata * documentation and/or other materials provided with the distribution. 13138627Stakawata * 14138627Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15138627Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16138627Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17138627Stakawata * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18138627Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19138627Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20138627Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21138627Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22138627Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23138627Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24138627Stakawata * SUCH DAMAGE. 25138627Stakawata * 26138627Stakawata * $Id: ppbconf.c,v 1.2 1997/08/16 14:05:35 msmith Exp $ 27138627Stakawata * 28138627Stakawata */ 29138627Stakawata#include <sys/param.h> 30138627Stakawata#include <sys/systm.h> 31138627Stakawata#include <sys/errno.h> 32138627Stakawata#include <sys/conf.h> 33138627Stakawata#include <sys/proc.h> 34138627Stakawata#include <sys/buf.h> 35138627Stakawata#include <sys/kernel.h> 36138627Stakawata#include <sys/malloc.h> 37138627Stakawata#include <sys/uio.h> 38138627Stakawata#include <sys/syslog.h> 39138627Stakawata 40138627Stakawata#include <machine/clock.h> 41138774Sscottl 42138774Sscottl#include <vm/vm.h> 43138774Sscottl#include <vm/vm_param.h> 44138627Stakawata#include <vm/pmap.h> 45138627Stakawata 46138627Stakawata#include <dev/ppbus/ppbconf.h> 47138627Stakawata#include <dev/ppbus/ppb_1284.h> 48138627Stakawata 49138627StakawataLIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ 50138627Stakawata 51138627Stakawata/* 52138627Stakawata * Add a null driver so that the linker set always exists. 53138627Stakawata */ 54138627Stakawata 55138627Stakawatastatic struct ppb_driver nulldriver = { 56138627Stakawata NULL, NULL, "null" 57138627Stakawata}; 58138627StakawataDATA_SET(ppbdriver_set, nulldriver); 59138627Stakawata 60138627Stakawata 61138627Stakawata/* 62138627Stakawata * ppb_alloc_bus() 63138627Stakawata * 64138627Stakawata * Allocate area to store the ppbus description. 65138627Stakawata * This function is called by ppcattach(). 66138627Stakawata */ 67138627Stakawatastruct ppb_data * 68138627Stakawatappb_alloc_bus(void) 69138627Stakawata{ 70138627Stakawata struct ppb_data *ppb; 71138627Stakawata static int ppbdata_initted = 0; /* done-init flag */ 72138627Stakawata 73138627Stakawata ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 74138627Stakawata M_TEMP, M_NOWAIT); 75138627Stakawata 76138627Stakawata /* 77138627Stakawata * Add the new parallel port bus to the list of existing ppbus. 78138627Stakawata */ 79138627Stakawata if (ppb) { 80138627Stakawata bzero(ppb, sizeof(struct ppb_data)); 81138627Stakawata 82138627Stakawata if (!ppbdata_initted) { /* list not initialised */ 83138627Stakawata LIST_INIT(&ppbdata); 84138627Stakawata ppbdata_initted = 1; 85138627Stakawata } 86138627Stakawata LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 87138627Stakawata } else { 88138627Stakawata printf("ppb_alloc_bus: cannot malloc!\n"); 89138627Stakawata } 90138627Stakawata return(ppb); 91138627Stakawata} 92138627Stakawata 93138627Stakawatastatic char *pnp_tokens[] = { 94138627Stakawata "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 95138627Stakawata "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 96138627Stakawata 97138627Stakawatastatic char *pnp_classes[] = { 98138627Stakawata "printer", "modem", "network device", 99138627Stakawata "hard disk", "PCMCIA", "multimedia device", 100138627Stakawata "floppy disk", "ports", "scanner", 101138627Stakawata "digital camera", "unknown device", NULL }; 102138627Stakawata 103138627Stakawata/* 104138627Stakawata * search_token() 105138627Stakawata * 106138627Stakawata * Search the first occurence of a token within a string 107138627Stakawata */ 108138627Stakawatastatic char * 109138627Stakawatasearch_token(char *str, int slen, char *token) 110138627Stakawata{ 111138627Stakawata char *p; 112138627Stakawata int tlen, i, j; 113138627Stakawata 114138627Stakawata#define UNKNOWN_LENGTH -1 115138627Stakawata 116138627Stakawata if (slen == UNKNOWN_LENGTH) 117138627Stakawata /* get string's length */ 118138627Stakawata for (slen = 0, p = str; *p != '\0'; p++) 119138627Stakawata slen ++; 120138627Stakawata 121138627Stakawata /* get token's length */ 122138627Stakawata for (tlen = 0, p = token; *p != '\0'; p++) 123138627Stakawata tlen ++; 124138627Stakawata 125138627Stakawata if (tlen == 0) 126138627Stakawata return (str); 127138627Stakawata 128138627Stakawata for (i = 0; i <= slen-tlen; i++) { 129138627Stakawata for (j = 0; j < tlen; j++) 130138627Stakawata if (str[i+j] != token[j]) 131138627Stakawata break; 132138627Stakawata if (j == tlen) 133138627Stakawata return (&str[i]); 134138627Stakawata } 135138627Stakawata 136138627Stakawata return (NULL); 137138627Stakawata} 138138627Stakawata 139138627Stakawata/* 140138627Stakawata * ppb_pnp_detect() 141138627Stakawata * 142138627Stakawata * Returns the class id. of the peripherial, -1 otherwise 143138627Stakawata */ 144138627Stakawatastatic int 145138627Stakawatappb_pnp_detect(struct ppb_data *ppb) 146138627Stakawata{ 147138627Stakawata char *token, *q, *class = 0; 148138627Stakawata int i, len, error; 149138627Stakawata char str[PPB_PnP_STRING_SIZE+1]; 150138627Stakawata 151138627Stakawata struct ppb_device pnpdev; /* temporary device to perform I/O */ 152138627Stakawata 153138627Stakawata /* initialize the pnpdev structure for future use */ 154138627Stakawata bzero(&pnpdev, sizeof(pnpdev)); 155138627Stakawata 156138627Stakawata pnpdev.ppb = ppb; 157138627Stakawata 158138627Stakawata#ifdef PnP_DEBUG 159138627Stakawata printf("ppb: <PnP> probing PnP devices on ppbus%d...\n", 160138627Stakawata ppb->ppb_link->adapter_unit); 161138627Stakawata#endif 162138627Stakawata 163138627Stakawata ppb_wctr(&pnpdev, nINIT | SELECTIN); 164138627Stakawata 165138627Stakawata /* select NIBBLE_1284_REQUEST_ID mode */ 166138627Stakawata if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) { 167138627Stakawata#ifdef PnP_DEBUG 168138627Stakawata printf("ppb: <PnP> nibble_1284_mode()=%d\n", error); 169138627Stakawata#endif 170138627Stakawata return (-1); 171138627Stakawata } 172138627Stakawata 173138627Stakawata len = 0; 174138627Stakawata for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) { 175138627Stakawata if ((error = nibble_1284_inbyte(&pnpdev, q))) { 176138627Stakawata#ifdef PnP_DEBUG 177138627Stakawata printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error); 178138627Stakawata#endif 179138627Stakawata return (-1); 180138627Stakawata } 181138627Stakawata if (len++ >= PPB_PnP_STRING_SIZE) { 182138627Stakawata printf("ppb: <PnP> not space left!\n"); 183138627Stakawata return (-1); 184138627Stakawata } 185138627Stakawata } 186138627Stakawata *q = '\0'; 187138627Stakawata 188138627Stakawata nibble_1284_sync(&pnpdev); 189138627Stakawata 190138627Stakawata#ifdef PnP_DEBUG 191138627Stakawata printf("ppb: <PnP> %d characters: ", len); 192138627Stakawata for (i = 0; i < len; i++) 193138627Stakawata printf("0x%x ", str[i]); 194138627Stakawata printf("\n"); 195138627Stakawata#endif 196138627Stakawata 197138627Stakawata /* replace ';' characters by '\0' */ 198138627Stakawata for (i = 0; i < len; i++) 199138627Stakawata str[i] = (str[i] == ';') ? '\0' : str[i]; 200138627Stakawata 201138627Stakawata if ((token = search_token(str, len, "MFG")) != NULL) 202138627Stakawata printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, 203138627Stakawata search_token(token, UNKNOWN_LENGTH, ":") + 1); 204138627Stakawata else 205138627Stakawata printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); 206138627Stakawata 207138627Stakawata if ((token = search_token(str, len, "MDL")) != NULL) 208138627Stakawata printf(" %s", 209138627Stakawata search_token(token, UNKNOWN_LENGTH, ":") + 1); 210138627Stakawata else 211138627Stakawata printf(" unknown"); 212138627Stakawata 213138627Stakawata if ((token = search_token(str, len, "VER")) != NULL) 214138627Stakawata printf("/%s", 215138627Stakawata search_token(token, UNKNOWN_LENGTH, ":") + 1); 216138627Stakawata 217138627Stakawata if ((token = search_token(str, len, "REV")) != NULL) 218138627Stakawata printf(".%s", 219138627Stakawata search_token(token, UNKNOWN_LENGTH, ":") + 1); 220138627Stakawata 221138627Stakawata printf(">"); 222138627Stakawata 223138627Stakawata if ((token = search_token(str, len, "CLS")) != NULL) { 224138627Stakawata class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 225138627Stakawata printf(" %s", class); 226138627Stakawata } 227138627Stakawata 228138627Stakawata if ((token = search_token(str, len, "CMD")) != NULL) 229138627Stakawata printf(" %s", 230138627Stakawata search_token(token, UNKNOWN_LENGTH, ":") + 1); 231138627Stakawata 232138627Stakawata printf("\n"); 233138627Stakawata 234138627Stakawata if (class) 235138627Stakawata /* identify class ident */ 236138627Stakawata for (i = 0; pnp_tokens[i] != NULL; i++) { 237138627Stakawata if (search_token(class, len, pnp_tokens[i]) != NULL) { 238138627Stakawata return (i); 239138627Stakawata break; 240138627Stakawata } 241138627Stakawata } 242138627Stakawata 243138627Stakawata return (PPB_PnP_UNKNOWN); 244138627Stakawata} 245138627Stakawata 246138627Stakawata/* 247138627Stakawata * ppb_attachdevs() 248138627Stakawata * 249138627Stakawata * Called by ppcattach(), this function probes the ppbus and 250138627Stakawata * attaches found devices. 251138627Stakawata */ 252138627Stakawataint 253138627Stakawatappb_attachdevs(struct ppb_data *ppb) 254138627Stakawata{ 255138627Stakawata int error; 256138627Stakawata struct ppb_device *dev; 257138627Stakawata struct ppb_driver **p_drvpp, *p_drvp; 258138774Sscottl 259138774Sscottl LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 260138627Stakawata p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 261138627Stakawata 262138627Stakawata /* detect PnP devices */ 263138627Stakawata ppb->class_id = ppb_pnp_detect(ppb); 264138627Stakawata 265138627Stakawata /* 266138627Stakawata * Blindly try all probes here. Later we should look at 267138627Stakawata * the parallel-port PnP standard, and intelligently seek 268138627Stakawata * drivers based on configuration first. 269138627Stakawata */ 270138627Stakawata while ((p_drvp = *p_drvpp++) != NULL) { 271138627Stakawata if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 272138627Stakawata /* 273138627Stakawata * Add the device to the list of probed devices. 274138627Stakawata */ 275138627Stakawata LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 276138627Stakawata 277138627Stakawata /* Call the device's attach routine */ 278138627Stakawata (void)p_drvp->attach(dev); 279138627Stakawata } 280138627Stakawata } 281138627Stakawata return (0); 282138627Stakawata} 283138627Stakawata 284138627Stakawata/* 285138627Stakawata * ppb_next_bus() 286138627Stakawata * 287138627Stakawata * Return the next bus in ppbus queue 288138627Stakawata */ 289138627Stakawatastruct ppb_data * 290138627Stakawatappb_next_bus(struct ppb_data *ppb) 291138627Stakawata{ 292138627Stakawata 293138627Stakawata if (ppb == NULL) 294138627Stakawata return (ppbdata.lh_first); 295138627Stakawata 296138627Stakawata return (ppb->ppb_chain.le_next); 297138627Stakawata} 298138627Stakawata 299138627Stakawata/* 300138627Stakawata * ppb_lookup_bus() 301138627Stakawata * 302138627Stakawata * Get ppb_data structure pointer according to the base address of the ppbus 303138627Stakawata */ 304138627Stakawatastruct ppb_data * 305138627Stakawatappb_lookup_bus(int base_port) 306138627Stakawata{ 307138627Stakawata struct ppb_data *ppb; 308138627Stakawata 309138627Stakawata for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 310138627Stakawata if (ppb->ppb_link->base == base_port) 311138627Stakawata break; 312138627Stakawata 313138627Stakawata return (ppb); 314138627Stakawata} 315138627Stakawata 316138627Stakawata/* 317138627Stakawata * ppb_attach_device() 318138627Stakawata * 319138627Stakawata * Called by loadable kernel modules to add a device 320138627Stakawata */ 321138627Stakawataint 322138627Stakawatappb_attach_device(struct ppb_device *dev) 323138627Stakawata{ 324138627Stakawata struct ppb_data *ppb = dev->ppb; 325138627Stakawata 326138627Stakawata /* add the device to the list of probed devices */ 327138627Stakawata LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 328138627Stakawata 329138627Stakawata return (0); 330138627Stakawata} 331138627Stakawata 332138627Stakawata/* 333138627Stakawata * ppb_remove_device() 334138627Stakawata * 335138627Stakawata * Called by loadable kernel modules to remove a device 336138627Stakawata */ 337138627Stakawatavoid 338138627Stakawatappb_remove_device(struct ppb_device *dev) 339138627Stakawata{ 340138627Stakawata 341138627Stakawata /* remove the device from the list of probed devices */ 342138627Stakawata LIST_REMOVE(dev, chain); 343138627Stakawata 344138627Stakawata return; 345138627Stakawata} 346138627Stakawata 347138627Stakawata/* 348138627Stakawata * ppb_request_bus() 349138627Stakawata * 350138627Stakawata * Allocate the device to perform transfers. 351138627Stakawata * 352138627Stakawata * how : PPB_WAIT or PPB_DONTWAIT 353138627Stakawata */ 354138627Stakawataint 355138627Stakawatappb_request_bus(struct ppb_device *dev, int how) 356138627Stakawata{ 357138627Stakawata int s, error = 0; 358138627Stakawata struct ppb_data *ppb = dev->ppb; 359138627Stakawata 360138627Stakawata while (!error) { 361138627Stakawata s = splhigh(); 362138627Stakawata if (ppb->ppb_owner) { 363138627Stakawata splx(s); 364138627Stakawata 365138627Stakawata switch (how) { 366138627Stakawata case (PPB_WAIT | PPB_INTR): 367138627Stakawata error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 368138627Stakawata break; 369138627Stakawata 370138627Stakawata case (PPB_WAIT | PPB_NOINTR): 371138627Stakawata error = tsleep(ppb, PPBPRI, "ppbreq", 0); 372138627Stakawata break; 373138627Stakawata 374138627Stakawata default: 375138627Stakawata return (EWOULDBLOCK); 376138627Stakawata break; 377138627Stakawata } 378138627Stakawata 379138627Stakawata } else { 380138627Stakawata ppb->ppb_owner = dev; 381138627Stakawata 382138627Stakawata splx(s); 383138627Stakawata return (0); 384138627Stakawata } 385138627Stakawata } 386138627Stakawata 387138627Stakawata return (error); 388138627Stakawata} 389138627Stakawata 390138627Stakawata/* 391138627Stakawata * ppb_release_bus() 392138627Stakawata * 393138627Stakawata * Release the device allocated with ppb_request_dev() 394138627Stakawata */ 395138627Stakawataint 396138627Stakawatappb_release_bus(struct ppb_device *dev) 397138627Stakawata{ 398138627Stakawata int s; 399138627Stakawata struct ppb_data *ppb = dev->ppb; 400138627Stakawata 401138627Stakawata s = splhigh(); 402138627Stakawata if (ppb->ppb_owner != dev) { 403138627Stakawata splx(s); 404138627Stakawata return (EACCES); 405138627Stakawata } 406138627Stakawata 407138627Stakawata ppb->ppb_owner = 0; 408138627Stakawata splx(s); 409138627Stakawata 410138627Stakawata /* wakeup waiting processes */ 411138627Stakawata wakeup(ppb); 412138627Stakawata 413138627Stakawata return (0); 414138627Stakawata} 415138627Stakawata