The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ppbus/ppbconf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  *
   28  */
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/linker_set.h>
   32 #include <sys/malloc.h>
   33 
   34 #include <vm/vm.h>
   35 #include <vm/pmap.h>
   36 
   37 #include <dev/ppbus/ppbconf.h>
   38 #include <dev/ppbus/ppb_1284.h>
   39 
   40 #include "opt_ppb_1284.h"
   41 
   42 LIST_HEAD(, ppb_data)   ppbdata;        /* list of existing ppbus */
   43 
   44 /*
   45  * Add a null driver so that the linker set always exists.
   46  */
   47 
   48 static struct ppb_driver nulldriver = {
   49     NULL, NULL, "null"
   50 };
   51 DATA_SET(ppbdriver_set, nulldriver);
   52 
   53 
   54 /*
   55  * ppb_alloc_bus()
   56  *
   57  * Allocate area to store the ppbus description.
   58  */
   59 struct ppb_data *
   60 ppb_alloc_bus(void)
   61 {
   62         struct ppb_data *ppb;
   63         static int ppbdata_initted = 0;         /* done-init flag */
   64 
   65         ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data),
   66                 M_TEMP, M_NOWAIT);
   67 
   68         /*
   69          * Add the new parallel port bus to the list of existing ppbus.
   70          */
   71         if (ppb) {
   72                 bzero(ppb, sizeof(struct ppb_data));
   73 
   74                 if (!ppbdata_initted) {         /* list not initialised */
   75                     LIST_INIT(&ppbdata);
   76                     ppbdata_initted = 1;
   77                 }
   78                 LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain);
   79         } else {
   80                 printf("ppb_alloc_bus: cannot malloc!\n");
   81         }
   82         return(ppb);
   83 }
   84 
   85 #define PPB_PNP_PRINTER         0
   86 #define PPB_PNP_MODEM           1
   87 #define PPB_PNP_NET             2
   88 #define PPB_PNP_HDC             3
   89 #define PPB_PNP_PCMCIA          4
   90 #define PPB_PNP_MEDIA           5
   91 #define PPB_PNP_FDC             6
   92 #define PPB_PNP_PORTS           7
   93 #define PPB_PNP_SCANNER         8
   94 #define PPB_PNP_DIGICAM         9
   95 
   96 #ifndef DONTPROBE_1284
   97 
   98 static char *pnp_tokens[] = {
   99         "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
  100         "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
  101 
  102 #if 0
  103 static char *pnp_classes[] = {
  104         "printer", "modem", "network device",
  105         "hard disk", "PCMCIA", "multimedia device",
  106         "floppy disk", "ports", "scanner",
  107         "digital camera", "unknown device", NULL };
  108 #endif
  109 
  110 /*
  111  * search_token()
  112  *
  113  * Search the first occurence of a token within a string
  114  *
  115  * XXX should use strxxx() calls
  116  */
  117 static char *
  118 search_token(char *str, int slen, char *token)
  119 {
  120         char *p;
  121         int tlen, i, j;
  122 
  123 #define UNKNOWN_LENGTH  -1
  124 
  125         if (slen == UNKNOWN_LENGTH)
  126                 /* get string's length */
  127                 for (slen = 0, p = str; *p != '\0'; p++)
  128                         slen ++;
  129 
  130         /* get token's length */
  131         for (tlen = 0, p = token; *p != '\0'; p++)
  132                 tlen ++;
  133 
  134         if (tlen == 0)
  135                 return (str);
  136 
  137         for (i = 0; i <= slen-tlen; i++) {
  138                 for (j = 0; j < tlen; j++)
  139                         if (str[i+j] != token[j])
  140                                 break;
  141                 if (j == tlen)
  142                         return (&str[i]);
  143         }
  144 
  145         return (NULL);
  146 }
  147 
  148 /*
  149  * ppb_pnp_detect()
  150  *
  151  * Returns the class id. of the peripherial, -1 otherwise
  152  */
  153 static int
  154 ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev)
  155 {
  156         char *token, *class = 0;
  157         int i, len, error;
  158         int class_id = -1;
  159         char str[PPB_PnP_STRING_SIZE+1];
  160 
  161         printf("Probing for PnP devices on ppbus%d:\n",
  162                         ppb->ppb_link->adapter_unit);
  163         
  164         if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str,
  165                                         PPB_PnP_STRING_SIZE, &len)))
  166                 goto end_detect;
  167 
  168 #ifdef DEBUG_1284
  169         printf("ppb: <PnP> %d characters: ", len);
  170         for (i = 0; i < len; i++)
  171                 printf("%c(0x%x) ", str[i], str[i]);
  172         printf("\n");
  173 #endif
  174 
  175         /* replace ';' characters by '\0' */
  176         for (i = 0; i < len; i++)
  177                 str[i] = (str[i] == ';') ? '\0' : str[i];
  178 
  179         if ((token = search_token(str, len, "MFG")) != NULL ||
  180                 (token = search_token(str, len, "MANUFACTURER")) != NULL)
  181                 printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
  182                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  183         else
  184                 printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
  185 
  186         if ((token = search_token(str, len, "MDL")) != NULL ||
  187                 (token = search_token(str, len, "MODEL")) != NULL)
  188                 printf(" %s",
  189                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  190         else
  191                 printf(" unknown");
  192 
  193         if ((token = search_token(str, len, "VER")) != NULL)
  194                 printf("/%s",
  195                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  196 
  197         if ((token = search_token(str, len, "REV")) != NULL)
  198                 printf(".%s",
  199                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  200 
  201         printf(">");
  202 
  203         if ((token = search_token(str, len, "CLS")) != NULL) {
  204                 class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
  205                 printf(" %s", class);
  206         }
  207 
  208         if ((token = search_token(str, len, "CMD")) != NULL ||
  209                 (token = search_token(str, len, "COMMAND")) != NULL)
  210                 printf(" %s",
  211                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  212 
  213         printf("\n");
  214 
  215         if (class)
  216                 /* identify class ident */
  217                 for (i = 0; pnp_tokens[i] != NULL; i++) {
  218                         if (search_token(class, len, pnp_tokens[i]) != NULL) {
  219                                 class_id = i;
  220                                 goto end_detect;
  221                         }
  222                 }
  223 
  224         class_id = PPB_PnP_UNKNOWN;
  225 
  226 end_detect:
  227         return (class_id);
  228 }
  229 
  230 /*
  231  * ppb_scan_bus()
  232  *
  233  * Scan the ppbus for IEEE1284 compliant devices
  234  */
  235 static int
  236 ppb_scan_bus(struct ppb_data *ppb)
  237 {
  238         struct ppb_device pnpdev;       /* temporary device to perform I/O */
  239         int error = 0;
  240 
  241         /* initialize the pnpdev structure for future use */
  242         bzero(&pnpdev, sizeof(pnpdev));
  243         pnpdev.ppb = ppb;
  244 
  245         if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) {
  246                 if (bootverbose)
  247                         printf("ppb: cannot allocate ppbus!\n");
  248 
  249                 return (error);
  250         }
  251 
  252         /* try all IEEE1284 modes, for one device only
  253          * 
  254          * XXX We should implement the IEEE1284.3 standard to detect
  255          * daisy chained devices
  256          */
  257 
  258         error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID);
  259 
  260         if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
  261                 goto end_scan;
  262 
  263         ppb_1284_terminate(&pnpdev);
  264 
  265         printf("ppb%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit);
  266 
  267         if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) {
  268                 printf("/NIBBLE");
  269                 ppb_1284_terminate(&pnpdev);
  270         }
  271 
  272         if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) {
  273                 printf("/PS2");
  274                 ppb_1284_terminate(&pnpdev);
  275         }
  276 
  277         if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) {
  278                 printf("/ECP");
  279                 ppb_1284_terminate(&pnpdev);
  280         }
  281 
  282         if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) {
  283                 printf("/ECP_RLE");
  284                 ppb_1284_terminate(&pnpdev);
  285         }
  286 
  287         if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) {
  288                 printf("/EPP");
  289                 ppb_1284_terminate(&pnpdev);
  290         }
  291 
  292         /* try more IEEE1284 modes */
  293         if (bootverbose) {
  294                 if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE,
  295                                 PPB_REQUEST_ID))) {
  296                         printf("/NIBBLE_ID");
  297                         ppb_1284_terminate(&pnpdev);
  298                 }
  299 
  300                 if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2,
  301                                 PPB_REQUEST_ID))) {
  302                         printf("/PS2_ID");
  303                         ppb_1284_terminate(&pnpdev);
  304                 }
  305 
  306                 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
  307                                 PPB_REQUEST_ID))) {
  308                         printf("/ECP_ID");
  309                         ppb_1284_terminate(&pnpdev);
  310                 }
  311 
  312                 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
  313                                 PPB_REQUEST_ID | PPB_USE_RLE))) {
  314                         printf("/ECP_RLE_ID");
  315                         ppb_1284_terminate(&pnpdev);
  316                 }
  317 
  318                 if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
  319                                 PPB_EXTENSIBILITY_LINK))) {
  320                         printf("/Extensibility Link");
  321                         ppb_1284_terminate(&pnpdev);
  322                 }
  323         }
  324 
  325         printf("\n");
  326 
  327         /* detect PnP devices */
  328         ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
  329 
  330         ppb_release_bus(&pnpdev);
  331 
  332         return (0);
  333 
  334 end_scan:
  335         ppb_release_bus(&pnpdev);
  336         return (error);
  337 }
  338 
  339 #endif /* !DONTPROBE_1284 */
  340 
  341 /*
  342  * ppb_attachdevs()
  343  *
  344  * Called by ppcattach(), this function probes the ppbus and
  345  * attaches found devices.
  346  */
  347 int
  348 ppb_attachdevs(struct ppb_data *ppb)
  349 {
  350         struct ppb_device *dev;
  351         struct ppb_driver **p_drvpp, *p_drvp;
  352 
  353         LIST_INIT(&ppb->ppb_devs);      /* initialise device/driver list */
  354         p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
  355 
  356 #ifndef DONTPROBE_1284
  357         /* detect IEEE1284 compliant devices */
  358         ppb_scan_bus(ppb);
  359 #endif /* !DONTPROBE_1284 */
  360         
  361         /*
  362          * Blindly try all probes here.  Later we should look at
  363          * the parallel-port PnP standard, and intelligently seek
  364          * drivers based on configuration first.
  365          */
  366         while ((p_drvp = *p_drvpp++) != NULL) {
  367             if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) {
  368                 /*
  369                  * Add the device to the list of probed devices.
  370                  */
  371                 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
  372                 
  373                 /* Call the device's attach routine */
  374                 (void)p_drvp->attach(dev);
  375             }
  376         }
  377         return (0);
  378 }
  379 
  380 /*
  381  * ppb_next_bus()
  382  *
  383  * Return the next bus in ppbus queue
  384  */
  385 struct ppb_data *
  386 ppb_next_bus(struct ppb_data *ppb)
  387 {
  388 
  389         if (ppb == NULL)
  390                 return (ppbdata.lh_first);
  391 
  392         return (ppb->ppb_chain.le_next);
  393 }
  394 
  395 /*
  396  * ppb_lookup_bus()
  397  *
  398  * Get ppb_data structure pointer according to the base address of the ppbus
  399  */
  400 struct ppb_data *
  401 ppb_lookup_bus(int base_port)
  402 {
  403         struct ppb_data *ppb;
  404 
  405         for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
  406                 if (ppb->ppb_link->base == base_port)
  407                         break;
  408 
  409         return (ppb);
  410 }
  411 
  412 /*
  413  * ppb_lookup_link()
  414  *
  415  * Get ppb_data structure pointer according to the unit value
  416  * of the corresponding link structure
  417  */
  418 struct ppb_data *
  419 ppb_lookup_link(int unit)
  420 {
  421         struct ppb_data *ppb;
  422 
  423         for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
  424                 if (ppb->ppb_link->adapter_unit == unit)
  425                         break;
  426 
  427         return (ppb);
  428 }
  429 
  430 /*
  431  * ppb_attach_device()
  432  *
  433  * Called by loadable kernel modules to add a device
  434  */
  435 int
  436 ppb_attach_device(struct ppb_device *dev)
  437 {
  438         struct ppb_data *ppb = dev->ppb;
  439 
  440         /* add the device to the list of probed devices */
  441         LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
  442 
  443         return (0);
  444 }
  445 
  446 /*
  447  * ppb_remove_device()
  448  *
  449  * Called by loadable kernel modules to remove a device
  450  */
  451 void
  452 ppb_remove_device(struct ppb_device *dev)
  453 {
  454 
  455         /* remove the device from the list of probed devices */
  456         LIST_REMOVE(dev, chain);
  457 
  458         return;
  459 }
  460 
  461 /*
  462  * ppb_request_bus()
  463  *
  464  * Allocate the device to perform transfers.
  465  *
  466  * how  : PPB_WAIT or PPB_DONTWAIT
  467  */
  468 int
  469 ppb_request_bus(struct ppb_device *dev, int how)
  470 {
  471         int s, error = 0;
  472         struct ppb_data *ppb = dev->ppb;
  473 
  474         while (!error) {
  475                 s = splhigh();  
  476                 if (ppb->ppb_owner) {
  477                         splx(s);
  478 
  479                         switch (how) {
  480                         case (PPB_WAIT | PPB_INTR):
  481                                 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
  482                                 break;
  483 
  484                         case (PPB_WAIT | PPB_NOINTR):
  485                                 error = tsleep(ppb, PPBPRI, "ppbreq", 0);
  486                                 break;
  487 
  488                         default:
  489                                 return (EWOULDBLOCK);
  490                                 break;
  491                         }
  492 
  493                 } else {
  494                         ppb->ppb_owner = dev;
  495 
  496                         /* restore the context of the device
  497                          * The first time, ctx.valid is certainly false
  498                          * then do not change anything. This is usefull for
  499                          * drivers that do not set there operating mode 
  500                          * during attachement
  501                          */
  502                         if (dev->ctx.valid)
  503                                 ppb_set_mode(dev, dev->ctx.mode);
  504 
  505                         splx(s);
  506                         return (0);
  507                 }
  508         }
  509 
  510         return (error);
  511 }
  512 
  513 /*
  514  * ppb_release_bus()
  515  *
  516  * Release the device allocated with ppb_request_dev()
  517  */
  518 int
  519 ppb_release_bus(struct ppb_device *dev)
  520 {
  521         int s;
  522         struct ppb_data *ppb = dev->ppb;
  523 
  524         s = splhigh();
  525         if (ppb->ppb_owner != dev) {
  526                 splx(s);
  527                 return (EACCES);
  528         }
  529 
  530         ppb->ppb_owner = 0;
  531         splx(s);
  532 
  533         /* save the context of the device */
  534         dev->ctx.mode = ppb_get_mode(dev);
  535 
  536         /* ok, now the context of the device is valid */
  537         dev->ctx.valid = 1;
  538 
  539         /* wakeup waiting processes */
  540         wakeup(ppb);
  541 
  542         return (0);
  543 }

Cache object: 2d74347ab74f9e10fdf345675d227c37


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.