ppbconf.c revision 28257
128219Smsmith/*- 228219Smsmith * Copyright (c) 1997 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 * 2628257Smsmith * $Id: ppbconf.c,v 1.1 1997/08/14 13:57:41 msmith Exp $ 2728219Smsmith * 2828219Smsmith */ 2928219Smsmith#include <sys/param.h> 3028219Smsmith#include <sys/systm.h> 3128219Smsmith#include <sys/errno.h> 3228219Smsmith#include <sys/conf.h> 3328219Smsmith#include <sys/proc.h> 3428219Smsmith#include <sys/buf.h> 3528219Smsmith#include <sys/kernel.h> 3628219Smsmith#include <sys/malloc.h> 3728219Smsmith#include <sys/uio.h> 3828219Smsmith#include <sys/syslog.h> 3928219Smsmith 4028219Smsmith#include <machine/clock.h> 4128219Smsmith#include <machine/lpt.h> 4228219Smsmith 4328219Smsmith#include <vm/vm.h> 4428219Smsmith#include <vm/vm_param.h> 4528219Smsmith#include <vm/pmap.h> 4628219Smsmith 4728219Smsmith#include <i386/isa/isa.h> 4828219Smsmith#include <i386/isa/isa_device.h> 4928219Smsmith 5028219Smsmith#include <dev/ppbus/ppbconf.h> 5128257Smsmith#include <dev/ppbus/ppb_1284.h> 5228219Smsmith 5328219SmsmithLIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ 5428219Smsmith 5528219Smsmith/* 5628219Smsmith * Add a null driver so that the linker set always exists. 5728219Smsmith */ 5828219Smsmith 5928219Smsmithstatic struct ppb_driver nulldriver = { 6028219Smsmith NULL, NULL, "null" 6128219Smsmith}; 6228219SmsmithDATA_SET(ppbdriver_set, nulldriver); 6328219Smsmith 6428219Smsmith 6528219Smsmith/* 6628219Smsmith * ppb_alloc_bus() 6728219Smsmith * 6828219Smsmith * Allocate area to store the ppbus description. 6928219Smsmith * This function is called by ppcattach(). 7028219Smsmith */ 7128219Smsmithstruct ppb_data * 7228219Smsmithppb_alloc_bus(void) 7328219Smsmith{ 7428219Smsmith struct ppb_data *ppb; 7528219Smsmith static int ppbdata_initted = 0; /* done-init flag */ 7628219Smsmith 7728219Smsmith ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 7828219Smsmith M_TEMP, M_NOWAIT); 7928219Smsmith 8028219Smsmith /* 8128219Smsmith * Add the new parallel port bus to the list of existing ppbus. 8228219Smsmith */ 8328219Smsmith if (ppb) { 8428219Smsmith bzero(ppb, sizeof(struct ppb_data)); 8528219Smsmith 8628219Smsmith if (!ppbdata_initted) { /* list not initialised */ 8728219Smsmith LIST_INIT(&ppbdata); 8828219Smsmith ppbdata_initted = 1; 8928219Smsmith } 9028219Smsmith LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 9128219Smsmith } else { 9228219Smsmith printf("ppb_alloc_bus: cannot malloc!\n"); 9328219Smsmith } 9428219Smsmith return(ppb); 9528219Smsmith} 9628219Smsmith 9728257Smsmithstatic char *pnp_tokens[] = { 9828257Smsmith "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 9928257Smsmith "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 10028257Smsmith 10128257Smsmithstatic char *pnp_classes[] = { 10228257Smsmith "printer", "modem", "network device", 10328257Smsmith "hard disk", "PCMCIA", "multimedia device", 10428257Smsmith "floppy disk", "ports", "scanner", 10528257Smsmith "digital camera", "unknown device", NULL }; 10628257Smsmith 10728219Smsmith/* 10828257Smsmith * search_token() 10928257Smsmith * 11028257Smsmith * Search the first occurence of a token within a string 11128257Smsmith */ 11228257Smsmithstatic char * 11328257Smsmithsearch_token(char *str, int slen, char *token) 11428257Smsmith{ 11528257Smsmith char *p; 11628257Smsmith int tlen, i, j; 11728257Smsmith 11828257Smsmith#define UNKNOWN_LENGTH -1 11928257Smsmith 12028257Smsmith if (slen == UNKNOWN_LENGTH) 12128257Smsmith /* get string's length */ 12228257Smsmith for (slen = 0, p = str; *p != '\0'; p++) 12328257Smsmith slen ++; 12428257Smsmith 12528257Smsmith /* get token's length */ 12628257Smsmith for (tlen = 0, p = token; *p != '\0'; p++) 12728257Smsmith tlen ++; 12828257Smsmith 12928257Smsmith if (tlen == 0) 13028257Smsmith return (str); 13128257Smsmith 13228257Smsmith for (i = 0; i <= slen-tlen; i++) { 13328257Smsmith for (j = 0; j < tlen; j++) 13428257Smsmith if (str[i+j] != token[j]) 13528257Smsmith break; 13628257Smsmith if (j == tlen) 13728257Smsmith return (&str[i]); 13828257Smsmith } 13928257Smsmith 14028257Smsmith return (NULL); 14128257Smsmith} 14228257Smsmith 14328257Smsmith/* 14428257Smsmith * ppb_pnp_detect() 14528257Smsmith * 14628257Smsmith * Returns the class id. of the peripherial, -1 otherwise 14728257Smsmith */ 14828257Smsmithstatic int 14928257Smsmithppb_pnp_detect(struct ppb_data *ppb) 15028257Smsmith{ 15128257Smsmith char *token, *q, *class = 0; 15228257Smsmith int i, len, error; 15328257Smsmith char str[PPB_PnP_STRING_SIZE+1]; 15428257Smsmith 15528257Smsmith struct ppb_device pnpdev; /* temporary device to perform I/O */ 15628257Smsmith 15728257Smsmith /* initialize the pnpdev structure for future use */ 15828257Smsmith bzero(&pnpdev, sizeof(pnpdev)); 15928257Smsmith 16028257Smsmith pnpdev.ppb = ppb; 16128257Smsmith 16228257Smsmith#ifdef PnP_DEBUG 16328257Smsmith printf("ppb: <PnP> probing PnP devices on ppbus%d...\n", 16428257Smsmith ppb->ppb_link->adapter_unit); 16528257Smsmith#endif 16628257Smsmith 16728257Smsmith ppb_wctr(&pnpdev, nINIT | SELECTIN); 16828257Smsmith 16928257Smsmith /* select NIBBLE_1284_REQUEST_ID mode */ 17028257Smsmith if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) { 17128257Smsmith#ifdef PnP_DEBUG 17228257Smsmith printf("ppb: <PnP> nibble_1284_mode()=%d\n", error); 17328257Smsmith#endif 17428257Smsmith return (-1); 17528257Smsmith } 17628257Smsmith 17728257Smsmith len = 0; 17828257Smsmith for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) { 17928257Smsmith if ((error = nibble_1284_inbyte(&pnpdev, q))) { 18028257Smsmith#ifdef PnP_DEBUG 18128257Smsmith printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error); 18228257Smsmith#endif 18328257Smsmith return (-1); 18428257Smsmith } 18528257Smsmith if (len++ >= PPB_PnP_STRING_SIZE) { 18628257Smsmith printf("ppb: <PnP> not space left!\n"); 18728257Smsmith return (-1); 18828257Smsmith } 18928257Smsmith } 19028257Smsmith *q = '\0'; 19128257Smsmith 19228257Smsmith nibble_1284_sync(&pnpdev); 19328257Smsmith 19428257Smsmith#ifdef PnP_DEBUG 19528257Smsmith printf("ppb: <PnP> %d characters: ", len); 19628257Smsmith for (i = 0; i < len; i++) 19728257Smsmith printf("0x%x ", str[i]); 19828257Smsmith printf("\n"); 19928257Smsmith#endif 20028257Smsmith 20128257Smsmith /* replace ';' characters by '\0' */ 20228257Smsmith for (i = 0; i < len; i++) 20328257Smsmith str[i] = (str[i] == ';') ? '\0' : str[i]; 20428257Smsmith 20528257Smsmith if ((token = search_token(str, len, "MFG")) != NULL) 20628257Smsmith printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, 20728257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 20828257Smsmith else 20928257Smsmith printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); 21028257Smsmith 21128257Smsmith if ((token = search_token(str, len, "MDL")) != NULL) 21228257Smsmith printf(" %s", 21328257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 21428257Smsmith else 21528257Smsmith printf(" unknown"); 21628257Smsmith 21728257Smsmith if ((token = search_token(str, len, "VER")) != NULL) 21828257Smsmith printf("/%s", 21928257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 22028257Smsmith 22128257Smsmith if ((token = search_token(str, len, "REV")) != NULL) 22228257Smsmith printf(".%s", 22328257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 22428257Smsmith 22528257Smsmith printf(">"); 22628257Smsmith 22728257Smsmith if ((token = search_token(str, len, "CLS")) != NULL) { 22828257Smsmith class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 22928257Smsmith printf(" %s", class); 23028257Smsmith } 23128257Smsmith 23228257Smsmith if ((token = search_token(str, len, "CMD")) != NULL) 23328257Smsmith printf(" %s", 23428257Smsmith search_token(token, UNKNOWN_LENGTH, ":") + 1); 23528257Smsmith 23628257Smsmith printf("\n"); 23728257Smsmith 23828257Smsmith if (class) 23928257Smsmith /* identify class ident */ 24028257Smsmith for (i = 0; pnp_tokens[i] != NULL; i++) { 24128257Smsmith if (search_token(class, len, pnp_tokens[i]) != NULL) { 24228257Smsmith return (i); 24328257Smsmith break; 24428257Smsmith } 24528257Smsmith } 24628257Smsmith 24728257Smsmith return (PPB_PnP_UNKNOWN); 24828257Smsmith} 24928257Smsmith 25028257Smsmith/* 25128219Smsmith * ppb_attachdevs() 25228219Smsmith * 25328219Smsmith * Called by ppcattach(), this function probes the ppbus and 25428219Smsmith * attaches found devices. 25528219Smsmith */ 25628219Smsmithint 25728219Smsmithppb_attachdevs(struct ppb_data *ppb) 25828219Smsmith{ 25928219Smsmith int error; 26028219Smsmith struct ppb_device *dev; 26128219Smsmith struct ppb_driver **p_drvpp, *p_drvp; 26228257Smsmith 26328219Smsmith LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 26428219Smsmith p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 26528257Smsmith 26628257Smsmith /* detect PnP devices */ 26728257Smsmith ppb->class_id = ppb_pnp_detect(ppb); 26828219Smsmith 26928219Smsmith /* 27028219Smsmith * Blindly try all probes here. Later we should look at 27128219Smsmith * the parallel-port PnP standard, and intelligently seek 27228219Smsmith * drivers based on configuration first. 27328219Smsmith */ 27428219Smsmith while ((p_drvp = *p_drvpp++) != NULL) { 27528219Smsmith if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 27628219Smsmith /* 27728219Smsmith * Add the device to the list of probed devices. 27828219Smsmith */ 27928219Smsmith LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 28028219Smsmith 28128219Smsmith /* Call the device's attach routine */ 28228219Smsmith (void)p_drvp->attach(dev); 28328219Smsmith } 28428219Smsmith } 28528219Smsmith return (0); 28628219Smsmith} 28728219Smsmith 28828219Smsmith/* 28928257Smsmith * ppb_next_bus() 29028219Smsmith * 29128257Smsmith * Return the next bus in ppbus queue 29228219Smsmith */ 29328257Smsmithstruct ppb_data * 29428257Smsmithppb_next_bus(struct ppb_data *ppb) 29528219Smsmith{ 29628219Smsmith 29728257Smsmith if (ppb == NULL) 29828257Smsmith return (ppbdata.lh_first); 29928219Smsmith 30028257Smsmith return (ppb->ppb_chain.le_next); 30128257Smsmith} 30228219Smsmith 30328257Smsmith/* 30428257Smsmith * ppb_lookup_bus() 30528257Smsmith * 30628257Smsmith * Get ppb_data structure pointer according to the base address of the ppbus 30728257Smsmith */ 30828257Smsmithstruct ppb_data * 30928257Smsmithppb_lookup_bus(int base_port) 31028257Smsmith{ 31128257Smsmith struct ppb_data *ppb; 31228219Smsmith 31328257Smsmith for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 31428257Smsmith if (ppb->ppb_link->base == base_port) 31528257Smsmith break; 31628219Smsmith 31728257Smsmith return (ppb); 31828219Smsmith} 31928219Smsmith 32028219Smsmith/* 32128257Smsmith * ppb_attach_device() 32228219Smsmith * 32328257Smsmith * Called by loadable kernel modules to add a device 32428219Smsmith */ 32528219Smsmithint 32628257Smsmithppb_attach_device(struct ppb_device *dev) 32728219Smsmith{ 32828219Smsmith struct ppb_data *ppb = dev->ppb; 32928219Smsmith 33028257Smsmith /* add the device to the list of probed devices */ 33128257Smsmith LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 33228219Smsmith 33328219Smsmith return (0); 33428219Smsmith} 33528219Smsmith 33628219Smsmith/* 33728257Smsmith * ppb_remove_device() 33828219Smsmith * 33928257Smsmith * Called by loadable kernel modules to remove a device 34028219Smsmith */ 34128219Smsmithvoid 34228257Smsmithppb_remove_device(struct ppb_device *dev) 34328219Smsmith{ 34428219Smsmith 34528257Smsmith /* remove the device from the list of probed devices */ 34628257Smsmith LIST_REMOVE(dev, chain); 34728219Smsmith 34828219Smsmith return; 34928219Smsmith} 35028219Smsmith 35128219Smsmith/* 35228257Smsmith * ppb_request_bus() 35328219Smsmith * 35428257Smsmith * Allocate the device to perform transfers. 35528257Smsmith * 35628257Smsmith * how : PPB_WAIT or PPB_DONTWAIT 35728219Smsmith */ 35828219Smsmithint 35928257Smsmithppb_request_bus(struct ppb_device *dev, int how) 36028219Smsmith{ 36128257Smsmith int s, error = 0; 36228219Smsmith struct ppb_data *ppb = dev->ppb; 36328219Smsmith 36428257Smsmith while (!error) { 36528257Smsmith s = splhigh(); 36628257Smsmith if (ppb->ppb_owner) { 36728257Smsmith splx(s); 36828219Smsmith 36928257Smsmith switch (how) { 37028257Smsmith case (PPB_WAIT | PPB_INTR): 37128257Smsmith error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 37228257Smsmith break; 37328219Smsmith 37428257Smsmith case (PPB_WAIT | PPB_NOINTR): 37528257Smsmith error = tsleep(ppb, PPBPRI, "ppbreq", 0); 37628257Smsmith break; 37728219Smsmith 37828257Smsmith default: 37928257Smsmith return (EWOULDBLOCK); 38028257Smsmith break; 38128257Smsmith } 38228219Smsmith 38328257Smsmith } else { 38428257Smsmith ppb->ppb_owner = dev; 38528219Smsmith 38628257Smsmith splx(s); 38728257Smsmith return (0); 38828257Smsmith } 38928257Smsmith } 39028219Smsmith 39128257Smsmith return (error); 39228219Smsmith} 39328219Smsmith 39428219Smsmith/* 39528257Smsmith * ppb_release_bus() 39628219Smsmith * 39728257Smsmith * Release the device allocated with ppb_request_dev() 39828219Smsmith */ 39928219Smsmithint 40028257Smsmithppb_release_bus(struct ppb_device *dev) 40128219Smsmith{ 40228257Smsmith int s; 40328219Smsmith struct ppb_data *ppb = dev->ppb; 40428219Smsmith 40528257Smsmith s = splhigh(); 40628257Smsmith if (ppb->ppb_owner != dev) { 40728257Smsmith splx(s); 40828219Smsmith return (EACCES); 40928257Smsmith } 41028219Smsmith 41128257Smsmith ppb->ppb_owner = 0; 41228257Smsmith splx(s); 41328219Smsmith 41428257Smsmith /* wakeup waiting processes */ 41528257Smsmith wakeup(ppb); 41628219Smsmith 41728219Smsmith return (0); 41828219Smsmith} 419