1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 /* 10 * MPC821/3 PCMCIA driver (prototype) 11 * 12 * unlike the i82365 adapter, there isn't an offset register: 13 * card addresses are simply the lower order 26 bits of the host address. 14 * 15 * to do: 16 * split allocation of memory/attrib (all 26 bits valid) and io space (typically 10 or 12 bits) 17 * correct config 18 * interrupts and i/o space access 19 * DMA? 20 * power control 21 */ 22 23 enum 24 { 25 Maxctlr= 1, 26 Maxslot= 2, 27 Slotashift= 16, 28 29 /* pipr */ 30 Cbvs1= 1<<15, 31 Cbvs2= 1<<14, 32 Cbwp= 1<<13, 33 Cbcd2= 1<<12, 34 Cbcd1= 1<<11, 35 Cbbvd2= 1<<10, 36 Cbbvd1= 1<<9, 37 Cbrdy= 1<<8, 38 39 /* pscr and per */ 40 Cbvs1_c= 1<<15, 41 Cbvs2_c= 1<<14, 42 Cbwp_c= 1<<13, 43 Cbcd2_c= 1<<12, 44 Cbcd1_c= 1<<11, 45 Cbbvd2_c= 1<<10, 46 Cbbvd1_c= 1<<9, 47 Cbrdy_l= 1<<7, 48 Cbrdy_h= 1<<6, 49 Cbrdy_r= 1<<5, 50 Cbrdy_f= 1<<4, 51 52 /* pgcr[n] */ 53 Cbdreq_int= 0<<14, 54 Cbdreq_iois16= 2<<14, 55 Cbdreq_spkr= 3<<14, 56 Cboe= 1<<7, 57 Cbreset= 1<<6, 58 59 /* porN */ 60 Rport8= 0<<6, 61 Rport16= 1<<6, 62 Rmtype= 7<<3, /* memory type field */ 63 Rmem= 0<<3, /* common memory space */ 64 Rattrib= 2<<3, /* attribute space */ 65 Rio= 3<<3, 66 Rdma= 4<<3, /* normal DMA */ 67 Rdmalx= 5<<3, /* DMA, last transaction */ 68 RA22_23= 6<<3, /* ``drive A22 and A23 signals on CE2 and CE1'' */ 69 RslotB= 1<<2, /* select slot B (always, on MPC823) */ 70 Rwp= 1<<1, /* write protect */ 71 Rvalid= 1<<0, /* region valid */ 72 73 Nmap= 8, /* max number of maps to use */ 74 75 /* 76 * configuration registers - they start at an offset in attribute 77 * memory found in the CIS. 78 */ 79 Rconfig= 0, 80 Creset= (1<<7), /* reset device */ 81 Clevel= (1<<6), /* level sensitive interrupt line */ 82 Rccsr= 2, 83 Ciack = (1<<0), 84 Cipend = (1<<1), 85 Cpwrdown= (1<<2), 86 Caudioen= (1<<3), 87 Ciois8= (1<<5), 88 Cchgena= (1<<6), 89 Cchange= (1<<7), 90 Rpin= 4, /* pin replacement register */ 91 Rscpr= 6, /* socket and copy register */ 92 Riob0= 10, 93 Riob1= 12, 94 Riob2= 14, 95 Riob3= 16, 96 Riolim= 18, 97 98 Maxctab= 8, /* maximum configuration table entries */ 99 MaxCIS = 8192, /* maximum CIS size in bytes */ 100 Mgran = 8192, /* maximum size of reads and writes */ 101 102 Statusbounce=20, /* msec debounce time */ 103 }; 104 105 typedef struct Ctlr Ctlr; 106 107 /* a controller (there's only one) */ 108 struct Ctlr 109 { 110 int dev; 111 int nslot; 112 113 /* memory maps */ 114 Lock mlock; /* lock down the maps */ 115 PCMmap mmap[Nmap]; /* maps */ 116 117 /* IO port allocation */ 118 ulong nextport; 119 }; 120 static Ctlr controller[Maxctlr]; 121 122 static PCMslot *slot; 123 static PCMslot *lastslot; 124 static int nslot; 125 126 static Map pcmmapv[Nmap+1]; 127 static RMap pcmmaps = {"PCMCIA mappings"}; 128 129 static void pcmciaintr(Ureg*, void*); 130 static void pcmciareset(void); 131 static int pcmio(int, ISAConf*); 132 static long pcmread(int, int, void*, long, ulong); 133 static long pcmwrite(int, int, void*, long, ulong); 134 static void slotdis(PCMslot*); 135 136 static ulong pcmmalloc(ulong, long); 137 static void pcmfree(ulong, long); 138 static void pcmciaproc(void*); 139 140 static void pcmciadump(PCMslot*); 141 142 /* 143 * get info about card 144 */ 145 static void 146 slotinfo(PCMslot *pp) 147 { 148 ulong pipr; 149 150 pipr = (m->iomem->pipr >> pp->slotshift) & 0xFF00; 151 print("pipr=%8.8lux/%lux\n", m->iomem->pipr, pipr); 152 pp->v3_3 = (pipr&Cbvs1)!=0; 153 pp->voltage = (((pipr & Cbvs2)!=0)<<1) | ((pipr & Cbvs1)!=0); 154 pp->occupied = (pipr&(Cbcd1|Cbcd2))==0; 155 pp->powered = pcmpowered(pp->slotno); 156 pp->battery = (pipr & (Cbbvd1|Cbbvd2))>>9; 157 pp->wrprot = (pipr&Cbwp)!=0; 158 pp->busy = (pipr&Cbrdy)==0; 159 } 160 161 static void 162 pcmdelay(int ms) 163 { 164 if(up == nil) 165 delay(ms); 166 else 167 tsleep(&up->sleep, return0, nil, ms); 168 } 169 170 /* 171 * enable the slot card 172 */ 173 static void 174 slotena(PCMslot *pp) 175 { 176 IMM *io; 177 178 if(pp->enabled) 179 return; 180 m->iomem->pgcr[pp->slotno] &= ~Cboe; 181 pcmpower(pp->slotno, 1); 182 eieio(); 183 pcmdelay(300); 184 io = m->iomem; 185 io->pgcr[pp->slotno] |= Cbreset; /* active high */ 186 eieio(); 187 pcmdelay(100); 188 io->pgcr[pp->slotno] &= ~Cbreset; 189 eieio(); 190 pcmdelay(500); /* ludicrous delay */ 191 192 /* get configuration */ 193 slotinfo(pp); 194 if(pp->occupied){ 195 if(pp->cisread == 0){ 196 pcmcisread(pp); 197 pp->cisread = 1; 198 } 199 pp->enabled = 1; 200 } else{ 201 print("empty slot\n"); 202 slotdis(pp); 203 } 204 } 205 206 /* 207 * disable the slot card 208 */ 209 static void 210 slotdis(PCMslot *pp) 211 { 212 int i; 213 Ctlr *ctlr; 214 PCMmap *pm; 215 216 iprint("slotdis %d\n", pp->slotno); 217 pcmpower(pp->slotno, 0); 218 m->iomem->pgcr[pp->slotno] |= Cboe; 219 ctlr = pp->ctlr; 220 for(i = 0; i < nelem(ctlr->mmap); i++){ 221 pm = &ctlr->mmap[i]; 222 if(m->iomem->pcmr[i].option & Rvalid && pm->slotno == pp->slotno) 223 pcmunmap(pp->slotno, pm); 224 } 225 pp->enabled = 0; 226 pp->cisread = 0; 227 } 228 229 static void 230 pcmciardy(Ureg *ur, void *a) 231 { 232 PCMslot *pp; 233 ulong w; 234 235 pp = a; 236 w = (m->iomem->pipr >> pp->slotshift) & 0xFF00; 237 if(pp->occupied && (w & Cbrdy) == 0){ /* interrupt */ 238 print("PCM.%dI#%lux|", pp->slotno, w); 239 if(pp->intr.f != nil) 240 pp->intr.f(ur, pp->intr.arg); 241 } 242 } 243 244 void 245 pcmintrenable(int slotno, void (*f)(Ureg*, void*), void *arg) 246 { 247 PCMslot *pp; 248 IMM *io; 249 char name[KNAMELEN]; 250 251 if(slotno < 0 || slotno >= nslot) 252 panic("pcmintrenable"); 253 snprint(name, sizeof(name), "pcmcia.irq%d", slotno); 254 io = ioplock(); 255 pp = slot+slotno; 256 pp->intr.f = f; 257 pp->intr.arg = arg; 258 intrenable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); 259 io->per |= Cbrdy_l; /* assumes used for irq, not rdy; assumes level interrupt always right */ 260 iopunlock(); 261 } 262 263 void 264 pcmintrdisable(int slotno, void (*f)(Ureg*, void*), void *arg) 265 { 266 PCMslot *pp; 267 IMM *io; 268 char name[KNAMELEN]; 269 270 if(slotno < 0 || slotno >= nslot) 271 panic("pcmintrdisable"); 272 snprint(name, sizeof(name), "pcmcia.irq%d", slotno); 273 io = ioplock(); 274 pp = slot+slotno; 275 if(pp->intr.f == f && pp->intr.arg == arg){ 276 pp->intr.f = nil; 277 pp->intr.arg = nil; 278 intrdisable(PCMCIAio, pcmciardy, pp, BUSUNKNOWN, name); 279 io->per &= ~Cbrdy_l; 280 } 281 iopunlock(); 282 } 283 284 /* 285 * status change interrupt 286 * 287 * this wakes a monitoring process to read the CIS, 288 * rather than holding other interrupts out here. 289 */ 290 291 static Rendez pcmstate; 292 293 static int 294 statechanged(void *a) 295 { 296 PCMslot *pp; 297 int in; 298 299 pp = a; 300 in = (m->iomem->pipr & (Cbcd1|Cbcd2))==0; 301 return in != pp->occupied; 302 } 303 304 static void 305 pcmciaintr(Ureg*, void*) 306 { 307 ulong events; 308 309 if(slot == 0) 310 return; 311 events = m->iomem->pscr & (Cbvs1_c|Cbvs2_c|Cbwp_c|Cbcd2_c|Cbcd1_c|Cbbvd2_c|Cbbvd1_c); 312 eieio(); 313 m->iomem->pscr = events; 314 /* TO DO: other slot */ 315 iprint("PCM: #%lux|", events); 316 iprint("pipr=#%lux|", m->iomem->pipr & 0xFF00); 317 wakeup(&pcmstate); 318 } 319 320 static void 321 pcmciaproc(void*) 322 { 323 ulong csc; 324 PCMslot *pp; 325 int was; 326 327 for(;;){ 328 sleep(&pcmstate, statechanged, slot+1); 329 tsleep(&up->sleep, return0, nil, Statusbounce); 330 /* 331 * voltage change 1,2 332 * write protect change 333 * card detect 1,2 334 * battery voltage 1 change (or SPKR-bar) 335 * battery voltage 2 change (or STSCHG-bar) 336 * card B rdy / IRQ-bar low 337 * card B rdy / IRQ-bar high 338 * card B rdy / IRQ-bar rising edge 339 * card B rdy / IRQ-bar falling edge 340 * 341 * TO DO: currently only handle card-present changes 342 */ 343 344 for(pp = slot; pp < lastslot; pp++){ 345 if(pp->memlen == 0) 346 continue; 347 csc = (m->iomem->pipr>>pp->slotshift) & (Cbcd1|Cbcd2); 348 was = pp->occupied; 349 slotinfo(pp); 350 if(csc == 0 && was != pp->occupied){ 351 if(!pp->occupied){ 352 slotdis(pp); 353 if(pp->special && pp->notify.f != nil) 354 pp->notify.f(pp->notify.arg, 1); 355 } 356 } 357 } 358 } 359 } 360 361 static uchar greycode[] = { 362 0, 1, 3, 2, 6, 7, 5, 4, 014, 015, 017, 016, 012, 013, 011, 010, 363 030, 031, 033, 032, 036, 037, 035, 034, 024, 025, 027 364 }; 365 366 /* 367 * get a map for pc card region, return corrected len 368 */ 369 PCMmap* 370 pcmmap(int slotno, ulong offset, int len, int attr) 371 { 372 Ctlr *ctlr; 373 PCMslot *pp; 374 PCMmap *pm, *nm; 375 IMM *io; 376 int i; 377 ulong e, bsize, code, opt; 378 379 if(0) 380 print("pcmmap: %d #%lux %d #%x\n", slotno, offset, len, attr); 381 pp = slot + slotno; 382 if(!pp->occupied) 383 return nil; 384 if(attr == 1){ /* account for ../port/cis.c's conventions */ 385 attr = Rattrib; 386 if(len <= 0) 387 len = MaxCIS*2; /* TO DO */ 388 } 389 ctlr = pp->ctlr; 390 391 /* convert offset to granularity */ 392 if(len <= 0) 393 len = 1; 394 e = offset+len; 395 for(i=0;; i++){ 396 if(i >= nelem(greycode)) 397 return nil; 398 bsize = 1<<i; 399 offset &= ~(bsize-1); 400 if(e <= offset+bsize) 401 break; 402 } 403 code = greycode[i]; 404 if(0) 405 print("i=%d bsize=%lud code=0%luo\n", i, bsize, code); 406 e = offset+bsize; 407 len = bsize; 408 409 lock(&ctlr->mlock); 410 411 /* look for an existing map that covers the right area */ 412 io = m->iomem; 413 nm = nil; 414 for(i=0; i<Nmap; i++){ 415 pm = &ctlr->mmap[i]; 416 if(io->pcmr[i].option & Rvalid && 417 pm->slotno == slotno && 418 pm->attr == attr && 419 offset >= pm->ca && e <= pm->cea){ 420 pm->ref++; 421 unlock(&ctlr->mlock); 422 return pm; 423 } 424 if(nm == 0 && pm->ref == 0) 425 nm = pm; 426 } 427 pm = nm; 428 if(pm == nil){ 429 unlock(&ctlr->mlock); 430 return nil; 431 } 432 433 /* set up new map */ 434 pm->isa = pcmmalloc(offset, len); 435 if(pm->isa == 0){ 436 /* address not available: in use, or too much to map */ 437 unlock(&ctlr->mlock); 438 return 0; 439 } 440 if(0) 441 print("mx=%d isa=#%lux\n", (int)(pm - ctlr->mmap), pm->isa); 442 443 pm->len = len; 444 pm->ca = offset; 445 pm->cea = pm->ca + pm->len; 446 pm->attr = attr; 447 i = pm - ctlr->mmap; 448 io->pcmr[i].option &= ~Rvalid; /* disable map before changing it */ 449 io->pcmr[i].base = pm->isa; 450 opt = attr; 451 opt |= code<<27; 452 if((attr&Rmtype) == Rio){ 453 opt |= 4<<12; /* PSST */ 454 opt |= 8<<7; /* PSL */ 455 opt |= 2<<16; /* PSHT */ 456 }else{ 457 opt |= 6<<12; /* PSST */ 458 opt |= 24<<7; /* PSL */ 459 opt |= 8<<16; /* PSHT */ 460 } 461 if((attr & Rport16) == 0) 462 opt |= Rport8; 463 if(slotno == 1) 464 opt |= RslotB; 465 io->pcmr[i].option = opt | Rvalid; 466 pm->slotno = slotno; 467 pm->ref = 1; 468 469 unlock(&ctlr->mlock); 470 return pm; 471 } 472 473 static void 474 pcmiomap(PCMslot *pp, PCMconftab *ct, int i) 475 { 476 int n, attr; 477 Ctlr *ctlr; 478 479 if(0) 480 print("pcm iomap #%lux %lud\n", ct->io[i].start, ct->io[i].len); 481 if(ct->io[i].len <= 0) 482 return; 483 if(ct->io[i].start == 0){ 484 n = 1<<ct->nlines; 485 ctlr = pp->ctlr; 486 lock(&ctlr->mlock); 487 if(ctlr->nextport == 0) 488 ctlr->nextport = 0xF000; 489 ctlr->nextport = (ctlr->nextport + n - 1) & ~(n-1); 490 ct->io[i].start = ctlr->nextport; 491 ct->io[i].len = n; 492 ctlr->nextport += n; 493 unlock(&ctlr->mlock); 494 } 495 attr = Rio; 496 if(ct->bit16) 497 attr |= Rport16; 498 ct->io[i].map = pcmmap(pp->slotno, ct->io[i].start, ct->io[i].len, attr); 499 } 500 501 void 502 pcmunmap(int slotno, PCMmap* pm) 503 { 504 int i; 505 PCMslot *pp; 506 Ctlr *ctlr; 507 508 pp = slot + slotno; 509 if(pp->memlen == 0) 510 return; 511 ctlr = pp->ctlr; 512 lock(&ctlr->mlock); 513 if(pp->slotno == pm->slotno && --pm->ref == 0){ 514 i = pm - ctlr->mmap; 515 m->iomem->pcmr[i].option = 0; 516 m->iomem->pcmr[i].base = 0; 517 pcmfree(pm->isa, pm->len); 518 } 519 unlock(&ctlr->mlock); 520 } 521 522 static void 523 increfp(PCMslot *pp) 524 { 525 if(incref(pp) == 1) 526 slotena(pp); 527 } 528 529 static void 530 decrefp(PCMslot *pp) 531 { 532 if(decref(pp) == 0) 533 slotdis(pp); 534 } 535 536 /* 537 * look for a card whose version contains 'idstr' 538 */ 539 int 540 pcmspecial(char *idstr, ISAConf *isa) 541 { 542 PCMslot *pp; 543 extern char *strstr(char*, char*); 544 545 pcmciareset(); 546 for(pp = slot; pp < lastslot; pp++){ 547 if(pp->special || pp->memlen == 0) 548 continue; /* already taken */ 549 increfp(pp); 550 if(pp->occupied && strstr(pp->verstr, idstr)){ 551 print("PCMslot #%d: Found %s - ",pp->slotno, idstr); 552 if(isa == 0 || pcmio(pp->slotno, isa) == 0){ 553 print("ok.\n"); 554 pp->special = 1; 555 return pp->slotno; 556 } 557 print("error with isa io\n"); 558 } 559 decrefp(pp); 560 } 561 return -1; 562 } 563 564 void 565 pcmspecialclose(int slotno) 566 { 567 PCMslot *pp; 568 569 if(slotno >= nslot) 570 panic("pcmspecialclose"); 571 pp = slot + slotno; 572 pp->special = 0; 573 decrefp(pp); 574 } 575 576 void 577 pcmnotify(int slotno, void (*f)(void*, int), void* a) 578 { 579 PCMslot *pp; 580 581 if(slotno < 0 || slotno >= nslot) 582 panic("pcmnotify"); 583 pp = slot + slotno; 584 if(pp->occupied && pp->special){ 585 pp->notify.f = f; 586 pp->notify.arg = a; 587 } 588 } 589 590 /* 591 * reserve pcmcia slot address space [addr, addr+size[, 592 * returning a pointer to it, or nil if the space was already reserved. 593 */ 594 static ulong 595 pcmmalloc(ulong addr, long size) 596 { 597 return rmapalloc(&pcmmaps, PHYSPCMCIA+addr, size, size); 598 } 599 600 static void 601 pcmfree(ulong a, long size) 602 { 603 if(a != 0 && size > 0) 604 mapfree(&pcmmaps, a, size); 605 } 606 607 enum 608 { 609 Qdir, 610 Qmem, 611 Qattr, 612 Qctl, 613 }; 614 615 #define SLOTNO(c) ((c->qid.path>>8)&0xff) 616 #define TYPE(c) (c->qid.path&0xff) 617 #define QID(s,t) (((s)<<8)|(t)) 618 619 static int 620 pcmgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) 621 { 622 int slotno; 623 Qid qid; 624 long len; 625 PCMslot *pp; 626 627 if(i>=3*nslot) 628 return -1; 629 slotno = i/3; 630 pp = slot + slotno; 631 if(pp->memlen == 0) 632 return 0; 633 len = 0; 634 switch(i%3){ 635 case 0: 636 qid.path = QID(slotno, Qmem); 637 sprint(up->genbuf, "pcm%dmem", slotno); 638 len = pp->memlen; 639 break; 640 case 1: 641 qid.path = QID(slotno, Qattr); 642 sprint(up->genbuf, "pcm%dattr", slotno); 643 len = pp->memlen; 644 break; 645 case 2: 646 qid.path = QID(slotno, Qctl); 647 sprint(up->genbuf, "pcm%dctl", slotno); 648 break; 649 } 650 qid.vers = 0; 651 devdir(c, qid, up->genbuf, len, eve, 0660, dp); 652 return 1; 653 } 654 655 /* 656 * used only when debugging 657 */ 658 static void 659 pcmciadump(PCMslot *) 660 { 661 IMM *io; 662 int i; 663 664 io = m->iomem; 665 print("pipr #%4.4lux pscr #%4.4lux per #%4.4lux pgcr[1] #%8.8lux\n", 666 io->pipr & 0xFFFF, io->pscr & 0xFFFF, io->per & 0xFFFF, io->pgcr[1]); 667 for(i=0; i<8; i++) 668 print("pbr%d #%8.8lux por%d #%8.8lux\n", i, io->pcmr[i].base, i, io->pcmr[i].option); 669 } 670 671 /* 672 * set up for slot cards 673 */ 674 static void 675 pcmciareset(void) 676 { 677 static int already; 678 int i; 679 Ctlr *cp; 680 IMM *io; 681 PCMslot *pp; 682 683 if(already) 684 return; 685 already = 1; 686 687 cp = controller; 688 /* TO DO: set low power mode? ... */ 689 690 mapinit(&pcmmaps, pcmmapv, sizeof(pcmmapv)); 691 mapfree(&pcmmaps, PHYSPCMCIA, PCMCIALEN); 692 693 io = m->iomem; 694 695 for(i=0; i<8; i++){ 696 io->pcmr[i].option = 0; 697 io->pcmr[i].base = 0; 698 } 699 700 io->pscr = ~0; /* reset status */ 701 /* TO DO: Cboe, Cbreset */ 702 /* TO DO: two slots except on 823 */ 703 pcmenable(); 704 /* TO DO: if the card is there turn on 5V power to keep its battery alive */ 705 slot = xalloc(Maxslot * sizeof(PCMslot)); 706 lastslot = slot; 707 slot[0].slotshift = Slotashift; 708 slot[1].slotshift = 0; 709 for(i=0; i<Maxslot; i++){ 710 pp = &slot[i]; 711 if(!pcmslotavail(i)){ 712 pp->memlen = 0; 713 continue; 714 } 715 io->per |= (Cbvs1_c|Cbvs2_c|Cbwp_c|Cbcd2_c|Cbcd1_c|Cbbvd2_c|Cbbvd1_c)<<pp->slotshift; /* enable status interrupts */ 716 io->pgcr[i] = (1<<(31-PCMCIAio)) | (1<<(23-PCMCIAstatus)); 717 pp->slotno = i; 718 pp->memlen = 8*MB; 719 pp->ctlr = cp; 720 //slotdis(pp); 721 lastslot = slot; 722 nslot = i+1; 723 } 724 if(1) 725 pcmciadump(slot); 726 intrenable(PCMCIAstatus, pcmciaintr, cp, BUSUNKNOWN, "pcmcia"); 727 print("pcmcia reset\n"); 728 } 729 730 static void 731 pcmciainit(void) 732 { 733 kproc("pcmcia", pcmciaproc, nil, 0); 734 } 735 736 static Chan* 737 pcmciaattach(char *spec) 738 { 739 return devattach('y', spec); 740 } 741 742 static Walkqid* 743 pcmciawalk(Chan *c, Chan *nc, char **name, int nname) 744 { 745 return devwalk(c, nc, name, nname, 0, 0, pcmgen); 746 } 747 748 static int 749 pcmciastat(Chan *c, uchar *dp, int n) 750 { 751 return devstat(c, dp, n, 0, 0, pcmgen); 752 } 753 754 static Chan* 755 pcmciaopen(Chan *c, int omode) 756 { 757 if(c->qid.type & QTDIR){ 758 if(omode != OREAD) 759 error(Eperm); 760 } else 761 increfp(slot + SLOTNO(c)); 762 c->mode = openmode(omode); 763 c->flag |= COPEN; 764 c->offset = 0; 765 return c; 766 } 767 768 static void 769 pcmciaclose(Chan *c) 770 { 771 if(c->flag & COPEN) 772 if((c->qid.type & QTDIR) == 0) 773 decrefp(slot+SLOTNO(c)); 774 } 775 776 /* a memmove using only bytes */ 777 static void 778 memmoveb(uchar *to, uchar *from, int n) 779 { 780 while(n-- > 0) 781 *to++ = *from++; 782 } 783 784 static long 785 pcmread(int slotno, int attr, void *a, long n, ulong offset) 786 { 787 int i, len; 788 PCMmap *m; 789 void *ka; 790 uchar *ac; 791 PCMslot *pp; 792 793 pp = slot + slotno; 794 if(pp->memlen < offset) 795 return 0; 796 if(pp->memlen < offset + n) 797 n = pp->memlen - offset; 798 799 ac = a; 800 for(len = n; len > 0; len -= i){ 801 if((i = len) > Mgran) 802 i = Mgran; 803 m = pcmmap(pp->slotno, offset, i, attr? Rattrib: Rmem); 804 if(m == 0) 805 error("can't map PCMCIA card"); 806 if(waserror()){ 807 if(m) 808 pcmunmap(pp->slotno, m); 809 nexterror(); 810 } 811 if(offset + len > m->cea) 812 i = m->cea - offset; 813 else 814 i = len; 815 ka = (char*)KADDR(m->isa) + (offset - m->ca); 816 memmoveb(ac, ka, i); 817 poperror(); 818 pcmunmap(pp->slotno, m); 819 offset += i; 820 ac += i; 821 } 822 823 return n; 824 } 825 826 static long 827 pcmciaread(Chan *c, void *a, long n, vlong offset) 828 { 829 char *cp, *buf; 830 ulong p; 831 PCMslot *pp; 832 833 p = TYPE(c); 834 switch(p){ 835 case Qdir: 836 return devdirread(c, a, n, 0, 0, pcmgen); 837 case Qmem: 838 case Qattr: 839 return pcmread(SLOTNO(c), p==Qattr, a, n, offset); 840 case Qctl: 841 buf = malloc(READSTR); 842 if(buf == nil) 843 error(Enomem); 844 if(waserror()){ 845 free(buf); 846 nexterror(); 847 } 848 cp = buf; 849 pp = slot + SLOTNO(c); 850 if(pp->occupied) 851 cp += sprint(cp, "occupied\n"); 852 if(pp->enabled) 853 cp += sprint(cp, "enabled\n"); 854 if(pp->powered) 855 cp += sprint(cp, "powered\n"); 856 if(pp->configed) 857 cp += sprint(cp, "configed\n"); 858 if(pp->wrprot) 859 cp += sprint(cp, "write protected\n"); 860 if(pp->busy) 861 cp += sprint(cp, "busy\n"); 862 if(pp->v3_3) 863 cp += sprint(cp, "3.3v ok\n"); 864 cp += sprint(cp, "battery lvl %d\n", pp->battery); 865 cp += sprint(cp, "voltage select %d\n", pp->voltage); 866 /* TO DO: could return pgcr[] values for debugging */ 867 *cp = 0; 868 n = readstr(offset, a, n, buf); 869 poperror(); 870 free(buf); 871 break; 872 default: 873 n=0; 874 break; 875 } 876 return n; 877 } 878 879 static long 880 pcmwrite(int dev, int attr, void *a, long n, ulong offset) 881 { 882 int i, len; 883 PCMmap *m; 884 void *ka; 885 uchar *ac; 886 PCMslot *pp; 887 888 pp = slot + dev; 889 if(pp->memlen < offset) 890 return 0; 891 if(pp->memlen < offset + n) 892 n = pp->memlen - offset; 893 894 ac = a; 895 for(len = n; len > 0; len -= i){ 896 if((i = len) > Mgran) 897 i = Mgran; 898 m = pcmmap(pp->slotno, offset, i, attr? Rattrib: Rmem); 899 if(m == 0) 900 error("can't map PCMCIA card"); 901 if(waserror()){ 902 if(m) 903 pcmunmap(pp->slotno, m); 904 nexterror(); 905 } 906 if(offset + len > m->cea) 907 i = m->cea - offset; 908 else 909 i = len; 910 ka = (char*)KADDR(m->isa) + (offset - m->ca); 911 memmoveb(ka, ac, i); 912 poperror(); 913 pcmunmap(pp->slotno, m); 914 offset += i; 915 ac += i; 916 } 917 918 return n; 919 } 920 921 static long 922 pcmciawrite(Chan *c, void *a, long n, vlong offset) 923 { 924 ulong p; 925 PCMslot *pp; 926 char buf[32]; 927 928 p = TYPE(c); 929 switch(p){ 930 case Qctl: 931 if(n >= sizeof(buf)) 932 n = sizeof(buf) - 1; 933 strncpy(buf, a, n); 934 buf[n] = 0; 935 pp = slot + SLOTNO(c); 936 if(!pp->occupied) 937 error(Eio); 938 939 /* set vpp on card */ 940 if(strncmp(buf, "vpp", 3) == 0){ 941 p = strtol(buf+3, nil, 0); 942 pcmsetvpp(pp->slotno, p); 943 } 944 break; 945 case Qmem: 946 case Qattr: 947 pp = slot + SLOTNO(c); 948 if(pp->occupied == 0 || pp->enabled == 0) 949 error(Eio); 950 n = pcmwrite(pp->slotno, p == Qattr, a, n, offset); 951 if(n < 0) 952 error(Eio); 953 break; 954 default: 955 error(Ebadusefd); 956 } 957 return n; 958 } 959 960 Dev pcmciadevtab = { 961 'y', 962 "pcmcia", 963 964 pcmciareset, 965 pcmciainit, 966 devshutdown, 967 pcmciaattach, 968 pcmciawalk, 969 pcmciastat, 970 pcmciaopen, 971 devcreate, 972 pcmciaclose, 973 pcmciaread, 974 devbread, 975 pcmciawrite, 976 devbwrite, 977 devremove, 978 devwstat, 979 }; 980 981 /* 982 * configure the PCMslot for IO. We assume very heavily that we can read 983 * configuration info from the CIS. If not, we won't set up correctly. 984 */ 985 static int 986 pcmio(int slotno, ISAConf *isa) 987 { 988 PCMslot *pp; 989 PCMconftab *ct, *et, *t; 990 PCMmap *pm; 991 uchar *p; 992 int irq, i, x; 993 994 irq = isa->irq; 995 if(irq == 2) 996 irq = 9; 997 998 if(slotno > nslot) 999 return -1; 1000 pp = slot + slotno; 1001 1002 if(!pp->occupied) 1003 return -1; 1004 1005 et = &pp->ctab[pp->nctab]; 1006 1007 /* assume default is right */ 1008 if(pp->def) 1009 ct = pp->def; 1010 else 1011 ct = pp->ctab; 1012 /* try for best match */ 1013 if(ct->nlines == 0 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){ 1014 for(t = pp->ctab; t < et; t++) 1015 if(t->nlines && t->io[0].start == isa->port && ((1<<irq) & t->irqs)){ 1016 ct = t; 1017 break; 1018 } 1019 } 1020 if(ct->nlines == 0 || ((1<<irq) & ct->irqs) == 0){ 1021 for(t = pp->ctab; t < et; t++) 1022 if(t->nlines && ((1<<irq) & t->irqs)){ 1023 ct = t; 1024 break; 1025 } 1026 } 1027 if(ct->nlines == 0){ 1028 for(t = pp->ctab; t < et; t++) 1029 if(t->nlines){ 1030 ct = t; 1031 break; 1032 } 1033 } 1034 print("slot %d: nlines=%d iolen=%lud irq=%d ct->index=%d nport=%d ct->port=#%lux/%lux\n", slotno, ct->nlines, ct->io[0].len, irq, ct->index, ct->nio, ct->io[0].start, isa->port); 1035 if(ct == et || ct->nlines == 0) 1036 return -1; 1037 /* route interrupts */ 1038 isa->irq = irq; 1039 //wrreg(pp, Rigc, irq | Fnotreset | Fiocard); 1040 delay(2); 1041 1042 /* set power and enable device */ 1043 pcmsetvcc(pp->slotno, ct->vcc); 1044 pcmsetvpp(pp->slotno, ct->vpp1); 1045 1046 delay(2); /* could poll BSY during power change */ 1047 1048 for(i=0; i<ct->nio; i++) 1049 pcmiomap(pp, ct, i); 1050 1051 if(ct->nio) 1052 isa->port = ct->io[0].start; 1053 1054 /* only touch Rconfig if it is present */ 1055 if(pp->cpresent & (1<<Rconfig)){ 1056 print("Rconfig present: #%lux\n", pp->caddr+Rconfig); 1057 /* Reset adapter */ 1058 pm = pcmmap(slotno, pp->caddr + Rconfig, 1, Rattrib); 1059 if(pm == nil) 1060 return -1; 1061 1062 p = (uchar*)KADDR(pm->isa) + (pp->caddr + Rconfig - pm->ca); 1063 1064 /* set configuration and interrupt type */ 1065 x = ct->index; 1066 if((ct->irqtype & 0x20) && ((ct->irqtype & 0x40)==0 || isa->irq>7)) 1067 x |= Clevel; 1068 *p = x; 1069 delay(5); 1070 1071 pcmunmap(pp->slotno, pm); 1072 print("Adapter reset\n"); 1073 } 1074 1075 return 0; 1076 } 1077