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/boot/common/isapnp.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) 1998, Michael Smith
    3  * Copyright (c) 1996, Sujal M. Patel
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/8.2/sys/boot/common/isapnp.c 119483 2003-08-25 23:30:41Z obrien $");
   30 
   31 /*
   32  * Machine-independant ISA PnP enumerator implementing a subset of the
   33  * ISA PnP specification.
   34  */
   35 #include <stand.h>
   36 #include <string.h>
   37 #include <bootstrap.h>
   38 #include <isapnp.h>
   39 
   40 #define inb(x)          (archsw.arch_isainb((x)))
   41 #define outb(x,y)       (archsw.arch_isaoutb((x),(y)))
   42 
   43 static void     isapnp_write(int d, int r);
   44 static void     isapnp_send_Initiation_LFSR(void);
   45 static int      isapnp_get_serial(u_int8_t *p);
   46 static int      isapnp_isolation_protocol(void);
   47 static void     isapnp_enumerate(void);
   48 
   49 /* PnP read data port */
   50 int             isapnp_readport = 0;
   51 
   52 #define _PNP_ID_LEN     9
   53 
   54 struct pnphandler isapnphandler =
   55 {
   56     "ISA bus",
   57     isapnp_enumerate
   58 };
   59 
   60 static void
   61 isapnp_write(int d, int r)
   62 {
   63     outb (_PNP_ADDRESS, d);
   64     outb (_PNP_WRITE_DATA, r);
   65 }
   66 
   67 /*
   68  * Send Initiation LFSR as described in "Plug and Play ISA Specification",
   69  * Intel May 94.
   70  */
   71 static void
   72 isapnp_send_Initiation_LFSR(void)
   73 {
   74     int cur, i;
   75 
   76     /* Reset the LSFR */
   77     outb(_PNP_ADDRESS, 0);
   78     outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
   79 
   80     cur = 0x6a;
   81     outb(_PNP_ADDRESS, cur);
   82 
   83     for (i = 1; i < 32; i++) {
   84         cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
   85         outb(_PNP_ADDRESS, cur);
   86     }
   87 }
   88 
   89 /*
   90  * Get the device's serial number.  Returns 1 if the serial is valid.
   91  */
   92 static int
   93 isapnp_get_serial(u_int8_t *data)
   94 {
   95     int         i, bit, valid = 0, sum = 0x6a;
   96 
   97     bzero(data, _PNP_ID_LEN);
   98     outb(_PNP_ADDRESS, SERIAL_ISOLATION);
   99     for (i = 0; i < 72; i++) {
  100         bit = inb(isapnp_readport) == 0x55;
  101         delay(250);     /* Delay 250 usec */
  102 
  103         /* Can't Short Circuit the next evaluation, so 'and' is last */
  104         bit = (inb(isapnp_readport) == 0xaa) && bit;
  105         delay(250);     /* Delay 250 usec */
  106 
  107         valid = valid || bit;
  108 
  109         if (i < 64)
  110             sum = (sum >> 1) |
  111                 (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
  112 
  113         data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
  114     }
  115 
  116     valid = valid && (data[8] == sum);
  117 
  118     return valid;
  119 }
  120 
  121 /*
  122  * Fills the buffer with resource info from the device.
  123  * Returns nonzero if the device fails to report
  124  */
  125 static int
  126 isapnp_get_resource_info(u_int8_t *buffer, int len)
  127 {
  128     int         i, j;
  129     u_char      temp;
  130 
  131     for (i = 0; i < len; i++) {
  132         outb(_PNP_ADDRESS, STATUS);
  133         for (j = 0; j < 100; j++) {
  134             if ((inb(isapnp_readport)) & 0x1)
  135                 break;
  136             delay(1);
  137         }
  138         if (j == 100) {
  139             printf("PnP device failed to report resource data\n");
  140             return(1);
  141         }
  142         outb(_PNP_ADDRESS, RESOURCE_DATA);
  143         temp = inb(isapnp_readport);
  144         if (buffer != NULL)
  145             buffer[i] = temp;
  146     }
  147     return(0);
  148 }
  149 
  150 /*
  151  * Scan Resource Data for useful information.
  152  *
  153  * We scan the resource data for compatible device IDs and
  154  * identifier strings; we only take the first identifier string
  155  * and assume it's for the card as a whole.
  156  *
  157  * Returns 0 if the scan completed OK, nonzero on error.
  158  */
  159 static int
  160 isapnp_scan_resdata(struct pnpinfo *pi)
  161 {
  162     u_char      tag, resinfo[8];
  163     u_int       limit;
  164     size_t      large_len;
  165     u_char      *str;
  166 
  167     limit = 1000;
  168     while ((limit-- > 0) && !isapnp_get_resource_info(&tag, 1)) {
  169         if (PNP_RES_TYPE(tag) == 0) {
  170             /* Small resource */
  171             switch (PNP_SRES_NUM(tag)) {
  172 
  173                 case COMP_DEVICE_ID:
  174                     /* Got a compatible device id resource */
  175                     if (isapnp_get_resource_info(resinfo, PNP_SRES_LEN(tag)))
  176                         return(1);
  177                     pnp_addident(pi, pnp_eisaformat(resinfo));
  178 
  179                 case END_TAG:
  180                     return(0);
  181                     break;
  182 
  183                 default:
  184                     /* Skip this resource */
  185                     if (isapnp_get_resource_info(NULL, PNP_SRES_LEN(tag)))
  186                         return(1);
  187                     break;
  188             }
  189         } else {
  190             /* Large resource */
  191             if (isapnp_get_resource_info(resinfo, 2))
  192                 return(1);
  193 
  194             large_len = resinfo[1];
  195             large_len = (large_len << 8) + resinfo[0];
  196 
  197             switch(PNP_LRES_NUM(tag)) {
  198 
  199             case ID_STRING_ANSI:
  200                 str = malloc(large_len + 1);
  201                 if (isapnp_get_resource_info(str, (ssize_t)large_len)) {
  202                     free(str);
  203                     return(1);
  204                 }
  205                 str[large_len] = 0;
  206                 if (pi->pi_desc == NULL) {
  207                     pi->pi_desc = (char *)str;
  208                 } else {
  209                     free(str);
  210                 }
  211                 break;
  212                 
  213             default:
  214                 /* Large resource, skip it */
  215                 if (isapnp_get_resource_info(NULL, (ssize_t)large_len))
  216                     return(1);
  217             }
  218         }
  219     }
  220     return(1);
  221 }
  222 
  223 /*
  224  * Run the isolation protocol. Upon exiting, all cards are aware that
  225  * they should use isapnp_readport as the READ_DATA port.
  226  */
  227 static int
  228 isapnp_isolation_protocol(void)
  229 {
  230     int                 csn;
  231     struct pnpinfo      *pi;
  232     u_int8_t            cardid[_PNP_ID_LEN];
  233     int                 ndevs;
  234 
  235     isapnp_send_Initiation_LFSR();
  236     ndevs = 0;
  237     
  238     isapnp_write(CONFIG_CONTROL, 0x04); /* Reset CSN for All Cards */
  239 
  240     for (csn = 1; ; csn++) {
  241         /* Wake up cards without a CSN (ie. all of them) */
  242         isapnp_write(WAKE, 0);
  243         isapnp_write(SET_RD_DATA, (isapnp_readport >> 2));
  244         outb(_PNP_ADDRESS, SERIAL_ISOLATION);
  245         delay(1000);    /* Delay 1 msec */
  246 
  247         if (isapnp_get_serial(cardid)) {
  248             isapnp_write(SET_CSN, csn);
  249             pi = pnp_allocinfo();
  250             ndevs++;
  251             pnp_addident(pi, pnp_eisaformat(cardid));
  252             /* scan the card obtaining all the identifiers it holds */
  253             if (isapnp_scan_resdata(pi)) {
  254                 pnp_freeinfo(pi);       /* error getting data, ignore */
  255             } else {
  256                 pnp_addinfo(pi);
  257             }
  258         } else {
  259             break;
  260         }
  261     }
  262     /* Move all cards to wait-for-key state */
  263     while (--csn > 0) {
  264         isapnp_send_Initiation_LFSR();
  265         isapnp_write(WAKE, csn);
  266         isapnp_write(CONFIG_CONTROL, 0x02);
  267         delay(1000); /* XXX is it really necessary ? */
  268         csn--;
  269     }
  270     return(ndevs);
  271 }
  272 
  273 /*
  274  * Locate ISA-PnP devices and populate the supplied list.
  275  */
  276 static void
  277 isapnp_enumerate(void) 
  278 {
  279     int         pnp_rd_port;
  280     
  281     /* Check for I/O port access */
  282     if ((archsw.arch_isainb == NULL) || (archsw.arch_isaoutb == NULL))
  283         return;
  284 
  285     /* 
  286      * Validate a possibly-suggested read port value.  If the autoscan failed
  287      * last time, this will return us to autoscan mode again.
  288      */
  289     if ((isapnp_readport > 0) &&
  290         (((isapnp_readport < 0x203) ||
  291           (isapnp_readport > 0x3ff) ||
  292           (isapnp_readport & 0x3) != 0x3)))
  293          /* invalid, go look for ourselves */
  294         isapnp_readport = 0;
  295 
  296     if (isapnp_readport < 0) {
  297         /* someone is telling us there is no ISA in the system */
  298         return;
  299 
  300     } else if (isapnp_readport > 0) {
  301         /* Someone has told us where the port is/should be, or we found one last time */
  302         isapnp_isolation_protocol();
  303 
  304     } else {
  305         /* No clues, look for it ourselves */
  306         for (pnp_rd_port = 0x80; pnp_rd_port < 0xff; pnp_rd_port += 0x10) {
  307             /* Look for something, quit when we find it */
  308             isapnp_readport = (pnp_rd_port << 2) | 0x3;
  309             if (isapnp_isolation_protocol() > 0)
  310                 break;
  311         }
  312     }
  313 }

Cache object: 4d7b74e1f960a02fc27118f05e8d5e3d


[ 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.