|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "../port/error.h" ! 7: #include "io.h" ! 8: #include "devtab.h" ! 9: ! 10: /* ! 11: * Support for up to 4 Slot card slots. Generalizing above that is hard ! 12: * since addressing is not obvious. - presotto ! 13: * ! 14: * WARNING: This has never been tried with more than one card slot. ! 15: */ ! 16: ! 17: /* ! 18: * Intel 82365SL PCIC controller for the PCMCIA or ! 19: * Cirrus Logic PD6710/PD6720 which is mostly register compatible ! 20: */ ! 21: enum ! 22: { ! 23: /* ! 24: * registers indices ! 25: */ ! 26: Rid= 0x0, /* identification and revision */ ! 27: Ris= 0x1, /* interface status */ ! 28: Rpc= 0x2, /* power control */ ! 29: Foutena= (1<<7), /* output enable */ ! 30: Fautopower= (1<<5), /* automatic power switching */ ! 31: Fcardena= (1<<4), /* PC card enable */ ! 32: Rigc= 0x3, /* interrupt and general control */ ! 33: Fiocard= (1<<5), /* I/O card (vs memory) */ ! 34: Fnotreset= (1<<6), /* reset if not set */ ! 35: FSMIena= (1<<4), /* enable change interrupt on SMI */ ! 36: Rcsc= 0x4, /* card status change */ ! 37: Rcscic= 0x5, /* card status change interrupt config */ ! 38: Fchangeena= (1<<3), /* card changed */ ! 39: Fbwarnena= (1<<1), /* card battery warning */ ! 40: Fbdeadena= (1<<0), /* card battery dead */ ! 41: Rwe= 0x6, /* address window enable */ ! 42: Fmem16= (1<<5), /* use A23-A12 to decode address */ ! 43: Rio= 0x7, /* I/O control */ ! 44: Fwidth16= (1<<0), /* 16 bit data width */ ! 45: Fiocs16= (1<<1), /* IOCS16 determines data width */ ! 46: Ftiming= (1<<3), /* timing register to use */ ! 47: Riobtm0lo= 0x8, /* I/O address 0 start low byte */ ! 48: Riobtm0hi= 0x9, /* I/O address 0 start high byte */ ! 49: Riotop0lo= 0xa, /* I/O address 0 stop low byte */ ! 50: Riotop0hi= 0xb, /* I/O address 0 stop high byte */ ! 51: Riobtm1lo= 0xc, /* I/O address 1 start low byte */ ! 52: Riobtm1hi= 0xd, /* I/O address 1 start high byte */ ! 53: Riotop1lo= 0xe, /* I/O address 1 stop low byte */ ! 54: Riotop1hi= 0xf, /* I/O address 1 stop high byte */ ! 55: Rmap= 0x10, /* map 0 */ ! 56: ! 57: /* ! 58: * CL-PD67xx extension registers ! 59: */ ! 60: Rmisc1= 0x16, /* misc control 1 */ ! 61: F5Vdetect= (1<<0), ! 62: Fvcc3V= (1<<1), ! 63: Fpmint= (1<<2), ! 64: Fpsirq= (1<<3), ! 65: Fspeaker= (1<<4), ! 66: Finpack= (1<<7), ! 67: Rfifo= 0x17, /* fifo control */ ! 68: Fflush= (1<<7), /* flush fifo */ ! 69: Rmisc2= 0x1E, /* misc control 2 */ ! 70: Flowpow= (1<<1), /* low power mode */ ! 71: Rchipinfo= 0x1F, /* chip information */ ! 72: Ratactl= 0x26, /* ATA control */ ! 73: ! 74: /* ! 75: * offsets into the system memory address maps ! 76: */ ! 77: Mbtmlo= 0x0, /* System mem addr mapping start low byte */ ! 78: Mbtmhi= 0x1, /* System mem addr mapping start high byte */ ! 79: F16bit= (1<<7), /* 16-bit wide data path */ ! 80: Mtoplo= 0x2, /* System mem addr mapping stop low byte */ ! 81: Mtophi= 0x3, /* System mem addr mapping stop high byte */ ! 82: Ftimer1= (1<<6), /* timer set 1 */ ! 83: Mofflo= 0x4, /* Card memory offset address low byte */ ! 84: Moffhi= 0x5, /* Card memory offset address high byte */ ! 85: Fregactive= (1<<6), /* attribute memory */ ! 86: ! 87: Mbits= 13, /* msb of Mchunk */ ! 88: Mchunk= 1<<Mbits, /* logical mapping granularity */ ! 89: Nmap= 4, /* max number of maps to use */ ! 90: ! 91: /* ! 92: * configuration registers - they start at an offset in attribute ! 93: * memory found in the CIS. ! 94: */ ! 95: Rconfig= 0, ! 96: Creset= (1<<7), /* reset device */ ! 97: Clevel= (1<<6), /* level sensitive interrupt line */ ! 98: ! 99: Maxctab= 8, /* maximum configuration table entries */ ! 100: }; ! 101: ! 102: #define MAP(x,o) (Rmap + (x)*0x8 + o) ! 103: ! 104: typedef struct I82365 I82365; ! 105: typedef struct Slot Slot; ! 106: typedef struct Conftab Conftab; ! 107: ! 108: /* a controller */ ! 109: enum ! 110: { ! 111: Ti82365, ! 112: Tpd6710, ! 113: Tpd6720, ! 114: }; ! 115: struct I82365 ! 116: { ! 117: int type; ! 118: int dev; ! 119: int nslot; ! 120: int xreg; /* index register address */ ! 121: int dreg; /* data register address */ ! 122: }; ! 123: static I82365 *controller[4]; ! 124: static int ncontroller; ! 125: ! 126: /* configuration table entry */ ! 127: struct Conftab ! 128: { ! 129: int index; ! 130: ushort irqs; /* legal irqs */ ! 131: ushort port; /* port address */ ! 132: uchar irqtype; ! 133: uchar nioregs; /* number of io registers */ ! 134: uchar bit16; /* true for 16 bit access */ ! 135: uchar vpp1; ! 136: uchar vpp2; ! 137: uchar memwait; ! 138: ulong maxwait; ! 139: ulong readywait; ! 140: ulong otherwait; ! 141: }; ! 142: ! 143: /* a card slot */ ! 144: struct Slot ! 145: { ! 146: Lock; ! 147: int ref; ! 148: ! 149: I82365 *cp; /* controller for this slot */ ! 150: long memlen; /* memory length */ ! 151: uchar base; /* index register base */ ! 152: uchar slotno; /* slot number */ ! 153: ! 154: /* status */ ! 155: uchar special; /* in use for a special device */ ! 156: uchar already; /* already inited */ ! 157: uchar occupied; ! 158: uchar battery; ! 159: uchar wrprot; ! 160: uchar powered; ! 161: uchar configed; ! 162: uchar enabled; ! 163: uchar busy; ! 164: ! 165: /* cis info */ ! 166: char verstr[512]; /* version string */ ! 167: uchar cpresent; /* config registers present */ ! 168: ulong caddr; /* relative address of config registers */ ! 169: int nctab; /* number of config table entries */ ! 170: Conftab ctab[Maxctab]; ! 171: Conftab *def; /* default conftab */ ! 172: ! 173: /* for walking through cis */ ! 174: int cispos; /* current position scanning cis */ ! 175: uchar *cisbase; ! 176: ! 177: /* memory maps */ ! 178: Lock mlock; /* lock down the maps */ ! 179: int time; ! 180: PCMmap mmap[Nmap]; /* maps, last is always for the kernel */ ! 181: }; ! 182: static Slot *slot; ! 183: static Slot *lastslot; ! 184: static nslot; ! 185: ! 186: static void cisread(Slot*); ! 187: static void i82365intr(Ureg*, void*); ! 188: static int pcmio(int, ISAConf*); ! 189: static long pcmread(int, int, void*, long, ulong); ! 190: static long pcmwrite(int, int, void*, long, ulong); ! 191: ! 192: /* ! 193: * reading and writing card registers ! 194: */ ! 195: static uchar ! 196: rdreg(Slot *pp, int index) ! 197: { ! 198: outb(pp->cp->xreg, pp->base + index); ! 199: return inb(pp->cp->dreg); ! 200: } ! 201: static void ! 202: wrreg(Slot *pp, int index, uchar val) ! 203: { ! 204: outb(pp->cp->xreg, pp->base + index); ! 205: outb(pp->cp->dreg, val); ! 206: } ! 207: ! 208: /* ! 209: * get info about card ! 210: */ ! 211: static void ! 212: slotinfo(Slot *pp) ! 213: { ! 214: uchar isr; ! 215: ! 216: isr = rdreg(pp, Ris); ! 217: pp->occupied = (isr & (3<<2)) == (3<<2); ! 218: pp->powered = isr & (1<<6); ! 219: pp->battery = (isr & 3) == 3; ! 220: pp->wrprot = isr & (1<<4); ! 221: pp->busy = isr & (1<<5); ! 222: } ! 223: ! 224: static int ! 225: vcode(int volt) ! 226: { ! 227: switch(volt){ ! 228: case 5: ! 229: return 1; ! 230: case 12: ! 231: return 2; ! 232: default: ! 233: return 0; ! 234: } ! 235: } ! 236: ! 237: /* ! 238: * enable the slot card ! 239: */ ! 240: static void ! 241: slotena(Slot *pp) ! 242: { ! 243: if(pp->enabled) ! 244: return; ! 245: ! 246: /* power up and unreset, wait's are empirical (???) */ ! 247: wrreg(pp, Rpc, Fautopower|Foutena|Fcardena); ! 248: delay(300); ! 249: wrreg(pp, Rigc, 0); ! 250: delay(100); ! 251: wrreg(pp, Rigc, Fnotreset); ! 252: delay(500); ! 253: ! 254: /* get configuration */ ! 255: slotinfo(pp); ! 256: if(pp->occupied){ ! 257: cisread(pp); ! 258: pp->enabled = 1; ! 259: } else ! 260: wrreg(pp, Rpc, Fautopower); ! 261: } ! 262: ! 263: /* ! 264: * disable the slot card ! 265: */ ! 266: static void ! 267: slotdis(Slot *pp) ! 268: { ! 269: wrreg(pp, Rpc, 0); /* turn off card power */ ! 270: wrreg(pp, Rwe, 0); /* no windows */ ! 271: pp->enabled = 0; ! 272: } ! 273: ! 274: /* ! 275: * status change interrupt ! 276: */ ! 277: static void ! 278: i82365intr(Ureg *ur, void *a) ! 279: { ! 280: uchar csc, was; ! 281: Slot *pp; ! 282: ! 283: USED(ur,a); ! 284: if(slot == 0) ! 285: return; ! 286: ! 287: for(pp = slot; pp < lastslot; pp++){ ! 288: csc = rdreg(pp, Rcsc); ! 289: was = pp->occupied; ! 290: slotinfo(pp); ! 291: if(csc & (1<<3) && was != pp->occupied){ ! 292: if(pp->occupied) ! 293: print("slot%d card inserted\n", pp->slotno); ! 294: else { ! 295: print("slot%d card removed\n", pp->slotno); ! 296: slotdis(pp); ! 297: } ! 298: } ! 299: } ! 300: } ! 301: ! 302: enum ! 303: { ! 304: Mshift= 12, ! 305: Mgran= (1<<Mshift), /* granularity of maps */ ! 306: Mmask= ~(Mgran-1), /* mask for address bits important to the chip */ ! 307: }; ! 308: ! 309: /* ! 310: * get a map for pc card region, return corrected len ! 311: */ ! 312: PCMmap* ! 313: pcmmap(int slotno, ulong offset, int len, int attr) ! 314: { ! 315: Slot *pp; ! 316: uchar we, bit; ! 317: PCMmap *m, *nm; ! 318: int i; ! 319: ulong e; ! 320: ! 321: pp = slot + slotno; ! 322: lock(&pp->mlock); ! 323: ! 324: /* convert offset to granularity */ ! 325: if(len <= 0) ! 326: len = 1; ! 327: e = ROUND(offset+len, Mgran); ! 328: offset &= Mmask; ! 329: len = e - offset; ! 330: ! 331: /* look for a map that covers the right area */ ! 332: we = rdreg(pp, Rwe); ! 333: bit = 1; ! 334: nm = 0; ! 335: for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){ ! 336: if((we & bit)) ! 337: if(m->attr == attr) ! 338: if(offset >= m->ca && e <= m->cea){ ! 339: ! 340: m->ref++; ! 341: unlock(&pp->mlock); ! 342: return m; ! 343: } ! 344: bit <<= 1; ! 345: if(nm == 0 && m->ref == 0) ! 346: nm = m; ! 347: } ! 348: m = nm; ! 349: if(m == 0){ ! 350: unlock(&pp->mlock); ! 351: return 0; ! 352: } ! 353: ! 354: /* if isa space isn't big enough, free it and get more */ ! 355: if(m->len < len){ ! 356: if(m->isa){ ! 357: putisa(m->isa, m->len); ! 358: m->len = 0; ! 359: } ! 360: m->isa = getisa(0, len, Mgran)&~KZERO; ! 361: if(m->isa == 0){ ! 362: print("pcmmap: out of isa space\n"); ! 363: unlock(&pp->mlock); ! 364: return 0; ! 365: } ! 366: m->len = len; ! 367: } ! 368: ! 369: /* set up new map */ ! 370: m->ca = offset; ! 371: m->cea = m->ca + m->len; ! 372: m->attr = attr; ! 373: i = m-pp->mmap; ! 374: bit = 1<<i; ! 375: wrreg(pp, Rwe, we & ~bit); /* disable map before changing it */ ! 376: wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift); ! 377: wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit); ! 378: wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift); ! 379: wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8))); ! 380: offset -= m->isa; ! 381: offset &= (1<<25)-1; ! 382: offset >>= Mshift; ! 383: wrreg(pp, MAP(i, Mofflo), offset); ! 384: wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0)); ! 385: wrreg(pp, Rwe, we | bit); /* enable map */ ! 386: m->ref = 1; ! 387: ! 388: unlock(&pp->mlock); ! 389: return m; ! 390: } ! 391: ! 392: void ! 393: pcmunmap(int slotno, PCMmap* m) ! 394: { ! 395: Slot *pp; ! 396: ! 397: pp = slot + slotno; ! 398: lock(&pp->mlock); ! 399: m->ref--; ! 400: unlock(&pp->mlock); ! 401: } ! 402: ! 403: ! 404: static void ! 405: increfp(Slot *pp) ! 406: { ! 407: lock(pp); ! 408: if(pp->ref++ == 0) ! 409: slotena(pp); ! 410: unlock(pp); ! 411: } ! 412: ! 413: static void ! 414: decrefp(Slot *pp) ! 415: { ! 416: lock(pp); ! 417: if(pp->ref-- == 1) ! 418: slotdis(pp); ! 419: unlock(pp); ! 420: } ! 421: ! 422: /* ! 423: * look for a card whose version contains 'idstr' ! 424: */ ! 425: int ! 426: pcmspecial(char *idstr, ISAConf *isa) ! 427: { ! 428: Slot *pp; ! 429: extern char *strstr(char*, char*); ! 430: ! 431: i82365reset(); ! 432: for(pp = slot; pp < lastslot; pp++){ ! 433: if(pp->special) ! 434: continue; /* already taken */ ! 435: increfp(pp); ! 436: ! 437: if(pp->occupied) ! 438: if(strstr(pp->verstr, idstr)) ! 439: if(isa == 0 || pcmio(pp->slotno, isa) == 0){ ! 440: pp->special = 1; ! 441: return pp->slotno; ! 442: } ! 443: ! 444: decrefp(pp); ! 445: } ! 446: return -1; ! 447: } ! 448: ! 449: void ! 450: pcmspecialclose(int slotno) ! 451: { ! 452: Slot *pp; ! 453: ! 454: if(slotno >= nslot) ! 455: panic("pcmspecialclose"); ! 456: pp = slot + slotno; ! 457: pp->special = 0; ! 458: decrefp(pp); ! 459: } ! 460: ! 461: enum ! 462: { ! 463: Qdir, ! 464: Qmem, ! 465: Qattr, ! 466: Qctl, ! 467: }; ! 468: ! 469: #define SLOTNO(c) ((c->qid.path>>8)&0xff) ! 470: #define TYPE(c) (c->qid.path&0xff) ! 471: #define QID(s,t) (((s)<<8)|(t)) ! 472: ! 473: static int ! 474: pcmgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) ! 475: { ! 476: int slotno; ! 477: Qid qid; ! 478: long len; ! 479: Slot *pp; ! 480: char name[NAMELEN]; ! 481: ! 482: USED(tab, ntab); ! 483: if(i>=3*nslot) ! 484: return -1; ! 485: slotno = i/3; ! 486: pp = slot + slotno; ! 487: len = 0; ! 488: switch(i%3){ ! 489: case 0: ! 490: qid.path = QID(slotno, Qmem); ! 491: sprint(name, "pcm%dmem", slotno); ! 492: len = pp->memlen; ! 493: break; ! 494: case 1: ! 495: qid.path = QID(slotno, Qattr); ! 496: sprint(name, "pcm%dattr", slotno); ! 497: len = pp->memlen; ! 498: break; ! 499: case 2: ! 500: qid.path = QID(slotno, Qctl); ! 501: sprint(name, "pcm%dctl", slotno); ! 502: break; ! 503: } ! 504: qid.vers = 0; ! 505: devdir(c, qid, name, len, eve, 0660, dp); ! 506: return 1; ! 507: } ! 508: ! 509: static char *chipname[] = ! 510: { ! 511: [Ti82365] "Intel 82365SL", ! 512: [Tpd6710] "Cirrus Logic PD6710", ! 513: [Tpd6720] "Cirrus Logic PD6720", ! 514: }; ! 515: ! 516: static I82365* ! 517: i82386probe(int x, int d, int dev) ! 518: { ! 519: uchar c; ! 520: I82365 *cp; ! 521: ! 522: outb(x, Rid + (dev<<7)); ! 523: c = inb(d); ! 524: if((c & 0xf0) != 0x80) ! 525: return 0; /* not this family */ ! 526: ! 527: cp = xalloc(sizeof(I82365)); ! 528: cp->xreg = x; ! 529: cp->dreg = d; ! 530: cp->dev = dev; ! 531: cp->type = Ti82365; ! 532: cp->nslot = 2; ! 533: ! 534: switch(c){ ! 535: case 0x82: ! 536: case 0x83: ! 537: /* could be a cirrus */ ! 538: outb(x, Rchipinfo + (dev<<7)); ! 539: outb(d, 0); ! 540: c = inb(d); ! 541: if((c & 0xdf) == 0xdc){ ! 542: c = inb(d); ! 543: if((c & 0xdf) != 0x0c) ! 544: break; ! 545: } ! 546: if(c & 0x40){ ! 547: cp->type = Tpd6720; ! 548: } else { ! 549: cp->type = Tpd6710; ! 550: cp->nslot = 1; ! 551: } ! 552: break; ! 553: } ! 554: ! 555: print("pcmcia controller%d is a %d slot %s\n", ncontroller, cp->nslot, ! 556: chipname[cp->type]); ! 557: ! 558: /* low power mode */ ! 559: outb(x, Rmisc2 + (dev<<7)); ! 560: outb(d, Flowpow); ! 561: ! 562: controller[ncontroller++] = cp; ! 563: return cp; ! 564: } ! 565: ! 566: static void ! 567: i82365dump(Slot *pp) ! 568: { ! 569: int i; ! 570: ! 571: for(i = 0; i < 0x40; i++){ ! 572: if((i&0x7) == 0) ! 573: print("\n%ux: ", i); ! 574: print("%ux ", rdreg(pp, i)); ! 575: } ! 576: print("\n"); ! 577: } ! 578: ! 579: /* ! 580: * set up for slot cards ! 581: */ ! 582: void ! 583: i82365reset(void) ! 584: { ! 585: static int already; ! 586: int i, j; ! 587: I82365 *cp; ! 588: Slot *pp; ! 589: ! 590: if(already) ! 591: return; ! 592: already = 1; ! 593: ! 594: /* look for controllers */ ! 595: i82386probe(0x3E0, 0x3E1, 0); ! 596: i82386probe(0x3E0, 0x3E1, 1); ! 597: i82386probe(0x3E2, 0x3E3, 0); ! 598: i82386probe(0x3E2, 0x3E3, 1); ! 599: for(i = 0; i < ncontroller; i++) ! 600: nslot += controller[i]->nslot; ! 601: slot = xalloc(nslot * sizeof(Slot)); ! 602: ! 603: /* if the card is there turn on 5V power to keep its battery alive */ ! 604: lastslot = slot; ! 605: for(i = 0; i < ncontroller; i++){ ! 606: cp = controller[i]; ! 607: for(j = 0; j < cp->nslot; j++){ ! 608: pp = lastslot++; ! 609: pp->slotno = pp - slot; ! 610: pp->memlen = 64*MB; ! 611: pp->base = (cp->dev<<7) | (j<<6); ! 612: pp->cp = cp; ! 613: slotdis(pp); ! 614: ! 615: /* interrupt on status change */ ! 616: wrreg(pp, Rcscic, ((PCMCIAvec-Int0vec)<<4) | Fchangeena); ! 617: } ! 618: } ! 619: ! 620: /* for card management interrupts */ ! 621: setvec(PCMCIAvec, i82365intr, 0); ! 622: } ! 623: ! 624: void ! 625: i82365init(void) ! 626: { ! 627: } ! 628: ! 629: Chan * ! 630: i82365attach(char *spec) ! 631: { ! 632: return devattach('y', spec); ! 633: } ! 634: ! 635: Chan * ! 636: i82365clone(Chan *c, Chan *nc) ! 637: { ! 638: return devclone(c, nc); ! 639: } ! 640: ! 641: int ! 642: i82365walk(Chan *c, char *name) ! 643: { ! 644: return devwalk(c, name, 0, 0, pcmgen); ! 645: } ! 646: ! 647: void ! 648: i82365stat(Chan *c, char *db) ! 649: { ! 650: devstat(c, db, 0, 0, pcmgen); ! 651: } ! 652: ! 653: Chan * ! 654: i82365open(Chan *c, int omode) ! 655: { ! 656: if(c->qid.path == CHDIR){ ! 657: if(omode != OREAD) ! 658: error(Eperm); ! 659: } else ! 660: increfp(slot + SLOTNO(c)); ! 661: c->mode = openmode(omode); ! 662: c->flag |= COPEN; ! 663: c->offset = 0; ! 664: return c; ! 665: } ! 666: ! 667: void ! 668: i82365create(Chan *c, char *name, int omode, ulong perm) ! 669: { ! 670: USED(c, name, omode, perm); ! 671: error(Eperm); ! 672: } ! 673: ! 674: void ! 675: i82365remove(Chan *c) ! 676: { ! 677: USED(c); ! 678: error(Eperm); ! 679: } ! 680: ! 681: void ! 682: i82365wstat(Chan *c, char *dp) ! 683: { ! 684: USED(c, dp); ! 685: error(Eperm); ! 686: } ! 687: ! 688: void ! 689: i82365close(Chan *c) ! 690: { ! 691: if(c->flag & COPEN) ! 692: if(c->qid.path != CHDIR) ! 693: decrefp(slot+SLOTNO(c)); ! 694: } ! 695: ! 696: /* a memmove using only bytes */ ! 697: static void ! 698: memmoveb(uchar *to, uchar *from, int n) ! 699: { ! 700: while(n-- > 0) ! 701: *to++ = *from++; ! 702: } ! 703: ! 704: /* a memmove using only shorts & bytes */ ! 705: static void ! 706: memmoves(uchar *to, uchar *from, int n) ! 707: { ! 708: ushort *t, *f; ! 709: ! 710: if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){ ! 711: while(n-- > 0) ! 712: *to++ = *from++; ! 713: } else { ! 714: n = n/2; ! 715: t = (ushort*)to; ! 716: f = (ushort*)from; ! 717: while(n-- > 0) ! 718: *t++ = *f++; ! 719: } ! 720: } ! 721: ! 722: static long ! 723: pcmread(int slotno, int attr, void *a, long n, ulong offset) ! 724: { ! 725: int i, len; ! 726: PCMmap *m; ! 727: ulong ka; ! 728: uchar *ac; ! 729: Slot *pp; ! 730: ! 731: pp = slot + slotno; ! 732: if(pp->memlen < offset) ! 733: return 0; ! 734: if(pp->memlen < offset + n) ! 735: n = pp->memlen - offset; ! 736: ! 737: m = 0; ! 738: if(waserror()){ ! 739: if(m) ! 740: pcmunmap(pp->slotno, m); ! 741: nexterror(); ! 742: } ! 743: ! 744: ac = a; ! 745: for(len = n; len > 0; len -= i){ ! 746: m = pcmmap(pp->slotno, offset, 0, attr); ! 747: if(m == 0) ! 748: error("can't map PCMCIA card"); ! 749: if(offset + len > m->cea) ! 750: i = m->cea - offset; ! 751: else ! 752: i = len; ! 753: ka = KZERO|(m->isa + offset - m->ca); ! 754: memmoveb(ac, (void*)ka, i); ! 755: pcmunmap(pp->slotno, m); ! 756: offset += i; ! 757: ac += i; ! 758: } ! 759: ! 760: poperror(); ! 761: return n; ! 762: } ! 763: ! 764: long ! 765: i82365read(Chan *c, void *a, long n, ulong offset) ! 766: { ! 767: char *cp, buf[2048]; ! 768: ulong p; ! 769: Slot *pp; ! 770: ! 771: p = TYPE(c); ! 772: switch(p){ ! 773: case Qdir: ! 774: return devdirread(c, a, n, 0, 0, pcmgen); ! 775: case Qmem: ! 776: case Qattr: ! 777: return pcmread(SLOTNO(c), p==Qattr, a, n, offset); ! 778: case Qctl: ! 779: cp = buf; ! 780: pp = slot + SLOTNO(c); ! 781: if(pp->occupied) ! 782: cp += sprint(cp, "occupied\n"); ! 783: if(pp->enabled) ! 784: cp += sprint(cp, "enabled\n"); ! 785: if(pp->powered) ! 786: cp += sprint(cp, "powered\n"); ! 787: if(pp->configed) ! 788: cp += sprint(cp, "configed\n"); ! 789: if(pp->wrprot) ! 790: cp += sprint(cp, "write protected\n"); ! 791: if(pp->busy) ! 792: cp += sprint(cp, "busy\n"); ! 793: cp += sprint(cp, "battery lvl %d\n", pp->battery); ! 794: { ! 795: int i; ! 796: ! 797: for(i = 0; i < 0x40; i++){ ! 798: if((i&0x7) == 0) ! 799: cp += sprint(cp, "\n%ux: ", i); ! 800: cp += sprint(cp, "%ux ", rdreg(pp, i)); ! 801: } ! 802: cp += sprint(cp, "\n"); ! 803: } ! 804: *cp = 0; ! 805: return readstr(offset, a, n, buf); ! 806: default: ! 807: n=0; ! 808: break; ! 809: } ! 810: return n; ! 811: } ! 812: ! 813: static long ! 814: pcmwrite(int dev, int attr, void *a, long n, ulong offset) ! 815: { ! 816: int i, len; ! 817: PCMmap *m; ! 818: ulong ka; ! 819: uchar *ac; ! 820: Slot *pp; ! 821: ! 822: pp = slot + dev; ! 823: if(pp->memlen < offset) ! 824: return 0; ! 825: if(pp->memlen < offset + n) ! 826: n = pp->memlen - offset; ! 827: ! 828: m = 0; ! 829: if(waserror()){ ! 830: if(m) ! 831: pcmunmap(pp->slotno, m); ! 832: nexterror(); ! 833: } ! 834: ! 835: ac = a; ! 836: for(len = n; len > 0; len -= i){ ! 837: m = pcmmap(pp->slotno, offset, 0, attr); ! 838: if(m == 0) ! 839: error("can't map PCMCIA card"); ! 840: if(offset + len > m->cea) ! 841: i = m->cea - offset; ! 842: else ! 843: i = len; ! 844: ka = KZERO|(m->isa + offset - m->ca); ! 845: memmoveb((void*)ka, ac, i); ! 846: pcmunmap(pp->slotno, m); ! 847: offset += i; ! 848: ac += i; ! 849: } ! 850: ! 851: poperror(); ! 852: return n; ! 853: } ! 854: ! 855: long ! 856: i82365write(Chan *c, void *a, long n, ulong offset) ! 857: { ! 858: ulong p; ! 859: Slot *pp; ! 860: ! 861: p = TYPE(c); ! 862: switch(p){ ! 863: case Qmem: ! 864: case Qattr: ! 865: pp = slot + SLOTNO(c); ! 866: if(pp->occupied == 0 || pp->enabled == 0) ! 867: error(Eio); ! 868: n = pcmwrite(pp->slotno, p == Qattr, a, n, offset); ! 869: if(n < 0) ! 870: error(Eio); ! 871: break; ! 872: default: ! 873: error(Ebadusefd); ! 874: } ! 875: return n; ! 876: } ! 877: ! 878: /* ! 879: * configure the Slot for IO. We assume very heavily that we can read ! 880: * cofiguration info from the CIS. If not, we won't set up correctly. ! 881: */ ! 882: static int ! 883: pcmio(int slotno, ISAConf *isa) ! 884: { ! 885: uchar we, x, *p; ! 886: Slot *pp; ! 887: Conftab *ct; ! 888: PCMmap *m; ! 889: int irq; ! 890: ! 891: irq = isa->irq; ! 892: if(irq == 2) ! 893: irq = 9; ! 894: ! 895: if(slotno > nslot) ! 896: return -1; ! 897: pp = slot + slotno; ! 898: ! 899: if(!pp->occupied) ! 900: return -1; ! 901: ! 902: /* find a configuration with the right port */ ! 903: for(ct = pp->ctab; ct < &pp->ctab[pp->nctab]; ct++){ ! 904: if(ct->nioregs && ct->port == isa->port && ((1<<irq) & ct->irqs)) ! 905: break; ! 906: } ! 907: ! 908: /* if non found, settle for one with the some ioregs */ ! 909: if(ct == &pp->ctab[pp->nctab]) ! 910: for(ct = pp->ctab; ct < &pp->ctab[pp->nctab]; ct++) ! 911: if(ct->nioregs && ((1<<irq) & ct->irqs)) ! 912: break; ! 913: ! 914: if(ct == &pp->ctab[pp->nctab]) ! 915: return -1; ! 916: ! 917: /* route interrupts */ ! 918: isa->irq = irq; ! 919: wrreg(pp, Rigc, irq | Fnotreset | Fiocard); ! 920: ! 921: /* set power and enable device */ ! 922: x = vcode(ct->vpp1); ! 923: wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena); ! 924: ! 925: /* 16-bit data path */ ! 926: if(ct->bit16) ! 927: x = Fiocs16|Fwidth16; ! 928: else ! 929: x = 0; ! 930: wrreg(pp, Rio, Ftiming|x); ! 931: ! 932: /* enable io port map 0 */ ! 933: if(isa->port == 0) ! 934: isa->port = ct->port; ! 935: we = rdreg(pp, Rwe); ! 936: wrreg(pp, Riobtm0lo, isa->port); ! 937: wrreg(pp, Riobtm0hi, isa->port>>8); ! 938: wrreg(pp, Riotop0lo, (isa->port+ct->nioregs-1)); ! 939: wrreg(pp, Riotop0hi, (isa->port+ct->nioregs-1)>>8); ! 940: wrreg(pp, Rwe, we | (1<<6)); ! 941: ! 942: /* only touch Rconfig if it is present */ ! 943: if(pp->cpresent & (1<<Rconfig)){ ! 944: /* Reset adapter */ ! 945: m = pcmmap(slotno, pp->caddr + Rconfig, 1, 1); ! 946: p = (uchar*)(KZERO|(m->isa + pp->caddr + Rconfig - m->ca)); ! 947: ! 948: /* set configuration and interrupt type */ ! 949: x = ct->index; ! 950: if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) ! 951: x |= Clevel; ! 952: *p = x; ! 953: delay(5); ! 954: ! 955: pcmunmap(slotno, m); ! 956: } ! 957: return 0; ! 958: } ! 959: ! 960: /* ! 961: * read and crack the card information structure enough to set ! 962: * important parameters like power ! 963: */ ! 964: static void tcfig(Slot*, int); ! 965: static void tentry(Slot*, int); ! 966: static void tvers1(Slot*, int); ! 967: ! 968: static void (*parse[256])(Slot*, int) = ! 969: { ! 970: [0x15] tvers1, ! 971: [0x1A] tcfig, ! 972: [0x1B] tentry, ! 973: }; ! 974: ! 975: static int ! 976: readc(Slot *pp, uchar *x) ! 977: { ! 978: if(pp->cispos >= Mchunk) ! 979: return 0; ! 980: *x = pp->cisbase[2*pp->cispos]; ! 981: pp->cispos++; ! 982: return 1; ! 983: } ! 984: ! 985: static void ! 986: cisread(Slot *pp) ! 987: { ! 988: uchar link; ! 989: uchar type; ! 990: int this, i; ! 991: PCMmap *m; ! 992: ! 993: memset(pp->ctab, 0, sizeof(pp->ctab)); ! 994: pp->caddr = 0; ! 995: pp->cpresent = 0; ! 996: pp->configed = 0; ! 997: pp->nctab = 0; ! 998: ! 999: m = pcmmap(pp->slotno, 0, 0, 1); ! 1000: if(m == 0) ! 1001: return; ! 1002: pp->cisbase = (uchar*)(KZERO|m->isa); ! 1003: pp->cispos = 0; ! 1004: ! 1005: /* loop through all the tuples */ ! 1006: for(i = 0; i < 1000; i++){ ! 1007: this = pp->cispos; ! 1008: if(readc(pp, &type) != 1) ! 1009: break; ! 1010: if(readc(pp, &link) != 1) ! 1011: break; ! 1012: if(parse[type]) ! 1013: (*parse[type])(pp, type); ! 1014: if(link == 0xff) ! 1015: break; ! 1016: pp->cispos = this + (2+link); ! 1017: } ! 1018: pcmunmap(pp->slotno, m); ! 1019: } ! 1020: ! 1021: static ulong ! 1022: getlong(Slot *pp, int size) ! 1023: { ! 1024: uchar c; ! 1025: int i; ! 1026: ulong x; ! 1027: ! 1028: x = 0; ! 1029: for(i = 0; i < size; i++){ ! 1030: if(readc(pp, &c) != 1) ! 1031: break; ! 1032: x |= c<<(i*8); ! 1033: } ! 1034: return x; ! 1035: } ! 1036: ! 1037: static void ! 1038: tcfig(Slot *pp, int ttype) ! 1039: { ! 1040: uchar size, rasize, rmsize; ! 1041: uchar last; ! 1042: ! 1043: USED(ttype); ! 1044: if(readc(pp, &size) != 1) ! 1045: return; ! 1046: rasize = (size&0x3) + 1; ! 1047: rmsize = ((size>>2)&0xf) + 1; ! 1048: if(readc(pp, &last) != 1) ! 1049: return; ! 1050: pp->caddr = getlong(pp, rasize); ! 1051: pp->cpresent = getlong(pp, rmsize); ! 1052: } ! 1053: ! 1054: static ulong vexp[8] = ! 1055: { ! 1056: 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 ! 1057: }; ! 1058: static ulong vmant[16] = ! 1059: { ! 1060: 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90, ! 1061: }; ! 1062: ! 1063: static ulong ! 1064: microvolt(Slot *pp) ! 1065: { ! 1066: uchar c; ! 1067: ulong microvolts; ! 1068: ulong exp; ! 1069: ! 1070: if(readc(pp, &c) != 1) ! 1071: return 0; ! 1072: exp = vexp[c&0x7]; ! 1073: microvolts = vmant[(c>>3)&0xf]*exp; ! 1074: while(c & 0x80){ ! 1075: if(readc(pp, &c) != 1) ! 1076: return 0; ! 1077: switch(c){ ! 1078: case 0x7d: ! 1079: break; /* high impedence when sleeping */ ! 1080: case 0x7e: ! 1081: case 0x7f: ! 1082: microvolts = 0; /* no connection */ ! 1083: break; ! 1084: default: ! 1085: exp /= 10; ! 1086: microvolts += exp*(c&0x7f); ! 1087: } ! 1088: } ! 1089: return microvolts; ! 1090: } ! 1091: ! 1092: static ulong ! 1093: nanoamps(Slot *pp) ! 1094: { ! 1095: uchar c; ! 1096: ulong nanoamps; ! 1097: ! 1098: if(readc(pp, &c) != 1) ! 1099: return 0; ! 1100: nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf]; ! 1101: while(c & 0x80){ ! 1102: if(readc(pp, &c) != 1) ! 1103: return 0; ! 1104: if(c == 0x7d || c == 0x7e || c == 0x7f) ! 1105: nanoamps = 0; ! 1106: } ! 1107: return nanoamps; ! 1108: } ! 1109: ! 1110: /* ! 1111: * only nominal voltage is important for config ! 1112: */ ! 1113: static ulong ! 1114: power(Slot *pp) ! 1115: { ! 1116: uchar feature; ! 1117: ulong mv; ! 1118: ! 1119: mv = 0; ! 1120: if(readc(pp, &feature) != 1) ! 1121: return 0; ! 1122: if(feature & 1) ! 1123: mv = microvolt(pp); ! 1124: if(feature & 2) ! 1125: microvolt(pp); ! 1126: if(feature & 4) ! 1127: microvolt(pp); ! 1128: if(feature & 8) ! 1129: nanoamps(pp); ! 1130: if(feature & 0x10) ! 1131: nanoamps(pp); ! 1132: if(feature & 0x20) ! 1133: nanoamps(pp); ! 1134: if(feature & 0x40) ! 1135: nanoamps(pp); ! 1136: return mv/1000000; ! 1137: } ! 1138: ! 1139: static ulong mantissa[16] = ! 1140: { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; ! 1141: ! 1142: static ulong exponent[8] = ! 1143: { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; ! 1144: ! 1145: static ulong ! 1146: ttiming(Slot *pp, int scale) ! 1147: { ! 1148: uchar unscaled; ! 1149: ulong nanosecs; ! 1150: ! 1151: if(readc(pp, &unscaled) != 1) ! 1152: return 0; ! 1153: nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10; ! 1154: nanosecs = nanosecs * vexp[scale]; ! 1155: return nanosecs; ! 1156: } ! 1157: ! 1158: static void ! 1159: timing(Slot *pp, Conftab *ct) ! 1160: { ! 1161: uchar c, i; ! 1162: ! 1163: if(readc(pp, &c) != 1) ! 1164: return; ! 1165: i = c&0x3; ! 1166: if(i != 3) ! 1167: ct->maxwait = ttiming(pp, i); /* max wait */ ! 1168: i = (c>>2)&0x7; ! 1169: if(i != 7) ! 1170: ct->readywait = ttiming(pp, i); /* max ready/busy wait */ ! 1171: i = (c>>5)&0x7; ! 1172: if(i != 7) ! 1173: ct->otherwait = ttiming(pp, i); /* reserved wait */ ! 1174: } ! 1175: ! 1176: void ! 1177: iospaces(Slot *pp, Conftab *ct) ! 1178: { ! 1179: uchar c; ! 1180: int i; ! 1181: ulong len; ! 1182: ! 1183: if(readc(pp, &c) != 1) ! 1184: return; ! 1185: ! 1186: ct->nioregs = 1<<(c&0x1f); ! 1187: ct->bit16 = ((c>>5)&3) >= 2; ! 1188: if((c & 0x80) == 0) ! 1189: return; ! 1190: ! 1191: if(readc(pp, &c) != 1) ! 1192: return; ! 1193: ! 1194: for(i = (c&0xf)+1; i; i--){ ! 1195: ct->port = getlong(pp, (c>>4)&0x3); ! 1196: len = getlong(pp, (c>>6)&0x3); ! 1197: USED(len); ! 1198: } ! 1199: } ! 1200: ! 1201: static void ! 1202: irq(Slot *pp, Conftab *ct) ! 1203: { ! 1204: uchar c; ! 1205: ! 1206: if(readc(pp, &c) != 1) ! 1207: return; ! 1208: ct->irqtype = c & 0xe0; ! 1209: if(c & 0x10) ! 1210: ct->irqs = getlong(pp, 2); ! 1211: else ! 1212: ct->irqs = 1<<(c&0xf); ! 1213: ct->irqs &= 0xDEB8; /* levels available to card */ ! 1214: } ! 1215: ! 1216: static void ! 1217: memspace(Slot *pp, int asize, int lsize, int host) ! 1218: { ! 1219: ulong haddress, address, len; ! 1220: ! 1221: len = getlong(pp, lsize)*256; ! 1222: address = getlong(pp, asize)*256; ! 1223: USED(len, address); ! 1224: if(host){ ! 1225: haddress = getlong(pp, asize)*256; ! 1226: USED(haddress); ! 1227: } ! 1228: } ! 1229: ! 1230: void ! 1231: tentry(Slot *pp, int ttype) ! 1232: { ! 1233: uchar c, i, feature; ! 1234: Conftab *ct; ! 1235: ! 1236: USED(ttype); ! 1237: ! 1238: if(pp->nctab >= Maxctab) ! 1239: return; ! 1240: if(readc(pp, &c) != 1) ! 1241: return; ! 1242: ct = &pp->ctab[pp->nctab++]; ! 1243: ! 1244: /* copy from last default config */ ! 1245: if(pp->def) ! 1246: *ct = *pp->def; ! 1247: ! 1248: ct->index = c & 0x3f; ! 1249: ! 1250: /* is this the new default? */ ! 1251: if(c & 0x40) ! 1252: pp->def = ct; ! 1253: ! 1254: /* memory wait specified? */ ! 1255: if(c & 0x80){ ! 1256: if(readc(pp, &i) != 1) ! 1257: return; ! 1258: if(i&0x80) ! 1259: ct->memwait = 1; ! 1260: } ! 1261: ! 1262: if(readc(pp, &feature) != 1) ! 1263: return; ! 1264: switch(feature&0x3){ ! 1265: case 1: ! 1266: ct->vpp1 = ct->vpp2 = power(pp); ! 1267: break; ! 1268: case 2: ! 1269: power(pp); ! 1270: ct->vpp1 = ct->vpp2 = power(pp); ! 1271: break; ! 1272: case 3: ! 1273: power(pp); ! 1274: ct->vpp1 = power(pp); ! 1275: ct->vpp2 = power(pp); ! 1276: break; ! 1277: default: ! 1278: break; ! 1279: } ! 1280: if(feature&0x4) ! 1281: timing(pp, ct); ! 1282: if(feature&0x8) ! 1283: iospaces(pp, ct); ! 1284: if(feature&0x10) ! 1285: irq(pp, ct); ! 1286: switch((feature>>5)&0x3){ ! 1287: case 1: ! 1288: memspace(pp, 0, 2, 0); ! 1289: break; ! 1290: case 2: ! 1291: memspace(pp, 2, 2, 0); ! 1292: break; ! 1293: case 3: ! 1294: if(readc(pp, &c) != 1) ! 1295: return; ! 1296: for(i = 0; i <= (c&0x7); i++) ! 1297: memspace(pp, (c>>5)&0x3, (c>>3)&0x3, c&0x80); ! 1298: break; ! 1299: } ! 1300: pp->configed++; ! 1301: } ! 1302: ! 1303: void ! 1304: tvers1(Slot *pp, int ttype) ! 1305: { ! 1306: uchar c, major, minor; ! 1307: int i; ! 1308: ! 1309: USED(ttype); ! 1310: if(readc(pp, &major) != 1) ! 1311: return; ! 1312: if(readc(pp, &minor) != 1) ! 1313: return; ! 1314: for(i = 0; i < sizeof(pp->verstr)-1; i++){ ! 1315: if(readc(pp, &c) != 1) ! 1316: return; ! 1317: if(c == 0) ! 1318: c = '\n'; ! 1319: if(c == 0xff) ! 1320: break; ! 1321: pp->verstr[i] = c; ! 1322: } ! 1323: pp->verstr[i] = 0; ! 1324: } ! 1325:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.