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/i386/isa/pnp.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) 1996, Sujal M. Patel
    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 #include <sys/interrupt.h>
   34 #include <machine/clock.h>
   35 #include <machine/md_var.h>
   36 
   37 #include <i386/isa/icu.h>
   38 #include <i386/isa/isa_device.h>
   39 #include <i386/isa/pnp.h>
   40 
   41 typedef struct _pnp_id {
   42         u_long vendor_id;
   43         u_long serial;
   44         u_char checksum;
   45         u_long comp_id;
   46 } pnp_id;
   47 
   48 static int num_pnp_cards = 0;
   49 pnp_id pnp_devices[MAX_PNP_CARDS];
   50 struct pnp_dlist_node *pnp_device_list;
   51 static struct pnp_dlist_node **pnp_device_list_last_ptr;
   52 
   53 /*
   54  * these entries are initialized using the autoconfig menu
   55  * The struct is invalid (and must be initialized) if the first
   56  * CSN is zero. The init code fills invalid entries with CSN 255
   57  * which is not a supported value.
   58  */
   59 
   60 struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN] = { { 0 } };
   61 
   62 /*
   63  * the following is a flag which tells if the data is valid.
   64  */
   65 static int doing_pnp_probe = 0 ;
   66 static int current_csn ;
   67 static int current_pnp_id ;
   68 static int current_pnp_serial ;
   69 
   70 /*
   71  * the following block is an example on what is needed for
   72  * a PnP device driver.
   73  */
   74 static  char*   nullpnp_probe(u_long csn, u_long vendor_id);
   75 static  void    nullpnp_attach(u_long csn, u_long vendor_id, char *name,
   76     struct isa_device *dev);
   77 static  u_long  nullpnp_count = 0 ;
   78 
   79 static struct pnp_device nullpnp_device = {
   80     "goodpnp",
   81     nullpnp_probe,
   82     nullpnp_attach,
   83     &nullpnp_count,
   84     NULL /* imask */
   85 };
   86 
   87 DATA_SET (pnpdevice_set, nullpnp_device);
   88 
   89 static char*
   90 nullpnp_probe(u_long tag, u_long type)
   91 {
   92     if (bootverbose)
   93             printf("Called nullpnp_probe with tag 0x%08lx, type 0x%08lx\n",
   94                     tag, type);
   95     return NULL;
   96 }
   97 
   98 static void
   99 nullpnp_attach(u_long csn, u_long vend_id, char *name,
  100         struct isa_device *dev)
  101 {
  102     printf("nullpnp_attach: csn %ld, vend_id 0x%08lx name %s unit %d\n",
  103             csn, vend_id, name, dev->id_unit);
  104     return;
  105 }
  106 
  107 /* The READ_DATA port that we are using currently */
  108 static int pnp_rd_port;
  109 
  110 static void   pnp_send_Initiation_LFSR (void);
  111 static int    pnp_get_serial (pnp_id *p);
  112 static void   config_pnp_device (pnp_id *p, int csn);
  113 static int    pnp_isolation_protocol (void);
  114 
  115 void
  116 pnp_write(int d, u_char r)
  117 {
  118     outb (_PNP_ADDRESS, d);
  119     outb (_PNP_WRITE_DATA, r);
  120 }
  121 
  122 u_char
  123 pnp_read(int d)
  124 {
  125     outb (_PNP_ADDRESS, d);
  126     return (inb(3 | (pnp_rd_port <<2)));
  127 }
  128 
  129 /*
  130  * Send Initiation LFSR as described in "Plug and Play ISA Specification",
  131  * Intel May 94.
  132  */
  133 static void
  134 pnp_send_Initiation_LFSR()
  135 {
  136     int cur, i;
  137 
  138     /* Reset the LSFR */
  139     outb(_PNP_ADDRESS, 0);
  140     outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
  141 
  142     cur = 0x6a;
  143     outb(_PNP_ADDRESS, cur);
  144 
  145     for (i = 1; i < 32; i++) {
  146         cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
  147         outb(_PNP_ADDRESS, cur);
  148     }
  149 }
  150 
  151 
  152 /*
  153  * Get the device's serial number.  Returns 1 if the serial is valid.
  154  */
  155 static int
  156 pnp_get_serial(pnp_id *p)
  157 {
  158     int i, bit, valid = 0, sum = 0x6a;
  159     u_char *data = (u_char *)p;
  160 
  161     bzero(data, sizeof(char) * 9);
  162     outb(_PNP_ADDRESS, SERIAL_ISOLATION);
  163     for (i = 0; i < 72; i++) {
  164         bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;
  165         DELAY(250);     /* Delay 250 usec */
  166 
  167         /* Can't Short Circuit the next evaluation, so 'and' is last */
  168         bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;
  169         DELAY(250);     /* Delay 250 usec */
  170 
  171         valid = valid || bit;
  172 
  173         if (i < 64)
  174             sum = (sum >> 1) |
  175                 (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
  176 
  177         data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
  178     }
  179 
  180     valid = valid && (data[8] == sum);
  181 
  182     return valid;
  183 }
  184 
  185 /*
  186  * Fill's the buffer with resource info from the device.
  187  * Returns 0 if the device fails to report
  188  */
  189 static int
  190 pnp_get_resource_info(u_char *buffer, int len)
  191 {
  192     int i, j;
  193     u_char temp;
  194 
  195     for (i = 0; i < len; i++) {
  196         outb(_PNP_ADDRESS, STATUS);
  197         for (j = 0; j < 100; j++) {
  198             if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)
  199                 break;
  200             DELAY(1);
  201         }
  202         if (j == 100) {
  203             printf("PnP device failed to report resource data\n");
  204             return 0;
  205         }
  206         outb(_PNP_ADDRESS, RESOURCE_DATA);
  207         temp = inb((pnp_rd_port << 2) | 0x3);
  208         if (buffer != NULL)
  209             buffer[i] = temp;
  210     }
  211     return 1;
  212 }
  213 
  214 /*
  215  * read_pnp_parms loads pnp parameters from the currently selected
  216  * device into the struct pnp_cinfo parameter passed.
  217  * The second argument specifies the Logical Device to use.
  218  */
  219 int
  220 read_pnp_parms(struct pnp_cinfo *d, int ldn)
  221 {
  222     int i ;
  223 
  224     if (doing_pnp_probe == 0 || d == NULL)
  225         return 0 ;      /* fail */
  226 
  227     bzero(d, sizeof(struct pnp_cinfo));
  228     d->vendor_id = current_pnp_id ;
  229     d->serial = current_pnp_serial ;
  230 
  231     d->csn = current_csn ;
  232     d->ldn = ldn ;      /* XXX this should be different ... */
  233     pnp_write (SET_LDN, ldn );
  234     i = pnp_read(SET_LDN) ;
  235     if (i != ldn) {
  236         printf("Warning: LDN %d does not exist\n", ldn);
  237     }
  238     for (i = 0; i < 8; i++) {
  239         d->port[i] = pnp_read(IO_CONFIG_BASE + i * 2) << 8 ;
  240         d->port[i] |= pnp_read(IO_CONFIG_BASE + i * 2 + 1);
  241 
  242         if (i < 4) {
  243             d->mem[i].base = pnp_read (MEM_CONFIG + i*8) << 16 ;
  244             d->mem[i].base |= pnp_read (MEM_CONFIG + i*8 + 1) << 8 ;
  245             d->mem[i].control = pnp_read (MEM_CONFIG + i*8 + 2) ;
  246             d->mem[i].range = pnp_read (MEM_CONFIG + i*8 + 3) << 16 ;
  247             d->mem[i].range |= pnp_read (MEM_CONFIG + i*8 + 4) << 8 ;
  248         }
  249         if (i < 2) {
  250             d->irq[i] = pnp_read(IRQ_CONFIG + i * 2);
  251             d->irq_type[i] = pnp_read(IRQ_CONFIG + 1 + i * 2);
  252             d->drq[i] = pnp_read(DRQ_CONFIG + i);
  253         }
  254     }
  255     d->enable = pnp_read(ACTIVATE);
  256     for (i = 0 ; i < MAX_PNP_LDN; i++) {
  257         if (pnp_ldn_overrides[i].csn == d->csn &&
  258                 pnp_ldn_overrides[i].ldn == ldn) {
  259             d->flags = pnp_ldn_overrides[i].flags ;
  260             d->override = pnp_ldn_overrides[i].override ;
  261             break ;
  262         }
  263     }
  264     if (bootverbose)
  265         printf("port 0x%04x 0x%04x 0x%04x 0x%04x irq %d:%d drq %d:%d en %d\n",
  266             d->port[0], d->port[1], d->port[2], d->port[3],
  267             d->irq[0], d->irq[1],
  268             d->drq[0], d->drq[1],
  269             d->enable);
  270     return 1 ; /* success */
  271 }
  272 
  273 /*
  274  * write_pnp_parms initializes a logical device with the parms
  275  * in d, and then activates the board if the last parameter is 1.
  276  */
  277 
  278 int
  279 write_pnp_parms(struct pnp_cinfo *d, int ldn)
  280 {
  281     int i, empty = -1 ;
  282 
  283     /*
  284      * some safety checks first.
  285      */
  286     if (doing_pnp_probe == 0 || d==NULL || d->vendor_id != current_pnp_id)
  287         return 0 ;      /* fail */
  288 
  289     pnp_write (SET_LDN, ldn );
  290     i = pnp_read(SET_LDN) ;
  291     if (i != ldn) {
  292         printf("Warning: LDN %d does not exist\n", ldn);
  293     }
  294     for (i = 0; i < 8; i++) {
  295         pnp_write(IO_CONFIG_BASE + i * 2, d->port[i] >> 8 );
  296         pnp_write(IO_CONFIG_BASE + i * 2 + 1, d->port[i] & 0xff );
  297     }
  298     for (i = 0; i < 4; i++) {
  299         pnp_write(MEM_CONFIG + i*8, (d->mem[i].base >> 16) & 0xff );
  300         pnp_write(MEM_CONFIG + i*8+1, (d->mem[i].base >> 8) & 0xff );
  301         pnp_write(MEM_CONFIG + i*8+2, d->mem[i].control & 0xff );
  302         pnp_write(MEM_CONFIG + i*8+3, (d->mem[i].range >> 16) & 0xff );
  303         pnp_write(MEM_CONFIG + i*8+4, (d->mem[i].range >> 8) & 0xff );
  304     }
  305     for (i = 0; i < 2; i++) {
  306         pnp_write(IRQ_CONFIG + i*2    , d->irq[i] );
  307         pnp_write(IRQ_CONFIG + i*2 + 1, d->irq_type[i] );
  308         pnp_write(DRQ_CONFIG + i, d->drq[i] );
  309     }
  310     /*
  311      * store parameters read into the current kernel
  312      * so manual editing next time is easier
  313      */
  314     for (i = 0 ; i < MAX_PNP_LDN; i++) {
  315         if (pnp_ldn_overrides[i].csn == d->csn &&
  316                 pnp_ldn_overrides[i].ldn == ldn) {
  317             d->flags = pnp_ldn_overrides[i].flags ;
  318             pnp_ldn_overrides[i] = *d ;
  319             break ;
  320         } else if (pnp_ldn_overrides[i].csn < 1 ||
  321                 pnp_ldn_overrides[i].csn == 255)
  322             empty = i ;
  323     }
  324     if (i== MAX_PNP_LDN && empty != -1)
  325         pnp_ldn_overrides[empty] = *d;
  326 
  327     /*
  328      * Here should really perform the range check, and
  329      * return a failure if not successful.
  330      */
  331     pnp_write (IO_RANGE_CHECK, 0);
  332     DELAY(1000); /* XXX is it really necessary ? */
  333     pnp_write (ACTIVATE, d->enable ? 1 : 0);
  334     DELAY(1000); /* XXX is it really necessary ? */
  335     return 1 ;
  336 }
  337 
  338 /*
  339  * To finalize a card's initialization, and before accessing its
  340  * registers, we need to bring the card in WaitForKey. To this purpose,
  341  * we need to issue a WaitForKey command, which brings _all_ cards
  342  * in that state. So, before configuring the next board, we must also
  343  * sent the Init-Key to bring cards to the SLEEP state again.
  344  *
  345  * In fact, one could hope that cards respond to normal I/O accesses
  346  * even in the SLEEP state, which could be done by issuing a WAKE[0].
  347  * This seems to work on the CS4236, but not on the CS4232 on my Zappa
  348  * motherboard .
  349  */
  350 int
  351 enable_pnp_card()
  352 {
  353     /* the next wake should bring the card in WaitForKey ? */
  354     pnp_write (WAKE, 0);
  355     pnp_write(CONFIG_CONTROL, 0x02);    /* All cards in WaitForKey */
  356     DELAY(1000); /* XXX is it really necessary ? */
  357     return 1 ; /* success */
  358 }
  359 
  360 /*
  361  * Configure PnP devices. pnp_id is made of:
  362  *      4 bytes: board id (which can be printed as an ascii string);
  363  *      4 bytes: board serial number (often 0 or -1 ?)
  364  */
  365 
  366 static void
  367 config_pnp_device(pnp_id *p, int csn)
  368 {
  369     static struct pnp_dlist_node *nod = NULL;
  370     int i;
  371     u_char *data = (u_char *)p;
  372     u_char *comp = (u_char *)&p->comp_id;
  373 
  374     /* these are for autoconfigure a-la pci */
  375     struct pnp_device *dvp, **dvpp;
  376     char *name = NULL;
  377 
  378     printf("CSN %d Vendor ID: %c%c%c%02x%02x [0x%08lx] Serial 0x%08lx Comp ID: %c%c%c%02x%02x [0x%08lx]\n",
  379         csn,
  380         ((data[0] & 0x7c) >> 2) + '@',
  381         (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + '@',
  382         (data[1] & 0x1f) + '@', data[2], data[3],
  383         p->vendor_id, p->serial,
  384         ((comp[0] & 0x7c) >> 2) + '@',
  385         (((comp[0] & 0x03) << 3) | ((comp[1] & 0xe0) >> 5)) + '@',
  386         (comp[1] & 0x1f) + '@', comp[2], comp[3],
  387         p->comp_id);
  388 
  389     doing_pnp_probe = 1 ;
  390     current_csn = csn ;
  391     current_pnp_id = p->vendor_id ;
  392     current_pnp_serial = p->serial ;
  393 
  394     /*
  395      * use kernel table to override possible devices
  396      */
  397     for (i = 0 ; i < MAX_PNP_LDN; i++) {
  398         if (pnp_ldn_overrides[i].csn == csn &&
  399                 pnp_ldn_overrides[i].override == 1) {
  400             struct pnp_cinfo d;
  401             if (bootverbose)
  402                 printf("PnP: override config for CSN %d LDN %d "
  403                     "vend_id 0x%08x\n", csn, pnp_ldn_overrides[i].ldn,
  404                     current_pnp_id);
  405             /* next assignement is done otherwise read fails */
  406             d.vendor_id = current_pnp_id ;
  407             read_pnp_parms(&d, pnp_ldn_overrides[i].ldn);
  408             if (pnp_ldn_overrides[i].enable == 0) {
  409                 /* just disable ... */
  410                 d.enable = 0;
  411                 write_pnp_parms(&d, pnp_ldn_overrides[i].ldn);
  412             } else {
  413                 /* set all parameters */
  414                 /* next assignement is done otherwise write fails */
  415                 pnp_ldn_overrides[i].vendor_id = current_pnp_id ;
  416                 write_pnp_parms(&pnp_ldn_overrides[i],
  417                     pnp_ldn_overrides[i].ldn);
  418             }
  419         }
  420     }
  421 
  422     /* lookup device in ioconfiguration */
  423     dvpp = (struct pnp_device **)pnpdevice_set.ls_items;
  424     while ((dvp = *dvpp++)) {
  425         if (dvp->pd_probe) {
  426             if ( ((name = (*dvp->pd_probe)(csn, p->vendor_id)) && *name) ||
  427                 (p->comp_id &&
  428                     (name = (*dvp->pd_probe)(csn, p->comp_id))))
  429                 break;
  430         }
  431     }
  432     if (dvp && name && *name && dvp->pd_count) { /* found a matching device */
  433         int unit ;
  434 
  435         /* pnpcb->pnpcb_seen |= ( 1ul << csn ) ; */
  436 
  437         /* get and increment the unit */
  438         unit = (*dvp->pd_count)++;
  439 
  440         /*
  441          * now call the attach routine. The board has not been
  442          * configured yet, so better not access isa registers in
  443          * the attach routine until enable_pnp_card() has been done.
  444          */
  445         
  446         if (nod == NULL)
  447                 nod = malloc(sizeof(struct pnp_dlist_node), M_DEVBUF, M_NOWAIT);
  448         if (nod == NULL)
  449                 panic("malloc failed for PnP resource use");
  450         bzero(nod, sizeof(*nod));
  451         nod->pnp = dvp;
  452         nod->dev.id_unit = unit ;
  453         if (dvp->pd_attach)
  454             (*dvp->pd_attach) (csn, p->vendor_id, name, &(nod->dev));
  455         printf("%s%d (%s <%s> sn 0x%08lx)", nod->dev.id_driver &&
  456             nod->dev.id_driver->name ? nod->dev.id_driver->name : "unknown",
  457             unit, dvp->pd_name, name, p->serial);
  458         if (nod->dev.id_alive) {
  459             if (nod->dev.id_irq != 0 && nod->dev.id_intr != NULL) {
  460                 /* the board uses interrupts. Register it. */
  461                 if (dvp->imask)
  462                     INTRMASK( *(dvp->imask), nod->dev.id_irq );
  463                 register_intr(ffs(nod->dev.id_irq) - 1, nod->dev.id_id,
  464                     nod->dev.id_ri_flags, nod->dev.id_intr,
  465                     dvp->imask, nod->dev.id_unit);
  466                 INTREN(nod->dev.id_irq);
  467             }
  468             if (nod->dev.id_alive != 0) {
  469                 if (nod->dev.id_iobase == -1) 
  470                     printf(" at ?");
  471                 else {
  472                     printf(" at 0x%x", nod->dev.id_iobase);
  473                     if ((nod->dev.id_iobase + nod->dev.id_alive -1) !=
  474                         nod->dev.id_iobase) {
  475                         printf("-0x%x", nod->dev.id_iobase + nod->dev.id_alive
  476                             - 1);
  477                     }
  478                 }
  479             }
  480             if (nod->dev.id_irq)
  481                 printf(" irq %d", ffs(nod->dev.id_irq) - 1);
  482             if (nod->dev.id_drq != -1)
  483                 printf(" drq %d", nod->dev.id_drq);
  484             if (nod->dev.id_maddr)
  485                 printf(" maddr 0x%lx", kvtop(nod->dev.id_maddr));
  486             if (nod->dev.id_msize)
  487                 printf(" msize %d", nod->dev.id_msize);
  488             if (nod->dev.id_flags)
  489                 printf(" flags 0x%x", nod->dev.id_flags);
  490 #ifdef PC98
  491             printf (" on isa");
  492 #else
  493             if (nod->dev.id_iobase && !(nod->dev.id_iobase & 0xf300)) {
  494                 printf(" on motherboard");
  495                 printf(" id %d", nod->dev.id_id);
  496             } else if (nod->dev.id_iobase >= 0x1000 &&
  497                 !(nod->dev.id_iobase & 0x300)) {
  498                 printf (" on eisa slot %d",
  499                     nod->dev.id_iobase >> 12);
  500             } else {
  501                 printf (" on isa");
  502             }
  503 #endif
  504             printf("\n");
  505             if (pnp_device_list_last_ptr == NULL)
  506                 pnp_device_list = nod;
  507             else
  508                 *pnp_device_list_last_ptr = nod;
  509             pnp_device_list_last_ptr = &(nod->next);
  510             nod = NULL;
  511         } else
  512             printf(" failed to attach\n");
  513     }
  514     doing_pnp_probe = 0 ;
  515 }
  516 
  517 /*
  518  * Scan Resource Data for Compatible Device ID.
  519  *
  520  * This function exits as soon as it gets a Compatible Device ID, an error
  521  * reading *ANY* Resource Data or ir reaches the end of Resource Data.
  522  * In the first case the return value will be TRUE, FALSE otherwise.
  523  */
  524 static int
  525 pnp_scan_resdata(pnp_id *p, int csn)
  526 {
  527     u_char tag, resinfo[8];
  528     int large_len, scanning = 1024, retval = FALSE;
  529 
  530     while (scanning-- > 0 && pnp_get_resource_info(&tag, 1)) {
  531         if (PNP_RES_TYPE(tag) == 0) {
  532             /* Small resource */
  533             switch (PNP_SRES_NUM(tag)) {
  534                 case COMP_DEVICE_ID:
  535                     /* Got a compatible device id resource */
  536                     if (pnp_get_resource_info(resinfo, PNP_SRES_LEN(tag))) {
  537                         bcopy(resinfo, &p->comp_id, 4);
  538                         retval = TRUE;
  539                         if (bootverbose)
  540                             printf("PnP: CSN %d COMP_DEVICE_ID = 0x%08lx\n", csn, p->comp_id);
  541                     }
  542                     /*
  543                      * We found what we were looking for, or got an error from
  544                      * pnp_get_resource, => stop scanning (FALLTHROUGH)
  545                      */
  546                 case END_TAG:
  547                     scanning = 0;
  548                     break;
  549                 default:
  550                     /* Skip this resource */
  551                     if (pnp_get_resource_info(NULL, PNP_SRES_LEN(tag)) == 0)
  552                         scanning = 0;
  553                     break;
  554             }
  555         } else
  556             /* Large resource, skip it */
  557             if (!(pnp_get_resource_info((u_char *)&large_len, 2) && pnp_get_resource_info(NULL, large_len)))
  558                 scanning = 0;
  559     }
  560 
  561     return retval;
  562 }
  563 
  564 /*
  565  * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
  566  * value (caller should try multiple READ_DATA locations before giving
  567  * up). Upon exiting, all cards are aware that they should use
  568  * pnp_rd_port as the READ_DATA port.
  569  *
  570  * In the first pass, a csn is assigned to each board and pnp_id's
  571  * are saved to an array, pnp_devices. In the second pass, each
  572  * card is woken up and the device configuration is called.
  573  */
  574 static int
  575 pnp_isolation_protocol()
  576 {
  577     int csn;
  578 
  579     pnp_send_Initiation_LFSR();
  580 
  581     pnp_write(CONFIG_CONTROL, 0x04);    /* Reset CSN for All Cards */
  582 
  583     for (csn = 1; (csn < MAX_PNP_CARDS); csn++) {
  584         /* Wake up cards without a CSN */
  585         pnp_write(WAKE, 0);
  586         pnp_write(SET_RD_DATA, pnp_rd_port);
  587         outb(_PNP_ADDRESS, SERIAL_ISOLATION);
  588         DELAY(1000);    /* Delay 1 msec */
  589 
  590         if (pnp_get_serial( &(pnp_devices[csn-1]) ) ) {
  591             pnp_write(SET_CSN, csn);
  592             /* pnp_write(CONFIG_CONTROL, 2); */
  593             if (!pnp_scan_resdata(&(pnp_devices[csn-1]), csn))
  594                 pnp_devices[csn-1].comp_id = NULL;
  595         } else
  596             break;
  597     }
  598     num_pnp_cards = csn - 1;
  599     for (csn = 1; csn <= num_pnp_cards ; csn++) {
  600         /*
  601          * make sure cards are in SLEEP state
  602          */
  603         pnp_send_Initiation_LFSR();
  604         pnp_write(WAKE, csn);
  605         config_pnp_device( &(pnp_devices[csn-1]), csn);
  606         /*
  607          * Put all cards in WaitForKey, just in case the previous
  608          * attach routine forgot it.
  609          */
  610         pnp_write(CONFIG_CONTROL, 0x02);
  611         DELAY(1000); /* XXX is it really necessary ? */
  612     }
  613     return num_pnp_cards ;
  614 }
  615 
  616 
  617 /*
  618  * pnp_configure()
  619  *
  620  * autoconfiguration of pnp devices. This routine just runs the
  621  * isolation protocol over several ports, until one is successful.
  622  *
  623  * may be called more than once ?
  624  *
  625  */
  626 
  627 void
  628 pnp_configure()
  629 {
  630     int num_pnp_devs;
  631 
  632     if (pnp_ldn_overrides[0].csn == 0) {
  633         if (bootverbose)
  634             printf("Initializing PnP override table\n");
  635         bzero (pnp_ldn_overrides, sizeof(pnp_ldn_overrides));
  636         pnp_ldn_overrides[0].csn = 255 ;
  637     }
  638     printf("Probing for PnP devices:\n");
  639 
  640     /* Try various READ_DATA ports from 0x203-0x3ff */
  641     for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) {
  642         if (bootverbose)
  643             printf("Trying Read_Port at %x\n", (pnp_rd_port << 2) | 0x3);
  644 
  645         num_pnp_devs = pnp_isolation_protocol();
  646         if (num_pnp_devs)
  647             break;
  648     }
  649     if (!num_pnp_devs) {
  650         if (bootverbose)
  651             printf("No Plug-n-Play devices were found\n");
  652         return;
  653     }
  654 }

Cache object: 7b89c06af37147072b4e6f71faf348cc


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