ppbconf.c revision 39134
128219Smsmith/*- 238061Smsmith * Copyright (c) 1997, 1998 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 * 2639134Snsouch * $Id: ppbconf.c,v 1.6 1998/08/03 19:14:31 msmith Exp $ 2728219Smsmith * 2828219Smsmith */ 2928219Smsmith#include <sys/param.h> 3028219Smsmith#include <sys/systm.h> 3128219Smsmith#include <sys/kernel.h> 3228219Smsmith#include <sys/malloc.h> 3328219Smsmith 3428219Smsmith#include <vm/vm.h> 3528219Smsmith#include <vm/pmap.h> 3628219Smsmith 3728219Smsmith#include <dev/ppbus/ppbconf.h> 3828257Smsmith#include <dev/ppbus/ppb_1284.h> 3928219Smsmith 4038061SmsmithLIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ 4128219Smsmith 4228219Smsmith/* 4328219Smsmith * Add a null driver so that the linker set always exists. 4428219Smsmith */ 4528219Smsmith 4628219Smsmithstatic struct ppb_driver nulldriver = { 4728219Smsmith NULL, NULL, "null" 4828219Smsmith}; 4928219SmsmithDATA_SET(ppbdriver_set, nulldriver); 5028219Smsmith 5128219Smsmith 5228219Smsmith/* 5328219Smsmith * ppb_alloc_bus() 5428219Smsmith * 5528219Smsmith * Allocate area to store the ppbus description. 5628219Smsmith */ 5728219Smsmithstruct ppb_data * 5828219Smsmithppb_alloc_bus(void) 5928219Smsmith{ 6028219Smsmith struct ppb_data *ppb; 6128219Smsmith static int ppbdata_initted = 0; /* done-init flag */ 6228219Smsmith 6328219Smsmith ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 6428219Smsmith M_TEMP, M_NOWAIT); 6528219Smsmith 6628219Smsmith /* 6728219Smsmith * Add the new parallel port bus to the list of existing ppbus. 6828219Smsmith */ 6928219Smsmith if (ppb) { 7028219Smsmith bzero(ppb, sizeof(struct ppb_data)); 7128219Smsmith 7228219Smsmith if (!ppbdata_initted) { /* list not initialised */ 7328219Smsmith LIST_INIT(&ppbdata); 7428219Smsmith ppbdata_initted = 1; 7528219Smsmith } 7628219Smsmith LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 7728219Smsmith } else { 7828219Smsmith printf("ppb_alloc_bus: cannot malloc!\n"); 7928219Smsmith } 8028219Smsmith return(ppb); 8128219Smsmith} 8228219Smsmith 8328257Smsmithstatic char *pnp_tokens[] = { 8428257Smsmith "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 8528257Smsmith "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 8628257Smsmith 8728257Smsmithstatic char *pnp_classes[] = { 8828257Smsmith "printer", "modem", "network device", 8928257Smsmith "hard disk", "PCMCIA", "multimedia device", 9028257Smsmith "floppy disk", "ports", "scanner", 9128257Smsmith "digital camera", "unknown device", NULL }; 9228257Smsmith 9328219Smsmith/* 9428257Smsmith * search_token() 9528257Smsmith * 9628257Smsmith * Search the first occurence of a token within a string 9739134Snsouch * 9839134Snsouch * XXX should use strxxx() calls 9928257Smsmith */ 10028257Smsmithstatic char * 10128257Smsmithsearch_token(char *str, int slen, char *token) 10228257Smsmith{ 10328257Smsmith char *p; 10428257Smsmith int tlen, i, j; 10528257Smsmith 10628257Smsmith#define UNKNOWN_LENGTH -1 10728257Smsmith 10828257Smsmith if (slen == UNKNOWN_LENGTH) 10928257Smsmith /* get string's length */ 11028257Smsmith for (slen = 0, p = str; *p != '\0'; p++) 11128257Smsmith slen ++; 11228257Smsmith 11328257Smsmith /* get token's length */ 11428257Smsmith for (tlen = 0, p = token; *p != '\0'; p++) 11528257Smsmith tlen ++; 11628257Smsmith 11728257Smsmith if (tlen == 0) 11828257Smsmith return (str); 11928257Smsmith 12028257Smsmith for (i = 0; i <= slen-tlen; i++) { 12128257Smsmith for (j = 0; j < tlen; j++) 12228257Smsmith if (str[i+j] != token[j]) 12328257Smsmith break; 12428257Smsmith if (j == tlen) 12528257Smsmith return (&str[i]); 12628257Smsmith } 12728257Smsmith 12828257Smsmith return (NULL); 12928257Smsmith} 13028257Smsmith 13128257Smsmith/* 13228257Smsmith * ppb_pnp_detect() 13328257Smsmith * 13428257Smsmith * Returns the class id. of the peripherial, -1 otherwise 13528257Smsmith */ 13628257Smsmithstatic int 13728257Smsmithppb_pnp_detect(struct ppb_data *ppb) 13828257Smsmith{ 13928257Smsmith char *token, *q, *class = 0; 14028257Smsmith int i, len, error; 14138061Smsmith int class_id = -1; 14228257Smsmith char str[PPB_PnP_STRING_SIZE+1]; 14328257Smsmith struct ppb_device pnpdev; /* temporary device to perform I/O */ 14428257Smsmith 14528257Smsmith /* initialize the pnpdev structure for future use */ 14628257Smsmith bzero(&pnpdev, sizeof(pnpdev)); 14728257Smsmith 14828257Smsmith pnpdev.ppb = ppb; 14928257Smsmith 15038061Smsmith if (bootverbose) 15138061Smsmith printf("ppb: <PnP> probing devices on ppbus %d...\n", 15238061Smsmith ppb->ppb_link->adapter_unit); 15328257Smsmith 15438061Smsmith if (ppb_request_bus(&pnpdev, PPB_DONTWAIT)) { 15538061Smsmith if (bootverbose) 15638061Smsmith printf("ppb: <PnP> cannot allocate ppbus!\n"); 15738061Smsmith return (-1); 15838061Smsmith } 15938061Smsmith 16039134Snsouch if ((error = ppb_1284_negociate(&pnpdev, NIBBLE_1284_REQUEST_ID))) { 16139134Snsouch if (bootverbose) 16239134Snsouch printf("ppb: <PnP> ppb_1284_negociate()=%d\n", error); 16328257Smsmith 16438061Smsmith goto end_detect; 16528257Smsmith } 16639134Snsouch 16728257Smsmith len = 0; 16839134Snsouch for (q=str; !(ppb_rstr(&pnpdev) & PERROR); q++) { 16928257Smsmith if ((error = nibble_1284_inbyte(&pnpdev, q))) { 17039134Snsouch if (bootverbose) { 17139134Snsouch *q = '\0'; 17239134Snsouch printf("ppb: <PnP> len=%d, %s\n", len, str); 17338061Smsmith printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", 17438061Smsmith error); 17539134Snsouch } 17638061Smsmith goto end_detect; 17728257Smsmith } 17839134Snsouch 17928257Smsmith if (len++ >= PPB_PnP_STRING_SIZE) { 18028257Smsmith printf("ppb: <PnP> not space left!\n"); 18138061Smsmith goto end_detect; 18228257Smsmith } 18328257Smsmith } 18428257Smsmith *q = '\0'; 18528257Smsmith 18628257Smsmith nibble_1284_sync(&pnpdev); 18728257Smsmith 18838061Smsmith if (bootverbose) { 18938061Smsmith printf("ppb: <PnP> %d characters: ", len); 19038061Smsmith for (i = 0; i < len; i++) 19138061Smsmith printf("0x%x ", str[i]); 19238061Smsmith printf("\n"); 19338061Smsmith } 19428257Smsmith 19528257Smsmith /* replace ';' characters by '\0' */ 19628257Smsmith for (i = 0; i < len; i++) 19728257Smsmith str[i] = (str[i] == ';') ? '\0' : str[i]; 19828257Smsmith 19928257Smsmith if ((token = search_token(str, len, "MFG")) != NULL) 20028257Smsmith printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, 20128257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 20228257Smsmith else 20328257Smsmith printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); 20428257Smsmith 20528257Smsmith if ((token = search_token(str, len, "MDL")) != NULL) 20628257Smsmith printf(" %s", 20728257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 20828257Smsmith else 20928257Smsmith printf(" unknown"); 21028257Smsmith 21128257Smsmith if ((token = search_token(str, len, "VER")) != NULL) 21228257Smsmith printf("/%s", 21328257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 21428257Smsmith 21528257Smsmith if ((token = search_token(str, len, "REV")) != NULL) 21628257Smsmith printf(".%s", 21728257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 21828257Smsmith 21928257Smsmith printf(">"); 22028257Smsmith 22128257Smsmith if ((token = search_token(str, len, "CLS")) != NULL) { 22228257Smsmith class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 22328257Smsmith printf(" %s", class); 22428257Smsmith } 22528257Smsmith 22628257Smsmith if ((token = search_token(str, len, "CMD")) != NULL) 22728257Smsmith printf(" %s", 22828257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 22928257Smsmith 23028257Smsmith printf("\n"); 23128257Smsmith 23228257Smsmith if (class) 23328257Smsmith /* identify class ident */ 23428257Smsmith for (i = 0; pnp_tokens[i] != NULL; i++) { 23528257Smsmith if (search_token(class, len, pnp_tokens[i]) != NULL) { 23638061Smsmith class_id = i; 23738061Smsmith goto end_detect; 23828257Smsmith } 23928257Smsmith } 24028257Smsmith 24138061Smsmith class_id = PPB_PnP_UNKNOWN; 24238061Smsmith 24338061Smsmithend_detect: 24439134Snsouch if ((error = ppb_1284_terminate(&pnpdev, VALID_STATE)) && bootverbose) 24539134Snsouch printf("ppb: ppb_1284_terminate()=%d\n", error); 24639134Snsouch 24738061Smsmith ppb_release_bus(&pnpdev); 24838061Smsmith return (class_id); 24928257Smsmith} 25028257Smsmith 25128257Smsmith/* 25228219Smsmith * ppb_attachdevs() 25328219Smsmith * 25428219Smsmith * Called by ppcattach(), this function probes the ppbus and 25528219Smsmith * attaches found devices. 25628219Smsmith */ 25728219Smsmithint 25828219Smsmithppb_attachdevs(struct ppb_data *ppb) 25928219Smsmith{ 26028219Smsmith int error; 26128219Smsmith struct ppb_device *dev; 26228219Smsmith struct ppb_driver **p_drvpp, *p_drvp; 26328257Smsmith 26428219Smsmith LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 26528219Smsmith p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 26628257Smsmith 26728257Smsmith /* detect PnP devices */ 26828257Smsmith ppb->class_id = ppb_pnp_detect(ppb); 26928219Smsmith 27028219Smsmith /* 27128219Smsmith * Blindly try all probes here. Later we should look at 27228219Smsmith * the parallel-port PnP standard, and intelligently seek 27328219Smsmith * drivers based on configuration first. 27428219Smsmith */ 27528219Smsmith while ((p_drvp = *p_drvpp++) != NULL) { 27628219Smsmith if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 27728219Smsmith /* 27828219Smsmith * Add the device to the list of probed devices. 27928219Smsmith */ 28028219Smsmith LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 28128219Smsmith 28228219Smsmith /* Call the device's attach routine */ 28328219Smsmith (void)p_drvp->attach(dev); 28428219Smsmith } 28528219Smsmith } 28628219Smsmith return (0); 28728219Smsmith} 28828219Smsmith 28928219Smsmith/* 29028257Smsmith * ppb_next_bus() 29128219Smsmith * 29228257Smsmith * Return the next bus in ppbus queue 29328219Smsmith */ 29428257Smsmithstruct ppb_data * 29528257Smsmithppb_next_bus(struct ppb_data *ppb) 29628219Smsmith{ 29728219Smsmith 29828257Smsmith if (ppb == NULL) 29928257Smsmith return (ppbdata.lh_first); 30028219Smsmith 30128257Smsmith return (ppb->ppb_chain.le_next); 30228257Smsmith} 30328219Smsmith 30428257Smsmith/* 30528257Smsmith * ppb_lookup_bus() 30628257Smsmith * 30728257Smsmith * Get ppb_data structure pointer according to the base address of the ppbus 30828257Smsmith */ 30928257Smsmithstruct ppb_data * 31028257Smsmithppb_lookup_bus(int base_port) 31128257Smsmith{ 31228257Smsmith struct ppb_data *ppb; 31328219Smsmith 31428257Smsmith for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 31528257Smsmith if (ppb->ppb_link->base == base_port) 31628257Smsmith break; 31728219Smsmith 31828257Smsmith return (ppb); 31928219Smsmith} 32028219Smsmith 32128219Smsmith/* 32238061Smsmith * ppb_lookup_link() 32338061Smsmith * 32438061Smsmith * Get ppb_data structure pointer according to the unit value 32538061Smsmith * of the corresponding link structure 32638061Smsmith */ 32738061Smsmithstruct ppb_data * 32838061Smsmithppb_lookup_link(int unit) 32938061Smsmith{ 33038061Smsmith struct ppb_data *ppb; 33138061Smsmith 33238061Smsmith for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 33338061Smsmith if (ppb->ppb_link->adapter_unit == unit) 33438061Smsmith break; 33538061Smsmith 33638061Smsmith return (ppb); 33738061Smsmith} 33838061Smsmith 33938061Smsmith/* 34028257Smsmith * ppb_attach_device() 34128219Smsmith * 34228257Smsmith * Called by loadable kernel modules to add a device 34328219Smsmith */ 34428219Smsmithint 34528257Smsmithppb_attach_device(struct ppb_device *dev) 34628219Smsmith{ 34728219Smsmith struct ppb_data *ppb = dev->ppb; 34828219Smsmith 34928257Smsmith /* add the device to the list of probed devices */ 35028257Smsmith LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 35128219Smsmith 35228219Smsmith return (0); 35328219Smsmith} 35428219Smsmith 35528219Smsmith/* 35628257Smsmith * ppb_remove_device() 35728219Smsmith * 35828257Smsmith * Called by loadable kernel modules to remove a device 35928219Smsmith */ 36028219Smsmithvoid 36128257Smsmithppb_remove_device(struct ppb_device *dev) 36228219Smsmith{ 36328219Smsmith 36428257Smsmith /* remove the device from the list of probed devices */ 36528257Smsmith LIST_REMOVE(dev, chain); 36628219Smsmith 36728219Smsmith return; 36828219Smsmith} 36928219Smsmith 37028219Smsmith/* 37128257Smsmith * ppb_request_bus() 37228219Smsmith * 37328257Smsmith * Allocate the device to perform transfers. 37428257Smsmith * 37528257Smsmith * how : PPB_WAIT or PPB_DONTWAIT 37628219Smsmith */ 37728219Smsmithint 37828257Smsmithppb_request_bus(struct ppb_device *dev, int how) 37928219Smsmith{ 38028257Smsmith int s, error = 0; 38128219Smsmith struct ppb_data *ppb = dev->ppb; 38228219Smsmith 38328257Smsmith while (!error) { 38428257Smsmith s = splhigh(); 38528257Smsmith if (ppb->ppb_owner) { 38628257Smsmith splx(s); 38728219Smsmith 38828257Smsmith switch (how) { 38928257Smsmith case (PPB_WAIT | PPB_INTR): 39028257Smsmith error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 39128257Smsmith break; 39228219Smsmith 39328257Smsmith case (PPB_WAIT | PPB_NOINTR): 39428257Smsmith error = tsleep(ppb, PPBPRI, "ppbreq", 0); 39528257Smsmith break; 39628219Smsmith 39728257Smsmith default: 39828257Smsmith return (EWOULDBLOCK); 39928257Smsmith break; 40028257Smsmith } 40128219Smsmith 40228257Smsmith } else { 40328257Smsmith ppb->ppb_owner = dev; 40428219Smsmith 40538061Smsmith /* restore the context of the device 40638061Smsmith * The first time, ctx.valid is certainly false 40738061Smsmith * then do not change anything. This is usefull for 40838061Smsmith * drivers that do not set there operating mode 40938061Smsmith * during attachement 41038061Smsmith */ 41138061Smsmith if (dev->ctx.valid) 41238061Smsmith ppb_set_mode(dev, dev->ctx.mode); 41338061Smsmith 41428257Smsmith splx(s); 41528257Smsmith return (0); 41628257Smsmith } 41728257Smsmith } 41828219Smsmith 41928257Smsmith return (error); 42028219Smsmith} 42128219Smsmith 42228219Smsmith/* 42328257Smsmith * ppb_release_bus() 42428219Smsmith * 42528257Smsmith * Release the device allocated with ppb_request_dev() 42628219Smsmith */ 42728219Smsmithint 42828257Smsmithppb_release_bus(struct ppb_device *dev) 42928219Smsmith{ 43028257Smsmith int s; 43128219Smsmith struct ppb_data *ppb = dev->ppb; 43228219Smsmith 43328257Smsmith s = splhigh(); 43428257Smsmith if (ppb->ppb_owner != dev) { 43528257Smsmith splx(s); 43628219Smsmith return (EACCES); 43728257Smsmith } 43828219Smsmith 43928257Smsmith ppb->ppb_owner = 0; 44028257Smsmith splx(s); 44128219Smsmith 44238061Smsmith /* save the context of the device */ 44338061Smsmith dev->ctx.mode = ppb_get_mode(dev); 44438061Smsmith 44538061Smsmith /* ok, now the context of the device is valid */ 44638061Smsmith dev->ctx.valid = 1; 44738061Smsmith 44828257Smsmith /* wakeup waiting processes */ 44928257Smsmith wakeup(ppb); 45028219Smsmith 45128219Smsmith return (0); 45228219Smsmith} 453