1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 #include "io.h" 8 9 enum{ 10 Linktarget = 0x13, 11 }; 12 13 /* 14 * read and crack the card information structure enough to set 15 * important parameters like power 16 */ 17 /* cis memory walking */ 18 typedef struct Cisdat { 19 uchar *cisbase; 20 int cispos; 21 int cisskip; 22 int cislen; 23 } Cisdat; 24 25 static void tcfig(PCMslot*, Cisdat*, int); 26 static void tentry(PCMslot*, Cisdat*, int); 27 static void tvers1(PCMslot*, Cisdat*, int); 28 static void tlonglnkmfc(PCMslot*, Cisdat*, int); 29 30 static int 31 readc(Cisdat *cis, uchar *x) 32 { 33 if(cis->cispos >= cis->cislen) 34 return 0; 35 *x = cis->cisbase[cis->cisskip*cis->cispos]; 36 cis->cispos++; 37 return 1; 38 } 39 40 static int 41 xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr) 42 { 43 PCMmap *m; 44 Cisdat cis; 45 int i, l; 46 uchar *p; 47 uchar type, link, n, c; 48 int this, subtype; 49 50 m = pcmmap(slotno, 0, 0, attr); 51 if(m == 0) 52 return -1; 53 54 cis.cisbase = KADDR(m->isa); 55 cis.cispos = 0; 56 cis.cisskip = attr ? 2 : 1; 57 cis.cislen = m->len; 58 59 /* loop through all the tuples */ 60 for(i = 0; i < 1000; i++){ 61 this = cis.cispos; 62 if(readc(&cis, &type) != 1) 63 break; 64 if(type == 0xFF) 65 break; 66 if(readc(&cis, &link) != 1) 67 break; 68 if(link == 0xFF) 69 break; 70 71 n = link; 72 if(link > 1 && subtuple != -1){ 73 if(readc(&cis, &c) != 1) 74 break; 75 subtype = c; 76 n--; 77 }else 78 subtype = -1; 79 80 if(type == tuple && subtype == subtuple){ 81 p = v; 82 for(l=0; l<nv && l<n; l++) 83 if(readc(&cis, p++) != 1) 84 break; 85 pcmunmap(slotno, m); 86 return nv; 87 } 88 cis.cispos = this + (2+link); 89 } 90 pcmunmap(slotno, m); 91 return -1; 92 } 93 94 int 95 pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv) 96 { 97 int n; 98 99 /* try attribute space, then memory */ 100 if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0) 101 return n; 102 return xcistuple(slotno, tuple, subtuple, v, nv, 0); 103 } 104 105 void 106 pcmcisread(PCMslot *pp) 107 { 108 int this; 109 Cisdat cis; 110 PCMmap *m; 111 uchar type, link; 112 113 memset(pp->ctab, 0, sizeof(pp->ctab)); 114 pp->ncfg = 0; 115 memset(pp->cfg, 0, sizeof(pp->cfg)); 116 pp->configed = 0; 117 pp->nctab = 0; 118 pp->verstr[0] = 0; 119 120 /* 121 * Read all tuples in attribute space. 122 */ 123 m = pcmmap(pp->slotno, 0, 0, 1); 124 if(m == 0) 125 return; 126 127 cis.cisbase = KADDR(m->isa); 128 cis.cispos = 0; 129 cis.cisskip = 2; 130 cis.cislen = m->len; 131 132 /* loop through all the tuples */ 133 for(;;){ 134 this = cis.cispos; 135 if(readc(&cis, &type) != 1) 136 break; 137 if(type == 0xFF) 138 break; 139 if(readc(&cis, &link) != 1) 140 break; 141 142 switch(type){ 143 default: 144 break; 145 case 6: 146 tlonglnkmfc(pp, &cis, type); 147 break; 148 case 0x15: 149 tvers1(pp, &cis, type); 150 break; 151 case 0x1A: 152 tcfig(pp, &cis, type); 153 break; 154 case 0x1B: 155 tentry(pp, &cis, type); 156 break; 157 } 158 159 if(link == 0xFF) 160 break; 161 cis.cispos = this + (2+link); 162 } 163 pcmunmap(pp->slotno, m); 164 } 165 166 static ulong 167 getlong(Cisdat *cis, int size) 168 { 169 uchar c; 170 int i; 171 ulong x; 172 173 x = 0; 174 for(i = 0; i < size; i++){ 175 if(readc(cis, &c) != 1) 176 break; 177 x |= c<<(i*8); 178 } 179 return x; 180 } 181 182 static void 183 tcfig(PCMslot *pp, Cisdat *cis, int ) 184 { 185 uchar size, rasize, rmsize; 186 uchar last; 187 188 if(readc(cis, &size) != 1) 189 return; 190 rasize = (size&0x3) + 1; 191 rmsize = ((size>>2)&0xf) + 1; 192 if(readc(cis, &last) != 1) 193 return; 194 195 if(pp->ncfg >= 8){ 196 print("tcfig: too many configuration registers\n"); 197 return; 198 } 199 200 pp->cfg[pp->ncfg].caddr = getlong(cis, rasize); 201 pp->cfg[pp->ncfg].cpresent = getlong(cis, rmsize); 202 pp->ncfg++; 203 } 204 205 static ulong vexp[8] = 206 { 207 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 208 }; 209 static ulong vmant[16] = 210 { 211 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, 212 }; 213 214 static ulong 215 microvolt(Cisdat *cis) 216 { 217 uchar c; 218 ulong microvolts; 219 ulong exp; 220 221 if(readc(cis, &c) != 1) 222 return 0; 223 exp = vexp[c&0x7]; 224 microvolts = vmant[(c>>3)&0xf]*exp; 225 while(c & 0x80){ 226 if(readc(cis, &c) != 1) 227 return 0; 228 switch(c){ 229 case 0x7d: 230 break; /* high impedence when sleeping */ 231 case 0x7e: 232 case 0x7f: 233 microvolts = 0; /* no connection */ 234 break; 235 default: 236 exp /= 10; 237 microvolts += exp*(c&0x7f); 238 } 239 } 240 return microvolts; 241 } 242 243 static ulong 244 nanoamps(Cisdat *cis) 245 { 246 uchar c; 247 ulong nanoamps; 248 249 if(readc(cis, &c) != 1) 250 return 0; 251 nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf]; 252 while(c & 0x80){ 253 if(readc(cis, &c) != 1) 254 return 0; 255 if(c == 0x7d || c == 0x7e || c == 0x7f) 256 nanoamps = 0; 257 } 258 return nanoamps; 259 } 260 261 /* 262 * only nominal voltage (feature 1) is important for config, 263 * other features must read card to stay in sync. 264 */ 265 static ulong 266 power(Cisdat *cis) 267 { 268 uchar feature; 269 ulong mv; 270 271 mv = 0; 272 if(readc(cis, &feature) != 1) 273 return 0; 274 if(feature & 1) 275 mv = microvolt(cis); 276 if(feature & 2) 277 microvolt(cis); 278 if(feature & 4) 279 microvolt(cis); 280 if(feature & 8) 281 nanoamps(cis); 282 if(feature & 0x10) 283 nanoamps(cis); 284 if(feature & 0x20) 285 nanoamps(cis); 286 if(feature & 0x40) 287 nanoamps(cis); 288 return mv/1000000; 289 } 290 291 static ulong mantissa[16] = 292 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; 293 294 static ulong exponent[8] = 295 { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; 296 297 static ulong 298 ttiming(Cisdat *cis, int scale) 299 { 300 uchar unscaled; 301 ulong nanosecs; 302 303 if(readc(cis, &unscaled) != 1) 304 return 0; 305 nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; 306 nanosecs = nanosecs * vexp[scale]; 307 return nanosecs; 308 } 309 310 static void 311 timing(Cisdat *cis, PCMconftab *ct) 312 { 313 uchar c, i; 314 315 if(readc(cis, &c) != 1) 316 return; 317 i = c&0x3; 318 if(i != 3) 319 ct->maxwait = ttiming(cis, i); /* max wait */ 320 i = (c>>2)&0x7; 321 if(i != 7) 322 ct->readywait = ttiming(cis, i); /* max ready/busy wait */ 323 i = (c>>5)&0x7; 324 if(i != 7) 325 ct->otherwait = ttiming(cis, i); /* reserved wait */ 326 } 327 328 static void 329 iospaces(Cisdat *cis, PCMconftab *ct) 330 { 331 uchar c; 332 int i, nio; 333 334 ct->nio = 0; 335 if(readc(cis, &c) != 1) 336 return; 337 338 ct->bit16 = ((c>>5)&3) >= 2; 339 if(!(c & 0x80)){ 340 ct->io[0].start = 0; 341 ct->io[0].len = 1<<(c&0x1f); 342 ct->nio = 1; 343 return; 344 } 345 346 if(readc(cis, &c) != 1) 347 return; 348 349 /* 350 * For each of the range descriptions read the 351 * start address and the length (value is length-1). 352 */ 353 nio = (c&0xf)+1; 354 for(i = 0; i < nio; i++){ 355 ct->io[i].start = getlong(cis, (c>>4)&0x3); 356 ct->io[i].len = getlong(cis, (c>>6)&0x3)+1; 357 } 358 ct->nio = nio; 359 } 360 361 static void 362 irq(Cisdat *cis, PCMconftab *ct) 363 { 364 uchar c; 365 366 if(readc(cis, &c) != 1) 367 return; 368 ct->irqtype = c & 0xe0; 369 if(c & 0x10) 370 ct->irqs = getlong(cis, 2); 371 else 372 ct->irqs = 1<<(c&0xf); 373 ct->irqs &= 0xDEB8; /* levels available to card */ 374 } 375 376 static void 377 memspace(Cisdat *cis, int asize, int lsize, int host) 378 { 379 ulong haddress, address, len; 380 381 len = getlong(cis, lsize)*256; 382 address = getlong(cis, asize)*256; 383 USED(len, address); 384 if(host){ 385 haddress = getlong(cis, asize)*256; 386 USED(haddress); 387 } 388 } 389 390 static void 391 tentry(PCMslot *pp, Cisdat *cis, int ) 392 { 393 uchar c, i, feature; 394 PCMconftab *ct; 395 396 if(pp->nctab >= nelem(pp->ctab)) 397 return; 398 if(readc(cis, &c) != 1) 399 return; 400 ct = &pp->ctab[pp->nctab++]; 401 402 /* copy from last default config */ 403 if(pp->def) 404 *ct = *pp->def; 405 406 ct->index = c & 0x3f; 407 408 /* is this the new default? */ 409 if(c & 0x40) 410 pp->def = ct; 411 412 /* memory wait specified? */ 413 if(c & 0x80){ 414 if(readc(cis, &i) != 1) 415 return; 416 if(i&0x80) 417 ct->memwait = 1; 418 } 419 420 if(readc(cis, &feature) != 1) 421 return; 422 switch(feature&0x3){ 423 case 1: 424 ct->vpp1 = ct->vpp2 = power(cis); 425 break; 426 case 2: 427 power(cis); 428 ct->vpp1 = ct->vpp2 = power(cis); 429 break; 430 case 3: 431 power(cis); 432 ct->vpp1 = power(cis); 433 ct->vpp2 = power(cis); 434 break; 435 default: 436 break; 437 } 438 if(feature&0x4) 439 timing(cis, ct); 440 if(feature&0x8) 441 iospaces(cis, ct); 442 if(feature&0x10) 443 irq(cis, ct); 444 switch((feature>>5)&0x3){ 445 case 1: 446 memspace(cis, 0, 2, 0); 447 break; 448 case 2: 449 memspace(cis, 2, 2, 0); 450 break; 451 case 3: 452 if(readc(cis, &c) != 1) 453 return; 454 for(i = 0; i <= (c&0x7); i++) 455 memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80); 456 break; 457 } 458 pp->configed++; 459 } 460 461 static void 462 tvers1(PCMslot *pp, Cisdat *cis, int ) 463 { 464 uchar c, major, minor, last; 465 int i; 466 467 if(readc(cis, &major) != 1) 468 return; 469 if(readc(cis, &minor) != 1) 470 return; 471 last = 0; 472 for(i = 0; i < sizeof(pp->verstr)-1; i++){ 473 if(readc(cis, &c) != 1) 474 return; 475 if(c == 0) 476 c = ';'; 477 if(c == '\n') 478 c = ';'; 479 if(c == 0xff) 480 break; 481 if(c == ';' && last == ';') 482 continue; 483 pp->verstr[i] = c; 484 last = c; 485 } 486 pp->verstr[i] = 0; 487 } 488 489 static void 490 tlonglnkmfc(PCMslot *pp, Cisdat *cis, int) 491 { 492 int i, npos, opos; 493 uchar nfn, space, expect, type, this, link; 494 495 readc(cis, &nfn); 496 for(i = 0; i < nfn; i++){ 497 readc(cis, &space); 498 npos = getlong(cis, 4); 499 opos = cis->cispos; 500 cis->cispos = npos; 501 expect = Linktarget; 502 503 while(1){ 504 this = cis->cispos; 505 if(readc(cis, &type) != 1) 506 break; 507 if(type == 0xFF) 508 break; 509 if(readc(cis, &link) != 1) 510 break; 511 512 if(expect && expect != type){ 513 print("tlonglnkmfc: expected %X found %X\n", 514 expect, type); 515 break; 516 } 517 expect = 0; 518 519 switch(type){ 520 default: 521 break; 522 case 0x15: 523 tvers1(pp, cis, type); 524 break; 525 case 0x1A: 526 tcfig(pp, cis, type); 527 break; 528 case 0x1B: 529 tentry(pp, cis, type); 530 break; 531 } 532 533 if(link == 0xFF) 534 break; 535 cis->cispos = this + (2+link); 536 } 537 cis->cispos = opos; 538 } 539 } 540