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/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  *      from: pnp.c,v 1.11 1999/05/06 22:11:19 peter Exp
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/bus.h>
   37 #include <sys/endian.h>
   38 #include <sys/malloc.h>
   39 #include <isa/isavar.h>
   40 #include <isa/pnpreg.h>
   41 #include <isa/pnpvar.h>
   42 #include <machine/bus.h>
   43 
   44 typedef struct _pnp_id {
   45         uint32_t vendor_id;
   46         uint32_t serial;
   47         u_char checksum;
   48 } pnp_id;
   49 
   50 struct pnp_set_config_arg {
   51         int     csn;            /* Card number to configure */
   52         int     ldn;            /* Logical device on card */
   53 };
   54 
   55 struct pnp_quirk {
   56         uint32_t vendor_id;     /* Vendor of the card */
   57         uint32_t logical_id;    /* ID of the device with quirk */
   58         int     type;
   59 #define PNP_QUIRK_WRITE_REG     1 /* Need to write a pnp register  */
   60 #define PNP_QUIRK_EXTRA_IO      2 /* Has extra io ports  */
   61         int     arg1;
   62         int     arg2;
   63 };
   64 
   65 struct pnp_quirk pnp_quirks[] = {
   66         /*
   67          * The Gravis UltraSound needs register 0xf2 to be set to 0xff
   68          * to enable power.
   69          * XXX need to know the logical device id.
   70          */
   71         { 0x0100561e /* GRV0001 */,     0,
   72           PNP_QUIRK_WRITE_REG,  0xf2,    0xff },
   73         /*
   74          * An emu8000 does not give us other than the first
   75          * port.
   76          */
   77         { 0x26008c0e /* SB16 */,        0x21008c0e,
   78           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   79         { 0x42008c0e /* SB32(CTL0042) */,       0x21008c0e,
   80           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   81         { 0x44008c0e /* SB32(CTL0044) */,       0x21008c0e,
   82           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   83         { 0x49008c0e /* SB32(CTL0049) */,       0x21008c0e,
   84           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   85         { 0xf1008c0e /* SB32(CTL00f1) */,       0x21008c0e,
   86           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   87         { 0xc1008c0e /* SB64(CTL00c1) */,       0x22008c0e,
   88           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   89         { 0xc5008c0e /* SB64(CTL00c5) */,       0x22008c0e,
   90           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   91         { 0xe4008c0e /* SB64(CTL00e4) */,       0x22008c0e,
   92           PNP_QUIRK_EXTRA_IO,   0x400,   0x800 },
   93 
   94         { 0 }
   95 };
   96 
   97 #ifdef PC98
   98 /* Some NEC PnP cards have 9 bytes serial code. */
   99 static pnp_id necids[] = {
  100         {0x4180a3b8, 0xffffffff, 0x00}, /* PC-9801CB-B04 (NEC8041) */
  101         {0x5181a3b8, 0xffffffff, 0x46}, /* PC-9821CB2-B04(NEC8151) */
  102         {0x5182a3b8, 0xffffffff, 0xb8}, /* PC-9801-XX    (NEC8251) */
  103         {0x9181a3b8, 0xffffffff, 0x00}, /* PC-9801-120   (NEC8191) */
  104         {0, 0, 0}
  105 };
  106 #endif
  107 
  108 /* The READ_DATA port that we are using currently */
  109 static int pnp_rd_port;
  110 
  111 static void   pnp_send_initiation_key(void);
  112 static int    pnp_get_serial(pnp_id *p);
  113 static int    pnp_isolation_protocol(device_t parent);
  114 
  115 char *
  116 pnp_eisaformat(uint32_t id)
  117 {
  118         uint8_t *data;
  119         static char idbuf[8];
  120         const char  hextoascii[] = "0123456789abcdef";
  121 
  122         id = htole32(id);
  123         data = (uint8_t *)&id;
  124         idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
  125         idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
  126         idbuf[2] = '@' + (data[1] & 0x1f);
  127         idbuf[3] = hextoascii[(data[2] >> 4)];
  128         idbuf[4] = hextoascii[(data[2] & 0xf)];
  129         idbuf[5] = hextoascii[(data[3] >> 4)];
  130         idbuf[6] = hextoascii[(data[3] & 0xf)];
  131         idbuf[7] = 0;
  132         return(idbuf);
  133 }
  134 
  135 static void
  136 pnp_write(int d, u_char r)
  137 {
  138         outb (_PNP_ADDRESS, d);
  139         outb (_PNP_WRITE_DATA, r);
  140 }
  141 
  142 /*
  143  * Send Initiation LFSR as described in "Plug and Play ISA Specification",
  144  * Intel May 94.
  145  */
  146 static void
  147 pnp_send_initiation_key()
  148 {
  149         int cur, i;
  150 
  151         /* Reset the LSFR */
  152         outb(_PNP_ADDRESS, 0);
  153         outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
  154 
  155         cur = 0x6a;
  156         outb(_PNP_ADDRESS, cur);
  157 
  158         for (i = 1; i < 32; i++) {
  159                 cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
  160                 outb(_PNP_ADDRESS, cur);
  161         }
  162 }
  163 
  164 
  165 /*
  166  * Get the device's serial number.  Returns 1 if the serial is valid.
  167  */
  168 static int
  169 pnp_get_serial(pnp_id *p)
  170 {
  171         int i, bit, valid = 0, sum = 0x6a;
  172         u_char *data = (u_char *)p;
  173 
  174         bzero(data, sizeof(char) * 9);
  175         outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
  176         for (i = 0; i < 72; i++) {
  177                 bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;
  178                 DELAY(250);     /* Delay 250 usec */
  179 
  180                 /* Can't Short Circuit the next evaluation, so 'and' is last */
  181                 bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;
  182                 DELAY(250);     /* Delay 250 usec */
  183 
  184                 valid = valid || bit;
  185                 if (i < 64)
  186                         sum = (sum >> 1) |
  187                           (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
  188                 data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
  189         }
  190 
  191         valid = valid && (data[8] == sum);
  192 
  193         return (valid);
  194 }
  195 
  196 /*
  197  * Fill's the buffer with resource info from the device.
  198  * Returns the number of characters read.
  199  */
  200 static int
  201 pnp_get_resource_info(u_char *buffer, int len)
  202 {
  203         int i, j, count;
  204         u_char temp;
  205 
  206         count = 0;
  207         for (i = 0; i < len; i++) {
  208                 outb(_PNP_ADDRESS, PNP_STATUS);
  209                 for (j = 0; j < 100; j++) {
  210                         if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)
  211                                 break;
  212                         DELAY(10);
  213                 }
  214                 if (j == 100) {
  215                         printf("PnP device failed to report resource data\n");
  216                         return (count);
  217                 }
  218                 outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
  219                 temp = inb((pnp_rd_port << 2) | 0x3);
  220                 if (buffer != NULL)
  221                         buffer[i] = temp;
  222                 count++;
  223         }
  224         return (count);
  225 }
  226 
  227 /*
  228  * This function is called after the bus has assigned resource
  229  * locations for a logical device.
  230  */
  231 static void
  232 pnp_set_config(void *arg, struct isa_config *config, int enable)
  233 {
  234         int csn = ((struct pnp_set_config_arg *) arg)->csn;
  235         int ldn = ((struct pnp_set_config_arg *) arg)->ldn;
  236         int i;
  237 
  238         /*
  239          * First put all cards into Sleep state with the initiation
  240          * key, then put our card into Config state.
  241          */
  242         pnp_send_initiation_key();
  243         pnp_write(PNP_WAKE, csn);
  244 
  245         /*
  246          * Select our logical device so that we can program it.
  247          */
  248         pnp_write(PNP_SET_LDN, ldn);
  249 
  250         /*
  251          * Constrain the number of resources we will try to program
  252          */
  253         if (config->ic_nmem > ISA_PNP_NMEM) {
  254                 printf("too many ISA memory ranges (%d > %d)\n",
  255                     config->ic_nmem, ISA_PNP_NMEM);
  256                 config->ic_nmem = ISA_PNP_NMEM;
  257         }
  258         if (config->ic_nport > ISA_PNP_NPORT) {
  259                 printf("too many ISA I/O ranges (%d > %d)\n", config->ic_nport,
  260                     ISA_PNP_NPORT);
  261                 config->ic_nport = ISA_PNP_NPORT;
  262         }
  263         if (config->ic_nirq > ISA_PNP_NIRQ) {
  264                 printf("too many ISA IRQs (%d > %d)\n", config->ic_nirq,
  265                     ISA_PNP_NIRQ);
  266                 config->ic_nirq = ISA_PNP_NIRQ;
  267         }
  268         if (config->ic_ndrq > ISA_PNP_NDRQ) {
  269                 printf("too many ISA DRQs (%d > %d)\n", config->ic_ndrq,
  270                     ISA_PNP_NDRQ);
  271                 config->ic_ndrq = ISA_PNP_NDRQ;
  272         }
  273 
  274         /*
  275          * Now program the resources.
  276          */
  277         for (i = 0; i < config->ic_nmem; i++) {
  278                 uint32_t start;
  279                 uint32_t size;
  280 
  281                 /* XXX: should handle memory control register, 32 bit memory */
  282                 if (config->ic_mem[i].ir_size == 0) {
  283                         pnp_write(PNP_MEM_BASE_HIGH(i), 0);
  284                         pnp_write(PNP_MEM_BASE_LOW(i), 0);
  285                         pnp_write(PNP_MEM_RANGE_HIGH(i), 0);
  286                         pnp_write(PNP_MEM_RANGE_LOW(i), 0);
  287                 } else {
  288                         start = config->ic_mem[i].ir_start;
  289                         size =  config->ic_mem[i].ir_size;
  290                         if (start & 0xff)
  291                                 panic("pnp_set_config: bogus memory assignment");
  292                         pnp_write(PNP_MEM_BASE_HIGH(i), (start >> 16) & 0xff);
  293                         pnp_write(PNP_MEM_BASE_LOW(i), (start >> 8) & 0xff);
  294                         pnp_write(PNP_MEM_RANGE_HIGH(i), (size >> 16) & 0xff);
  295                         pnp_write(PNP_MEM_RANGE_LOW(i), (size >> 8) & 0xff);
  296                 }
  297         }
  298         for (; i < ISA_PNP_NMEM; i++) {
  299                 pnp_write(PNP_MEM_BASE_HIGH(i), 0);
  300                 pnp_write(PNP_MEM_BASE_LOW(i), 0);
  301                 pnp_write(PNP_MEM_RANGE_HIGH(i), 0);
  302                 pnp_write(PNP_MEM_RANGE_LOW(i), 0);
  303         }
  304 
  305         for (i = 0; i < config->ic_nport; i++) {
  306                 uint32_t start;
  307 
  308                 if (config->ic_port[i].ir_size == 0) {
  309                         pnp_write(PNP_IO_BASE_HIGH(i), 0);
  310                         pnp_write(PNP_IO_BASE_LOW(i), 0);
  311                 } else {
  312                         start = config->ic_port[i].ir_start;
  313                         pnp_write(PNP_IO_BASE_HIGH(i), (start >> 8) & 0xff);
  314                         pnp_write(PNP_IO_BASE_LOW(i), (start >> 0) & 0xff);
  315                 }
  316         }
  317         for (; i < ISA_PNP_NPORT; i++) {
  318                 pnp_write(PNP_IO_BASE_HIGH(i), 0);
  319                 pnp_write(PNP_IO_BASE_LOW(i), 0);
  320         }
  321 
  322         for (i = 0; i < config->ic_nirq; i++) {
  323                 int irq;
  324 
  325                 /* XXX: interrupt type */
  326                 if (config->ic_irqmask[i] == 0) {
  327                         pnp_write(PNP_IRQ_LEVEL(i), 0);
  328                         pnp_write(PNP_IRQ_TYPE(i), 2);
  329                 } else {
  330                         irq = ffs(config->ic_irqmask[i]) - 1;
  331                         pnp_write(PNP_IRQ_LEVEL(i), irq);
  332                         pnp_write(PNP_IRQ_TYPE(i), 2); /* XXX */
  333                 }
  334         }
  335         for (; i < ISA_PNP_NIRQ; i++) {
  336                 /*
  337                  * IRQ 0 is not a valid interrupt selection and
  338                  * represents no interrupt selection.
  339                  */
  340                 pnp_write(PNP_IRQ_LEVEL(i), 0);
  341                 pnp_write(PNP_IRQ_TYPE(i), 2);
  342         }               
  343 
  344         for (i = 0; i < config->ic_ndrq; i++) {
  345                 int drq;
  346 
  347                 if (config->ic_drqmask[i] == 0) {
  348                         pnp_write(PNP_DMA_CHANNEL(i), 4);
  349                 } else {
  350                         drq = ffs(config->ic_drqmask[i]) - 1;
  351                         pnp_write(PNP_DMA_CHANNEL(i), drq);
  352                 }
  353         }
  354         for (; i < ISA_PNP_NDRQ; i++) {
  355                 /*
  356                  * DMA channel 4, the cascade channel is used to
  357                  * indicate no DMA channel is active.
  358                  */
  359                 pnp_write(PNP_DMA_CHANNEL(i), 4);
  360         }               
  361 
  362         pnp_write(PNP_ACTIVATE, enable ? 1 : 0);
  363 
  364         /*
  365          * Wake everyone up again, we are finished.
  366          */
  367         pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
  368 }
  369 
  370 /*
  371  * Process quirks for a logical device.. The card must be in Config state.
  372  */
  373 void
  374 pnp_check_quirks(uint32_t vendor_id, uint32_t logical_id, int ldn,
  375     struct isa_config *config)
  376 {
  377         struct pnp_quirk *qp;
  378 
  379         for (qp = &pnp_quirks[0]; qp->vendor_id; qp++) {
  380                 if (qp->vendor_id == vendor_id
  381                     && (qp->logical_id == 0 || qp->logical_id == logical_id)) {
  382                         switch (qp->type) {
  383                         case PNP_QUIRK_WRITE_REG:
  384                                 pnp_write(PNP_SET_LDN, ldn);
  385                                 pnp_write(qp->arg1, qp->arg2);
  386                                 break;
  387                         case PNP_QUIRK_EXTRA_IO:
  388                                 if (config == NULL)
  389                                         break;
  390                                 if (qp->arg1 != 0) {
  391                                         config->ic_nport++;
  392                                         config->ic_port[config->ic_nport - 1] = config->ic_port[0];
  393                                         config->ic_port[config->ic_nport - 1].ir_start += qp->arg1;
  394                                         config->ic_port[config->ic_nport - 1].ir_end += qp->arg1;
  395                                 }
  396                                 if (qp->arg2 != 0) {
  397                                         config->ic_nport++;
  398                                         config->ic_port[config->ic_nport - 1] = config->ic_port[0];
  399                                         config->ic_port[config->ic_nport - 1].ir_start += qp->arg2;
  400                                         config->ic_port[config->ic_nport - 1].ir_end += qp->arg2;
  401                                 }
  402                                 break;
  403                         }
  404                 }
  405         }
  406 }
  407 
  408 /*
  409  * Scan Resource Data for Logical Devices.
  410  *
  411  * This function exits as soon as it gets an error reading *ANY*
  412  * Resource Data or it reaches the end of Resource Data.  In the first
  413  * case the return value will be TRUE, FALSE otherwise.
  414  */
  415 static int
  416 pnp_create_devices(device_t parent, pnp_id *p, int csn,
  417     u_char *resources, int len)
  418 {
  419         u_char tag, *resp, *resinfo, *startres = 0;
  420         int large_len, scanning = len, retval = FALSE;
  421         uint32_t logical_id;
  422         device_t dev = 0;
  423         int ldn = 0;
  424         struct pnp_set_config_arg *csnldn;
  425         char buf[100];
  426         char *desc = 0;
  427 
  428         resp = resources;
  429         while (scanning > 0) {
  430                 tag = *resp++;
  431                 scanning--;
  432                 if (PNP_RES_TYPE(tag) != 0) {
  433                         /* Large resource */
  434                         if (scanning < 2) {
  435                                 scanning = 0;
  436                                 continue;
  437                         }
  438                         large_len = resp[0] + (resp[1] << 8);
  439                         resp += 2;
  440 
  441                         if (scanning < large_len) {
  442                                 scanning = 0;
  443                                 continue;
  444                         }
  445                         resinfo = resp;
  446                         resp += large_len;
  447                         scanning -= large_len;
  448 
  449                         if (PNP_LRES_NUM(tag) == PNP_TAG_ID_ANSI) {
  450                                 if (dev) {
  451                                         /*
  452                                          * This is an optional device
  453                                          * indentifier string. Skipt it
  454                                          * for now.
  455                                          */
  456                                         continue;
  457                                 }
  458                                 /* else mandately card identifier string */
  459                                 if (large_len > sizeof(buf) - 1)
  460                                         large_len = sizeof(buf) - 1;
  461                                 bcopy(resinfo, buf, large_len);
  462 
  463                                 /*
  464                                  * Trim trailing spaces.
  465                                  */
  466                                 while (buf[large_len-1] == ' ')
  467                                         large_len--;
  468                                 buf[large_len] = '\0';
  469                                 desc = buf;
  470                                 continue;
  471                         }
  472 
  473                         continue;
  474                 }
  475                 
  476                 /* Small resource */
  477                 if (scanning < PNP_SRES_LEN(tag)) {
  478                         scanning = 0;
  479                         continue;
  480                 }
  481                 resinfo = resp;
  482                 resp += PNP_SRES_LEN(tag);
  483                 scanning -= PNP_SRES_LEN(tag);
  484                         
  485                 switch (PNP_SRES_NUM(tag)) {
  486                 case PNP_TAG_LOGICAL_DEVICE:
  487                         /*
  488                          * Parse the resources for the previous
  489                          * logical device (if any).
  490                          */
  491                         if (startres) {
  492                                 pnp_parse_resources(dev, startres,
  493                                     resinfo - startres - 1, ldn);
  494                                 dev = 0;
  495                                 startres = 0;
  496                         }
  497 
  498                         /* 
  499                          * A new logical device. Scan for end of
  500                          * resources.
  501                          */
  502                         bcopy(resinfo, &logical_id, 4);
  503                         pnp_check_quirks(p->vendor_id, logical_id, ldn, NULL);
  504                         dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1);
  505                         if (desc)
  506                                 device_set_desc_copy(dev, desc);
  507                         else
  508                                 device_set_desc_copy(dev,
  509                                     pnp_eisaformat(logical_id));
  510                         isa_set_vendorid(dev, p->vendor_id);
  511                         isa_set_serial(dev, p->serial);
  512                         isa_set_logicalid(dev, logical_id);
  513                         isa_set_configattr(dev,
  514                             ISACFGATTR_CANDISABLE | ISACFGATTR_DYNAMIC);
  515                         csnldn = malloc(sizeof *csnldn, M_DEVBUF, M_NOWAIT);
  516                         if (!csnldn) {
  517                                 device_printf(parent, "out of memory\n");
  518                                 scanning = 0;
  519                                 break;
  520                         }
  521                         csnldn->csn = csn;
  522                         csnldn->ldn = ldn;
  523                         ISA_SET_CONFIG_CALLBACK(parent, dev, pnp_set_config,
  524                             csnldn);
  525                         isa_set_pnp_csn(dev, csn);
  526                         isa_set_pnp_ldn(dev, ldn);
  527                         ldn++;
  528                         startres = resp;
  529                         break;
  530                     
  531                 case PNP_TAG_END:
  532                         if (!startres) {
  533                                 device_printf(parent, "malformed resources\n");
  534                                 scanning = 0;
  535                                 break;
  536                         }
  537                         pnp_parse_resources(dev, startres,
  538                             resinfo - startres - 1, ldn);
  539                         dev = 0;
  540                         startres = 0;
  541                         scanning = 0;
  542                         break;
  543 
  544                 default:
  545                         /* Skip this resource */
  546                         break;
  547                 }
  548         }
  549 
  550         return (retval);
  551 }
  552 
  553 /*
  554  * Read 'amount' bytes of resources from the card, allocating memory
  555  * as needed. If a buffer is already available, it should be passed in
  556  * '*resourcesp' and its length in '*spacep'. The number of resource
  557  * bytes already in the buffer should be passed in '*lenp'. The memory
  558  * allocated will be returned in '*resourcesp' with its size and the
  559  * number of bytes of resources in '*spacep' and '*lenp' respectively.
  560  *
  561  * XXX: Multiple problems here, we forget to free() stuff in one
  562  * XXX: error return, and in another case we free (*resourcesp) but
  563  * XXX: don't tell the caller.
  564  */
  565 static int
  566 pnp_read_bytes(int amount, u_char **resourcesp, int *spacep, int *lenp)
  567 {
  568         u_char *resources = *resourcesp;
  569         u_char *newres;
  570         int space = *spacep;
  571         int len = *lenp;
  572 
  573         if (space == 0) {
  574                 space = 1024;
  575                 resources = malloc(space, M_TEMP, M_NOWAIT);
  576                 if (!resources)
  577                         return (ENOMEM);
  578         }
  579         
  580         if (len + amount > space) {
  581                 int extra = 1024;
  582                 while (len + amount > space + extra)
  583                         extra += 1024;
  584                 newres = malloc(space + extra, M_TEMP, M_NOWAIT);
  585                 if (!newres) {
  586                         /* XXX: free resources */
  587                         return (ENOMEM);
  588                 }
  589                 bcopy(resources, newres, len);
  590                 free(resources, M_TEMP);
  591                 resources = newres;
  592                 space += extra;
  593         }
  594 
  595         if (pnp_get_resource_info(resources + len, amount) != amount)
  596                 return (EINVAL);
  597         len += amount;
  598 
  599         *resourcesp = resources;
  600         *spacep = space;
  601         *lenp = len;
  602 
  603         return (0);
  604 }
  605 
  606 /*
  607  * Read all resources from the card, allocating memory as needed. If a
  608  * buffer is already available, it should be passed in '*resourcesp'
  609  * and its length in '*spacep'. The memory allocated will be returned
  610  * in '*resourcesp' with its size and the number of bytes of resources
  611  * in '*spacep' and '*lenp' respectively.
  612  */
  613 static int
  614 pnp_read_resources(u_char **resourcesp, int *spacep, int *lenp)
  615 {
  616         u_char *resources = *resourcesp;
  617         int space = *spacep;
  618         int len = 0;
  619         int error, done;
  620         u_char tag;
  621 
  622         error = 0;
  623         done = 0;
  624         while (!done) {
  625                 error = pnp_read_bytes(1, &resources, &space, &len);
  626                 if (error)
  627                         goto out;
  628                 tag = resources[len-1];
  629                 if (PNP_RES_TYPE(tag) == 0) {
  630                         /*
  631                          * Small resource, read contents.
  632                          */
  633                         error = pnp_read_bytes(PNP_SRES_LEN(tag),
  634                             &resources, &space, &len);
  635                         if (error)
  636                                 goto out;
  637                         if (PNP_SRES_NUM(tag) == PNP_TAG_END)
  638                                 done = 1;
  639                 } else {
  640                         /*
  641                          * Large resource, read length and contents.
  642                          */
  643                         error = pnp_read_bytes(2, &resources, &space, &len);
  644                         if (error)
  645                                 goto out;
  646                         error = pnp_read_bytes(resources[len-2]
  647                             + (resources[len-1] << 8), &resources, &space,
  648                             &len);
  649                         if (error)
  650                                 goto out;
  651                 }
  652         }
  653 
  654  out:
  655         *resourcesp = resources;
  656         *spacep = space;
  657         *lenp = len;
  658         return (error);
  659 }
  660 
  661 /*
  662  * Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
  663  * value (caller should try multiple READ_DATA locations before giving
  664  * up). Upon exiting, all cards are aware that they should use
  665  * pnp_rd_port as the READ_DATA port.
  666  *
  667  * In the first pass, a csn is assigned to each board and pnp_id's
  668  * are saved to an array, pnp_devices. In the second pass, each
  669  * card is woken up and the device configuration is called.
  670  */
  671 static int
  672 pnp_isolation_protocol(device_t parent)
  673 {
  674         int csn;
  675         pnp_id id;
  676         int found = 0, len;
  677         u_char *resources = 0;
  678         int space = 0;
  679         int error;
  680 #ifdef PC98
  681         int n, necpnp;
  682         u_char buffer[10];
  683 #endif
  684 
  685         /*
  686          * Put all cards into the Sleep state so that we can clear
  687          * their CSNs.
  688          */
  689         pnp_send_initiation_key();
  690 
  691         /*
  692          * Clear the CSN for all cards.
  693          */
  694         pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_RESET_CSN);
  695 
  696         /*
  697          * Move all cards to the Isolation state.
  698          */
  699         pnp_write(PNP_WAKE, 0);
  700 
  701         /*
  702          * Tell them where the read point is going to be this time.
  703          */
  704         pnp_write(PNP_SET_RD_DATA, pnp_rd_port);
  705 
  706         for (csn = 1; csn < PNP_MAX_CARDS; csn++) {
  707                 /*
  708                  * Start the serial isolation protocol.
  709                  */
  710                 outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
  711                 DELAY(1000);    /* Delay 1 msec */
  712 
  713                 if (pnp_get_serial(&id)) {
  714                         /*
  715                          * We have read the id from a card
  716                          * successfully. The card which won the
  717                          * isolation protocol will be in Isolation
  718                          * mode and all others will be in Sleep.
  719                          * Program the CSN of the isolated card
  720                          * (taking it to Config state) and read its
  721                          * resources, creating devices as we find
  722                          * logical devices on the card.
  723                          */
  724                         pnp_write(PNP_SET_CSN, csn);
  725 #ifdef PC98
  726                         if (bootverbose)
  727                                 printf("PnP Vendor ID = %x\n", id.vendor_id);
  728                         /* Check for NEC PnP (9 bytes serial). */
  729                         for (n = necpnp = 0; necids[n].vendor_id; n++) {
  730                                 if (id.vendor_id == necids[n].vendor_id) {
  731                                         necpnp = 1;
  732                                         break;
  733                                 }
  734                         }
  735                         if (necpnp) {
  736                                 if (bootverbose)
  737                                         printf("An NEC-PnP card (%s).\n",
  738                                             pnp_eisaformat(id.vendor_id));
  739                                 /*  Read dummy 9 bytes serial area. */
  740                                 pnp_get_resource_info(buffer, 9);
  741                         } else {
  742                                 if (bootverbose)
  743                                         printf("A Normal-ISA-PnP card (%s).\n",
  744                                             pnp_eisaformat(id.vendor_id));
  745                         }
  746 #endif
  747                         if (bootverbose)
  748                                 printf("Reading PnP configuration for %s.\n",
  749                                     pnp_eisaformat(id.vendor_id));
  750                         error = pnp_read_resources(&resources, &space, &len);
  751                         if (error)
  752                                 break;
  753                         pnp_create_devices(parent, &id, csn, resources, len);
  754                         found++;
  755                 } else
  756                         break;
  757 
  758                 /*
  759                  * Put this card back to the Sleep state and
  760                  * simultaneously move all cards which don't have a
  761                  * CSN yet to Isolation state.
  762                  */
  763                 pnp_write(PNP_WAKE, 0);
  764         }
  765 
  766         /*
  767          * Unless we have chosen the wrong read port, all cards will
  768          * be in Sleep state. Put them back into WaitForKey for
  769          * now. Their resources will be programmed later.
  770          */
  771         pnp_write(PNP_CONFIG_CONTROL, PNP_CONFIG_CONTROL_WAIT_FOR_KEY);
  772 
  773         /*
  774          * Cleanup.
  775          */
  776         if (resources)
  777                 free(resources, M_TEMP);
  778 
  779         return (found);
  780 }
  781 
  782 
  783 /*
  784  * pnp_identify()
  785  *
  786  * autoconfiguration of pnp devices. This routine just runs the
  787  * isolation protocol over several ports, until one is successful.
  788  *
  789  * may be called more than once ?
  790  *
  791  */
  792 
  793 static void
  794 pnp_identify(driver_t *driver, device_t parent)
  795 {
  796         int num_pnp_devs;
  797 
  798         /* Try various READ_DATA ports from 0x203-0x3ff */
  799         for (pnp_rd_port = 0x80; (pnp_rd_port < 0xff); pnp_rd_port += 0x10) {
  800                 if (bootverbose)
  801                         printf("pnp_identify: Trying Read_Port at %x\n",
  802                             (pnp_rd_port << 2) | 0x3);
  803 
  804                 num_pnp_devs = pnp_isolation_protocol(parent);
  805                 if (num_pnp_devs)
  806                         break;
  807         }
  808         if (bootverbose)
  809                 printf("PNP Identify complete\n");
  810 }
  811 
  812 static device_method_t pnp_methods[] = {
  813         /* Device interface */
  814         DEVMETHOD(device_identify,      pnp_identify),
  815 
  816         { 0, 0 }
  817 };
  818 
  819 static driver_t pnp_driver = {
  820         "pnp",
  821         pnp_methods,
  822         1,                      /* no softc */
  823 };
  824 
  825 static devclass_t pnp_devclass;
  826 
  827 DRIVER_MODULE(pnp, isa, pnp_driver, pnp_devclass, 0, 0);

Cache object: d613f0b9a01e99402cf5b7b231262104


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