]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/devpccard.c
kernel: cleanup the software mouse cursor mess
[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
525         if (initialized)
526                 return;
527         initialized = 1;
528
529         if((p=getconf("pccard0")) && strncmp(p, "disabled", 8)==0)
530                 return;
531
532         if(_pcmspecial)
533                 return;
534
535         /* Allocate legacy space */
536         if (ioalloc(LegacyAddr, 2, 0, "i82365.0") < 0)
537                 print("#Y: WARNING: Cannot allocate legacy ports\n");
538
539         /* Find all CardBus controllers */
540         pci = nil;
541         intl = 0xff;
542         while ((pci = pcimatch(pci, 0, 0)) != nil) {
543                 ulong baddr;
544                 Cardbus *cb;
545                 uchar pin;
546
547                 if(pci->ccrb != 6 || pci->ccru != 7)
548                         continue;
549                 for (i = 0; i != nelem(variant); i++)
550                         if (pci->vid == variant[i].vid && pci->did == variant[i].did)
551                                 break;
552                 if (i == nelem(variant))
553                         continue;
554
555                 /* initialize this slot */
556                 cb = &cbslots[nslots];
557
558                 cb->pci = pci;
559                 cb->variant = &variant[i];
560
561                 if (pci->vid != TI_vid) {
562                         /*
563                          * Gross hack, needs a fix.  Inherit the mappings from
564                          * 9load for the TIs (pb)
565                          */
566                         pcicfgw32(pci, PciCBMBR0, 0xffffffff);
567                         pcicfgw32(pci, PciCBMLR0, 0);
568                         pcicfgw32(pci, PciCBMBR1, 0xffffffff);
569                         pcicfgw32(pci, PciCBMLR1, 0);
570                         pcicfgw32(pci, PciCBIBR0, 0xffffffff);
571                         pcicfgw32(pci, PciCBILR0, 0);
572                         pcicfgw32(pci, PciCBIBR1, 0xffffffff);
573                         pcicfgw32(pci, PciCBILR1, 0);
574                 }
575
576                 /* Set up PCI bus numbers if needed. */
577                 if (pcicfgr8(pci, PciSBN) == 0) {
578                         static int busbase = 0x20;
579
580                         pcicfgw8(pci, PciSBN, busbase);
581                         pcicfgw8(pci, PciUBN, busbase + 2);
582                         busbase += 3;
583                 }
584
585                 /* Patch up intl if needed. */
586                 if ((pin = pcicfgr8(pci, PciINTP)) != 0 &&
587                     (pci->intl == 0xff || pci->intl == 0)) {
588                         pci->intl = pciipin(nil, pin);
589                         pcicfgw8(pci, PciINTL, pci->intl);
590
591                         if (pci->intl == 0xff || pci->intl == 0)
592                                 print("#Y%ld: No interrupt?\n", cb - cbslots);
593                 }
594
595                 /* Don't you love standards! */
596                 if (pci->vid == TI_vid) {
597                         if (pci->did <= TI_1131_did) {
598                                 uchar cc;
599
600                                 cc = pcicfgr8(pci, TI1131xCC);
601                                 cc &= ~(TI113X_CC_PCI_IRQ_ENA |
602                                         TI113X_CC_PCI_IREQ |
603                                         TI113X_CC_PCI_CSC |
604                                         TI113X_CC_ZVENABLE);
605                                 cc |= TI113X_CC_PCI_IRQ_ENA |
606                                         TI113X_CC_PCI_IREQ |
607                                         TI113X_CC_SPKROUTEN;
608                                 pcicfgw8(pci, TI1131xCC, cc);
609
610                                 /* PCI interrupts only */
611                                 pcicfgw8(pci, TI1131xDC,
612                                         pcicfgr8(pci, TI1131xDC) & ~6);
613
614                                 /* CSC ints to PCI bus. */
615                                 wrreg(cb, Rigc, rdreg(cb, Rigc) | 0x10);
616                         }
617                         else if (pci->did == TI_1250_did) {
618                                 print("No support yet for the TI_1250_did, prod pb\n");
619                         }
620                         else if (pci->did == TI_1420_did) {
621                                 /* Disable Vcc protection */
622                                 pcicfgw32(cb->pci, 0x80,
623                                         pcicfgr32(cb->pci, 0x80) | (1 << 21));
624                         }
625
626                         pcicfgw16(cb->pci, PciPMC, pcicfgr16(cb->pci, PciPMC) & ~3);
627                 }
628                 if (pci->vid == O2_vid) {
629                         if(DEBUG)
630                                 print("writing O2 config\n");
631                         pcicfgw8(cb->pci, 0x94, 0xCA);
632                         pcicfgw8(cb->pci, 0xD4, 0xCA);
633                 }
634
635                 if ((baddr = pcicfgr32(cb->pci, PciBAR0)) == 0) {
636                         int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000;
637                         baddr = upaalloc(-1, size, size);
638                         if(baddr == -1)
639                                 continue;
640                         pcicfgw32(cb->pci, PciBAR0, baddr);
641                         cb->regs = (ulong *)vmap(baddr, size);
642                 }
643                 else
644                         cb->regs = (ulong *)vmap(baddr, 4096);
645                 if(cb->regs == nil)
646                         continue;
647                 cb->state = SlotEmpty;
648
649                 if (intl != 0xff && intl != pci->intl)
650                         intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus");
651
652                 /* Don't really know what to do with this... */
653                 i82365probe(cb, LegacyAddr, LegacyAddr + 1);
654
655                 print("#Y%ld: %s, %.8ulX intl %d\n", cb - cbslots,
656                          variant[i].name, baddr, pci->intl);
657
658                 nslots++;
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         if(iobase == -1)
819                 return;
820
821         rombase = memlen;
822         memlen += romlen;
823         if(memlen < 1*1024*1024)
824                 memlen = 1*1024*1024;
825         membase = upaalloc(-1, memlen, 4*1024*1024);    /* TO DO: better alignment */
826         if(membase == -1)
827                 return;
828
829         pcicfgw32(cb->pci, PciCBIBR0, iobase);
830         pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1);
831         pcicfgw32(cb->pci, PciCBIBR1, 0);
832         pcicfgw32(cb->pci, PciCBILR1, 0);
833
834         pcicfgw32(cb->pci, PciCBMBR0, membase);
835         pcicfgw32(cb->pci, PciCBMLR0, membase + memlen-1);
836         pcicfgw32(cb->pci, PciCBMBR1, 0);
837         pcicfgw32(cb->pci, PciCBMLR1, 0);
838
839 //      pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */
840         rombase += membase;
841
842         for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
843                 r = pcicfgr16(pci, PciPCR);
844                 r &= ~(PciPCR_IO|PciPCR_MEM);
845                 pcicfgw16(pci, PciPCR, r);
846
847                 /*
848                  * Treat the found device as an ordinary PCI card.
849                  * It seems that the CIS is not always present in
850                  * CardBus cards.
851                  * XXX, need to support multifunction cards
852                  */
853                 for(i = 0; i < Nbars; i++) {
854                         if(pci->mem[i].size == 0)
855                                 continue;
856                         bar = pci->mem[i].bar;
857                         if(bar & 1)
858                                 bar += iobase;
859                         else
860                                 bar += membase;
861                         pci->mem[i].bar = bar;
862                         pcicfgw32(pci, PciBAR0 + 4*i, bar);
863                         if((bar & 1) == 0){
864                                 print("%T mem[%d] %8.8lux %d\n", pci->tbdf, i, bar, pci->mem[i].size);
865                                 if(bar & 0x80){ /* TO DO: enable prefetch */
866                                         ;
867                                 }
868                         }
869                 }
870                 if((size = pcibarsize(pci, PciEBAR0)) > 0) {    /* TO DO: can this be done by pci.c? */
871                         pci->rom.bar = rombase;
872                         pci->rom.size = size;
873                         rombase += size;
874                         pcicfgw32(pci, PciEBAR0, pci->rom.bar);
875                 }
876
877                 /* Set the basic PCI registers for the device */
878                 pci->pcr = pcicfgr16(pci, PciPCR);
879                 pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master;
880                 pci->cls = 8;
881                 pci->ltr = 64;
882                 pcicfgw16(pci, PciPCR, pci->pcr);
883                 pcicfgw8(pci, PciCLS, pci->cls);
884                 pcicfgw8(pci, PciLTR, pci->ltr);
885
886                 if (pcicfgr8(pci, PciINTP)) {
887                         pci->intl = pcicfgr8(cb->pci, PciINTL);
888                         pcicfgw8(pci, PciINTL, pci->intl);
889
890                         /* Route interrupts to INTA#/B# */
891                         pcicfgw16(cb->pci, PciBCR,
892                                           pcicfgr16(cb->pci, PciBCR) & ~(1 << 7));
893                 }
894         }
895 }
896
897 static void
898 unconfigure(Cardbus *cb)
899 {
900         Pcidev *pci;
901         int i, ioindex, memindex, r;
902
903         if (cb->type == PC16) {
904                 print("#Y%d: Don't know how to unconfigure a PC16 card\n",
905                          (int)(cb - cbslots));
906
907                 memset(&cb->linfo, 0, sizeof(Pcminfo));
908                 return;
909         }
910
911         pci = cb->pci->bridge;
912         if (pci == nil)
913                 return;         /* Not configured */
914         cb->pci->bridge = nil;
915
916         memindex = ioindex = 0;
917         while (pci) {
918                 Pcidev *_pci;
919
920                 for (i = 0; i != Nbars; i++) {
921                         if (pci->mem[i].size == 0)
922                                 continue;
923                         if (pci->mem[i].bar & 1) {
924                                 iofree(pci->mem[i].bar & ~1);
925                                 pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8,
926                                                  (ushort)-1);
927                                 pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0);
928                                 ioindex++;
929                                 continue;
930                         }
931
932                         upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size);
933                         pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
934                         pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
935                         r = pcicfgr16(cb->pci, PciBCR);
936                         r &= ~(1 << (8 + memindex));
937                         pcicfgw16(cb->pci, PciBCR, r);
938                         memindex++;
939                 }
940
941                 if (pci->rom.bar && memindex < 2) {
942                         upafree(pci->rom.bar & ~0xF, pci->rom.size);
943                         pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
944                         pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
945                         memindex++;
946                 }
947
948                 _pci = pci->list;
949                 free(_pci);
950                 pci = _pci;
951         }
952 }
953
954 static void
955 i82365configure(Cardbus *cb)
956 {
957         int this;
958         Cisdat cis;
959         PCMmap *m;
960         uchar type, link;
961
962         /*
963          * Read all tuples in attribute space.
964          */
965         m = isamap(cb, 0, 0, 1);
966         if(m == 0)
967                 return;
968
969         cis.cisbase = KADDR(m->isa);
970         cis.cispos = 0;
971         cis.cisskip = 2;
972         cis.cislen = m->len;
973
974         /* loop through all the tuples */
975         for(;;){
976                 this = cis.cispos;
977                 if(readc(&cis, &type) != 1)
978                         break;
979                 if(type == 0xFF)
980                         break;
981                 if(readc(&cis, &link) != 1)
982                         break;
983
984                 switch(type){
985                 default:
986                         break;
987                 case 0x15:
988                         tvers1(cb, &cis, type);
989                         break;
990                 case 0x1A:
991                         tcfig(cb, &cis, type);
992                         break;
993                 case 0x1B:
994                         tentry(cb, &cis, type);
995                         break;
996                 }
997
998                 if(link == 0xFF)
999                         break;
1000                 cis.cispos = this + (2+link);
1001         }
1002         isaunmap(m);
1003 }
1004
1005 /*
1006  *  look for a card whose version contains 'idstr'
1007  */
1008 static int
1009 pccard_pcmspecial(char *idstr, ISAConf *isa)
1010 {
1011         int i, irq;
1012         PCMconftab *ct, *et;
1013         Pcminfo *pi;
1014         Cardbus *cb;
1015         uchar x, we, *p;
1016
1017         cb = nil;
1018         for (i = 0; i != nslots; i++) {
1019                 cb = &cbslots[i];
1020
1021                 lock(cb);
1022                 if (cb->state == SlotConfigured &&
1023                     cb->type == PC16 &&
1024                     !cb->special &&
1025                     strstr(cb->linfo.verstr, idstr))
1026                         break;
1027                 unlock(cb);
1028         }
1029
1030         if (i == nslots) {
1031                 if(0 && DEBUG)
1032                         print("#Y: %s not found\n", idstr);
1033                 return -1;
1034         }
1035
1036         pi = &cb->linfo;
1037
1038         /*
1039           *  configure the PCMslot for IO.  We assume very heavily that we can read
1040           *  configuration info from the CIS.  If not, we won't set up correctly.
1041           */
1042         irq = isa->irq;
1043         if(irq == 2)
1044                 irq = 9;
1045
1046         et = &pi->ctab[pi->nctab];
1047         ct = nil;
1048         for(i = 0; i < isa->nopt; i++){
1049                 int index;
1050                 char *cp;
1051
1052                 if(strncmp(isa->opt[i], "index=", 6))
1053                         continue;
1054                 index = strtol(&isa->opt[i][6], &cp, 0);
1055                 if(cp == &isa->opt[i][6] || index >= pi->nctab) {
1056                         unlock(cb);
1057                         print("#Y%d: Cannot find index %d in conf table\n",
1058                                  (int)(cb - cbslots), index);
1059                         return -1;
1060                 }
1061                 ct = &pi->ctab[index];
1062         }
1063
1064         if(ct == nil){
1065                 PCMconftab *t;
1066
1067                 /* assume default is right */
1068                 if(pi->defctab)
1069                         ct = pi->defctab;
1070                 else
1071                         ct = pi->ctab;
1072
1073                 /* try for best match */
1074                 if(ct->nio == 0
1075                 || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
1076                         for(t = pi->ctab; t < et; t++)
1077                                 if(t->nio
1078                                 && t->io[0].start == isa->port
1079                                 && ((1<<irq) & t->irqs)){
1080                                         ct = t;
1081                                         break;
1082                                 }
1083                 }
1084                 if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
1085                         for(t = pi->ctab; t < et; t++)
1086                                 if(t->nio && ((1<<irq) & t->irqs)){
1087                                         ct = t;
1088                                         break;
1089                                 }
1090                 }
1091                 if(ct->nio == 0){
1092                         for(t = pi->ctab; t < et; t++)
1093                                 if(t->nio){
1094                                         ct = t;
1095                                         break;
1096                                 }
1097                 }
1098         }
1099
1100         if(ct == et || ct->nio == 0) {
1101                 unlock(cb);
1102                 print("#Y%d: No configuration?\n", (int)(cb - cbslots));
1103                 return -1;
1104         }
1105         if(isa->port == 0 && ct->io[0].start == 0) {
1106                 unlock(cb);
1107                 print("#Y%d: No part or start address\n", (int)(cb - cbslots));
1108                 return -1;
1109         }
1110
1111         cb->special = 1;        /* taken */
1112
1113         /* route interrupts */
1114         isa->irq = irq;
1115         wrreg(cb, Rigc, irq | Fnotreset | Fiocard);
1116
1117         /* set power and enable device */
1118         x = vcode(ct->vpp1);
1119         wrreg(cb, Rpc, x|Fautopower|Foutena|Fcardena);
1120
1121         /* 16-bit data path */
1122         if(ct->bit16)
1123                 x = Ftiming|Fiocs16|Fwidth16;
1124         else
1125                 x = Ftiming;
1126         if(ct->nio == 2 && ct->io[1].start)
1127                 x |= x<<4;
1128         wrreg(cb, Rio, x);
1129
1130         /*
1131          * enable io port map 0
1132          * the 'top' register value includes the last valid address
1133          */
1134         if(isa->port == 0)
1135                 isa->port = ct->io[0].start;
1136         we = rdreg(cb, Rwe);
1137         wrreg(cb, Riobtm0lo, isa->port);
1138         wrreg(cb, Riobtm0hi, isa->port>>8);
1139         i = isa->port+ct->io[0].len-1;
1140         wrreg(cb, Riotop0lo, i);
1141         wrreg(cb, Riotop0hi, i>>8);
1142         we |= 1<<6;
1143         if(ct->nio == 2 && ct->io[1].start){
1144                 wrreg(cb, Riobtm1lo, ct->io[1].start);
1145                 wrreg(cb, Riobtm1hi, ct->io[1].start>>8);
1146                 i = ct->io[1].start+ct->io[1].len-1;
1147                 wrreg(cb, Riotop1lo, i);
1148                 wrreg(cb, Riotop1hi, i>>8);
1149                 we |= 1<<7;
1150         }
1151         wrreg(cb, Rwe, we);
1152
1153         /* only touch Rconfig if it is present */
1154         if(pi->conf_present & (1<<Rconfig)){
1155                 PCMmap *m;
1156
1157                 /*  Reset adapter */
1158                 m = isamap(cb, pi->conf_addr + Rconfig, 1, 1);
1159                 p = KADDR(m->isa + pi->conf_addr + Rconfig - m->ca);
1160
1161                 /* set configuration and interrupt type */
1162                 x = ct->index;
1163                 if(ct->irqtype & 0x20)
1164                         x |= Clevel;
1165                 *p = x;
1166                 delay(5);
1167
1168                 isaunmap(m);
1169         }
1170
1171         pi->port = isa->port;
1172         pi->irq = isa->irq;
1173         unlock(cb);
1174
1175         print("#Y%ld: %s irq %d, port %lX\n", cb - cbslots, pi->verstr, isa->irq, isa->port);
1176         return (int)(cb - cbslots);
1177 }
1178
1179 static void
1180 pccard_pcmspecialclose(int slotno)
1181 {
1182         Cardbus *cb = &cbslots[slotno];
1183
1184         wrreg(cb, Rwe, 0);      /* no windows */
1185         cb->special = 0;
1186 }
1187
1188 static Chan*
1189 pccardattach(char *spec)
1190 {
1191         if (!managerstarted) {
1192                 managerstarted = 1;
1193                 kproc("cardbus", processevents, nil);
1194         }
1195         return devattach('Y', spec);
1196 }
1197
1198 enum
1199 {
1200         Qdir,
1201         Qctl,
1202
1203         Nents = 1,
1204 };
1205
1206 #define SLOTNO(c)       ((ulong)((c->qid.path>>8)&0xff))
1207 #define TYPE(c) ((ulong)(c->qid.path&0xff))
1208 #define QID(s,t)        (((s)<<8)|(t))
1209
1210 static int
1211 pccardgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
1212 {
1213         int slotno;
1214         Qid qid;
1215         long len;
1216         int entry;
1217
1218         if(i == DEVDOTDOT){
1219                 mkqid(&qid, Qdir, 0, QTDIR);
1220                 devdir(c, qid, "#Y", 0, eve, 0555, dp);
1221                 return 1;
1222         }
1223
1224         len = 0;
1225         if(i >= Nents * nslots) return -1;
1226         slotno = i / Nents;
1227         entry = i % Nents;
1228         if (entry == 0) {
1229                 qid.path = QID(slotno, Qctl);
1230                 snprint(up->genbuf, sizeof up->genbuf, "cb%dctl", slotno);
1231         }
1232         else {
1233                 /* Entries for memory regions.  I'll implement them when
1234                      needed. (pb) */
1235         }
1236         qid.vers = 0;
1237         qid.type = QTFILE;
1238         devdir(c, qid, up->genbuf, len, eve, 0660, dp);
1239         return 1;
1240 }
1241
1242 static Walkqid*
1243 pccardwalk(Chan *c, Chan *nc, char **name, int nname)
1244 {
1245         return devwalk(c, nc, name, nname, 0, 0, pccardgen);
1246 }
1247
1248 static int
1249 pccardstat(Chan *c, uchar *db, int n)
1250 {
1251         return devstat(c, db, n, 0, 0, pccardgen);
1252 }
1253
1254 static void
1255 increfp(Cardbus *cb)
1256 {
1257         lock(&cb->refslock);
1258         cb->refs++;
1259         unlock(&cb->refslock);
1260 }
1261
1262 static void
1263 decrefp(Cardbus *cb)
1264 {
1265         lock(&cb->refslock);
1266         cb->refs--;
1267         unlock(&cb->refslock);
1268 }
1269
1270 static Chan*
1271 pccardopen(Chan *c, int omode)
1272 {
1273         if (c->qid.type & QTDIR){
1274                 if(omode != OREAD)
1275                         error(Eperm);
1276         } else
1277                 increfp(&cbslots[SLOTNO(c)]);
1278         c->mode = openmode(omode);
1279         c->flag |= COPEN;
1280         c->offset = 0;
1281         return c;
1282 }
1283
1284 static void
1285 pccardclose(Chan *c)
1286 {
1287         if(c->flag & COPEN)
1288                 if((c->qid.type & QTDIR) == 0)
1289                         decrefp(&cbslots[SLOTNO(c)]);
1290 }
1291
1292 static long
1293 pccardread(Chan *c, void *a, long n, vlong offset)
1294 {
1295         Cardbus *cb;
1296         char *buf, *p, *e;
1297         int i;
1298
1299         switch(TYPE(c)){
1300         case Qdir:
1301                 return devdirread(c, a, n, 0, 0, pccardgen);
1302
1303         case Qctl:
1304                 buf = p = smalloc(READSTR);
1305                 buf[0] = 0;
1306                 e = p + READSTR;
1307
1308                 cb = &cbslots[SLOTNO(c)];
1309                 lock(cb);
1310                 p = seprint(p, e, "slot %ld: %s; ", cb - cbslots, states[cb->state]);
1311
1312                 switch (cb->type) {
1313                 case -1:
1314                         seprint(p, e, "\n");
1315                         break;
1316
1317                 case PC32:
1318                         if (cb->pci->bridge) {
1319                                 Pcidev *pci = cb->pci->bridge;
1320                                 int i;
1321
1322                                 while (pci) {
1323                                         p = seprint(p, e, "%.4uX %.4uX; irq %d\n",
1324                                                           pci->vid, pci->did, pci->intl);
1325                                         for (i = 0; i != Nbars; i++)
1326                                                 if (pci->mem[i].size)
1327                                                         p = seprint(p, e,
1328                                                                           "\tmem[%d] %.8ulX (%.8uX)\n",
1329                                                                           i, pci->mem[i].bar,
1330                                                                           pci->mem[i].size);
1331                                         if (pci->rom.size)
1332                                                 p = seprint(p, e, "\tROM %.8ulX (%.8uX)\n",
1333                                                                   pci->rom.bar, pci->rom.size);
1334                                         pci = pci->list;
1335                                 }
1336                         }
1337                         break;
1338
1339                 case PC16:
1340                         if (cb->state == SlotConfigured) {
1341                                 Pcminfo *pi = &cb->linfo;
1342
1343                                 p = seprint(p, e, "%s port %X; irq %d;\n",
1344                                                   pi->verstr, pi->port,
1345                                                   pi->irq);
1346                                 for (i = 0; i != pi->nctab; i++) {
1347                                         PCMconftab *ct;
1348                                         int j;
1349
1350                                         ct = &pi->ctab[i];
1351                                         p = seprint(p, e,
1352                                                 "\tconfiguration[%d] irqs %.4uX; vpp %d, %d; %s\n",
1353                                                           i, ct->irqs, ct->vpp1, ct->vpp2,
1354                                                           (ct == pi->defctab)? "(default);": "");
1355                                         for (j = 0; j != ct->nio; j++)
1356                                                 if (ct->io[j].len > 0)
1357                                                         p = seprint(p, e, "\t\tio[%d] %.8ulX %uld\n",
1358                                                                           j, ct->io[j].start, ct->io[j].len);
1359                                 }
1360                         }
1361                         break;
1362                 }
1363                 unlock(cb);
1364
1365                 n = readstr(offset, a, n, buf);
1366                 free(buf);
1367                 return n;
1368         }
1369         return 0;
1370 }
1371
1372 static long
1373 pccardwrite(Chan *c, void *v, long n, vlong)
1374 {
1375         Rune r;
1376         ulong n0;
1377         char *device;
1378         Cmdbuf *cbf;
1379         Cmdtab *ct;
1380         Cardbus *cb;
1381
1382         n0 = n;
1383         switch(TYPE(c)){
1384         case Qctl:
1385                 cb = &cbslots[SLOTNO(c)];
1386
1387                 cbf = parsecmd(v, n);
1388                 if(waserror()){
1389                         free(cbf);
1390                         nexterror();
1391                 }
1392                 ct = lookupcmd(cbf, pccardctlmsg, nelem(pccardctlmsg));
1393                 switch(ct->index){
1394                 case CMdown:
1395                         device = cbf->f[1];
1396                         device += chartorune(&r, device);
1397                         if ((n = devno(r, 1)) >= 0 && devtab[n]->config)
1398                                 devtab[n]->config(0, device, nil);
1399                         qengine(cb, CardEjected);
1400                         break;
1401                 case CMpower:
1402                         if ((cb->regs[SocketState] & SS_CCD) == 0)
1403                                 qengine(cb, CardDetected);
1404                         break;
1405                 }
1406                 poperror();
1407                 free(cbf);
1408                 break;
1409         }
1410         return n0 - n;
1411 }
1412
1413 Dev pccarddevtab = {
1414         'Y',
1415         "cardbus",
1416
1417         devreset,
1418         devinit,
1419         devshutdown,
1420         pccardattach,
1421         pccardwalk,
1422         pccardstat,
1423         pccardopen,
1424         devcreate,
1425         pccardclose,
1426         pccardread,
1427         devbread,
1428         pccardwrite,
1429         devbwrite,
1430         devremove,
1431         devwstat,
1432 };
1433
1434 static PCMmap *
1435 isamap(Cardbus *cb, ulong offset, int len, int attr)
1436 {
1437         uchar we, bit;
1438         PCMmap *m, *nm;
1439         Pcminfo *pi;
1440         int i;
1441         ulong e;
1442
1443         pi = &cb->linfo;
1444
1445         /* convert offset to granularity */
1446         if(len <= 0)
1447                 len = 1;
1448         e = ROUND(offset+len, Mgran);
1449         offset &= Mmask;
1450         len = e - offset;
1451
1452         /* look for a map that covers the right area */
1453         we = rdreg(cb, Rwe);
1454         bit = 1;
1455         nm = 0;
1456         for(m = pi->mmap; m < &pi->mmap[nelem(pi->mmap)]; m++){
1457                 if((we & bit))
1458                 if(m->attr == attr)
1459                 if(offset >= m->ca && e <= m->cea){
1460                         m->ref++;
1461                         return m;
1462                 }
1463                 bit <<= 1;
1464                 if(nm == 0 && m->ref == 0)
1465                         nm = m;
1466         }
1467         m = nm;
1468         if(m == 0)
1469                 return 0;
1470
1471         /* if isa space isn't big enough, free it and get more */
1472         if(m->len < len){
1473                 if(m->len){
1474                         umbfree(m->isa, m->len);
1475                         m->len = 0;
1476                 }
1477                 m->isa = umballoc(-1, len, Mgran);
1478                 if(m->isa == -1){
1479                         m->isa = 0;
1480                         print("isamap: out of isa space\n");
1481                         return 0;
1482                 }
1483                 m->len = len;
1484         }
1485
1486         /* set up new map */
1487         m->ca = offset;
1488         m->cea = m->ca + m->len;
1489         m->attr = attr;
1490         i = m - pi->mmap;
1491         bit = 1<<i;
1492         wrreg(cb, Rwe, we & ~bit);              /* disable map before changing it */
1493         wrreg(cb, MAP(i, Mbtmlo), m->isa>>Mshift);
1494         wrreg(cb, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
1495         wrreg(cb, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
1496         wrreg(cb, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
1497         offset -= m->isa;
1498         offset &= (1<<25)-1;
1499         offset >>= Mshift;
1500         wrreg(cb, MAP(i, Mofflo), offset);
1501         wrreg(cb, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
1502         wrreg(cb, Rwe, we | bit);               /* enable map */
1503         m->ref = 1;
1504
1505         return m;
1506 }
1507
1508 static void
1509 isaunmap(PCMmap* m)
1510 {
1511         m->ref--;
1512 }
1513
1514 /*
1515  *  reading and writing card registers
1516  */
1517 static uchar
1518 rdreg(Cardbus *cb, int index)
1519 {
1520         outb(cb->lindex, cb->lbase + index);
1521         return inb(cb->ldata);
1522 }
1523
1524 static void
1525 wrreg(Cardbus *cb, int index, uchar val)
1526 {
1527         outb(cb->lindex, cb->lbase + index);
1528         outb(cb->ldata, val);
1529 }
1530
1531 static int
1532 readc(Cisdat *cis, uchar *x)
1533 {
1534         if(cis->cispos >= cis->cislen)
1535                 return 0;
1536         *x = cis->cisbase[cis->cisskip*cis->cispos];
1537         cis->cispos++;
1538         return 1;
1539 }
1540
1541 static ulong
1542 getlong(Cisdat *cis, int size)
1543 {
1544         uchar c;
1545         int i;
1546         ulong x;
1547
1548         x = 0;
1549         for(i = 0; i < size; i++){
1550                 if(readc(cis, &c) != 1)
1551                         break;
1552                 x |= c<<(i*8);
1553         }
1554         return x;
1555 }
1556
1557 static void
1558 tcfig(Cardbus *cb, Cisdat *cis, int )
1559 {
1560         uchar size, rasize, rmsize;
1561         uchar last;
1562         Pcminfo *pi;
1563
1564         if(readc(cis, &size) != 1)
1565                 return;
1566         rasize = (size&0x3) + 1;
1567         rmsize = ((size>>2)&0xf) + 1;
1568         if(readc(cis, &last) != 1)
1569                 return;
1570
1571         pi = &cb->linfo;
1572         pi->conf_addr = getlong(cis, rasize);
1573         pi->conf_present = getlong(cis, rmsize);
1574 }
1575
1576 static void
1577 tvers1(Cardbus *cb, Cisdat *cis, int )
1578 {
1579         uchar c, major, minor, last;
1580         int  i;
1581         Pcminfo *pi;
1582
1583         pi = &cb->linfo;
1584         if(readc(cis, &major) != 1)
1585                 return;
1586         if(readc(cis, &minor) != 1)
1587                 return;
1588         last = 0;
1589         for(i = 0; i < sizeof(pi->verstr) - 1; i++){
1590                 if(readc(cis, &c) != 1)
1591                         return;
1592                 if(c == 0)
1593                         c = ';';
1594                 if(c == '\n')
1595                         c = ';';
1596                 if(c == 0xff)
1597                         break;
1598                 if(c == ';' && last == ';')
1599                         continue;
1600                 pi->verstr[i] = c;
1601                 last = c;
1602         }
1603         pi->verstr[i] = 0;
1604 }
1605
1606 static ulong
1607 microvolt(Cisdat *cis)
1608 {
1609         uchar c;
1610         ulong microvolts;
1611         ulong exp;
1612
1613         if(readc(cis, &c) != 1)
1614                 return 0;
1615         exp = exponent[c&0x7];
1616         microvolts = vmant[(c>>3)&0xf]*exp;
1617         while(c & 0x80){
1618                 if(readc(cis, &c) != 1)
1619                         return 0;
1620                 switch(c){
1621                 case 0x7d:
1622                         break;          /* high impedence when sleeping */
1623                 case 0x7e:
1624                 case 0x7f:
1625                         microvolts = 0; /* no connection */
1626                         break;
1627                 default:
1628                         exp /= 10;
1629                         microvolts += exp*(c&0x7f);
1630                 }
1631         }
1632         return microvolts;
1633 }
1634
1635 static ulong
1636 nanoamps(Cisdat *cis)
1637 {
1638         uchar c;
1639         ulong nanoamps;
1640
1641         if(readc(cis, &c) != 1)
1642                 return 0;
1643         nanoamps = exponent[c&0x7]*vmant[(c>>3)&0xf];
1644         while(c & 0x80){
1645                 if(readc(cis, &c) != 1)
1646                         return 0;
1647                 if(c == 0x7d || c == 0x7e || c == 0x7f)
1648                         nanoamps = 0;
1649         }
1650         return nanoamps;
1651 }
1652
1653 /*
1654  * only nominal voltage (feature 1) is important for config,
1655  * other features must read card to stay in sync.
1656  */
1657 static ulong
1658 power(Cisdat *cis)
1659 {
1660         uchar feature;
1661         ulong mv;
1662
1663         mv = 0;
1664         if(readc(cis, &feature) != 1)
1665                 return 0;
1666         if(feature & 1)
1667                 mv = microvolt(cis);
1668         if(feature & 2)
1669                 microvolt(cis);
1670         if(feature & 4)
1671                 microvolt(cis);
1672         if(feature & 8)
1673                 nanoamps(cis);
1674         if(feature & 0x10)
1675                 nanoamps(cis);
1676         if(feature & 0x20)
1677                 nanoamps(cis);
1678         if(feature & 0x40)
1679                 nanoamps(cis);
1680         return mv/1000000;
1681 }
1682
1683 static ulong
1684 ttiming(Cisdat *cis, int scale)
1685 {
1686         uchar unscaled;
1687         ulong nanosecs;
1688
1689         if(readc(cis, &unscaled) != 1)
1690                 return 0;
1691         nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
1692         nanosecs = nanosecs * exponent[scale];
1693         return nanosecs;
1694 }
1695
1696 static void
1697 timing(Cisdat *cis, PCMconftab *ct)
1698 {
1699         uchar c, i;
1700
1701         if(readc(cis, &c) != 1)
1702                 return;
1703         i = c&0x3;
1704         if(i != 3)
1705                 ct->maxwait = ttiming(cis, i);          /* max wait */
1706         i = (c>>2)&0x7;
1707         if(i != 7)
1708                 ct->readywait = ttiming(cis, i);        /* max ready/busy wait */
1709         i = (c>>5)&0x7;
1710         if(i != 7)
1711                 ct->otherwait = ttiming(cis, i);        /* reserved wait */
1712 }
1713
1714 static void
1715 iospaces(Cisdat *cis, PCMconftab *ct)
1716 {
1717         uchar c;
1718         int i, nio;
1719
1720         ct->nio = 0;
1721         if(readc(cis, &c) != 1)
1722                 return;
1723
1724         ct->bit16 = ((c>>5)&3) >= 2;
1725         if(!(c & 0x80)){
1726                 ct->io[0].start = 0;
1727                 ct->io[0].len = 1<<(c&0x1f);
1728                 ct->nio = 1;
1729                 return;
1730         }
1731
1732         if(readc(cis, &c) != 1)
1733                 return;
1734
1735         /*
1736          * For each of the range descriptions read the
1737          * start address and the length (value is length-1).
1738          */
1739         nio = (c&0xf)+1;
1740         for(i = 0; i < nio; i++){
1741                 ct->io[i].start = getlong(cis, (c>>4)&0x3);
1742                 ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
1743         }
1744         ct->nio = nio;
1745 }
1746
1747 static void
1748 irq(Cisdat *cis, PCMconftab *ct)
1749 {
1750         uchar c;
1751
1752         if(readc(cis, &c) != 1)
1753                 return;
1754         ct->irqtype = c & 0xe0;
1755         if(c & 0x10)
1756                 ct->irqs = getlong(cis, 2);
1757         else
1758                 ct->irqs = 1<<(c&0xf);
1759         ct->irqs &= 0xDEB8;             /* levels available to card */
1760 }
1761
1762 static void
1763 memspace(Cisdat *cis, int asize, int lsize, int host)
1764 {
1765         ulong haddress, address, len;
1766
1767         len = getlong(cis, lsize)*256;
1768         address = getlong(cis, asize)*256;
1769         USED(len, address);
1770         if(host){
1771                 haddress = getlong(cis, asize)*256;
1772                 USED(haddress);
1773         }
1774 }
1775
1776 static void
1777 tentry(Cardbus *cb, Cisdat *cis, int )
1778 {
1779         uchar c, i, feature;
1780         PCMconftab *ct;
1781         Pcminfo *pi;
1782
1783         pi = &cb->linfo;
1784         if(pi->nctab >= nelem(pi->ctab))
1785                 return;
1786         if(readc(cis, &c) != 1)
1787                 return;
1788         ct = &pi->ctab[pi->nctab++];
1789
1790         /* copy from last default config */
1791         if(pi->defctab)
1792                 *ct = *pi->defctab;
1793
1794         ct->index = c & 0x3f;
1795
1796         /* is this the new default? */
1797         if(c & 0x40)
1798                 pi->defctab = ct;
1799
1800         /* memory wait specified? */
1801         if(c & 0x80){
1802                 if(readc(cis, &i) != 1)
1803                         return;
1804                 if(i&0x80)
1805                         ct->memwait = 1;
1806         }
1807
1808         if(readc(cis, &feature) != 1)
1809                 return;
1810         switch(feature&0x3){
1811         case 1:
1812                 ct->vpp1 = ct->vpp2 = power(cis);
1813                 break;
1814         case 2:
1815                 power(cis);
1816                 ct->vpp1 = ct->vpp2 = power(cis);
1817                 break;
1818         case 3:
1819                 power(cis);
1820                 ct->vpp1 = power(cis);
1821                 ct->vpp2 = power(cis);
1822                 break;
1823         default:
1824                 break;
1825         }
1826         if(feature&0x4)
1827                 timing(cis, ct);
1828         if(feature&0x8)
1829                 iospaces(cis, ct);
1830         if(feature&0x10)
1831                 irq(cis, ct);
1832         switch((feature>>5)&0x3){
1833         case 1:
1834                 memspace(cis, 0, 2, 0);
1835                 break;
1836         case 2:
1837                 memspace(cis, 2, 2, 0);
1838                 break;
1839         case 3:
1840                 if(readc(cis, &c) != 1)
1841                         return;
1842                 for(i = 0; i <= (c&0x7); i++)
1843                         memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
1844                 break;
1845         }
1846 }
1847
1848 static void
1849 i82365probe(Cardbus *cb, int lindex, int ldata)
1850 {
1851         uchar c, id;
1852         int dev = 0;    /* According to the Ricoh spec 00->3F _and_ 80->BF seem
1853                                      to be the same socket A (ditto for B). */
1854
1855         outb(lindex, Rid + (dev<<7));
1856         id = inb(ldata);
1857         if((id & 0xf0) != 0x80)
1858                 return;         /* not a memory & I/O card */
1859         if((id & 0x0f) == 0x00)
1860                 return;         /* no revision number, not possible */
1861
1862         cb->lindex = lindex;
1863         cb->ldata = ldata;
1864         cb->ltype = Ti82365;
1865         cb->lbase = (int)(cb - cbslots) * 0x40;
1866
1867         switch(id){
1868         case 0x82:
1869         case 0x83:
1870         case 0x84:
1871                 /* could be a cirrus */
1872                 outb(cb->lindex, Rchipinfo + (dev<<7));
1873                 outb(cb->ldata, 0);
1874                 c = inb(cb->ldata);
1875                 if((c & 0xc0) != 0xc0)
1876                         break;
1877                 c = inb(cb->ldata);
1878                 if((c & 0xc0) != 0x00)
1879                         break;
1880                 if(c & 0x20){
1881                         cb->ltype = Tpd6720;
1882                 } else {
1883                         cb->ltype = Tpd6710;
1884                 }
1885
1886                 /* low power mode */
1887                 outb(cb->lindex, Rmisc2 + (dev<<7));
1888                 c = inb(cb->ldata);
1889                 outb(cb->ldata, c & ~Flowpow);
1890                 break;
1891                 break;
1892         }
1893
1894         /* if it's not a Cirrus, it could be a Vadem... */
1895         if(cb->ltype == Ti82365){
1896                 /* unlock the Vadem extended regs */
1897                 outb(cb->lindex, 0x0E + (dev<<7));
1898                 outb(cb->lindex, 0x37 + (dev<<7));
1899
1900                 /* make the id register show the Vadem id */
1901                 outb(cb->lindex, 0x3A + (dev<<7));
1902                 c = inb(cb->ldata);
1903                 outb(cb->ldata, c|0xC0);
1904                 outb(cb->lindex, Rid + (dev<<7));
1905                 c = inb(cb->ldata);
1906                 if(c & 0x08)
1907                         cb->ltype = Tvg46x;
1908
1909                 /* go back to Intel compatible id */
1910                 outb(cb->lindex, 0x3A + (dev<<7));
1911                 c = inb(cb->ldata);
1912                 outb(cb->ldata, c & ~0xC0);
1913         }
1914 }
1915
1916 static int
1917 vcode(int volt)
1918 {
1919         switch(volt){
1920         case 5:
1921                 return 1;
1922         case 12:
1923                 return 2;
1924         default:
1925                 return 0;
1926         }
1927 }