Back to index

lshw  02.16
isapnp.cc
Go to the documentation of this file.
00001 /*
00002  *  isapnp.cc
00003  *
00004  *  This scan, only available on (older) i386 systems, tries to detect PnP
00005  *  (Plug'n Play) ISA devices.
00006  *
00007  *  This detection is loosely based on the implementation used in the Linux
00008  *  kernel itself.
00009  */
00010 
00011 #include "version.h"
00012 #include "isapnp.h"
00013 #include "pnp.h"
00014 
00015 __ID("@(#) $Id: isapnp.cc 2433 2012-01-10 22:01:30Z lyonel $");
00016 
00017 #ifdef __i386__
00018 
00019 #include <stdio.h>
00020 #include <unistd.h>
00021 #include <stdlib.h>
00022 #include <fcntl.h>
00023 #include <time.h>
00024 #include <string.h>
00025 
00026 /* config parameters */
00027 #define PNP_CONFIG_NORMAL 0x0001
00028 #define PNP_CONFIG_FORCE  0x0002                  /* disables validity checking */
00029 
00030 /* capabilities */
00031 #define PNP_READ    0x0001
00032 #define PNP_WRITE   0x0002
00033 #define PNP_DISABLE   0x0004
00034 #define PNP_CONFIGURABLE  0x0008
00035 #define PNP_REMOVABLE   0x0010
00036 
00037 /* status */
00038 #define PNP_READY   0x0000
00039 #define PNP_ATTACHED    0x0001
00040 #define PNP_BUSY    0x0002
00041 #define PNP_FAULTY    0x0004
00042 
00043 #define ISAPNP_CFG_ACTIVATE   0x30                /* byte */
00044 #define ISAPNP_CFG_MEM      0x40                  /* 4 * dword */
00045 #define ISAPNP_CFG_PORT     0x60                  /* 8 * word */
00046 #define ISAPNP_CFG_IRQ      0x70                  /* 2 * word */
00047 #define ISAPNP_CFG_DMA      0x74                  /* 2 * byte */
00048 
00049 #define ISAPNP_VENDOR(a,b,c)  (((((a)-'A'+1)&0x3f)<<2)|\
00050 ((((b)-'A'+1)&0x18)>>3)|((((b)-'A'+1)&7)<<13)|\
00051 ((((c)-'A'+1)&0x1f)<<8))
00052 #define ISAPNP_DEVICE(x)  ((((x)&0xf000)>>8)|\
00053 (((x)&0x0f00)>>8)|\
00054 (((x)&0x00f0)<<8)|\
00055 (((x)&0x000f)<<8))
00056 #define ISAPNP_FUNCTION(x)  ISAPNP_DEVICE(x)
00057 
00058 #define DEVICE_COUNT_COMPATIBLE 4
00059 
00060 #define ISAPNP_ANY_ID   0xffff
00061 #define ISAPNP_CARD_DEVS  8
00062 
00063 #define ISAPNP_CARD_ID(_va, _vb, _vc, _device) \
00064 .card_vendor = ISAPNP_VENDOR(_va, _vb, _vc), .card_device = ISAPNP_DEVICE(_device)
00065 #define ISAPNP_CARD_END \
00066 .card_vendor = 0, .card_device = 0
00067 #define ISAPNP_DEVICE_ID(_va, _vb, _vc, _function) \
00068 { .vendor = ISAPNP_VENDOR(_va, _vb, _vc), .function = ISAPNP_FUNCTION(_function) }
00069 
00070 struct isapnp_card_id
00071 {
00072   unsigned long driver_data;                      /* data private to the driver */
00073   unsigned short card_vendor, card_device;
00074   struct
00075   {
00076     unsigned short vendor, function;
00077   }
00078   devs[ISAPNP_CARD_DEVS];                         /* logical devices */
00079 };
00080 
00081 #define ISAPNP_DEVICE_SINGLE(_cva, _cvb, _cvc, _cdevice, _dva, _dvb, _dvc, _dfunction) \
00082 .card_vendor = ISAPNP_VENDOR(_cva, _cvb, _cvc), .card_device =  ISAPNP_DEVICE(_cdevice), \
00083 .vendor = ISAPNP_VENDOR(_dva, _dvb, _dvc), .function = ISAPNP_FUNCTION(_dfunction)
00084 #define ISAPNP_DEVICE_SINGLE_END \
00085 .card_vendor = 0, .card_device = 0
00086 
00087 struct isapnp_device_id
00088 {
00089   unsigned short card_vendor, card_device;
00090   unsigned short vendor, function;
00091   unsigned long driver_data;                      /* data private to the driver */
00092 };
00093 
00094 static int isapnp_rdp;                            /* Read Data Port */
00095 static int isapnp_reset = 0;                      /* reset all PnP cards (deactivate) */
00096 static bool isapnp_error = false;
00097 
00098 #define _PIDXR    0x279
00099 #define _PNPWRP   0xa79
00100 
00101 /* short tags */
00102 #define _STAG_PNPVERNO    0x01
00103 #define _STAG_LOGDEVID    0x02
00104 #define _STAG_COMPATDEVID 0x03
00105 #define _STAG_IRQ   0x04
00106 #define _STAG_DMA   0x05
00107 #define _STAG_STARTDEP    0x06
00108 #define _STAG_ENDDEP    0x07
00109 #define _STAG_IOPORT    0x08
00110 #define _STAG_FIXEDIO   0x09
00111 #define _STAG_VENDOR    0x0e
00112 #define _STAG_END   0x0f
00113 /* long tags */
00114 #define _LTAG_MEMRANGE    0x81
00115 #define _LTAG_ANSISTR   0x82
00116 #define _LTAG_UNICODESTR  0x83
00117 #define _LTAG_VENDOR    0x84
00118 #define _LTAG_MEM32RANGE  0x85
00119 #define _LTAG_FIXEDMEM32RANGE 0x86
00120 
00121 static unsigned char isapnp_checksum_value;
00122 static int isapnp_detected;
00123 
00124 /* some prototypes */
00125 
00126 static void udelay(unsigned long l)
00127 {
00128   struct timespec delay;
00129 
00130   delay.tv_sec = 0;
00131   delay.tv_nsec = l / 100;
00132 
00133   nanosleep(&delay, NULL);
00134 }
00135 
00136 
00137 static bool write_data(unsigned char x)
00138 {
00139   bool result = true;
00140   int fd = open("/dev/port", O_WRONLY);
00141 
00142   if (fd >= 0)
00143   {
00144     lseek(fd, _PNPWRP, SEEK_SET);
00145     if(write(fd, &x, 1) != 1)
00146       result = false;
00147     close(fd);
00148 
00149     return result;
00150   }
00151   else
00152   {
00153     isapnp_error = true;
00154     return false;
00155   }
00156 }
00157 
00158 
00159 static bool write_address(unsigned char x)
00160 {
00161   bool result = true;
00162   int fd = open("/dev/port", O_WRONLY);
00163 
00164   if (fd >= 0)
00165   {
00166     lseek(fd, _PIDXR, SEEK_SET);
00167     if(write(fd, &x, 1) != 1)
00168       result = false;
00169     close(fd);
00170     udelay(20);
00171     return result;
00172   }
00173   else
00174   {
00175     isapnp_error = true;
00176     return false;
00177   }
00178 }
00179 
00180 
00181 static unsigned char read_data(void)
00182 {
00183   int fd = open("/dev/port", O_RDONLY);
00184   unsigned char val = 0;
00185 
00186   if (fd >= 0)
00187   {
00188     lseek(fd, isapnp_rdp, SEEK_SET);
00189     if(read(fd, &val, 1) != 1)
00190       val = 0;
00191     close(fd);
00192   }
00193   else
00194   {
00195     isapnp_error = true;
00196   }
00197   return val;
00198 }
00199 
00200 
00201 static unsigned char isapnp_read_byte(unsigned char idx)
00202 {
00203   if (write_address(idx))
00204     return read_data();
00205   else
00206     return 0;
00207 }
00208 
00209 
00210 static bool isapnp_write_byte(unsigned char idx,
00211 unsigned char val)
00212 {
00213   return write_address(idx) && write_data(val);
00214 }
00215 
00216 
00217 static bool isapnp_key(void)
00218 {
00219   unsigned char code = 0x6a, msb;
00220   int i;
00221 
00222   udelay(100);
00223   if (!write_address(0x00))
00224     return false;
00225   if (!write_address(0x00))
00226     return false;
00227 
00228   if (!write_address(code))
00229     return false;
00230 
00231   for (i = 1; i < 32; i++)
00232   {
00233     msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
00234     code = (code >> 1) | msb;
00235     if (!write_address(code))
00236       return false;
00237   }
00238 
00239   return true;
00240 }
00241 
00242 
00243 /* place all pnp cards in wait-for-key state */
00244 static bool isapnp_wait(void)
00245 {
00246   return isapnp_write_byte(0x02, 0x02);
00247 }
00248 
00249 
00250 static bool isapnp_wake(unsigned char csn)
00251 {
00252   return isapnp_write_byte(0x03, csn);
00253 }
00254 
00255 
00256 static bool isapnp_peek(unsigned char *data,
00257 int bytes)
00258 {
00259   int i, j;
00260   unsigned char d = 0;
00261 
00262   isapnp_error = false;
00263 
00264   for (i = 1; i <= bytes; i++)
00265   {
00266     for (j = 0; j < 20; j++)
00267     {
00268       d = isapnp_read_byte(0x05);
00269       if (isapnp_error)
00270         return false;
00271       if (d & 1)
00272         break;
00273       udelay(10);
00274     }
00275     if (!(d & 1))
00276     {
00277       if (data != NULL)
00278         *data++ = 0xff;
00279       continue;
00280     }
00281     d = isapnp_read_byte(0x04);                   /* PRESDI */
00282     isapnp_checksum_value += d;
00283     if (data != NULL)
00284       *data++ = d;
00285   }
00286   return true;
00287 }
00288 
00289 
00290 #define RDP_STEP  32                              /* minimum is 4 */
00291 
00292 static int isapnp_next_rdp(void)
00293 {
00294   int rdp = isapnp_rdp;
00295   while (rdp <= 0x3ff)
00296   {
00297 /*
00298  *      We cannot use NE2000 probe spaces for ISAPnP or we
00299  *      will lock up machines.
00300  */
00301     if ((rdp < 0x280 || rdp > 0x380) /*&& !check_region(rdp, 1) */ )
00302     {
00303       isapnp_rdp = rdp;
00304       return 0;
00305     }
00306     rdp += RDP_STEP;
00307   }
00308   return -1;
00309 }
00310 
00311 
00312 /* Set read port address */
00313 static inline bool isapnp_set_rdp(void)
00314 {
00315   if (isapnp_write_byte(0x00, isapnp_rdp >> 2))
00316   {
00317     udelay(100);
00318     return true;
00319   }
00320   else
00321     return false;
00322 }
00323 
00324 
00325 /*
00326  *     Perform an isolation. The port selection code now tries to avoid
00327  *     "dangerous to read" ports.
00328  */
00329 
00330 static int isapnp_isolate_rdp_select(void)
00331 {
00332   if (!isapnp_wait())
00333     return -1;
00334   if (!isapnp_key())
00335     return -1;
00336 
00337 /*
00338  * Control: reset CSN and conditionally everything else too
00339  */
00340   if (!isapnp_write_byte(0x02, isapnp_reset ? 0x05 : 0x04))
00341     return -1;
00342   udelay(2);
00343 
00344   if (!isapnp_wait())
00345     return -1;
00346   if (!isapnp_key())
00347     return -1;
00348   if (!isapnp_wake(0x00))
00349     return -1;
00350 
00351   if (isapnp_next_rdp() < 0)
00352   {
00353     isapnp_wait();
00354     return -1;
00355   }
00356 
00357   isapnp_set_rdp();
00358   udelay(1);
00359   if (!write_address(0x01))
00360     return -1;
00361   udelay(1);
00362   return 0;
00363 }
00364 
00365 
00366 /*
00367  *  Isolate (assign uniqued CSN) to all ISA PnP devices.
00368  */
00369 
00370 static int isapnp_isolate(void)
00371 {
00372   unsigned char checksum = 0x6a;
00373   unsigned char chksum = 0x00;
00374   unsigned char bit = 0x00;
00375   int data;
00376   int csn = 0;
00377   int i;
00378   int iteration = 1;
00379 
00380   isapnp_rdp = 0x213;
00381   if (isapnp_isolate_rdp_select() < 0)
00382     return -1;
00383 
00384   isapnp_error = false;
00385 
00386   while (1)
00387   {
00388     for (i = 1; i <= 64; i++)
00389     {
00390       if (isapnp_error)
00391         return -1;
00392 
00393       data = read_data() << 8;
00394       udelay(250);
00395       data = data | read_data();
00396       udelay(250);
00397       if (data == 0x55aa)
00398         bit = 0x01;
00399       checksum =
00400         ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >>
00401         1);
00402       bit = 0x00;
00403     }
00404     for (i = 65; i <= 72; i++)
00405     {
00406       if (isapnp_error)
00407         return -1;
00408 
00409       data = read_data() << 8;
00410       udelay(250);
00411       data = data | read_data();
00412       udelay(250);
00413       if (data == 0x55aa)
00414         chksum |= (1 << (i - 65));
00415     }
00416     if (checksum != 0x00 && checksum == chksum)
00417     {
00418       csn++;
00419 
00420       if (isapnp_error)
00421         return -1;
00422 
00423       if (!isapnp_write_byte(0x06, csn))
00424         return -1;
00425       udelay(250);
00426       iteration++;
00427       if (!isapnp_wake(0x00))
00428         return -1;
00429       isapnp_set_rdp();
00430       udelay(1000);
00431       if (!write_address(0x01))
00432         return -1;
00433       udelay(1000);
00434       goto __next;
00435     }
00436     if (iteration == 1)
00437     {
00438       isapnp_rdp += RDP_STEP;
00439       if (isapnp_isolate_rdp_select() < 0)
00440         return -1;
00441     }
00442     else if (iteration > 1)
00443     {
00444       break;
00445     }
00446     __next:
00447     checksum = 0x6a;
00448     chksum = 0x00;
00449     bit = 0x00;
00450   }
00451   if (!isapnp_wait())
00452     return -1;
00453   return csn;
00454 }
00455 
00456 
00457 /*
00458  *  Read one tag from stream.
00459  */
00460 
00461 static int isapnp_read_tag(unsigned char *type,
00462 unsigned short *size)
00463 {
00464   unsigned char tag, tmp[2];
00465 
00466   isapnp_peek(&tag, 1);
00467   if (tag == 0)                                   /* invalid tag */
00468     return -1;
00469   if (tag & 0x80)
00470   {                                               /* large item */
00471     *type = tag;
00472     isapnp_peek(tmp, 2);
00473     *size = (tmp[1] << 8) | tmp[0];
00474   }
00475   else
00476   {
00477     *type = (tag >> 3) & 0x0f;
00478     *size = tag & 0x07;
00479   }
00480 #if 0
00481   printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type,
00482     *size);
00483 #endif
00484   if (type == 0)                                  /* wrong type */
00485     return -1;
00486   if (*type == 0xff && *size == 0xffff)           /* probably invalid data */
00487     return -1;
00488   return 0;
00489 }
00490 
00491 
00492 /*
00493  *  Skip specified number of bytes from stream.
00494  */
00495 
00496 static void isapnp_skip_bytes(int count)
00497 {
00498   isapnp_peek(NULL, count);
00499 }
00500 
00501 
00502 /*
00503  *  Parse EISA id.
00504  */
00505 
00506 static const char *isapnp_parse_id(unsigned short vendor,
00507 unsigned short device)
00508 {
00509   static char id[8];
00510   snprintf(id, sizeof(id), "%c%c%c%x%x%x%x",
00511     'A' + ((vendor >> 2) & 0x3f) - 1,
00512     'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
00513     'A' + ((vendor >> 8) & 0x1f) - 1,
00514     (device >> 4) & 0x0f,
00515     device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
00516 
00517   return id;
00518 }
00519 
00520 
00521 /*
00522  *  Parse logical device tag.
00523  */
00524 
00525 static hwNode *isapnp_parse_device(hwNode & card,
00526 int size,
00527 int number)
00528 {
00529   unsigned char tmp[6];
00530 
00531   isapnp_peek(tmp, size);
00532   return card.
00533     addChild(hwNode
00534     (isapnp_parse_id
00535     ((tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2])));
00536 }
00537 
00538 
00539 /*
00540  *  Add IRQ resource to resources list.
00541  */
00542 
00543 static void isapnp_parse_irq_resource(hwNode & n,
00544 int size)
00545 {
00546   unsigned char tmp[3];
00547 
00548   isapnp_peek(tmp, size);
00549 /*
00550  * irq = isapnp_alloc(sizeof(struct pnp_irq));
00551  * if (!irq)
00552  * return;
00553  * irq->map = (tmp[1] << 8) | tmp[0];
00554  * if (size > 2)
00555  * irq->flags = tmp[2];
00556  * else
00557  * irq->flags = IORESOURCE_IRQ_HIGHEDGE;
00558  * return;
00559  */
00560 }
00561 
00562 
00563 /*
00564  *  Add DMA resource to resources list.
00565  */
00566 
00567 static void isapnp_parse_dma_resource(int size)
00568 {
00569   unsigned char tmp[2];
00570 
00571   isapnp_peek(tmp, size);
00572 /*
00573  * dma = isapnp_alloc(sizeof(struct pnp_dma));
00574  * if (!dma)
00575  * return;
00576  * dma->map = tmp[0];
00577  * dma->flags = tmp[1];
00578  * return;
00579  */
00580 }
00581 
00582 
00583 /*
00584  *  Add port resource to resources list.
00585  */
00586 
00587 static void isapnp_parse_port_resource(hwNode & n,
00588 int size)
00589 {
00590   unsigned char tmp[7];
00591 
00592   isapnp_peek(tmp, size);
00593 /*
00594  * port = isapnp_alloc(sizeof(struct pnp_port));
00595  * if (!port)
00596  * return;
00597  * port->min = (tmp[2] << 8) | tmp[1];
00598  * port->max = (tmp[4] << 8) | tmp[3];
00599  * port->align = tmp[5];
00600  * port->size = tmp[6];
00601  * port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
00602  * return;
00603  */
00604 }
00605 
00606 
00607 /*
00608  *  Add fixed port resource to resources list.
00609  */
00610 
00611 static void isapnp_parse_fixed_port_resource(int size)
00612 {
00613   unsigned char tmp[3];
00614 
00615   isapnp_peek(tmp, size);
00616 /*
00617  * port = isapnp_alloc(sizeof(struct pnp_port));
00618  * if (!port)
00619  * return;
00620  * port->min = port->max = (tmp[1] << 8) | tmp[0];
00621  * port->size = tmp[2];
00622  * port->align = 0;
00623  * port->flags = PNP_PORT_FLAG_FIXED;
00624  * return;
00625  */
00626 }
00627 
00628 
00629 /*
00630  *  Add memory resource to resources list.
00631  */
00632 
00633 static void isapnp_parse_mem_resource(int size)
00634 {
00635   unsigned char tmp[9];
00636 
00637   isapnp_peek(tmp, size);
00638 /*
00639  * mem = isapnp_alloc(sizeof(struct pnp_mem));
00640  * if (!mem)
00641  * return;
00642  * mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
00643  * mem->max = ((tmp[4] << 8) | tmp[3]) << 8;
00644  * mem->align = (tmp[6] << 8) | tmp[5];
00645  * mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
00646  * mem->flags = tmp[0];
00647  * return;
00648  */
00649 }
00650 
00651 
00652 /*
00653  *  Add 32-bit memory resource to resources list.
00654  */
00655 
00656 static void isapnp_parse_mem32_resource(int size)
00657 {
00658   unsigned char tmp[17];
00659 
00660   isapnp_peek(tmp, size);
00661 /*
00662  * mem = isapnp_alloc(sizeof(struct pnp_mem));
00663  * if (!mem)
00664  * return;
00665  * mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
00666  * mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
00667  * mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
00668  * mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
00669  * mem->flags = tmp[0];
00670  */
00671 }
00672 
00673 
00674 /*
00675  *  Add 32-bit fixed memory resource to resources list.
00676  */
00677 
00678 static void isapnp_parse_fixed_mem32_resource(int size)
00679 {
00680   unsigned char tmp[9];
00681 
00682   isapnp_peek(tmp, size);
00683 /*
00684  * mem = isapnp_alloc(sizeof(struct pnp_mem));
00685  * if (!mem)
00686  * return;
00687  * mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
00688  * mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
00689  * mem->align = 0;
00690  * mem->flags = tmp[0];
00691  */
00692 }
00693 
00694 
00695 /*
00696  *  Parse card name for ISA PnP device.
00697  */
00698 
00699 static string isapnp_parse_name(unsigned short &size)
00700 {
00701   char buffer[1024];
00702   unsigned short size1 = size >= sizeof(buffer) ? (sizeof(buffer) - 1) : size;
00703   isapnp_peek((unsigned char *) buffer, size1);
00704   buffer[size1] = '\0';
00705   size -= size1;
00706 
00707   return hw::strip(buffer);
00708 }
00709 
00710 
00711 /*
00712  *  Parse resource map for logical device.
00713  */
00714 
00715 static int isapnp_create_device(hwNode & card,
00716 unsigned short size)
00717 {
00718   int number = 0, skip = 0, priority = 0, compat = 0;
00719   unsigned char type, tmp[17];
00720   hwNode *dev = NULL;
00721 
00722   if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
00723     return 1;
00724 /*
00725  * option = pnp_register_independent_option(dev);
00726  * if (!option)
00727  * return 1;
00728  */
00729 
00730   while (1)
00731   {
00732     if (isapnp_read_tag(&type, &size) < 0)
00733       return 1;
00734     if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
00735       goto __skip;
00736     switch (type)
00737     {
00738       case _STAG_LOGDEVID:
00739         if (size >= 5 && size <= 6)
00740         {
00741           if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
00742             return 1;
00743           size = 0;
00744           skip = 0;
00745 /*
00746  * option = pnp_register_independent_option(dev);
00747  * if (!option)
00748  * return 1;
00749  * pnp_add_card_device(card,dev);
00750  */
00751         }
00752         else
00753         {
00754           skip = 1;
00755         }
00756         priority = 0;
00757         compat = 0;
00758         break;
00759       case _STAG_COMPATDEVID:
00760         if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE)
00761         {
00762           isapnp_peek(tmp, 4);
00763           if (dev->getClass() == hw::generic)
00764             dev->
00765               setClass(pnp_class
00766               (isapnp_parse_id
00767               ((tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2])));
00768           dev->
00769             addCapability(string(isapnp_parse_id
00770             ((tmp[1] << 8) | tmp[0],
00771             (tmp[3] << 8) | tmp[2])) +
00772             string("-compatible"));
00773           compat++;
00774           size = 0;
00775         }
00776         break;
00777       case _STAG_IRQ:
00778         if (size < 2 || size > 3)
00779           goto __skip;
00780         isapnp_parse_irq_resource(card, size);
00781         size = 0;
00782         break;
00783       case _STAG_DMA:
00784         if (size != 2)
00785           goto __skip;
00786         isapnp_parse_dma_resource(size);
00787         size = 0;
00788         break;
00789       case _STAG_STARTDEP:
00790         if (size > 1)
00791           goto __skip;
00792 //priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
00793         if (size > 0)
00794         {
00795           isapnp_peek(tmp, size);
00796           priority = 0x100 | tmp[0];
00797           size = 0;
00798         }
00799 /*
00800  * option = pnp_register_dependent_option(dev,priority);
00801  * if (!option)
00802  * return 1;
00803  */
00804         break;
00805       case _STAG_ENDDEP:
00806         if (size != 0)
00807           goto __skip;
00808         priority = 0;
00809         break;
00810       case _STAG_IOPORT:
00811         if (size != 7)
00812           goto __skip;
00813         isapnp_parse_port_resource(*dev, size);
00814         size = 0;
00815         break;
00816       case _STAG_FIXEDIO:
00817         if (size != 3)
00818           goto __skip;
00819         isapnp_parse_fixed_port_resource(size);
00820         size = 0;
00821         break;
00822       case _STAG_VENDOR:
00823         break;
00824       case _LTAG_MEMRANGE:
00825         if (size != 9)
00826           goto __skip;
00827         isapnp_parse_mem_resource(size);
00828         size = 0;
00829         break;
00830       case _LTAG_ANSISTR:
00831         dev->setProduct(isapnp_parse_name(size));
00832         break;
00833       case _LTAG_UNICODESTR:
00834 /*
00835  * silently ignore
00836  */
00837 /*
00838  * who use unicode for hardware identification?
00839  */
00840         break;
00841       case _LTAG_VENDOR:
00842         break;
00843       case _LTAG_MEM32RANGE:
00844         if (size != 17)
00845           goto __skip;
00846         isapnp_parse_mem32_resource(size);
00847         size = 0;
00848         break;
00849       case _LTAG_FIXEDMEM32RANGE:
00850         if (size != 9)
00851           goto __skip;
00852         isapnp_parse_fixed_mem32_resource(size);
00853         size = 0;
00854         break;
00855       case _STAG_END:
00856         if (size > 0)
00857           isapnp_skip_bytes(size);
00858         return 1;
00859       default:
00860         break;
00861     }
00862     __skip:
00863     if (size > 0)
00864       isapnp_skip_bytes(size);
00865   }
00866   return 0;
00867 }
00868 
00869 
00870 static string bcd_version(unsigned char v,
00871 const char *separator = "")
00872 {
00873   char version[10];
00874 
00875   snprintf(version, sizeof(version), "%d%s%d", (v & 0xf0) >> 4, separator,
00876     v & 0x0f);
00877 
00878   return string(version);
00879 }
00880 
00881 
00882 /*
00883  *  Parse resource map for ISA PnP card.
00884  */
00885 
00886 static bool isapnp_parse_resource_map(hwNode & card)
00887 {
00888   unsigned char type, tmp[17];
00889   unsigned short size;
00890 
00891   while (1)
00892   {
00893     if (isapnp_read_tag(&type, &size) < 0)
00894       return false;
00895     switch (type)
00896     {
00897       case _STAG_PNPVERNO:
00898         if (size != 2)
00899           goto __skip;
00900         isapnp_peek(tmp, 2);
00901         card.addCapability("pnp-" + bcd_version(tmp[0], "."));
00902         card.setVersion(bcd_version(tmp[1]));
00903         size = 0;
00904         break;
00905       case _STAG_LOGDEVID:
00906         if (size >= 5 && size <= 6)
00907         {
00908           if (isapnp_create_device(card, size) == 1)
00909             return false;
00910           size = 0;
00911         }
00912         break;
00913       case _STAG_VENDOR:
00914         break;
00915       case _LTAG_ANSISTR:
00916         card.setProduct(isapnp_parse_name(size));
00917         break;
00918       case _LTAG_UNICODESTR:
00919 /*
00920  * silently ignore
00921  */
00922 /*
00923  * who uses unicode for hardware identification?
00924  */
00925         break;
00926       case _LTAG_VENDOR:
00927         break;
00928       case _STAG_END:
00929         if (size > 0)
00930           isapnp_skip_bytes(size);
00931         return true;
00932       default:
00933         break;
00934     }
00935     __skip:
00936     if (size > 0)
00937       isapnp_skip_bytes(size);
00938   }
00939 
00940   return true;
00941 }
00942 
00943 
00944 /*
00945  *  Compute ISA PnP checksum for first eight bytes.
00946  */
00947 
00948 static unsigned char isapnp_checksum(unsigned char *data)
00949 {
00950   int i, j;
00951   unsigned char checksum = 0x6a, bit, b;
00952 
00953   for (i = 0; i < 8; i++)
00954   {
00955     b = data[i];
00956     for (j = 0; j < 8; j++)
00957     {
00958       bit = 0;
00959       if (b & (1 << j))
00960         bit = 1;
00961       checksum =
00962         ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >>
00963         1);
00964     }
00965   }
00966   return checksum;
00967 }
00968 
00969 
00970 /*
00971  *  Parse EISA id for ISA PnP card.
00972  */
00973 
00974 static const char *isapnp_parse_card_id(unsigned short vendor,
00975 unsigned short device)
00976 {
00977   static char id[8];
00978 
00979   snprintf(id, sizeof(id), "%c%c%c%x%x%x%x",
00980     'A' + ((vendor >> 2) & 0x3f) - 1,
00981     'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
00982     'A' + ((vendor >> 8) & 0x1f) - 1,
00983     (device >> 4) & 0x0f,
00984     device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
00985   return id;
00986 }
00987 
00988 
00989 /*
00990  *  Build device list for all present ISA PnP devices.
00991  */
00992 
00993 static int isapnp_build_device_list(hwNode & n)
00994 {
00995   int csn;
00996   unsigned char header[9], checksum;
00997 
00998   isapnp_wait();
00999   isapnp_key();
01000   for (csn = 1; csn <= 10; csn++)
01001   {
01002     long serial = 0;
01003 
01004     isapnp_wake(csn);
01005     isapnp_peek(header, 9);
01006 
01007     hwNode card(isapnp_parse_card_id((header[1] << 8) | header[0],
01008       (header[3] << 8) | header[2]));
01009 
01010     checksum = isapnp_checksum(header);
01011 /*
01012  * Don't be strict on the checksum, here !
01013  * e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)
01014  */
01015     if (header[8] == 0)
01016       ;
01017                                                   /* not valid CSN */
01018     else if (checksum == 0x00 || checksum != header[8])
01019       continue;
01020 
01021     card.setPhysId(csn);
01022     card.
01023       setVendor(vendorname
01024       (isapnp_parse_card_id
01025       ((header[1] << 8) | header[0],
01026       (header[3] << 8) | header[2])));
01027     card.addCapability("pnp");
01028     card.addCapability("isapnp");
01029     card.setBusInfo("isapnp@" + card.getPhysId());
01030     serial =
01031       (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
01032     if (serial != -1)
01033     {
01034       char number[20];
01035 
01036       snprintf(number, sizeof(number), "%ld", serial);
01037       card.setSerial(number);
01038     }
01039     isapnp_checksum_value = 0x00;
01040     isapnp_parse_resource_map(card);
01041 /*
01042  * if (isapnp_checksum_value != 0x00)
01043  * fprintf(stderr, "isapnp: checksum for device %i is not valid (0x%x)\n",
01044  * csn, isapnp_checksum_value);
01045  */
01046 
01047     n.addChild(card);
01048   }
01049   isapnp_wait();
01050   return 0;
01051 }
01052 
01053 
01054 static bool isabus(const hwNode & n)
01055 {
01056   return (n.getClass() == hw::bridge) && n.isCapable("isa");
01057 }
01058 #endif
01059 
01060 bool scan_isapnp(hwNode & n)
01061 {
01062 #ifdef __i386__
01063   int cards;
01064 
01065   isapnp_rdp = 0;
01066   isapnp_detected = 1;
01067   cards = isapnp_isolate();
01068   if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff))
01069   {
01070     isapnp_detected = 0;
01071     return false;
01072   }
01073 
01074   hwNode *isaroot = n.findChild(isabus);
01075 
01076   if (isaroot)
01077     isapnp_build_device_list(*isaroot);
01078   else
01079     isapnp_build_device_list(n);
01080 #endif
01081   return true;
01082 }