]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devpccard.c
devkbd: bits bad! revert repeat/delay, better patches welcome
[plan9front.git] / sys / src / 9 / pc / devpccard.c
1 /*
2      cardbus and pcmcia (grmph) support.
3 */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "../port/error.h"
10 #include "io.h"
11
12 #define DEBUG   0
13
14 #pragma varargck        type    "T"     int
15
16 #define MAP(x,o)        (Rmap + (x)*0x8 + o)
17
18 enum {
19         TI_vid = 0x104c,
20         TI_1131_did = 0xAC15,
21         TI_1250_did = 0xAC16,
22         TI_1450_did = 0xAC1B,
23         TI_1251A_did = 0xAC1D,
24         TI_1420_did = 0xAC51,
25
26         Ricoh_vid = 0x1180,
27         Ricoh_475_did = 0x0475,
28         Ricoh_476_did = 0x0476,
29         Ricoh_478_did = 0x0478,
30
31         O2_vid = 0x1217,
32         O2_OZ711M3_did = 0x7134,
33
34         Nslots = 4,             /* Maximum number of CardBus slots to use */
35
36         K = 1024,
37         M = K * K,
38
39         LegacyAddr = 0x3e0,
40         NUMEVENTS = 10,
41
42         TI1131xSC = 0x80,               /* system control */
43                 TI122X_SC_INTRTIE = 1 << 29,
44         TI12xxIM = 0x8c,                /*  */
45         TI1131xCC = 0x91,               /* card control */
46                 TI113X_CC_RIENB = 1 << 7,
47                 TI113X_CC_ZVENABLE = 1 << 6,
48                 TI113X_CC_PCI_IRQ_ENA = 1 << 5,
49                 TI113X_CC_PCI_IREQ = 1 << 4,
50                 TI113X_CC_PCI_CSC = 1 << 3,
51                 TI113X_CC_SPKROUTEN = 1 << 1,
52                 TI113X_CC_IFG = 1 << 0,
53         TI1131xDC = 0x92,               /* device control */
54 };
55
56 typedef struct Variant Variant;
57 struct Variant {
58         ushort  vid;
59         ushort  did;
60         char    *name;
61 };
62
63 static Variant variant[] = {
64 {       Ricoh_vid,      Ricoh_475_did,  "Ricoh 475 PCI/Cardbus bridge", },
65 {       Ricoh_vid,      Ricoh_476_did,  "Ricoh 476 PCI/Cardbus bridge", },
66 {       Ricoh_vid,      Ricoh_478_did,  "Ricoh 478 PCI/Cardbus bridge", },
67 {       TI_vid,         TI_1131_did,    "TI PCI-1131 Cardbus Controller", },
68 {       TI_vid,         TI_1250_did,    "TI PCI-1250 Cardbus Controller", },
69 {       TI_vid,         TI_1450_did,    "TI PCI-1450 Cardbus Controller", },
70 {       TI_vid,         TI_1251A_did,   "TI PCI-1251A Cardbus Controller", },
71 {       TI_vid,         TI_1420_did,    "TI PCI-1420 Cardbus Controller", },
72 {       O2_vid,         O2_OZ711M3_did, "O2Micro OZ711M3 MemoryCardBus", },
73 };
74
75 /* Cardbus registers */
76 enum {
77         SocketEvent = 0,
78                 SE_CCD = 3 << 1,
79                 SE_POWER = 1 << 3,
80         SocketMask = 1,
81         SocketState = 2,
82                 SS_CCD = 3 << 1,
83                 SS_POWER = 1 << 3,
84                 SS_PC16 = 1 << 4,
85                 SS_CBC = 1 << 5,
86                 SS_NOTCARD = 1 << 7,
87                 SS_BADVCC = 1 << 9,
88                 SS_5V = 1 << 10,
89                 SS_3V = 1 << 11,
90         SocketForce = 3,
91         SocketControl = 4,
92                 SC_5V = 0x22,
93                 SC_3V = 0x33,
94 };
95
96 enum {
97         PciPCR_IO = 1 << 0,
98         PciPCR_MEM = 1 << 1,
99         PciPCR_Master = 1 << 2,
100
101         PciPMC = 0xa4,
102
103         Nbars = 6,
104         Ncmd = 10,
105         CBIRQ = 9,
106
107         PC16,
108         PC32,
109 };
110
111 enum {
112         Ti82365,
113         Tpd6710,
114         Tpd6720,
115         Tvg46x,
116 };
117
118 /*
119  *  Intel 82365SL PCIC controller for the PCMCIA or
120  *  Cirrus Logic PD6710/PD6720 which is mostly register compatible
121  */
122 enum
123 {
124         /*
125          *  registers indices
126          */
127         Rid=            0x0,            /* identification and revision */
128         Ris=            0x1,            /* interface status */
129         Rpc=            0x2,            /* power control */
130          Foutena=        (1<<7),        /*  output enable */
131          Fautopower=     (1<<5),        /*  automatic power switching */
132          Fcardena=       (1<<4),        /*  PC card enable */
133         Rigc=           0x3,            /* interrupt and general control */
134          Fiocard=        (1<<5),        /*  I/O card (vs memory) */
135          Fnotreset=      (1<<6),        /*  reset if not set */
136          FSMIena=        (1<<4),        /*  enable change interrupt on SMI */
137         Rcsc=           0x4,            /* card status change */
138         Rcscic=         0x5,            /* card status change interrupt config */
139          Fchangeena=     (1<<3),        /*  card changed */
140          Fbwarnena=      (1<<1),        /*  card battery warning */
141          Fbdeadena=      (1<<0),        /*  card battery dead */
142         Rwe=            0x6,            /* address window enable */
143          Fmem16=         (1<<5),        /*  use A23-A12 to decode address */
144         Rio=            0x7,            /* I/O control */
145          Fwidth16=       (1<<0),        /*  16 bit data width */
146          Fiocs16=        (1<<1),        /*  IOCS16 determines data width */
147          Fzerows=        (1<<2),        /*  zero wait state */
148          Ftiming=        (1<<3),        /*  timing register to use */
149         Riobtm0lo=      0x8,            /* I/O address 0 start low byte */
150         Riobtm0hi=      0x9,            /* I/O address 0 start high byte */
151         Riotop0lo=      0xa,            /* I/O address 0 stop low byte */
152         Riotop0hi=      0xb,            /* I/O address 0 stop high byte */
153         Riobtm1lo=      0xc,            /* I/O address 1 start low byte */
154         Riobtm1hi=      0xd,            /* I/O address 1 start high byte */
155         Riotop1lo=      0xe,            /* I/O address 1 stop low byte */
156         Riotop1hi=      0xf,            /* I/O address 1 stop high byte */
157         Rmap=           0x10,           /* map 0 */
158
159         /*
160          *  CL-PD67xx extension registers
161          */
162         Rmisc1=         0x16,           /* misc control 1 */
163          F5Vdetect=      (1<<0),
164          Fvcc3V=         (1<<1),
165          Fpmint=         (1<<2),
166          Fpsirq=         (1<<3),
167          Fspeaker=       (1<<4),
168          Finpack=        (1<<7),
169         Rfifo=          0x17,           /* fifo control */
170          Fflush=         (1<<7),        /*  flush fifo */
171         Rmisc2=         0x1E,           /* misc control 2 */
172          Flowpow=        (1<<1),        /*  low power mode */
173         Rchipinfo=      0x1F,           /* chip information */
174         Ratactl=        0x26,           /* ATA control */
175
176         /*
177          *  offsets into the system memory address maps
178          */
179         Mbtmlo=         0x0,            /* System mem addr mapping start low byte */
180         Mbtmhi=         0x1,            /* System mem addr mapping start high byte */
181          F16bit=         (1<<7),        /*  16-bit wide data path */
182         Mtoplo=         0x2,            /* System mem addr mapping stop low byte */
183         Mtophi=         0x3,            /* System mem addr mapping stop high byte */
184          Ftimer1=        (1<<6),        /*  timer set 1 */
185         Mofflo=         0x4,            /* Card memory offset address low byte */
186         Moffhi=         0x5,            /* Card memory offset address high byte */
187          Fregactive=     (1<<6),        /*  attribute memory */
188
189         /*
190          *  configuration registers - they start at an offset in attribute
191          *  memory found in the CIS.
192          */
193         Rconfig=        0,
194          Creset=         (1<<7),        /*  reset device */
195          Clevel=         (1<<6),        /*  level sensitive interrupt line */
196 };
197
198 /*
199  *  read and crack the card information structure enough to set
200  *  important parameters like power
201  */
202 /* cis memory walking */
203 typedef struct Cisdat Cisdat;
204 struct Cisdat {
205         uchar           *cisbase;
206         int             cispos;
207         int             cisskip;
208         int             cislen;
209 };
210
211 typedef struct Pcminfo Pcminfo;
212 struct Pcminfo {
213         char            verstr[512];            /* Version string */
214         PCMmap          mmap[4];                /* maps, last is always for the kernel */
215         ulong           conf_addr;              /* Config address */
216         uchar           conf_present;           /* Config register present */
217         int             nctab;                  /* In use configuration tables */
218         PCMconftab      ctab[8];                /* Configuration tables */
219         PCMconftab      *defctab;               /* Default conftab */
220
221         int             port;                   /* Actual port usage */
222         int             irq;                    /* Actual IRQ usage */
223 };
224
225 typedef struct Cardbus Cardbus;
226 struct Cardbus {
227         Lock;
228         Variant         *variant;               /* Which CardBus chipset */
229         Pcidev          *pci;                   /* The bridge itself */
230         ulong           *regs;                  /* Cardbus registers */
231         int             ltype;                  /* Legacy type */
232         int             lindex;                 /* Legacy port index address */
233         int             ldata;                  /* Legacy port data address */
234         int             lbase;                  /* Base register for this socket */
235
236         int             state;                  /* Current state of card */
237         int             type;                   /* Type of card */
238         Pcminfo         linfo;                  /* PCMCIA slot info */
239
240         int             special;                /* card is allocated to a driver */
241
242         int             refs;                   /* Number of refs to slot */
243         Lock            refslock;               /* inc/dev ref lock */
244 };
245
246 static int managerstarted;
247
248 enum {
249         Mshift= 12,
250         Mgran=  (1<<Mshift),    /* granularity of maps */
251         Mmask=  ~(Mgran-1),     /* mask for address bits important to the chip */
252 };
253
254 static Cardbus cbslots[Nslots];
255 static int nslots;
256
257 static ulong exponent[8] = {
258         1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
259 };
260
261 static ulong vmant[16] = {
262         10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
263 };
264
265 static ulong mantissa[16] = {
266         0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80,
267 };
268
269 static char Enocard[] = "No card in slot";
270
271 enum
272 {
273         CMdown,
274         CMpower,
275 };
276
277 static Cmdtab pccardctlmsg[] =
278 {
279         CMdown,         "down", 2,
280         CMpower,        "power",        1,
281 };
282
283 static int powerup(Cardbus *);
284 static void configure(Cardbus *);
285 static void powerdown(Cardbus *cb);
286 static void unconfigure(Cardbus *cb);
287
288 static void i82365probe(Cardbus *cb, int lindex, int ldata);
289 static void i82365configure(Cardbus *cb);
290 static PCMmap *isamap(Cardbus *cb, ulong offset, int len, int attr);
291 static void isaunmap(PCMmap* m);
292 static uchar rdreg(Cardbus *cb, int index);
293 static void wrreg(Cardbus *cb, int index, uchar val);
294 static int readc(Cisdat *cis, uchar *x);
295 static void tvers1(Cardbus *cb, Cisdat *cis, int );
296 static void tcfig(Cardbus *cb, Cisdat *cis, int );
297 static void tentry(Cardbus *cb, Cisdat *cis, int );
298 static int vcode(int volt);
299 static int pccard_pcmspecial(char *idstr, ISAConf *isa);
300 static void pccard_pcmspecialclose(int slotno);
301
302 enum {
303         CardDetected,
304         CardPowered,
305         CardEjected,
306         CardConfigured,
307 };
308
309 static char *messages[] = {
310 [CardDetected]          "CardDetected",
311 [CardPowered]           "CardPowered",
312 [CardEjected]           "CardEjected",
313 [CardConfigured]        "CardConfigured",
314 };
315
316 enum {
317         SlotEmpty,
318         SlotFull,
319         SlotPowered,
320         SlotConfigured,
321 };
322
323 static char *states[] = {
324 [SlotEmpty]             "SlotEmpty",
325 [SlotFull]              "SlotFull",
326 [SlotPowered]           "SlotPowered",
327 [SlotConfigured]        "SlotConfigured",
328 };
329
330 static void
331 engine(Cardbus *cb, int message)
332 {
333         if(DEBUG)
334                 print("engine(%ld): %s(%s)\n", cb - cbslots,
335                         states[cb->state], messages[message]);
336         switch (cb->state) {
337         case SlotEmpty:
338
339                 switch (message) {
340                 case CardDetected:
341                         cb->state = SlotFull;
342                         powerup(cb);
343                         break;
344                 case CardEjected:
345                         break;
346                 default:
347                         if(DEBUG)
348                                 print("#Y%ld: Invalid message %s in SlotEmpty state\n",
349                                         cb - cbslots, messages[message]);
350                         break;
351                 }
352                 break;
353
354         case SlotFull:
355
356                 switch (message) {
357                 case CardPowered:
358                         cb->state = SlotPowered;
359                         configure(cb);
360                         break;
361                 case CardEjected:
362                         cb->state = SlotEmpty;
363                         powerdown(cb);
364                         break;
365                 default:
366                         if(DEBUG)
367                                 print("#Y%ld: Invalid message %s in SlotFull state\n",
368                                         cb - cbslots, messages[message]);
369                         break;
370                 }
371                 break;
372
373         case SlotPowered:
374
375                 switch (message) {
376                 case CardConfigured:
377                         cb->state = SlotConfigured;
378                         break;
379                 case CardEjected:
380                         cb->state = SlotEmpty;
381                         unconfigure(cb);
382                         powerdown(cb);
383                         break;
384                 default:
385                         print("#Y%ld: Invalid message %s in SlotPowered state\n",
386                                 cb - cbslots, messages[message]);
387                         break;
388                 }
389                 break;
390
391         case SlotConfigured:
392
393                 switch (message) {
394                 case CardEjected:
395                         cb->state = SlotEmpty;
396                         unconfigure(cb);
397                         powerdown(cb);
398                         break;
399                 default:
400                         if(DEBUG)
401                                 print("#Y%ld: Invalid message %s in SlotConfigured state\n",
402                                         cb - cbslots, messages[message]);
403                         break;
404                 }
405                 break;
406         }
407 }
408
409 static void
410 qengine(Cardbus *cb, int message)
411 {
412         lock(cb);
413         engine(cb, message);
414         unlock(cb);
415 }
416
417 typedef struct Events Events;
418 struct Events {
419         Cardbus *cb;
420         int     message;
421 };
422
423 static Lock levents;
424 static Events events[NUMEVENTS];
425 static Rendez revents;
426 static int nevents;
427
428 static void
429 iengine(Cardbus *cb, int message)
430 {
431         if (nevents >= NUMEVENTS) {
432                 print("#Y: Too many events queued, discarding request\n");
433                 return;
434         }
435         ilock(&levents);
436         events[nevents].cb = cb;
437         events[nevents].message = message;
438         nevents++;
439         iunlock(&levents);
440         wakeup(&revents);
441 }
442
443 static int
444 eventoccured(void)
445 {
446         return nevents > 0;
447 }
448
449 static void
450 processevents(void *)
451 {
452         int message;
453         Cardbus *cb;
454
455         while(waserror())
456                 ;
457
458         for(;;){
459                 sleep(&revents, (int (*)(void *))eventoccured, nil);
460
461                 cb = nil;
462                 message = 0;
463                 ilock(&levents);
464                 if (nevents > 0) {
465                         cb = events[0].cb;
466                         message = events[0].message;
467                         nevents--;
468                         if (nevents > 0)
469                                 memmove(events, &events[1], nevents * sizeof(Events));
470                 }
471                 iunlock(&levents);
472
473                 if (cb)
474                         qengine(cb, message);
475         }
476 }
477
478 static void
479 cbinterrupt(Ureg *, void *)
480 {
481         int i;
482
483         for (i = 0; i != nslots; i++) {
484                 Cardbus *cb = &cbslots[i];
485                 ulong event, state;
486
487                 event = cb->regs[SocketEvent];
488                 if(!(event & (SE_POWER|SE_CCD)))
489                         continue;
490                 state = cb->regs[SocketState];
491                 rdreg(cb, Rcsc);        /* Ack the interrupt */
492
493                 if(DEBUG)
494                         print("#Y%ld: interrupt: event %.8lX, state %.8lX, (%s)\n",
495                                 cb - cbslots, event, state, states[cb->state]);
496
497                 if (event & SE_CCD) {
498                         cb->regs[SocketEvent] |= SE_CCD;        /* Ack interrupt */
499                         if (state & SE_CCD) {
500                                 if (cb->state != SlotEmpty) {
501                                         print("#Y: take cardejected interrupt\n");
502                                         iengine(cb, CardEjected);
503                                 }
504                         }
505                         else
506                                 iengine(cb, CardDetected);
507                 }
508
509                 if (event & SE_POWER) {
510                         cb->regs[SocketEvent] |= SE_POWER;      /* Ack interrupt */
511                         iengine(cb, CardPowered);
512                 }
513         }
514 }
515
516 void
517 devpccardlink(void)
518 {
519         static int initialized;
520         Pcidev *pci;
521         int i;
522         uchar intl;
523         char *p;
524         void *baddrva;
525
526         if (initialized)
527                 return;
528         initialized = 1;
529
530         if((p=getconf("pccard0")) && strncmp(p, "disabled", 8)==0)
531                 return;
532
533         if(_pcmspecial)
534                 return;
535
536         /* Allocate legacy space */
537         if (ioalloc(LegacyAddr, 2, 0, "i82365.0") < 0)
538                 print("#Y: WARNING: Cannot allocate legacy ports\n");
539
540         /* Find all CardBus controllers */
541         pci = nil;
542         intl = 0xff;
543         while ((pci = pcimatch(pci, 0, 0)) != nil) {
544                 ulong baddr;
545                 Cardbus *cb;
546                 int slot;
547                 uchar pin;
548
549                 if(pci->ccrb != 6 || pci->ccru != 7)
550                         continue;
551                 for (i = 0; i != nelem(variant); i++)
552                         if (pci->vid == variant[i].vid && pci->did == variant[i].did)
553                                 break;
554                 if (i == nelem(variant))
555                         continue;
556
557                 /* initialize this slot */
558                 slot = nslots++;
559                 cb = &cbslots[slot];
560
561                 cb->pci = pci;
562                 cb->variant = &variant[i];
563
564                 if (pci->vid != TI_vid) {
565                         /*
566                          * Gross hack, needs a fix.  Inherit the mappings from
567                          * 9load for the TIs (pb)
568                          */
569                         pcicfgw32(pci, PciCBMBR0, 0xffffffff);
570                         pcicfgw32(pci, PciCBMLR0, 0);
571                         pcicfgw32(pci, PciCBMBR1, 0xffffffff);
572                         pcicfgw32(pci, PciCBMLR1, 0);
573                         pcicfgw32(pci, PciCBIBR0, 0xffffffff);
574                         pcicfgw32(pci, PciCBILR0, 0);
575                         pcicfgw32(pci, PciCBIBR1, 0xffffffff);
576                         pcicfgw32(pci, PciCBILR1, 0);
577                 }
578
579                 /* Set up PCI bus numbers if needed. */
580                 if (pcicfgr8(pci, PciSBN) == 0) {
581                         static int busbase = 0x20;
582
583                         pcicfgw8(pci, PciSBN, busbase);
584                         pcicfgw8(pci, PciUBN, busbase + 2);
585                         busbase += 3;
586                 }
587
588                 /* Patch up intl if needed. */
589                 if ((pin = pcicfgr8(pci, PciINTP)) != 0 &&
590                     (pci->intl == 0xff || pci->intl == 0)) {
591                         pci->intl = pciipin(nil, pin);
592                         pcicfgw8(pci, PciINTL, pci->intl);
593
594                         if (pci->intl == 0xff || pci->intl == 0)
595                                 print("#Y%ld: No interrupt?\n", cb - cbslots);
596                 }
597
598                 /* Don't you love standards! */
599                 if (pci->vid == TI_vid) {
600                         if (pci->did <= TI_1131_did) {
601                                 uchar cc;
602
603                                 cc = pcicfgr8(pci, TI1131xCC);
604                                 cc &= ~(TI113X_CC_PCI_IRQ_ENA |
605                                         TI113X_CC_PCI_IREQ |
606                                         TI113X_CC_PCI_CSC |
607                                         TI113X_CC_ZVENABLE);
608                                 cc |= TI113X_CC_PCI_IRQ_ENA |
609                                         TI113X_CC_PCI_IREQ |
610                                         TI113X_CC_SPKROUTEN;
611                                 pcicfgw8(pci, TI1131xCC, cc);
612
613                                 /* PCI interrupts only */
614                                 pcicfgw8(pci, TI1131xDC,
615                                         pcicfgr8(pci, TI1131xDC) & ~6);
616
617                                 /* CSC ints to PCI bus. */
618                                 wrreg(cb, Rigc, rdreg(cb, Rigc) | 0x10);
619                         }
620                         else if (pci->did == TI_1250_did) {
621                                 print("No support yet for the TI_1250_did, prod pb\n");
622                         }
623                         else if (pci->did == TI_1420_did) {
624                                 /* Disable Vcc protection */
625                                 pcicfgw32(cb->pci, 0x80,
626                                         pcicfgr32(cb->pci, 0x80) | (1 << 21));
627                         }
628
629                         pcicfgw16(cb->pci, PciPMC, pcicfgr16(cb->pci, PciPMC) & ~3);
630                 }
631                 if (pci->vid == O2_vid) {
632                         if(DEBUG)
633                                 print("writing O2 config\n");
634                         pcicfgw8(cb->pci, 0x94, 0xCA);
635                         pcicfgw8(cb->pci, 0xD4, 0xCA);
636                 }
637
638                 if (intl != 0xff && intl != pci->intl)
639                         intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus");
640                 intl = pci->intl;
641
642                 if ((baddr = pcicfgr32(cb->pci, PciBAR0)) == 0) {
643                         int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000;
644
645                         baddr = upaalloc(size, size);
646                         baddrva = vmap(baddr, size);
647                         pcicfgw32(cb->pci, PciBAR0, baddr);
648                         cb->regs = (ulong *)baddrva;
649                 }
650                 else
651                         cb->regs = (ulong *)vmap(baddr, 4096);
652                 cb->state = SlotEmpty;
653
654                 /* Don't really know what to do with this... */
655                 i82365probe(cb, LegacyAddr, LegacyAddr + 1);
656
657                 print("#Y%ld: %s, %.8ulX intl %d\n", cb - cbslots,
658                          variant[i].name, baddr, pci->intl);
659         }
660
661         if (nslots == 0){
662                 iofree(LegacyAddr);
663                 return;
664         }
665
666         _pcmspecial = pccard_pcmspecial;
667         _pcmspecialclose = pccard_pcmspecialclose;
668
669         for (i = 0; i != nslots; i++) {
670                 Cardbus *cb = &cbslots[i];
671
672                 if ((cb->regs[SocketState] & SE_CCD) == 0)
673                         engine(cb, CardDetected);
674         }
675
676         delay(500);                     /* Allow time for power up */
677
678         for (i = 0; i != nslots; i++) {
679                 Cardbus *cb = &cbslots[i];
680
681                 if (cb->regs[SocketState] & SE_POWER)
682                         engine(cb, CardPowered);
683
684                 /* Ack and enable interrupts on all events */
685                 // cb->regs[SocketEvent] = cb->regs[SocketEvent];
686                 cb->regs[SocketMask] |= 0xF;
687                 wrreg(cb, Rcscic, 0xC);
688         }
689 }
690
691 static int
692 powerup(Cardbus *cb)
693 {
694         ulong state;
695         ushort bcr;
696
697         state = cb->regs[SocketState];
698         if (state & SS_PC16) {
699                 if(DEBUG)
700                         print("#Y%ld: Probed a PC16 card, powering up card\n",
701                                 cb - cbslots);
702                 cb->type = PC16;
703                 memset(&cb->linfo, 0, sizeof(Pcminfo));
704
705                 /* power up and unreset, wait's are empirical (???) */
706                 wrreg(cb, Rpc, Fautopower|Foutena|Fcardena);
707                 delay(300);
708                 wrreg(cb, Rigc, 0);
709                 delay(100);
710                 wrreg(cb, Rigc, Fnotreset);
711                 delay(500);
712
713 //              return 1;
714         }
715
716         if (state & SS_CCD)
717                 return 0;
718
719         if (state & SS_NOTCARD) {
720                 print("#Y%ld: No card inserted\n", cb - cbslots);
721                 return 0;
722         }
723
724         if ((state & SS_3V) == 0 && (state & SS_5V) == 0) {
725                 print("#Y%ld: Unsupported voltage, powering down card!\n",
726                         cb - cbslots);
727                 cb->regs[SocketControl] = 0;
728                 return 0;
729         }
730
731         if(DEBUG)
732                 print("#Y%ld: card %spowered at %d volt\n", cb - cbslots,
733                         (state & SS_POWER)? "": "not ",
734                         (state & SS_3V)? 3: (state & SS_5V)? 5: -1);
735
736         /* Power up the card
737          * and make sure the secondary bus is not in reset.
738          */
739         cb->regs[SocketControl] = (state & SS_5V)? SC_5V: SC_3V;
740         delay(50);
741         bcr = pcicfgr16(cb->pci, PciBCR);
742         bcr &= ~0x40;
743         pcicfgw16(cb->pci, PciBCR, bcr);
744         delay(100);
745
746         if (state & SS_PC16)
747                 cb->type = PC16;
748         else
749                 cb->type = PC32;
750
751         return 1;
752 }
753
754 static void
755 powerdown(Cardbus *cb)
756 {
757         ushort bcr;
758
759         if (cb->type == PC16) {
760
761                 wrreg(cb, Rpc, 0);      /* turn off card power */
762                 wrreg(cb, Rwe, 0);      /* no windows */
763
764                 cb->type = -1;
765                 return;
766         }
767
768         bcr = pcicfgr16(cb->pci, PciBCR);
769         bcr |= 0x40;
770         pcicfgw16(cb->pci, PciBCR, bcr);
771         cb->regs[SocketControl] = 0;
772         cb->type = -1;
773 }
774
775 static void
776 configure(Cardbus *cb)
777 {
778         int i, r;
779         ulong size, bar;
780         Pcidev *pci;
781         ulong membase, iobase, memlen, iolen, rombase, romlen;
782
783         if(DEBUG)
784                 print("configuring slot %ld (%s)\n", cb - cbslots, states[cb->state]);
785         if (cb->state == SlotConfigured)
786                 return;
787         engine(cb, CardConfigured);
788
789         delay(50);                                      /* Emperically established */
790
791         if (cb->type == PC16) {
792                 i82365configure(cb);
793                 return;
794         }
795
796         /* Scan the CardBus for new PCI devices */
797         pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge);
798
799         /*
800          * size the devices on the bus, reserve a minimum for devices arriving later,
801          * allow for ROM space, allocate space, and set the cardbus mapping registers
802          */
803         pcibussize(cb->pci->bridge, &memlen, &iolen);   /* TO DO: need initial alignments */
804
805         romlen = 0;
806         for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
807                 size = pcibarsize(pci, PciEBAR0);
808                 if(size > 0){
809                         pci->rom.bar = -1;
810                         pci->rom.size = size;
811                         romlen += size;
812                 }
813         }
814
815         if(iolen < 512)
816                 iolen = 512;
817         iobase = ioreserve(~0, iolen, 0, "cardbus");
818         pcicfgw32(cb->pci, PciCBIBR0, iobase);
819         pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1);
820         pcicfgw32(cb->pci, PciCBIBR1, 0);
821         pcicfgw32(cb->pci, PciCBILR1, 0);
822
823         rombase = memlen;
824         memlen += romlen;
825         if(memlen < 1*1024*1024)
826                 memlen = 1*1024*1024;
827         membase = upaalloc(memlen, 4*1024*1024);        /* TO DO: better alignment */
828         pcicfgw32(cb->pci, PciCBMBR0, membase);
829         pcicfgw32(cb->pci, PciCBMLR0, membase + memlen-1);
830         pcicfgw32(cb->pci, PciCBMBR1, 0);
831         pcicfgw32(cb->pci, PciCBMLR1, 0);
832
833 //      pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */
834         rombase += membase;
835
836         for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
837                 r = pcicfgr16(pci, PciPCR);
838                 r &= ~(PciPCR_IO|PciPCR_MEM);
839                 pcicfgw16(pci, PciPCR, r);
840
841                 /*
842                  * Treat the found device as an ordinary PCI card.
843                  * It seems that the CIS is not always present in
844                  * CardBus cards.
845                  * XXX, need to support multifunction cards
846                  */
847                 for(i = 0; i < Nbars; i++) {
848                         if(pci->mem[i].size == 0)
849                                 continue;
850                         bar = pci->mem[i].bar;
851                         if(bar & 1)
852                                 bar += iobase;
853                         else
854                                 bar += membase;
855                         pci->mem[i].bar = bar;
856                         pcicfgw32(pci, PciBAR0 + 4*i, bar);
857                         if((bar & 1) == 0){
858                                 print("%T mem[%d] %8.8lux %d\n", pci->tbdf, i, bar, pci->mem[i].size);
859                                 if(bar & 0x80){ /* TO DO: enable prefetch */
860                                         ;
861                                 }
862                         }
863                 }
864                 if((size = pcibarsize(pci, PciEBAR0)) > 0) {    /* TO DO: can this be done by pci.c? */
865                         pci->rom.bar = rombase;
866                         pci->rom.size = size;
867                         rombase += size;
868                         pcicfgw32(pci, PciEBAR0, pci->rom.bar);
869                 }
870
871                 /* Set the basic PCI registers for the device */
872                 pci->pcr = pcicfgr16(pci, PciPCR);
873                 pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master;
874                 pci->cls = 8;
875                 pci->ltr = 64;
876                 pcicfgw16(pci, PciPCR, pci->pcr);
877                 pcicfgw8(pci, PciCLS, pci->cls);
878                 pcicfgw8(pci, PciLTR, pci->ltr);
879
880                 if (pcicfgr8(pci, PciINTP)) {
881                         pci->intl = pcicfgr8(cb->pci, PciINTL);
882                         pcicfgw8(pci, PciINTL, pci->intl);
883
884                         /* Route interrupts to INTA#/B# */
885                         pcicfgw16(cb->pci, PciBCR,
886                                           pcicfgr16(cb->pci, PciBCR) & ~(1 << 7));
887                 }
888         }
889 }
890
891 static void
892 unconfigure(Cardbus *cb)
893 {
894         Pcidev *pci;
895         int i, ioindex, memindex, r;
896
897         if (cb->type == PC16) {
898                 print("#Y%d: Don't know how to unconfigure a PC16 card\n",
899                          (int)(cb - cbslots));
900
901                 memset(&cb->linfo, 0, sizeof(Pcminfo));
902                 return;
903         }
904
905         pci = cb->pci->bridge;
906         if (pci == nil)
907                 return;         /* Not configured */
908         cb->pci->bridge = nil;
909
910         memindex = ioindex = 0;
911         while (pci) {
912                 Pcidev *_pci;
913
914                 for (i = 0; i != Nbars; i++) {
915                         if (pci->mem[i].size == 0)
916                                 continue;
917                         if (pci->mem[i].bar & 1) {
918                                 iofree(pci->mem[i].bar & ~1);
919                                 pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8,
920                                                  (ushort)-1);
921                                 pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0);
922                                 ioindex++;
923                                 continue;
924                         }
925
926                         upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size);
927                         pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
928                         pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
929                         r = pcicfgr16(cb->pci, PciBCR);
930                         r &= ~(1 << (8 + memindex));
931                         pcicfgw16(cb->pci, PciBCR, r);
932                         memindex++;
933                 }
934
935                 if (pci->rom.bar && memindex < 2) {
936                         upafree(pci->rom.bar & ~0xF, pci->rom.size);
937                         pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
938                         pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
939                         memindex++;
940                 }
941
942                 _pci = pci->list;
943                 free(_pci);
944                 pci = _pci;
945         }
946 }
947
948 static void
949 i82365configure(Cardbus *cb)
950 {
951         int this;
952         Cisdat cis;
953         PCMmap *m;
954         uchar type, link;
955
956         /*
957          * Read all tuples in attribute space.
958          */
959         m = isamap(cb, 0, 0, 1);
960         if(m == 0)
961                 return;
962
963         cis.cisbase = KADDR(m->isa);
964         cis.cispos = 0;
965         cis.cisskip = 2;
966         cis.cislen = m->len;
967
968         /* loop through all the tuples */
969         for(;;){
970                 this = cis.cispos;
971                 if(readc(&cis, &type) != 1)
972                         break;
973                 if(type == 0xFF)
974                         break;
975                 if(readc(&cis, &link) != 1)
976                         break;
977
978                 switch(type){
979                 default:
980                         break;
981                 case 0x15:
982                         tvers1(cb, &cis, type);
983                         break;
984                 case 0x1A:
985                         tcfig(cb, &cis, type);
986                         break;
987                 case 0x1B:
988                         tentry(cb, &cis, type);
989                         break;
990                 }
991
992                 if(link == 0xFF)
993                         break;
994                 cis.cispos = this + (2+link);
995         }
996         isaunmap(m);
997 }
998
999 /*
1000  *  look for a card whose version contains 'idstr'
1001  */
1002 static int
1003 pccard_pcmspecial(char *idstr, ISAConf *isa)
1004 {
1005         int i, irq;
1006         PCMconftab *ct, *et;
1007         Pcminfo *pi;
1008         Cardbus *cb;
1009         uchar x, we, *p;
1010
1011         cb = nil;
1012         for (i = 0; i != nslots; i++) {
1013                 cb = &cbslots[i];
1014
1015                 lock(cb);
1016                 if (cb->state == SlotConfigured &&
1017                     cb->type == PC16 &&
1018                     !cb->special &&
1019                     strstr(cb->linfo.verstr, idstr))
1020                         break;
1021                 unlock(cb);
1022         }
1023
1024         if (i == nslots) {
1025                 if(0 && DEBUG)
1026                         print("#Y: %s not found\n", idstr);
1027                 return -1;
1028         }
1029
1030         pi = &cb->linfo;
1031
1032         /*
1033           *  configure the PCMslot for IO.  We assume very heavily that we can read
1034           *  configuration info from the CIS.  If not, we won't set up correctly.
1035           */
1036         irq = isa->irq;
1037         if(irq == 2)
1038                 irq = 9;
1039
1040         et = &pi->ctab[pi->nctab];
1041         ct = nil;
1042         for(i = 0; i < isa->nopt; i++){
1043                 int index;
1044                 char *cp;
1045
1046                 if(strncmp(isa->opt[i], "index=", 6))
1047                         continue;
1048                 index = strtol(&isa->opt[i][6], &cp, 0);
1049                 if(cp == &isa->opt[i][6] || index >= pi->nctab) {
1050                         unlock(cb);
1051                         print("#Y%d: Cannot find index %d in conf table\n",
1052                                  (int)(cb - cbslots), index);
1053                         return -1;
1054                 }
1055                 ct = &pi->ctab[index];
1056         }
1057
1058         if(ct == nil){
1059                 PCMconftab *t;
1060
1061                 /* assume default is right */
1062                 if(pi->defctab)
1063                         ct = pi->defctab;
1064                 else
1065                         ct = pi->ctab;
1066
1067                 /* try for best match */
1068                 if(ct->nio == 0
1069                 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
1070                         for(t = pi->ctab; t < et; t++)
1071                                 if(t->nio
1072                                 && t->io[0].start == isa->port
1073                                 && ((1<<irq) & t->irqs)){
1074                                         ct = t;
1075                                         break;
1076                                 }
1077                 }
1078                 if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
1079                         for(t = pi->ctab; t < et; t++)
1080                                 if(t->nio && ((1<<irq) & t->irqs)){
1081                                         ct = t;
1082                                         break;
1083                                 }
1084                 }
1085                 if(ct->nio == 0){
1086                         for(t = pi->ctab; t < et; t++)
1087                                 if(t->nio){
1088                                         ct = t;
1089                                         break;
1090                                 }
1091                 }
1092         }
1093
1094         if(ct == et || ct->nio == 0) {
1095                 unlock(cb);
1096                 print("#Y%d: No configuration?\n", (int)(cb - cbslots));
1097                 return -1;
1098         }
1099         if(isa->port == 0 && ct->io[0].start == 0) {
1100                 unlock(cb);
1101                 print("#Y%d: No part or start address\n", (int)(cb - cbslots));
1102                 return -1;
1103         }
1104
1105         cb->special = 1;        /* taken */
1106
1107         /* route interrupts */
1108         isa->irq = irq;
1109         wrreg(cb, Rigc, irq | Fnotreset | Fiocard);
1110
1111         /* set power and enable device */
1112         x = vcode(ct->vpp1);
1113         wrreg(cb, Rpc, x|Fautopower|Foutena|Fcardena);
1114
1115         /* 16-bit data path */
1116         if(ct->bit16)
1117                 x = Ftiming|Fiocs16|Fwidth16;
1118         else
1119                 x = Ftiming;
1120         if(ct->nio == 2 && ct->io[1].start)
1121                 x |= x<<4;
1122         wrreg(cb, Rio, x);
1123
1124         /*
1125          * enable io port map 0
1126          * the 'top' register value includes the last valid address
1127          */
1128         if(isa->port == 0)
1129                 isa->port = ct->io[0].start;
1130         we = rdreg(cb, Rwe);
1131         wrreg(cb, Riobtm0lo, isa->port);
1132         wrreg(cb, Riobtm0hi, isa->port>>8);
1133         i = isa->port+ct->io[0].len-1;
1134         wrreg(cb, Riotop0lo, i);
1135         wrreg(cb, Riotop0hi, i>>8);
1136         we |= 1<<6;
1137         if(ct->nio == 2 && ct->io[1].start){
1138                 wrreg(cb, Riobtm1lo, ct->io[1].start);
1139                 wrreg(cb, Riobtm1hi, ct->io[1].start>>8);
1140                 i = ct->io[1].start+ct->io[1].len-1;
1141                 wrreg(cb, Riotop1lo, i);
1142                 wrreg(cb, Riotop1hi, i>>8);
1143                 we |= 1<<7;
1144         }
1145         wrreg(cb, Rwe, we);
1146
1147         /* only touch Rconfig if it is present */
1148         if(pi->conf_present & (1<<Rconfig)){
1149                 PCMmap *m;
1150
1151                 /*  Reset adapter */
1152                 m = isamap(cb, pi->conf_addr + Rconfig, 1, 1);
1153                 p = KADDR(m->isa + pi->conf_addr + Rconfig - m->ca);
1154
1155                 /* set configuration and interrupt type */
1156                 x = ct->index;
1157                 if(ct->irqtype & 0x20)
1158                         x |= Clevel;
1159                 *p = x;
1160                 delay(5);
1161
1162                 isaunmap(m);
1163         }
1164
1165         pi->port = isa->port;
1166         pi->irq = isa->irq;
1167         unlock(cb);
1168
1169         print("#Y%ld: %s irq %d, port %lX\n", cb - cbslots, pi->verstr, isa->irq, isa->port);
1170         return (int)(cb - cbslots);
1171 }
1172
1173 static void
1174 pccard_pcmspecialclose(int slotno)
1175 {
1176         Cardbus *cb = &cbslots[slotno];
1177
1178         wrreg(cb, Rwe, 0);      /* no windows */
1179         cb->special = 0;
1180 }
1181
1182 static Chan*
1183 pccardattach(char *spec)
1184 {
1185         if (!managerstarted) {
1186                 managerstarted = 1;
1187                 kproc("cardbus", processevents, nil);
1188         }
1189         return devattach('Y', spec);
1190 }
1191
1192 enum
1193 {
1194         Qdir,
1195         Qctl,
1196
1197         Nents = 1,
1198 };
1199
1200 #define SLOTNO(c)       ((ulong)((c->qid.path>>8)&0xff))
1201 #define TYPE(c) ((ulong)(c->qid.path&0xff))
1202 #define QID(s,t)        (((s)<<8)|(t))
1203
1204 static int
1205 pccardgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
1206 {
1207         int slotno;
1208         Qid qid;
1209         long len;
1210         int entry;
1211
1212         if(i == DEVDOTDOT){
1213                 mkqid(&qid, Qdir, 0, QTDIR);
1214                 devdir(c, qid, "#Y", 0, eve, 0555, dp);
1215                 return 1;
1216         }
1217
1218         len = 0;
1219         if(i >= Nents * nslots) return -1;
1220         slotno = i / Nents;
1221         entry = i % Nents;
1222         if (entry == 0) {
1223                 qid.path = QID(slotno, Qctl);
1224                 snprint(up->genbuf, sizeof up->genbuf, "cb%dctl", slotno);
1225         }
1226         else {
1227                 /* Entries for memory regions.  I'll implement them when
1228                      needed. (pb) */
1229         }
1230         qid.vers = 0;
1231         qid.type = QTFILE;
1232         devdir(c, qid, up->genbuf, len, eve, 0660, dp);
1233         return 1;
1234 }
1235
1236 static Walkqid*
1237 pccardwalk(Chan *c, Chan *nc, char **name, int nname)
1238 {
1239         return devwalk(c, nc, name, nname, 0, 0, pccardgen);
1240 }
1241
1242 static int
1243 pccardstat(Chan *c, uchar *db, int n)
1244 {
1245         return devstat(c, db, n, 0, 0, pccardgen);
1246 }
1247
1248 static void
1249 increfp(Cardbus *cb)
1250 {
1251         lock(&cb->refslock);
1252         cb->refs++;
1253         unlock(&cb->refslock);
1254 }
1255
1256 static void
1257 decrefp(Cardbus *cb)
1258 {
1259         lock(&cb->refslock);
1260         cb->refs--;
1261         unlock(&cb->refslock);
1262 }
1263
1264 static Chan*
1265 pccardopen(Chan *c, int omode)
1266 {
1267         if (c->qid.type & QTDIR){
1268                 if(omode != OREAD)
1269                         error(Eperm);
1270         } else
1271                 increfp(&cbslots[SLOTNO(c)]);
1272         c->mode = openmode(omode);
1273         c->flag |= COPEN;
1274         c->offset = 0;
1275         return c;
1276 }
1277
1278 static void
1279 pccardclose(Chan *c)
1280 {
1281         if(c->flag & COPEN)
1282                 if((c->qid.type & QTDIR) == 0)
1283                         decrefp(&cbslots[SLOTNO(c)]);
1284 }
1285
1286 static long
1287 pccardread(Chan *c, void *a, long n, vlong offset)
1288 {
1289         Cardbus *cb;
1290         char *buf, *p, *e;
1291         int i;
1292
1293         switch(TYPE(c)){
1294         case Qdir:
1295                 return devdirread(c, a, n, 0, 0, pccardgen);
1296
1297         case Qctl:
1298                 buf = p = smalloc(READSTR);
1299                 buf[0] = 0;
1300                 e = p + READSTR;
1301
1302                 cb = &cbslots[SLOTNO(c)];
1303                 lock(cb);
1304                 p = seprint(p, e, "slot %ld: %s; ", cb - cbslots, states[cb->state]);
1305
1306                 switch (cb->type) {
1307                 case -1:
1308                         seprint(p, e, "\n");
1309                         break;
1310
1311                 case PC32:
1312                         if (cb->pci->bridge) {
1313                                 Pcidev *pci = cb->pci->bridge;
1314                                 int i;
1315
1316                                 while (pci) {
1317                                         p = seprint(p, e, "%.4uX %.4uX; irq %d\n",
1318                                                           pci->vid, pci->did, pci->intl);
1319                                         for (i = 0; i != Nbars; i++)
1320                                                 if (pci->mem[i].size)
1321                                                         p = seprint(p, e,
1322                                                                           "\tmem[%d] %.8ulX (%.8uX)\n",
1323                                                                           i, pci->mem[i].bar,
1324                                                                           pci->mem[i].size);
1325                                         if (pci->rom.size)
1326                                                 p = seprint(p, e, "\tROM %.8ulX (%.8uX)\n",
1327                                                                   pci->rom.bar, pci->rom.size);
1328                                         pci = pci->list;
1329                                 }
1330                         }
1331                         break;
1332
1333                 case PC16:
1334                         if (cb->state == SlotConfigured) {
1335                                 Pcminfo *pi = &cb->linfo;
1336
1337                                 p = seprint(p, e, "%s port %X; irq %d;\n",
1338                                                   pi->verstr, pi->port,
1339                                                   pi->irq);
1340                                 for (i = 0; i != pi->nctab; i++) {
1341                                         PCMconftab *ct;
1342                                         int j;
1343
1344                                         ct = &pi->ctab[i];
1345                                         p = seprint(p, e,
1346                                                 "\tconfiguration[%d] irqs %.4uX; vpp %d, %d; %s\n",
1347                                                           i, ct->irqs, ct->vpp1, ct->vpp2,
1348                                                           (ct == pi->defctab)? "(default);": "");
1349                                         for (j = 0; j != ct->nio; j++)
1350                                                 if (ct->io[j].len > 0)
1351                                                         p = seprint(p, e, "\t\tio[%d] %.8ulX %uld\n",
1352                                                                           j, ct->io[j].start, ct->io[j].len);
1353                                 }
1354                         }
1355                         break;
1356                 }
1357                 unlock(cb);
1358
1359                 n = readstr(offset, a, n, buf);
1360                 free(buf);
1361                 return n;
1362         }
1363         return 0;
1364 }
1365
1366 static long
1367 pccardwrite(Chan *c, void *v, long n, vlong)
1368 {
1369         Rune r;
1370         ulong n0;
1371         char *device;
1372         Cmdbuf *cbf;
1373         Cmdtab *ct;
1374         Cardbus *cb;
1375
1376         n0 = n;
1377         switch(TYPE(c)){
1378         case Qctl:
1379                 cb = &cbslots[SLOTNO(c)];
1380
1381                 cbf = parsecmd(v, n);
1382                 if(waserror()){
1383                         free(cbf);
1384                         nexterror();
1385                 }
1386                 ct = lookupcmd(cbf, pccardctlmsg, nelem(pccardctlmsg));
1387                 switch(ct->index){
1388                 case CMdown:
1389                         device = cbf->f[1];
1390                         device += chartorune(&r, device);
1391                         if ((n = devno(r, 1)) >= 0 && devtab[n]->config)
1392                                 devtab[n]->config(0, device, nil);
1393                         qengine(cb, CardEjected);
1394                         break;
1395                 case CMpower:
1396                         if ((cb->regs[SocketState] & SS_CCD) == 0)
1397                                 qengine(cb, CardDetected);
1398                         break;
1399                 }
1400                 poperror();
1401                 free(cbf);
1402                 break;
1403         }
1404         return n0 - n;
1405 }
1406
1407 Dev pccarddevtab = {
1408         'Y',
1409         "cardbus",
1410
1411         devreset,
1412         devinit,
1413         devshutdown,
1414         pccardattach,
1415         pccardwalk,
1416         pccardstat,
1417         pccardopen,
1418         devcreate,
1419         pccardclose,
1420         pccardread,
1421         devbread,
1422         pccardwrite,
1423         devbwrite,
1424         devremove,
1425         devwstat,
1426 };
1427
1428 static PCMmap *
1429 isamap(Cardbus *cb, ulong offset, int len, int attr)
1430 {
1431         uchar we, bit;
1432         PCMmap *m, *nm;
1433         Pcminfo *pi;
1434         int i;
1435         ulong e;
1436
1437         pi = &cb->linfo;
1438
1439         /* convert offset to granularity */
1440         if(len <= 0)
1441                 len = 1;
1442         e = ROUND(offset+len, Mgran);
1443         offset &= Mmask;
1444         len = e - offset;
1445
1446         /* look for a map that covers the right area */
1447         we = rdreg(cb, Rwe);
1448         bit = 1;
1449         nm = 0;
1450         for(m = pi->mmap; m < &pi->mmap[nelem(pi->mmap)]; m++){
1451                 if((we & bit))
1452                 if(m->attr == attr)
1453                 if(offset >= m->ca && e <= m->cea){
1454
1455                         m->ref++;
1456                         return m;
1457                 }
1458                 bit <<= 1;
1459                 if(nm == 0 && m->ref == 0)
1460                         nm = m;
1461         }
1462         m = nm;
1463         if(m == 0)
1464                 return 0;
1465
1466         /* if isa space isn't big enough, free it and get more */
1467         if(m->len < len){
1468                 if(m->isa){
1469                         umbfree(m->isa, m->len);
1470                         m->len = 0;
1471                 }
1472                 m->isa = PADDR(umbmalloc(0, len, Mgran));
1473                 if(m->isa == 0){
1474                         print("isamap: out of isa space\n");
1475                         return 0;
1476                 }
1477                 m->len = len;
1478         }
1479
1480         /* set up new map */
1481         m->ca = offset;
1482         m->cea = m->ca + m->len;
1483         m->attr = attr;
1484         i = m - pi->mmap;
1485         bit = 1<<i;
1486         wrreg(cb, Rwe, we & ~bit);              /* disable map before changing it */
1487         wrreg(cb, MAP(i, Mbtmlo), m->isa>>Mshift);
1488         wrreg(cb, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
1489         wrreg(cb, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
1490         wrreg(cb, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
1491         offset -= m->isa;
1492         offset &= (1<<25)-1;
1493         offset >>= Mshift;
1494         wrreg(cb, MAP(i, Mofflo), offset);
1495         wrreg(cb, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
1496         wrreg(cb, Rwe, we | bit);               /* enable map */
1497         m->ref = 1;
1498
1499         return m;
1500 }
1501
1502 static void
1503 isaunmap(PCMmap* m)
1504 {
1505         m->ref--;
1506 }
1507
1508 /*
1509  *  reading and writing card registers
1510  */
1511 static uchar
1512 rdreg(Cardbus *cb, int index)
1513 {
1514         outb(cb->lindex, cb->lbase + index);
1515         return inb(cb->ldata);
1516 }
1517
1518 static void
1519 wrreg(Cardbus *cb, int index, uchar val)
1520 {
1521         outb(cb->lindex, cb->lbase + index);
1522         outb(cb->ldata, val);
1523 }
1524
1525 static int
1526 readc(Cisdat *cis, uchar *x)
1527 {
1528         if(cis->cispos >= cis->cislen)
1529                 return 0;
1530         *x = cis->cisbase[cis->cisskip*cis->cispos];
1531         cis->cispos++;
1532         return 1;
1533 }
1534
1535 static ulong
1536 getlong(Cisdat *cis, int size)
1537 {
1538         uchar c;
1539         int i;
1540         ulong x;
1541
1542         x = 0;
1543         for(i = 0; i < size; i++){
1544                 if(readc(cis, &c) != 1)
1545                         break;
1546                 x |= c<<(i*8);
1547         }
1548         return x;
1549 }
1550
1551 static void
1552 tcfig(Cardbus *cb, Cisdat *cis, int )
1553 {
1554         uchar size, rasize, rmsize;
1555         uchar last;
1556         Pcminfo *pi;
1557
1558         if(readc(cis, &size) != 1)
1559                 return;
1560         rasize = (size&0x3) + 1;
1561         rmsize = ((size>>2)&0xf) + 1;
1562         if(readc(cis, &last) != 1)
1563                 return;
1564
1565         pi = &cb->linfo;
1566         pi->conf_addr = getlong(cis, rasize);
1567         pi->conf_present = getlong(cis, rmsize);
1568 }
1569
1570 static void
1571 tvers1(Cardbus *cb, Cisdat *cis, int )
1572 {
1573         uchar c, major, minor, last;
1574         int  i;
1575         Pcminfo *pi;
1576
1577         pi = &cb->linfo;
1578         if(readc(cis, &major) != 1)
1579                 return;
1580         if(readc(cis, &minor) != 1)
1581                 return;
1582         last = 0;
1583         for(i = 0; i < sizeof(pi->verstr) - 1; i++){
1584                 if(readc(cis, &c) != 1)
1585                         return;
1586                 if(c == 0)
1587                         c = ';';
1588                 if(c == '\n')
1589                         c = ';';
1590                 if(c == 0xff)
1591                         break;
1592                 if(c == ';' && last == ';')
1593                         continue;
1594                 pi->verstr[i] = c;
1595                 last = c;
1596         }
1597         pi->verstr[i] = 0;
1598 }
1599
1600 static ulong
1601 microvolt(Cisdat *cis)
1602 {
1603         uchar c;
1604         ulong microvolts;
1605         ulong exp;
1606
1607         if(readc(cis, &c) != 1)
1608                 return 0;
1609         exp = exponent[c&0x7];
1610         microvolts = vmant[(c>>3)&0xf]*exp;
1611         while(c & 0x80){
1612                 if(readc(cis, &c) != 1)
1613                         return 0;
1614                 switch(c){
1615                 case 0x7d:
1616                         break;          /* high impedence when sleeping */
1617                 case 0x7e:
1618                 case 0x7f:
1619                         microvolts = 0; /* no connection */
1620                         break;
1621                 default:
1622                         exp /= 10;
1623                         microvolts += exp*(c&0x7f);
1624                 }
1625         }
1626         return microvolts;
1627 }
1628
1629 static ulong
1630 nanoamps(Cisdat *cis)
1631 {
1632         uchar c;
1633         ulong nanoamps;
1634
1635         if(readc(cis, &c) != 1)
1636                 return 0;
1637         nanoamps = exponent[c&0x7]*vmant[(c>>3)&0xf];
1638         while(c & 0x80){
1639                 if(readc(cis, &c) != 1)
1640                         return 0;
1641                 if(c == 0x7d || c == 0x7e || c == 0x7f)
1642                         nanoamps = 0;
1643         }
1644         return nanoamps;
1645 }
1646
1647 /*
1648  * only nominal voltage (feature 1) is important for config,
1649  * other features must read card to stay in sync.
1650  */
1651 static ulong
1652 power(Cisdat *cis)
1653 {
1654         uchar feature;
1655         ulong mv;
1656
1657         mv = 0;
1658         if(readc(cis, &feature) != 1)
1659                 return 0;
1660         if(feature & 1)
1661                 mv = microvolt(cis);
1662         if(feature & 2)
1663                 microvolt(cis);
1664         if(feature & 4)
1665                 microvolt(cis);
1666         if(feature & 8)
1667                 nanoamps(cis);
1668         if(feature & 0x10)
1669                 nanoamps(cis);
1670         if(feature & 0x20)
1671                 nanoamps(cis);
1672         if(feature & 0x40)
1673                 nanoamps(cis);
1674         return mv/1000000;
1675 }
1676
1677 static ulong
1678 ttiming(Cisdat *cis, int scale)
1679 {
1680         uchar unscaled;
1681         ulong nanosecs;
1682
1683         if(readc(cis, &unscaled) != 1)
1684                 return 0;
1685         nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
1686         nanosecs = nanosecs * exponent[scale];
1687         return nanosecs;
1688 }
1689
1690 static void
1691 timing(Cisdat *cis, PCMconftab *ct)
1692 {
1693         uchar c, i;
1694
1695         if(readc(cis, &c) != 1)
1696                 return;
1697         i = c&0x3;
1698         if(i != 3)
1699                 ct->maxwait = ttiming(cis, i);          /* max wait */
1700         i = (c>>2)&0x7;
1701         if(i != 7)
1702                 ct->readywait = ttiming(cis, i);        /* max ready/busy wait */
1703         i = (c>>5)&0x7;
1704         if(i != 7)
1705                 ct->otherwait = ttiming(cis, i);        /* reserved wait */
1706 }
1707
1708 static void
1709 iospaces(Cisdat *cis, PCMconftab *ct)
1710 {
1711         uchar c;
1712         int i, nio;
1713
1714         ct->nio = 0;
1715         if(readc(cis, &c) != 1)
1716                 return;
1717
1718         ct->bit16 = ((c>>5)&3) >= 2;
1719         if(!(c & 0x80)){
1720                 ct->io[0].start = 0;
1721                 ct->io[0].len = 1<<(c&0x1f);
1722                 ct->nio = 1;
1723                 return;
1724         }
1725
1726         if(readc(cis, &c) != 1)
1727                 return;
1728
1729         /*
1730          * For each of the range descriptions read the
1731          * start address and the length (value is length-1).
1732          */
1733         nio = (c&0xf)+1;
1734         for(i = 0; i < nio; i++){
1735                 ct->io[i].start = getlong(cis, (c>>4)&0x3);
1736                 ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
1737         }
1738         ct->nio = nio;
1739 }
1740
1741 static void
1742 irq(Cisdat *cis, PCMconftab *ct)
1743 {
1744         uchar c;
1745
1746         if(readc(cis, &c) != 1)
1747                 return;
1748         ct->irqtype = c & 0xe0;
1749         if(c & 0x10)
1750                 ct->irqs = getlong(cis, 2);
1751         else
1752                 ct->irqs = 1<<(c&0xf);
1753         ct->irqs &= 0xDEB8;             /* levels available to card */
1754 }
1755
1756 static void
1757 memspace(Cisdat *cis, int asize, int lsize, int host)
1758 {
1759         ulong haddress, address, len;
1760
1761         len = getlong(cis, lsize)*256;
1762         address = getlong(cis, asize)*256;
1763         USED(len, address);
1764         if(host){
1765                 haddress = getlong(cis, asize)*256;
1766                 USED(haddress);
1767         }
1768 }
1769
1770 static void
1771 tentry(Cardbus *cb, Cisdat *cis, int )
1772 {
1773         uchar c, i, feature;
1774         PCMconftab *ct;
1775         Pcminfo *pi;
1776
1777         pi = &cb->linfo;
1778         if(pi->nctab >= nelem(pi->ctab))
1779                 return;
1780         if(readc(cis, &c) != 1)
1781                 return;
1782         ct = &pi->ctab[pi->nctab++];
1783
1784         /* copy from last default config */
1785         if(pi->defctab)
1786                 *ct = *pi->defctab;
1787
1788         ct->index = c & 0x3f;
1789
1790         /* is this the new default? */
1791         if(c & 0x40)
1792                 pi->defctab = ct;
1793
1794         /* memory wait specified? */
1795         if(c & 0x80){
1796                 if(readc(cis, &i) != 1)
1797                         return;
1798                 if(i&0x80)
1799                         ct->memwait = 1;
1800         }
1801
1802         if(readc(cis, &feature) != 1)
1803                 return;
1804         switch(feature&0x3){
1805         case 1:
1806                 ct->vpp1 = ct->vpp2 = power(cis);
1807                 break;
1808         case 2:
1809                 power(cis);
1810                 ct->vpp1 = ct->vpp2 = power(cis);
1811                 break;
1812         case 3:
1813                 power(cis);
1814                 ct->vpp1 = power(cis);
1815                 ct->vpp2 = power(cis);
1816                 break;
1817         default:
1818                 break;
1819         }
1820         if(feature&0x4)
1821                 timing(cis, ct);
1822         if(feature&0x8)
1823                 iospaces(cis, ct);
1824         if(feature&0x10)
1825                 irq(cis, ct);
1826         switch((feature>>5)&0x3){
1827         case 1:
1828                 memspace(cis, 0, 2, 0);
1829                 break;
1830         case 2:
1831                 memspace(cis, 2, 2, 0);
1832                 break;
1833         case 3:
1834                 if(readc(cis, &c) != 1)
1835                         return;
1836                 for(i = 0; i <= (c&0x7); i++)
1837                         memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
1838                 break;
1839         }
1840 }
1841
1842 static void
1843 i82365probe(Cardbus *cb, int lindex, int ldata)
1844 {
1845         uchar c, id;
1846         int dev = 0;    /* According to the Ricoh spec 00->3F _and_ 80->BF seem
1847                                      to be the same socket A (ditto for B). */
1848
1849         outb(lindex, Rid + (dev<<7));
1850         id = inb(ldata);
1851         if((id & 0xf0) != 0x80)
1852                 return;         /* not a memory & I/O card */
1853         if((id & 0x0f) == 0x00)
1854                 return;         /* no revision number, not possible */
1855
1856         cb->lindex = lindex;
1857         cb->ldata = ldata;
1858         cb->ltype = Ti82365;
1859         cb->lbase = (int)(cb - cbslots) * 0x40;
1860
1861         switch(id){
1862         case 0x82:
1863         case 0x83:
1864         case 0x84:
1865                 /* could be a cirrus */
1866                 outb(cb->lindex, Rchipinfo + (dev<<7));
1867                 outb(cb->ldata, 0);
1868                 c = inb(cb->ldata);
1869                 if((c & 0xc0) != 0xc0)
1870                         break;
1871                 c = inb(cb->ldata);
1872                 if((c & 0xc0) != 0x00)
1873                         break;
1874                 if(c & 0x20){
1875                         cb->ltype = Tpd6720;
1876                 } else {
1877                         cb->ltype = Tpd6710;
1878                 }
1879
1880                 /* low power mode */
1881                 outb(cb->lindex, Rmisc2 + (dev<<7));
1882                 c = inb(cb->ldata);
1883                 outb(cb->ldata, c & ~Flowpow);
1884                 break;
1885                 break;
1886         }
1887
1888         /* if it's not a Cirrus, it could be a Vadem... */
1889         if(cb->ltype == Ti82365){
1890                 /* unlock the Vadem extended regs */
1891                 outb(cb->lindex, 0x0E + (dev<<7));
1892                 outb(cb->lindex, 0x37 + (dev<<7));
1893
1894                 /* make the id register show the Vadem id */
1895                 outb(cb->lindex, 0x3A + (dev<<7));
1896                 c = inb(cb->ldata);
1897                 outb(cb->ldata, c|0xC0);
1898                 outb(cb->lindex, Rid + (dev<<7));
1899                 c = inb(cb->ldata);
1900                 if(c & 0x08)
1901                         cb->ltype = Tvg46x;
1902
1903                 /* go back to Intel compatible id */
1904                 outb(cb->lindex, 0x3A + (dev<<7));
1905                 c = inb(cb->ldata);
1906                 outb(cb->ldata, c & ~0xC0);
1907         }
1908 }
1909
1910 static int
1911 vcode(int volt)
1912 {
1913         switch(volt){
1914         case 5:
1915                 return 1;
1916         case 12:
1917                 return 2;
1918         default:
1919                 return 0;
1920         }
1921 }