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