19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier cardbus and pcmcia (grmph) support.
39a747e4fSDavid du Colombier */
49a747e4fSDavid du Colombier #include "u.h"
59a747e4fSDavid du Colombier #include "../port/lib.h"
69a747e4fSDavid du Colombier #include "mem.h"
79a747e4fSDavid du Colombier #include "dat.h"
89a747e4fSDavid du Colombier #include "fns.h"
99a747e4fSDavid du Colombier #include "../port/error.h"
109a747e4fSDavid du Colombier #include "io.h"
119a747e4fSDavid du Colombier
1264c7f6b6SDavid du Colombier #define DEBUG 0
1364c7f6b6SDavid du Colombier
14c91329d7SDavid du Colombier #pragma varargck type "T" int
15c91329d7SDavid du Colombier
169a747e4fSDavid du Colombier #define MAP(x,o) (Rmap + (x)*0x8 + o)
179a747e4fSDavid du Colombier
189a747e4fSDavid du Colombier enum {
199a747e4fSDavid du Colombier TI_vid = 0x104c,
209a747e4fSDavid du Colombier TI_1131_did = 0xAC15,
219a747e4fSDavid du Colombier TI_1250_did = 0xAC16,
229a747e4fSDavid du Colombier TI_1450_did = 0xAC1B,
239a747e4fSDavid du Colombier TI_1251A_did = 0xAC1D,
24d9306527SDavid du Colombier TI_1420_did = 0xAC51,
259a747e4fSDavid du Colombier
269a747e4fSDavid du Colombier Ricoh_vid = 0x1180,
27375daca8SDavid du Colombier Ricoh_475_did = 0x0475,
289a747e4fSDavid du Colombier Ricoh_476_did = 0x0476,
299a747e4fSDavid du Colombier Ricoh_478_did = 0x0478,
309a747e4fSDavid du Colombier
31ff1040beSDavid du Colombier O2_vid = 0x1217,
32ff1040beSDavid du Colombier O2_OZ711M3_did = 0x7134,
33ff1040beSDavid du Colombier
349a747e4fSDavid du Colombier Nslots = 4, /* Maximum number of CardBus slots to use */
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier K = 1024,
379a747e4fSDavid du Colombier M = K * K,
389a747e4fSDavid du Colombier
399a747e4fSDavid du Colombier LegacyAddr = 0x3e0,
409a747e4fSDavid du Colombier NUMEVENTS = 10,
419a747e4fSDavid du Colombier
4241dd6b47SDavid du Colombier TI1131xSC = 0x80, /* system control */
439a747e4fSDavid du Colombier TI122X_SC_INTRTIE = 1 << 29,
4441dd6b47SDavid du Colombier TI12xxIM = 0x8c, /* */
4541dd6b47SDavid du Colombier TI1131xCC = 0x91, /* card control */
469a747e4fSDavid du Colombier TI113X_CC_RIENB = 1 << 7,
479a747e4fSDavid du Colombier TI113X_CC_ZVENABLE = 1 << 6,
489a747e4fSDavid du Colombier TI113X_CC_PCI_IRQ_ENA = 1 << 5,
499a747e4fSDavid du Colombier TI113X_CC_PCI_IREQ = 1 << 4,
509a747e4fSDavid du Colombier TI113X_CC_PCI_CSC = 1 << 3,
519a747e4fSDavid du Colombier TI113X_CC_SPKROUTEN = 1 << 1,
529a747e4fSDavid du Colombier TI113X_CC_IFG = 1 << 0,
5341dd6b47SDavid du Colombier TI1131xDC = 0x92, /* device control */
549a747e4fSDavid du Colombier };
559a747e4fSDavid du Colombier
5659c21d95SDavid du Colombier typedef struct Variant Variant;
5759c21d95SDavid du Colombier struct Variant {
5859c21d95SDavid du Colombier ushort vid;
5959c21d95SDavid du Colombier ushort did;
6059c21d95SDavid du Colombier char *name;
6159c21d95SDavid du Colombier };
629a747e4fSDavid du Colombier
639a747e4fSDavid du Colombier static Variant variant[] = {
64375daca8SDavid du Colombier { Ricoh_vid, Ricoh_475_did, "Ricoh 475 PCI/Cardbus bridge", },
659a747e4fSDavid du Colombier { Ricoh_vid, Ricoh_476_did, "Ricoh 476 PCI/Cardbus bridge", },
669a747e4fSDavid du Colombier { Ricoh_vid, Ricoh_478_did, "Ricoh 478 PCI/Cardbus bridge", },
679a747e4fSDavid du Colombier { TI_vid, TI_1131_did, "TI PCI-1131 Cardbus Controller", },
689a747e4fSDavid du Colombier { TI_vid, TI_1250_did, "TI PCI-1250 Cardbus Controller", },
699a747e4fSDavid du Colombier { TI_vid, TI_1450_did, "TI PCI-1450 Cardbus Controller", },
709a747e4fSDavid du Colombier { TI_vid, TI_1251A_did, "TI PCI-1251A Cardbus Controller", },
71d9306527SDavid du Colombier { TI_vid, TI_1420_did, "TI PCI-1420 Cardbus Controller", },
72ff1040beSDavid du Colombier { O2_vid, O2_OZ711M3_did, "O2Micro OZ711M3 MemoryCardBus", },
739a747e4fSDavid du Colombier };
749a747e4fSDavid du Colombier
759a747e4fSDavid du Colombier /* Cardbus registers */
769a747e4fSDavid du Colombier enum {
779a747e4fSDavid du Colombier SocketEvent = 0,
789a747e4fSDavid du Colombier SE_CCD = 3 << 1,
799a747e4fSDavid du Colombier SE_POWER = 1 << 3,
809a747e4fSDavid du Colombier SocketMask = 1,
819a747e4fSDavid du Colombier SocketState = 2,
829a747e4fSDavid du Colombier SS_CCD = 3 << 1,
839a747e4fSDavid du Colombier SS_POWER = 1 << 3,
849a747e4fSDavid du Colombier SS_PC16 = 1 << 4,
859a747e4fSDavid du Colombier SS_CBC = 1 << 5,
869a747e4fSDavid du Colombier SS_NOTCARD = 1 << 7,
879a747e4fSDavid du Colombier SS_BADVCC = 1 << 9,
889a747e4fSDavid du Colombier SS_5V = 1 << 10,
899a747e4fSDavid du Colombier SS_3V = 1 << 11,
909a747e4fSDavid du Colombier SocketForce = 3,
919a747e4fSDavid du Colombier SocketControl = 4,
929a747e4fSDavid du Colombier SC_5V = 0x22,
939a747e4fSDavid du Colombier SC_3V = 0x33,
949a747e4fSDavid du Colombier };
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier enum {
979a747e4fSDavid du Colombier PciPCR_IO = 1 << 0,
989a747e4fSDavid du Colombier PciPCR_MEM = 1 << 1,
999a747e4fSDavid du Colombier PciPCR_Master = 1 << 2,
1009a747e4fSDavid du Colombier
101d9306527SDavid du Colombier PciPMC = 0xa4,
102d9306527SDavid du Colombier
1039a747e4fSDavid du Colombier Nbars = 6,
1049a747e4fSDavid du Colombier Ncmd = 10,
1059a747e4fSDavid du Colombier CBIRQ = 9,
1069a747e4fSDavid du Colombier
1079a747e4fSDavid du Colombier PC16,
1089a747e4fSDavid du Colombier PC32,
1099a747e4fSDavid du Colombier };
1109a747e4fSDavid du Colombier
1119a747e4fSDavid du Colombier enum {
1129a747e4fSDavid du Colombier Ti82365,
1139a747e4fSDavid du Colombier Tpd6710,
1149a747e4fSDavid du Colombier Tpd6720,
1159a747e4fSDavid du Colombier Tvg46x,
1169a747e4fSDavid du Colombier };
1179a747e4fSDavid du Colombier
1189a747e4fSDavid du Colombier /*
1199a747e4fSDavid du Colombier * Intel 82365SL PCIC controller for the PCMCIA or
1209a747e4fSDavid du Colombier * Cirrus Logic PD6710/PD6720 which is mostly register compatible
1219a747e4fSDavid du Colombier */
1229a747e4fSDavid du Colombier enum
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier /*
1259a747e4fSDavid du Colombier * registers indices
1269a747e4fSDavid du Colombier */
1279a747e4fSDavid du Colombier Rid= 0x0, /* identification and revision */
1289a747e4fSDavid du Colombier Ris= 0x1, /* interface status */
1299a747e4fSDavid du Colombier Rpc= 0x2, /* power control */
1309a747e4fSDavid du Colombier Foutena= (1<<7), /* output enable */
1319a747e4fSDavid du Colombier Fautopower= (1<<5), /* automatic power switching */
1329a747e4fSDavid du Colombier Fcardena= (1<<4), /* PC card enable */
1339a747e4fSDavid du Colombier Rigc= 0x3, /* interrupt and general control */
1349a747e4fSDavid du Colombier Fiocard= (1<<5), /* I/O card (vs memory) */
1359a747e4fSDavid du Colombier Fnotreset= (1<<6), /* reset if not set */
1369a747e4fSDavid du Colombier FSMIena= (1<<4), /* enable change interrupt on SMI */
1379a747e4fSDavid du Colombier Rcsc= 0x4, /* card status change */
1389a747e4fSDavid du Colombier Rcscic= 0x5, /* card status change interrupt config */
1399a747e4fSDavid du Colombier Fchangeena= (1<<3), /* card changed */
1409a747e4fSDavid du Colombier Fbwarnena= (1<<1), /* card battery warning */
1419a747e4fSDavid du Colombier Fbdeadena= (1<<0), /* card battery dead */
1429a747e4fSDavid du Colombier Rwe= 0x6, /* address window enable */
1439a747e4fSDavid du Colombier Fmem16= (1<<5), /* use A23-A12 to decode address */
1449a747e4fSDavid du Colombier Rio= 0x7, /* I/O control */
1459a747e4fSDavid du Colombier Fwidth16= (1<<0), /* 16 bit data width */
1469a747e4fSDavid du Colombier Fiocs16= (1<<1), /* IOCS16 determines data width */
1479a747e4fSDavid du Colombier Fzerows= (1<<2), /* zero wait state */
1489a747e4fSDavid du Colombier Ftiming= (1<<3), /* timing register to use */
1499a747e4fSDavid du Colombier Riobtm0lo= 0x8, /* I/O address 0 start low byte */
1509a747e4fSDavid du Colombier Riobtm0hi= 0x9, /* I/O address 0 start high byte */
1519a747e4fSDavid du Colombier Riotop0lo= 0xa, /* I/O address 0 stop low byte */
1529a747e4fSDavid du Colombier Riotop0hi= 0xb, /* I/O address 0 stop high byte */
1539a747e4fSDavid du Colombier Riobtm1lo= 0xc, /* I/O address 1 start low byte */
1549a747e4fSDavid du Colombier Riobtm1hi= 0xd, /* I/O address 1 start high byte */
1559a747e4fSDavid du Colombier Riotop1lo= 0xe, /* I/O address 1 stop low byte */
1569a747e4fSDavid du Colombier Riotop1hi= 0xf, /* I/O address 1 stop high byte */
1579a747e4fSDavid du Colombier Rmap= 0x10, /* map 0 */
1589a747e4fSDavid du Colombier
1599a747e4fSDavid du Colombier /*
1609a747e4fSDavid du Colombier * CL-PD67xx extension registers
1619a747e4fSDavid du Colombier */
1629a747e4fSDavid du Colombier Rmisc1= 0x16, /* misc control 1 */
1639a747e4fSDavid du Colombier F5Vdetect= (1<<0),
1649a747e4fSDavid du Colombier Fvcc3V= (1<<1),
1659a747e4fSDavid du Colombier Fpmint= (1<<2),
1669a747e4fSDavid du Colombier Fpsirq= (1<<3),
1679a747e4fSDavid du Colombier Fspeaker= (1<<4),
1689a747e4fSDavid du Colombier Finpack= (1<<7),
1699a747e4fSDavid du Colombier Rfifo= 0x17, /* fifo control */
1709a747e4fSDavid du Colombier Fflush= (1<<7), /* flush fifo */
1719a747e4fSDavid du Colombier Rmisc2= 0x1E, /* misc control 2 */
1729a747e4fSDavid du Colombier Flowpow= (1<<1), /* low power mode */
1739a747e4fSDavid du Colombier Rchipinfo= 0x1F, /* chip information */
1749a747e4fSDavid du Colombier Ratactl= 0x26, /* ATA control */
1759a747e4fSDavid du Colombier
1769a747e4fSDavid du Colombier /*
1779a747e4fSDavid du Colombier * offsets into the system memory address maps
1789a747e4fSDavid du Colombier */
1799a747e4fSDavid du Colombier Mbtmlo= 0x0, /* System mem addr mapping start low byte */
1809a747e4fSDavid du Colombier Mbtmhi= 0x1, /* System mem addr mapping start high byte */
1819a747e4fSDavid du Colombier F16bit= (1<<7), /* 16-bit wide data path */
1829a747e4fSDavid du Colombier Mtoplo= 0x2, /* System mem addr mapping stop low byte */
1839a747e4fSDavid du Colombier Mtophi= 0x3, /* System mem addr mapping stop high byte */
1849a747e4fSDavid du Colombier Ftimer1= (1<<6), /* timer set 1 */
1859a747e4fSDavid du Colombier Mofflo= 0x4, /* Card memory offset address low byte */
1869a747e4fSDavid du Colombier Moffhi= 0x5, /* Card memory offset address high byte */
1879a747e4fSDavid du Colombier Fregactive= (1<<6), /* attribute memory */
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier /*
1909a747e4fSDavid du Colombier * configuration registers - they start at an offset in attribute
1919a747e4fSDavid du Colombier * memory found in the CIS.
1929a747e4fSDavid du Colombier */
1939a747e4fSDavid du Colombier Rconfig= 0,
1949a747e4fSDavid du Colombier Creset= (1<<7), /* reset device */
1959a747e4fSDavid du Colombier Clevel= (1<<6), /* level sensitive interrupt line */
1969a747e4fSDavid du Colombier };
1979a747e4fSDavid du Colombier
1989a747e4fSDavid du Colombier /*
1999a747e4fSDavid du Colombier * read and crack the card information structure enough to set
2009a747e4fSDavid du Colombier * important parameters like power
2019a747e4fSDavid du Colombier */
2029a747e4fSDavid du Colombier /* cis memory walking */
20359c21d95SDavid du Colombier typedef struct Cisdat Cisdat;
20459c21d95SDavid du Colombier struct Cisdat {
2059a747e4fSDavid du Colombier uchar *cisbase;
2069a747e4fSDavid du Colombier int cispos;
2079a747e4fSDavid du Colombier int cisskip;
2089a747e4fSDavid du Colombier int cislen;
20959c21d95SDavid du Colombier };
2109a747e4fSDavid du Colombier
21159c21d95SDavid du Colombier typedef struct Pcminfo Pcminfo;
21259c21d95SDavid du Colombier struct Pcminfo {
2139a747e4fSDavid du Colombier char verstr[512]; /* Version string */
2149a747e4fSDavid du Colombier PCMmap mmap[4]; /* maps, last is always for the kernel */
2159a747e4fSDavid du Colombier ulong conf_addr; /* Config address */
2169a747e4fSDavid du Colombier uchar conf_present; /* Config register present */
2179a747e4fSDavid du Colombier int nctab; /* In use configuration tables */
2189a747e4fSDavid du Colombier PCMconftab ctab[8]; /* Configuration tables */
2199a747e4fSDavid du Colombier PCMconftab *defctab; /* Default conftab */
2209a747e4fSDavid du Colombier
2219a747e4fSDavid du Colombier int port; /* Actual port usage */
2229a747e4fSDavid du Colombier int irq; /* Actual IRQ usage */
22359c21d95SDavid du Colombier };
2249a747e4fSDavid du Colombier
22559c21d95SDavid du Colombier typedef struct Cardbus Cardbus;
22659c21d95SDavid du Colombier struct Cardbus {
2273ff48bf5SDavid du Colombier Lock;
2289a747e4fSDavid du Colombier Variant *variant; /* Which CardBus chipset */
2299a747e4fSDavid du Colombier Pcidev *pci; /* The bridge itself */
2309a747e4fSDavid du Colombier ulong *regs; /* Cardbus registers */
2319a747e4fSDavid du Colombier int ltype; /* Legacy type */
2329a747e4fSDavid du Colombier int lindex; /* Legacy port index address */
2339a747e4fSDavid du Colombier int ldata; /* Legacy port data address */
2349a747e4fSDavid du Colombier int lbase; /* Base register for this socket */
2359a747e4fSDavid du Colombier
2369a747e4fSDavid du Colombier int state; /* Current state of card */
2379a747e4fSDavid du Colombier int type; /* Type of card */
2389a747e4fSDavid du Colombier Pcminfo linfo; /* PCMCIA slot info */
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier int special; /* card is allocated to a driver */
2419a747e4fSDavid du Colombier
2429a747e4fSDavid du Colombier int refs; /* Number of refs to slot */
2433ff48bf5SDavid du Colombier Lock refslock; /* inc/dev ref lock */
24459c21d95SDavid du Colombier };
2459a747e4fSDavid du Colombier
2469a747e4fSDavid du Colombier static int managerstarted;
2479a747e4fSDavid du Colombier
2489a747e4fSDavid du Colombier enum {
2499a747e4fSDavid du Colombier Mshift= 12,
2509a747e4fSDavid du Colombier Mgran= (1<<Mshift), /* granularity of maps */
2519a747e4fSDavid du Colombier Mmask= ~(Mgran-1), /* mask for address bits important to the chip */
2529a747e4fSDavid du Colombier };
2539a747e4fSDavid du Colombier
2549a747e4fSDavid du Colombier static Cardbus cbslots[Nslots];
2559a747e4fSDavid du Colombier static int nslots;
2569a747e4fSDavid du Colombier
2579a747e4fSDavid du Colombier static ulong exponent[8] = {
2589a747e4fSDavid du Colombier 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
2599a747e4fSDavid du Colombier };
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier static ulong vmant[16] = {
2629a747e4fSDavid du Colombier 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
2639a747e4fSDavid du Colombier };
2649a747e4fSDavid du Colombier
2659a747e4fSDavid du Colombier static ulong mantissa[16] = {
2669a747e4fSDavid du Colombier 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80,
2679a747e4fSDavid du Colombier };
2689a747e4fSDavid du Colombier
2699a747e4fSDavid du Colombier static char Enocard[] = "No card in slot";
2709a747e4fSDavid du Colombier
2719a747e4fSDavid du Colombier enum
2729a747e4fSDavid du Colombier {
2739a747e4fSDavid du Colombier CMdown,
2749a747e4fSDavid du Colombier CMpower,
2759a747e4fSDavid du Colombier };
2769a747e4fSDavid du Colombier
2779a747e4fSDavid du Colombier static Cmdtab pccardctlmsg[] =
2789a747e4fSDavid du Colombier {
2799a747e4fSDavid du Colombier CMdown, "down", 2,
2809a747e4fSDavid du Colombier CMpower, "power", 1,
2819a747e4fSDavid du Colombier };
2829a747e4fSDavid du Colombier
2839a747e4fSDavid du Colombier static int powerup(Cardbus *);
2849a747e4fSDavid du Colombier static void configure(Cardbus *);
2859a747e4fSDavid du Colombier static void powerdown(Cardbus *cb);
2869a747e4fSDavid du Colombier static void unconfigure(Cardbus *cb);
2879a747e4fSDavid du Colombier
2889a747e4fSDavid du Colombier static void i82365probe(Cardbus *cb, int lindex, int ldata);
2899a747e4fSDavid du Colombier static void i82365configure(Cardbus *cb);
2909a747e4fSDavid du Colombier static PCMmap *isamap(Cardbus *cb, ulong offset, int len, int attr);
2919a747e4fSDavid du Colombier static void isaunmap(PCMmap* m);
2929a747e4fSDavid du Colombier static uchar rdreg(Cardbus *cb, int index);
2939a747e4fSDavid du Colombier static void wrreg(Cardbus *cb, int index, uchar val);
2949a747e4fSDavid du Colombier static int readc(Cisdat *cis, uchar *x);
2959a747e4fSDavid du Colombier static void tvers1(Cardbus *cb, Cisdat *cis, int );
2969a747e4fSDavid du Colombier static void tcfig(Cardbus *cb, Cisdat *cis, int );
2979a747e4fSDavid du Colombier static void tentry(Cardbus *cb, Cisdat *cis, int );
2989a747e4fSDavid du Colombier static int vcode(int volt);
2999a747e4fSDavid du Colombier static int pccard_pcmspecial(char *idstr, ISAConf *isa);
3009a747e4fSDavid du Colombier static void pccard_pcmspecialclose(int slotno);
3019a747e4fSDavid du Colombier
3029a747e4fSDavid du Colombier enum {
3039a747e4fSDavid du Colombier CardDetected,
3049a747e4fSDavid du Colombier CardPowered,
3059a747e4fSDavid du Colombier CardEjected,
3069a747e4fSDavid du Colombier CardConfigured,
3079a747e4fSDavid du Colombier };
3089a747e4fSDavid du Colombier
3099a747e4fSDavid du Colombier static char *messages[] = {
3109a747e4fSDavid du Colombier [CardDetected] "CardDetected",
3119a747e4fSDavid du Colombier [CardPowered] "CardPowered",
3129a747e4fSDavid du Colombier [CardEjected] "CardEjected",
3139a747e4fSDavid du Colombier [CardConfigured] "CardConfigured",
3149a747e4fSDavid du Colombier };
3159a747e4fSDavid du Colombier
3169a747e4fSDavid du Colombier enum {
3179a747e4fSDavid du Colombier SlotEmpty,
3189a747e4fSDavid du Colombier SlotFull,
3199a747e4fSDavid du Colombier SlotPowered,
3209a747e4fSDavid du Colombier SlotConfigured,
3219a747e4fSDavid du Colombier };
3229a747e4fSDavid du Colombier
3239a747e4fSDavid du Colombier static char *states[] = {
3249a747e4fSDavid du Colombier [SlotEmpty] "SlotEmpty",
3259a747e4fSDavid du Colombier [SlotFull] "SlotFull",
3269a747e4fSDavid du Colombier [SlotPowered] "SlotPowered",
3279a747e4fSDavid du Colombier [SlotConfigured] "SlotConfigured",
3289a747e4fSDavid du Colombier };
3299a747e4fSDavid du Colombier
3309a747e4fSDavid du Colombier static void
engine(Cardbus * cb,int message)3319a747e4fSDavid du Colombier engine(Cardbus *cb, int message)
3329a747e4fSDavid du Colombier {
33364c7f6b6SDavid du Colombier if(DEBUG)
33464c7f6b6SDavid du Colombier print("engine(%ld): %s(%s)\n", cb - cbslots,
33564c7f6b6SDavid du Colombier states[cb->state], messages[message]);
3369a747e4fSDavid du Colombier switch (cb->state) {
3379a747e4fSDavid du Colombier case SlotEmpty:
3389a747e4fSDavid du Colombier
3399a747e4fSDavid du Colombier switch (message) {
3409a747e4fSDavid du Colombier case CardDetected:
3419a747e4fSDavid du Colombier cb->state = SlotFull;
3429a747e4fSDavid du Colombier powerup(cb);
3439a747e4fSDavid du Colombier break;
3449a747e4fSDavid du Colombier case CardEjected:
3459a747e4fSDavid du Colombier break;
3469a747e4fSDavid du Colombier default:
34764c7f6b6SDavid du Colombier if(DEBUG)
34864c7f6b6SDavid du Colombier print("#Y%ld: Invalid message %s in SlotEmpty state\n",
34964c7f6b6SDavid du Colombier cb - cbslots, messages[message]);
3509a747e4fSDavid du Colombier break;
3519a747e4fSDavid du Colombier }
3529a747e4fSDavid du Colombier break;
3539a747e4fSDavid du Colombier
3549a747e4fSDavid du Colombier case SlotFull:
3559a747e4fSDavid du Colombier
3569a747e4fSDavid du Colombier switch (message) {
3579a747e4fSDavid du Colombier case CardPowered:
3589a747e4fSDavid du Colombier cb->state = SlotPowered;
3599a747e4fSDavid du Colombier configure(cb);
3609a747e4fSDavid du Colombier break;
3619a747e4fSDavid du Colombier case CardEjected:
3629a747e4fSDavid du Colombier cb->state = SlotEmpty;
3639a747e4fSDavid du Colombier powerdown(cb);
3649a747e4fSDavid du Colombier break;
3659a747e4fSDavid du Colombier default:
36664c7f6b6SDavid du Colombier if(DEBUG)
36764c7f6b6SDavid du Colombier print("#Y%ld: Invalid message %s in SlotFull state\n",
36864c7f6b6SDavid du Colombier cb - cbslots, messages[message]);
3699a747e4fSDavid du Colombier break;
3709a747e4fSDavid du Colombier }
3719a747e4fSDavid du Colombier break;
3729a747e4fSDavid du Colombier
3739a747e4fSDavid du Colombier case SlotPowered:
3749a747e4fSDavid du Colombier
3759a747e4fSDavid du Colombier switch (message) {
3769a747e4fSDavid du Colombier case CardConfigured:
3779a747e4fSDavid du Colombier cb->state = SlotConfigured;
3789a747e4fSDavid du Colombier break;
3799a747e4fSDavid du Colombier case CardEjected:
3809a747e4fSDavid du Colombier cb->state = SlotEmpty;
3819a747e4fSDavid du Colombier unconfigure(cb);
3829a747e4fSDavid du Colombier powerdown(cb);
3839a747e4fSDavid du Colombier break;
3849a747e4fSDavid du Colombier default:
38564c7f6b6SDavid du Colombier print("#Y%ld: Invalid message %s in SlotPowered state\n",
38664c7f6b6SDavid du Colombier cb - cbslots, messages[message]);
3879a747e4fSDavid du Colombier break;
3889a747e4fSDavid du Colombier }
3899a747e4fSDavid du Colombier break;
3909a747e4fSDavid du Colombier
3919a747e4fSDavid du Colombier case SlotConfigured:
3929a747e4fSDavid du Colombier
3939a747e4fSDavid du Colombier switch (message) {
3949a747e4fSDavid du Colombier case CardEjected:
3959a747e4fSDavid du Colombier cb->state = SlotEmpty;
3969a747e4fSDavid du Colombier unconfigure(cb);
3979a747e4fSDavid du Colombier powerdown(cb);
3989a747e4fSDavid du Colombier break;
3999a747e4fSDavid du Colombier default:
40064c7f6b6SDavid du Colombier if(DEBUG)
40164c7f6b6SDavid du Colombier print("#Y%ld: Invalid message %s in SlotConfigured state\n",
40264c7f6b6SDavid du Colombier cb - cbslots, messages[message]);
4039a747e4fSDavid du Colombier break;
4049a747e4fSDavid du Colombier }
4059a747e4fSDavid du Colombier break;
4069a747e4fSDavid du Colombier }
4079a747e4fSDavid du Colombier }
4089a747e4fSDavid du Colombier
4099a747e4fSDavid du Colombier static void
qengine(Cardbus * cb,int message)4109a747e4fSDavid du Colombier qengine(Cardbus *cb, int message)
4119a747e4fSDavid du Colombier {
4123ff48bf5SDavid du Colombier lock(cb);
4139a747e4fSDavid du Colombier engine(cb, message);
4143ff48bf5SDavid du Colombier unlock(cb);
4159a747e4fSDavid du Colombier }
4169a747e4fSDavid du Colombier
41759c21d95SDavid du Colombier typedef struct Events Events;
41859c21d95SDavid du Colombier struct Events {
41959c21d95SDavid du Colombier Cardbus *cb;
42059c21d95SDavid du Colombier int message;
42159c21d95SDavid du Colombier };
4229a747e4fSDavid du Colombier
4239a747e4fSDavid du Colombier static Lock levents;
42459c21d95SDavid du Colombier static Events events[NUMEVENTS];
4259a747e4fSDavid du Colombier static Rendez revents;
4269a747e4fSDavid du Colombier static int nevents;
4279a747e4fSDavid du Colombier
4289a747e4fSDavid du Colombier static void
iengine(Cardbus * cb,int message)4299a747e4fSDavid du Colombier iengine(Cardbus *cb, int message)
4309a747e4fSDavid du Colombier {
4319a747e4fSDavid du Colombier if (nevents >= NUMEVENTS) {
4329a747e4fSDavid du Colombier print("#Y: Too many events queued, discarding request\n");
4339a747e4fSDavid du Colombier return;
4349a747e4fSDavid du Colombier }
4359a747e4fSDavid du Colombier ilock(&levents);
43659c21d95SDavid du Colombier events[nevents].cb = cb;
43759c21d95SDavid du Colombier events[nevents].message = message;
4389a747e4fSDavid du Colombier nevents++;
4399a747e4fSDavid du Colombier iunlock(&levents);
4409a747e4fSDavid du Colombier wakeup(&revents);
4419a747e4fSDavid du Colombier }
4429a747e4fSDavid du Colombier
4439a747e4fSDavid du Colombier static int
eventoccured(void)4449a747e4fSDavid du Colombier eventoccured(void)
4459a747e4fSDavid du Colombier {
4469a747e4fSDavid du Colombier return nevents > 0;
4479a747e4fSDavid du Colombier }
4489a747e4fSDavid du Colombier
4499a747e4fSDavid du Colombier static void
processevents(void *)4509a747e4fSDavid du Colombier processevents(void *)
4519a747e4fSDavid du Colombier {
4529a747e4fSDavid du Colombier while (1) {
4539a747e4fSDavid du Colombier int message;
4549a747e4fSDavid du Colombier Cardbus *cb;
4559a747e4fSDavid du Colombier
4569a747e4fSDavid du Colombier sleep(&revents, (int (*)(void *))eventoccured, nil);
4579a747e4fSDavid du Colombier
4589a747e4fSDavid du Colombier cb = nil;
4599a747e4fSDavid du Colombier message = 0;
4609a747e4fSDavid du Colombier ilock(&levents);
4619a747e4fSDavid du Colombier if (nevents > 0) {
46259c21d95SDavid du Colombier cb = events[0].cb;
46359c21d95SDavid du Colombier message = events[0].message;
4649a747e4fSDavid du Colombier nevents--;
4659a747e4fSDavid du Colombier if (nevents > 0)
46659c21d95SDavid du Colombier memmove(events, &events[1], nevents * sizeof(Events));
4679a747e4fSDavid du Colombier }
4689a747e4fSDavid du Colombier iunlock(&levents);
4699a747e4fSDavid du Colombier
4709a747e4fSDavid du Colombier if (cb)
4719a747e4fSDavid du Colombier qengine(cb, message);
4729a747e4fSDavid du Colombier }
4739a747e4fSDavid du Colombier }
4749a747e4fSDavid du Colombier
4759a747e4fSDavid du Colombier static void
cbinterrupt(Ureg *,void *)4769a747e4fSDavid du Colombier cbinterrupt(Ureg *, void *)
4779a747e4fSDavid du Colombier {
4789a747e4fSDavid du Colombier int i;
4799a747e4fSDavid du Colombier
4809a747e4fSDavid du Colombier for (i = 0; i != nslots; i++) {
4819a747e4fSDavid du Colombier Cardbus *cb = &cbslots[i];
4829a747e4fSDavid du Colombier ulong event, state;
4839a747e4fSDavid du Colombier
4849a747e4fSDavid du Colombier event = cb->regs[SocketEvent];
48564c7f6b6SDavid du Colombier if(!(event & (SE_POWER|SE_CCD)))
48664c7f6b6SDavid du Colombier continue;
4879a747e4fSDavid du Colombier state = cb->regs[SocketState];
4889a747e4fSDavid du Colombier rdreg(cb, Rcsc); /* Ack the interrupt */
4899a747e4fSDavid du Colombier
49064c7f6b6SDavid du Colombier if(DEBUG)
49164c7f6b6SDavid du Colombier print("#Y%ld: interrupt: event %.8lX, state %.8lX, (%s)\n",
49264c7f6b6SDavid du Colombier cb - cbslots, event, state, states[cb->state]);
4939a747e4fSDavid du Colombier
4949a747e4fSDavid du Colombier if (event & SE_CCD) {
4959a747e4fSDavid du Colombier cb->regs[SocketEvent] |= SE_CCD; /* Ack interrupt */
4969a747e4fSDavid du Colombier if (state & SE_CCD) {
4979a747e4fSDavid du Colombier if (cb->state != SlotEmpty) {
4989a747e4fSDavid du Colombier print("#Y: take cardejected interrupt\n");
4999a747e4fSDavid du Colombier iengine(cb, CardEjected);
5009a747e4fSDavid du Colombier }
5019a747e4fSDavid du Colombier }
5029a747e4fSDavid du Colombier else
5039a747e4fSDavid du Colombier iengine(cb, CardDetected);
5049a747e4fSDavid du Colombier }
5059a747e4fSDavid du Colombier
5069a747e4fSDavid du Colombier if (event & SE_POWER) {
5079a747e4fSDavid du Colombier cb->regs[SocketEvent] |= SE_POWER; /* Ack interrupt */
5089a747e4fSDavid du Colombier iengine(cb, CardPowered);
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier }
5119a747e4fSDavid du Colombier }
5129a747e4fSDavid du Colombier
5139a747e4fSDavid du Colombier void
devpccardlink(void)5149a747e4fSDavid du Colombier devpccardlink(void)
5159a747e4fSDavid du Colombier {
5169a747e4fSDavid du Colombier static int initialized;
5179a747e4fSDavid du Colombier Pcidev *pci;
5189a747e4fSDavid du Colombier int i;
5199a747e4fSDavid du Colombier uchar intl;
520b7b24591SDavid du Colombier char *p;
5214de34a7eSDavid du Colombier void *baddrva;
5229a747e4fSDavid du Colombier
5239a747e4fSDavid du Colombier if (initialized)
5249a747e4fSDavid du Colombier return;
5259a747e4fSDavid du Colombier initialized = 1;
5269a747e4fSDavid du Colombier
527b7b24591SDavid du Colombier if((p=getconf("pccard0")) && strncmp(p, "disabled", 8)==0)
528b7b24591SDavid du Colombier return;
529b7b24591SDavid du Colombier
5309a747e4fSDavid du Colombier if(_pcmspecial)
5319a747e4fSDavid du Colombier return;
5329a747e4fSDavid du Colombier
5339a747e4fSDavid du Colombier /* Allocate legacy space */
5349a747e4fSDavid du Colombier if (ioalloc(LegacyAddr, 2, 0, "i82365.0") < 0)
5359a747e4fSDavid du Colombier print("#Y: WARNING: Cannot allocate legacy ports\n");
5369a747e4fSDavid du Colombier
5379a747e4fSDavid du Colombier /* Find all CardBus controllers */
5389a747e4fSDavid du Colombier pci = nil;
53928a8a86bSDavid du Colombier intl = 0xff;
5409a747e4fSDavid du Colombier while ((pci = pcimatch(pci, 0, 0)) != nil) {
5419a747e4fSDavid du Colombier ulong baddr;
5429a747e4fSDavid du Colombier Cardbus *cb;
5439a747e4fSDavid du Colombier int slot;
5449a747e4fSDavid du Colombier uchar pin;
5459a747e4fSDavid du Colombier
54664c7f6b6SDavid du Colombier if(pci->ccrb != 6 || pci->ccru != 7)
54764c7f6b6SDavid du Colombier continue;
5489a747e4fSDavid du Colombier for (i = 0; i != nelem(variant); i++)
54959c21d95SDavid du Colombier if (pci->vid == variant[i].vid && pci->did == variant[i].did)
5509a747e4fSDavid du Colombier break;
5519a747e4fSDavid du Colombier if (i == nelem(variant))
5529a747e4fSDavid du Colombier continue;
5539a747e4fSDavid du Colombier
5549a747e4fSDavid du Colombier /* initialize this slot */
5559a747e4fSDavid du Colombier slot = nslots++;
5569a747e4fSDavid du Colombier cb = &cbslots[slot];
5579a747e4fSDavid du Colombier
5589a747e4fSDavid du Colombier cb->pci = pci;
5599a747e4fSDavid du Colombier cb->variant = &variant[i];
5609a747e4fSDavid du Colombier
5619a747e4fSDavid du Colombier if (pci->vid != TI_vid) {
56241dd6b47SDavid du Colombier /*
56341dd6b47SDavid du Colombier * Gross hack, needs a fix. Inherit the mappings from
56441dd6b47SDavid du Colombier * 9load for the TIs (pb)
56541dd6b47SDavid du Colombier */
5669a747e4fSDavid du Colombier pcicfgw32(pci, PciCBMBR0, 0xffffffff);
5679a747e4fSDavid du Colombier pcicfgw32(pci, PciCBMLR0, 0);
5689a747e4fSDavid du Colombier pcicfgw32(pci, PciCBMBR1, 0xffffffff);
5699a747e4fSDavid du Colombier pcicfgw32(pci, PciCBMLR1, 0);
5709a747e4fSDavid du Colombier pcicfgw32(pci, PciCBIBR0, 0xffffffff);
5719a747e4fSDavid du Colombier pcicfgw32(pci, PciCBILR0, 0);
5729a747e4fSDavid du Colombier pcicfgw32(pci, PciCBIBR1, 0xffffffff);
5739a747e4fSDavid du Colombier pcicfgw32(pci, PciCBILR1, 0);
5749a747e4fSDavid du Colombier }
5759a747e4fSDavid du Colombier
57641dd6b47SDavid du Colombier /* Set up PCI bus numbers if needed. */
5779a747e4fSDavid du Colombier if (pcicfgr8(pci, PciSBN) == 0) {
5789a747e4fSDavid du Colombier static int busbase = 0x20;
5799a747e4fSDavid du Colombier
5809a747e4fSDavid du Colombier pcicfgw8(pci, PciSBN, busbase);
5819a747e4fSDavid du Colombier pcicfgw8(pci, PciUBN, busbase + 2);
5829a747e4fSDavid du Colombier busbase += 3;
5839a747e4fSDavid du Colombier }
5849a747e4fSDavid du Colombier
58541dd6b47SDavid du Colombier /* Patch up intl if needed. */
5869a747e4fSDavid du Colombier if ((pin = pcicfgr8(pci, PciINTP)) != 0 &&
5879a747e4fSDavid du Colombier (pci->intl == 0xff || pci->intl == 0)) {
5889a747e4fSDavid du Colombier pci->intl = pciipin(nil, pin);
5899a747e4fSDavid du Colombier pcicfgw8(pci, PciINTL, pci->intl);
5909a747e4fSDavid du Colombier
5919a747e4fSDavid du Colombier if (pci->intl == 0xff || pci->intl == 0)
59264c7f6b6SDavid du Colombier print("#Y%ld: No interrupt?\n", cb - cbslots);
5939a747e4fSDavid du Colombier }
5949a747e4fSDavid du Colombier
59541dd6b47SDavid du Colombier /* Don't you love standards! */
5969a747e4fSDavid du Colombier if (pci->vid == TI_vid) {
5979a747e4fSDavid du Colombier if (pci->did <= TI_1131_did) {
5989a747e4fSDavid du Colombier uchar cc;
5999a747e4fSDavid du Colombier
6009a747e4fSDavid du Colombier cc = pcicfgr8(pci, TI1131xCC);
6019a747e4fSDavid du Colombier cc &= ~(TI113X_CC_PCI_IRQ_ENA |
6029a747e4fSDavid du Colombier TI113X_CC_PCI_IREQ |
6039a747e4fSDavid du Colombier TI113X_CC_PCI_CSC |
6049a747e4fSDavid du Colombier TI113X_CC_ZVENABLE);
6059a747e4fSDavid du Colombier cc |= TI113X_CC_PCI_IRQ_ENA |
6069a747e4fSDavid du Colombier TI113X_CC_PCI_IREQ |
6079a747e4fSDavid du Colombier TI113X_CC_SPKROUTEN;
6089a747e4fSDavid du Colombier pcicfgw8(pci, TI1131xCC, cc);
6099a747e4fSDavid du Colombier
61041dd6b47SDavid du Colombier /* PCI interrupts only */
6119a747e4fSDavid du Colombier pcicfgw8(pci, TI1131xDC,
6129a747e4fSDavid du Colombier pcicfgr8(pci, TI1131xDC) & ~6);
6139a747e4fSDavid du Colombier
61441dd6b47SDavid du Colombier /* CSC ints to PCI bus. */
6159a747e4fSDavid du Colombier wrreg(cb, Rigc, rdreg(cb, Rigc) | 0x10);
6169a747e4fSDavid du Colombier }
6179a747e4fSDavid du Colombier else if (pci->did == TI_1250_did) {
6189a747e4fSDavid du Colombier print("No support yet for the TI_1250_did, prod pb\n");
6199a747e4fSDavid du Colombier }
620d9306527SDavid du Colombier else if (pci->did == TI_1420_did) {
62141dd6b47SDavid du Colombier /* Disable Vcc protection */
622d9306527SDavid du Colombier pcicfgw32(cb->pci, 0x80,
623d9306527SDavid du Colombier pcicfgr32(cb->pci, 0x80) | (1 << 21));
624d9306527SDavid du Colombier }
625d9306527SDavid du Colombier
626d9306527SDavid du Colombier pcicfgw16(cb->pci, PciPMC, pcicfgr16(cb->pci, PciPMC) & ~3);
6279a747e4fSDavid du Colombier }
62864c7f6b6SDavid du Colombier if (pci->vid == O2_vid) {
62964c7f6b6SDavid du Colombier if(DEBUG)
63064c7f6b6SDavid du Colombier print("writing O2 config\n");
63164c7f6b6SDavid du Colombier pcicfgw8(cb->pci, 0x94, 0xCA);
63264c7f6b6SDavid du Colombier pcicfgw8(cb->pci, 0xD4, 0xCA);
63364c7f6b6SDavid du Colombier }
6349a747e4fSDavid du Colombier
63528a8a86bSDavid du Colombier if (intl != 0xff && intl != pci->intl)
6369a747e4fSDavid du Colombier intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus");
6379a747e4fSDavid du Colombier intl = pci->intl;
6389a747e4fSDavid du Colombier
6399a747e4fSDavid du Colombier if ((baddr = pcicfgr32(cb->pci, PciBAR0)) == 0) {
6404de34a7eSDavid du Colombier int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000;
6419a747e4fSDavid du Colombier
6424de34a7eSDavid du Colombier baddr = upaalloc(size, size);
6434de34a7eSDavid du Colombier baddrva = vmap(baddr, size);
6449a747e4fSDavid du Colombier pcicfgw32(cb->pci, PciBAR0, baddr);
6454de34a7eSDavid du Colombier cb->regs = (ulong *)baddrva;
6469a747e4fSDavid du Colombier }
6479a747e4fSDavid du Colombier else
6484de34a7eSDavid du Colombier cb->regs = (ulong *)vmap(baddr, 4096);
6499a747e4fSDavid du Colombier cb->state = SlotEmpty;
6509a747e4fSDavid du Colombier
6519a747e4fSDavid du Colombier /* Don't really know what to do with this... */
6529a747e4fSDavid du Colombier i82365probe(cb, LegacyAddr, LegacyAddr + 1);
6539a747e4fSDavid du Colombier
6549a747e4fSDavid du Colombier print("#Y%ld: %s, %.8ulX intl %d\n", cb - cbslots,
65559c21d95SDavid du Colombier variant[i].name, baddr, pci->intl);
6569a747e4fSDavid du Colombier }
6579a747e4fSDavid du Colombier
6589a747e4fSDavid du Colombier if (nslots == 0){
6599a747e4fSDavid du Colombier iofree(LegacyAddr);
6609a747e4fSDavid du Colombier return;
6619a747e4fSDavid du Colombier }
6629a747e4fSDavid du Colombier
6639a747e4fSDavid du Colombier _pcmspecial = pccard_pcmspecial;
6649a747e4fSDavid du Colombier _pcmspecialclose = pccard_pcmspecialclose;
6659a747e4fSDavid du Colombier
6669a747e4fSDavid du Colombier for (i = 0; i != nslots; i++) {
6679a747e4fSDavid du Colombier Cardbus *cb = &cbslots[i];
6689a747e4fSDavid du Colombier
6699a747e4fSDavid du Colombier if ((cb->regs[SocketState] & SE_CCD) == 0)
6709a747e4fSDavid du Colombier engine(cb, CardDetected);
6719a747e4fSDavid du Colombier }
6729a747e4fSDavid du Colombier
6739a747e4fSDavid du Colombier delay(500); /* Allow time for power up */
6749a747e4fSDavid du Colombier
6759a747e4fSDavid du Colombier for (i = 0; i != nslots; i++) {
6769a747e4fSDavid du Colombier Cardbus *cb = &cbslots[i];
6779a747e4fSDavid du Colombier
6789a747e4fSDavid du Colombier if (cb->regs[SocketState] & SE_POWER)
6799a747e4fSDavid du Colombier engine(cb, CardPowered);
6809a747e4fSDavid du Colombier
6819a747e4fSDavid du Colombier /* Ack and enable interrupts on all events */
6829a747e4fSDavid du Colombier // cb->regs[SocketEvent] = cb->regs[SocketEvent];
6839a747e4fSDavid du Colombier cb->regs[SocketMask] |= 0xF;
6849a747e4fSDavid du Colombier wrreg(cb, Rcscic, 0xC);
6859a747e4fSDavid du Colombier }
6869a747e4fSDavid du Colombier }
6879a747e4fSDavid du Colombier
6889a747e4fSDavid du Colombier static int
powerup(Cardbus * cb)6899a747e4fSDavid du Colombier powerup(Cardbus *cb)
6909a747e4fSDavid du Colombier {
6919a747e4fSDavid du Colombier ulong state;
6929a747e4fSDavid du Colombier ushort bcr;
6939a747e4fSDavid du Colombier
694d9306527SDavid du Colombier state = cb->regs[SocketState];
695d9306527SDavid du Colombier if (state & SS_PC16) {
69664c7f6b6SDavid du Colombier if(DEBUG)
69764c7f6b6SDavid du Colombier print("#Y%ld: Probed a PC16 card, powering up card\n",
69864c7f6b6SDavid du Colombier cb - cbslots);
6999a747e4fSDavid du Colombier cb->type = PC16;
7009a747e4fSDavid du Colombier memset(&cb->linfo, 0, sizeof(Pcminfo));
7019a747e4fSDavid du Colombier
7029a747e4fSDavid du Colombier /* power up and unreset, wait's are empirical (???) */
7039a747e4fSDavid du Colombier wrreg(cb, Rpc, Fautopower|Foutena|Fcardena);
7049a747e4fSDavid du Colombier delay(300);
7059a747e4fSDavid du Colombier wrreg(cb, Rigc, 0);
7069a747e4fSDavid du Colombier delay(100);
7079a747e4fSDavid du Colombier wrreg(cb, Rigc, Fnotreset);
708d9306527SDavid du Colombier delay(500);
7099a747e4fSDavid du Colombier
7102c77d828SDavid du Colombier // return 1;
7119a747e4fSDavid du Colombier }
7129a747e4fSDavid du Colombier
7139a747e4fSDavid du Colombier if (state & SS_CCD)
7149a747e4fSDavid du Colombier return 0;
7159a747e4fSDavid du Colombier
716d9306527SDavid du Colombier if (state & SS_NOTCARD) {
71764c7f6b6SDavid du Colombier print("#Y%ld: No card inserted\n", cb - cbslots);
7189a747e4fSDavid du Colombier return 0;
7199a747e4fSDavid du Colombier }
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier if ((state & SS_3V) == 0 && (state & SS_5V) == 0) {
7229a747e4fSDavid du Colombier print("#Y%ld: Unsupported voltage, powering down card!\n",
7239a747e4fSDavid du Colombier cb - cbslots);
7249a747e4fSDavid du Colombier cb->regs[SocketControl] = 0;
7259a747e4fSDavid du Colombier return 0;
7269a747e4fSDavid du Colombier }
7279a747e4fSDavid du Colombier
72864c7f6b6SDavid du Colombier if(DEBUG)
72964c7f6b6SDavid du Colombier print("#Y%ld: card %spowered at %d volt\n", cb - cbslots,
73064c7f6b6SDavid du Colombier (state & SS_POWER)? "": "not ",
73164c7f6b6SDavid du Colombier (state & SS_3V)? 3: (state & SS_5V)? 5: -1);
7329a747e4fSDavid du Colombier
7339a747e4fSDavid du Colombier /* Power up the card
7349a747e4fSDavid du Colombier * and make sure the secondary bus is not in reset.
7359a747e4fSDavid du Colombier */
7369a747e4fSDavid du Colombier cb->regs[SocketControl] = (state & SS_5V)? SC_5V: SC_3V;
7379a747e4fSDavid du Colombier delay(50);
7389a747e4fSDavid du Colombier bcr = pcicfgr16(cb->pci, PciBCR);
7399a747e4fSDavid du Colombier bcr &= ~0x40;
7409a747e4fSDavid du Colombier pcicfgw16(cb->pci, PciBCR, bcr);
7419a747e4fSDavid du Colombier delay(100);
7429a747e4fSDavid du Colombier
7432c77d828SDavid du Colombier if (state & SS_PC16)
7442c77d828SDavid du Colombier cb->type = PC16;
7452c77d828SDavid du Colombier else
74664c7f6b6SDavid du Colombier cb->type = PC32;
74764c7f6b6SDavid du Colombier
7489a747e4fSDavid du Colombier return 1;
7499a747e4fSDavid du Colombier }
7509a747e4fSDavid du Colombier
7519a747e4fSDavid du Colombier static void
powerdown(Cardbus * cb)7529a747e4fSDavid du Colombier powerdown(Cardbus *cb)
7539a747e4fSDavid du Colombier {
7549a747e4fSDavid du Colombier ushort bcr;
7559a747e4fSDavid du Colombier
7569a747e4fSDavid du Colombier if (cb->type == PC16) {
7579a747e4fSDavid du Colombier
7589a747e4fSDavid du Colombier wrreg(cb, Rpc, 0); /* turn off card power */
7599a747e4fSDavid du Colombier wrreg(cb, Rwe, 0); /* no windows */
7609a747e4fSDavid du Colombier
7619a747e4fSDavid du Colombier cb->type = -1;
7629a747e4fSDavid du Colombier return;
7639a747e4fSDavid du Colombier }
7649a747e4fSDavid du Colombier
7659a747e4fSDavid du Colombier bcr = pcicfgr16(cb->pci, PciBCR);
7669a747e4fSDavid du Colombier bcr |= 0x40;
7679a747e4fSDavid du Colombier pcicfgw16(cb->pci, PciBCR, bcr);
7689a747e4fSDavid du Colombier cb->regs[SocketControl] = 0;
7699a747e4fSDavid du Colombier cb->type = -1;
7709a747e4fSDavid du Colombier }
7719a747e4fSDavid du Colombier
7729a747e4fSDavid du Colombier static void
configure(Cardbus * cb)7739a747e4fSDavid du Colombier configure(Cardbus *cb)
7749a747e4fSDavid du Colombier {
775c91329d7SDavid du Colombier int i, r;
77664c7f6b6SDavid du Colombier ulong size, bar;
777c91329d7SDavid du Colombier Pcidev *pci;
778c91329d7SDavid du Colombier ulong membase, iobase, memlen, iolen, rombase, romlen;
7799a747e4fSDavid du Colombier
78064c7f6b6SDavid du Colombier if(DEBUG)
781c91329d7SDavid du Colombier print("configuring slot %ld (%s)\n", cb - cbslots, states[cb->state]);
7829a747e4fSDavid du Colombier if (cb->state == SlotConfigured)
7839a747e4fSDavid du Colombier return;
7849a747e4fSDavid du Colombier engine(cb, CardConfigured);
7859a747e4fSDavid du Colombier
7869a747e4fSDavid du Colombier delay(50); /* Emperically established */
7879a747e4fSDavid du Colombier
7889a747e4fSDavid du Colombier if (cb->type == PC16) {
7899a747e4fSDavid du Colombier i82365configure(cb);
7909a747e4fSDavid du Colombier return;
7919a747e4fSDavid du Colombier }
7929a747e4fSDavid du Colombier
7939a747e4fSDavid du Colombier /* Scan the CardBus for new PCI devices */
7949a747e4fSDavid du Colombier pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge);
795c91329d7SDavid du Colombier
796c91329d7SDavid du Colombier /*
797c91329d7SDavid du Colombier * size the devices on the bus, reserve a minimum for devices arriving later,
798c91329d7SDavid du Colombier * allow for ROM space, allocate space, and set the cardbus mapping registers
799c91329d7SDavid du Colombier */
800c91329d7SDavid du Colombier pcibussize(cb->pci->bridge, &memlen, &iolen); /* TO DO: need initial alignments */
801c91329d7SDavid du Colombier
802c91329d7SDavid du Colombier romlen = 0;
803c91329d7SDavid du Colombier for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
804c91329d7SDavid du Colombier size = pcibarsize(pci, PciEBAR0);
805c91329d7SDavid du Colombier if(size > 0){
806c91329d7SDavid du Colombier pci->rom.bar = -1;
807c91329d7SDavid du Colombier pci->rom.size = size;
808c91329d7SDavid du Colombier romlen += size;
809c91329d7SDavid du Colombier }
810c91329d7SDavid du Colombier }
811c91329d7SDavid du Colombier
812c91329d7SDavid du Colombier if(iolen < 512)
813c91329d7SDavid du Colombier iolen = 512;
814c91329d7SDavid du Colombier iobase = ioreserve(~0, iolen, 0, "cardbus");
815c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBIBR0, iobase);
816c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1);
817c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBIBR1, 0);
818c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBILR1, 0);
819c91329d7SDavid du Colombier
820c91329d7SDavid du Colombier rombase = memlen;
821c91329d7SDavid du Colombier memlen += romlen;
822c91329d7SDavid du Colombier if(memlen < 1*1024*1024)
823c91329d7SDavid du Colombier memlen = 1*1024*1024;
824c91329d7SDavid du Colombier membase = upaalloc(memlen, 4*1024*1024); /* TO DO: better alignment */
825c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBMBR0, membase);
826c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBMLR0, membase + memlen-1);
827c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBMBR1, 0);
828c91329d7SDavid du Colombier pcicfgw32(cb->pci, PciCBMLR1, 0);
829c91329d7SDavid du Colombier
830c91329d7SDavid du Colombier // pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */
831c91329d7SDavid du Colombier rombase += membase;
832c91329d7SDavid du Colombier
833c91329d7SDavid du Colombier for(pci = cb->pci->bridge; pci != nil; pci = pci->list){
83464c7f6b6SDavid du Colombier r = pcicfgr16(pci, PciPCR);
83564c7f6b6SDavid du Colombier r &= ~(PciPCR_IO|PciPCR_MEM);
83664c7f6b6SDavid du Colombier pcicfgw16(pci, PciPCR, r);
8379a747e4fSDavid du Colombier
83864c7f6b6SDavid du Colombier /*
83964c7f6b6SDavid du Colombier * Treat the found device as an ordinary PCI card.
84064c7f6b6SDavid du Colombier * It seems that the CIS is not always present in
84164c7f6b6SDavid du Colombier * CardBus cards.
84264c7f6b6SDavid du Colombier * XXX, need to support multifunction cards
84364c7f6b6SDavid du Colombier */
844c91329d7SDavid du Colombier for(i = 0; i < Nbars; i++) {
84564c7f6b6SDavid du Colombier if(pci->mem[i].size == 0)
84664c7f6b6SDavid du Colombier continue;
847c91329d7SDavid du Colombier bar = pci->mem[i].bar;
848c91329d7SDavid du Colombier if(bar & 1)
849c91329d7SDavid du Colombier bar += iobase;
850c91329d7SDavid du Colombier else
851c91329d7SDavid du Colombier bar += membase;
852c91329d7SDavid du Colombier pci->mem[i].bar = bar;
853c91329d7SDavid du Colombier pcicfgw32(pci, PciBAR0 + 4*i, bar);
854c91329d7SDavid du Colombier if((bar & 1) == 0){
855c91329d7SDavid du Colombier print("%T mem[%d] %8.8lux %d\n", pci->tbdf, i, bar, pci->mem[i].size);
856c91329d7SDavid du Colombier if(bar & 0x80){ /* TO DO: enable prefetch */
857c91329d7SDavid du Colombier ;
8589a747e4fSDavid du Colombier }
8599a747e4fSDavid du Colombier }
8609a747e4fSDavid du Colombier }
861c91329d7SDavid du Colombier if((size = pcibarsize(pci, PciEBAR0)) > 0) { /* TO DO: can this be done by pci.c? */
862c91329d7SDavid du Colombier pci->rom.bar = rombase;
8639a747e4fSDavid du Colombier pci->rom.size = size;
864c91329d7SDavid du Colombier rombase += size;
8659a747e4fSDavid du Colombier pcicfgw32(pci, PciEBAR0, pci->rom.bar);
8669a747e4fSDavid du Colombier }
8679a747e4fSDavid du Colombier
8689a747e4fSDavid du Colombier /* Set the basic PCI registers for the device */
86964c7f6b6SDavid du Colombier pci->pcr = pcicfgr16(pci, PciPCR);
87064c7f6b6SDavid du Colombier pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master;
8716437e9bfSDavid du Colombier pci->cls = 8;
8726437e9bfSDavid du Colombier pci->ltr = 64;
8736437e9bfSDavid du Colombier pcicfgw16(pci, PciPCR, pci->pcr);
8746437e9bfSDavid du Colombier pcicfgw8(pci, PciCLS, pci->cls);
8756437e9bfSDavid du Colombier pcicfgw8(pci, PciLTR, pci->ltr);
8769a747e4fSDavid du Colombier
8779a747e4fSDavid du Colombier if (pcicfgr8(pci, PciINTP)) {
8789a747e4fSDavid du Colombier pci->intl = pcicfgr8(cb->pci, PciINTL);
8799a747e4fSDavid du Colombier pcicfgw8(pci, PciINTL, pci->intl);
8809a747e4fSDavid du Colombier
8819a747e4fSDavid du Colombier /* Route interrupts to INTA#/B# */
8829a747e4fSDavid du Colombier pcicfgw16(cb->pci, PciBCR,
8839a747e4fSDavid du Colombier pcicfgr16(cb->pci, PciBCR) & ~(1 << 7));
8849a747e4fSDavid du Colombier }
8859a747e4fSDavid du Colombier }
8869a747e4fSDavid du Colombier }
8879a747e4fSDavid du Colombier
8889a747e4fSDavid du Colombier static void
unconfigure(Cardbus * cb)8899a747e4fSDavid du Colombier unconfigure(Cardbus *cb)
8909a747e4fSDavid du Colombier {
8919a747e4fSDavid du Colombier Pcidev *pci;
89264c7f6b6SDavid du Colombier int i, ioindex, memindex, r;
8939a747e4fSDavid du Colombier
8949a747e4fSDavid du Colombier if (cb->type == PC16) {
8959a747e4fSDavid du Colombier print("#Y%d: Don't know how to unconfigure a PC16 card\n",
8969a747e4fSDavid du Colombier (int)(cb - cbslots));
8979a747e4fSDavid du Colombier
8989a747e4fSDavid du Colombier memset(&cb->linfo, 0, sizeof(Pcminfo));
8999a747e4fSDavid du Colombier return;
9009a747e4fSDavid du Colombier }
9019a747e4fSDavid du Colombier
9029a747e4fSDavid du Colombier pci = cb->pci->bridge;
9039a747e4fSDavid du Colombier if (pci == nil)
9049a747e4fSDavid du Colombier return; /* Not configured */
9059a747e4fSDavid du Colombier cb->pci->bridge = nil;
9069a747e4fSDavid du Colombier
9079a747e4fSDavid du Colombier memindex = ioindex = 0;
9089a747e4fSDavid du Colombier while (pci) {
9099a747e4fSDavid du Colombier Pcidev *_pci;
9109a747e4fSDavid du Colombier
9119a747e4fSDavid du Colombier for (i = 0; i != Nbars; i++) {
91264c7f6b6SDavid du Colombier if (pci->mem[i].size == 0)
91364c7f6b6SDavid du Colombier continue;
9149a747e4fSDavid du Colombier if (pci->mem[i].bar & 1) {
9159a747e4fSDavid du Colombier iofree(pci->mem[i].bar & ~1);
9169a747e4fSDavid du Colombier pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8,
9179a747e4fSDavid du Colombier (ushort)-1);
9189a747e4fSDavid du Colombier pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0);
9199a747e4fSDavid du Colombier ioindex++;
9209a747e4fSDavid du Colombier continue;
9219a747e4fSDavid du Colombier }
9229a747e4fSDavid du Colombier
9239a747e4fSDavid du Colombier upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size);
92464c7f6b6SDavid du Colombier pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
9259a747e4fSDavid du Colombier pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
92664c7f6b6SDavid du Colombier r = pcicfgr16(cb->pci, PciBCR);
92764c7f6b6SDavid du Colombier r &= ~(1 << (8 + memindex));
92864c7f6b6SDavid du Colombier pcicfgw16(cb->pci, PciBCR, r);
9299a747e4fSDavid du Colombier memindex++;
9309a747e4fSDavid du Colombier }
9319a747e4fSDavid du Colombier
9329a747e4fSDavid du Colombier if (pci->rom.bar && memindex < 2) {
9339a747e4fSDavid du Colombier upafree(pci->rom.bar & ~0xF, pci->rom.size);
93464c7f6b6SDavid du Colombier pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1);
9359a747e4fSDavid du Colombier pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0);
9369a747e4fSDavid du Colombier memindex++;
9379a747e4fSDavid du Colombier }
9389a747e4fSDavid du Colombier
9399a747e4fSDavid du Colombier _pci = pci->list;
9409a747e4fSDavid du Colombier free(_pci);
9419a747e4fSDavid du Colombier pci = _pci;
9429a747e4fSDavid du Colombier }
9439a747e4fSDavid du Colombier }
9449a747e4fSDavid du Colombier
9459a747e4fSDavid du Colombier static void
i82365configure(Cardbus * cb)9469a747e4fSDavid du Colombier i82365configure(Cardbus *cb)
9479a747e4fSDavid du Colombier {
9489a747e4fSDavid du Colombier int this;
9499a747e4fSDavid du Colombier Cisdat cis;
9509a747e4fSDavid du Colombier PCMmap *m;
9519a747e4fSDavid du Colombier uchar type, link;
9529a747e4fSDavid du Colombier
9539a747e4fSDavid du Colombier /*
9549a747e4fSDavid du Colombier * Read all tuples in attribute space.
9559a747e4fSDavid du Colombier */
9569a747e4fSDavid du Colombier m = isamap(cb, 0, 0, 1);
9579a747e4fSDavid du Colombier if(m == 0)
9589a747e4fSDavid du Colombier return;
9599a747e4fSDavid du Colombier
9609a747e4fSDavid du Colombier cis.cisbase = KADDR(m->isa);
9619a747e4fSDavid du Colombier cis.cispos = 0;
9629a747e4fSDavid du Colombier cis.cisskip = 2;
9639a747e4fSDavid du Colombier cis.cislen = m->len;
9649a747e4fSDavid du Colombier
9659a747e4fSDavid du Colombier /* loop through all the tuples */
9669a747e4fSDavid du Colombier for(;;){
9679a747e4fSDavid du Colombier this = cis.cispos;
9689a747e4fSDavid du Colombier if(readc(&cis, &type) != 1)
9699a747e4fSDavid du Colombier break;
9709a747e4fSDavid du Colombier if(type == 0xFF)
9719a747e4fSDavid du Colombier break;
9729a747e4fSDavid du Colombier if(readc(&cis, &link) != 1)
9739a747e4fSDavid du Colombier break;
9749a747e4fSDavid du Colombier
9759a747e4fSDavid du Colombier switch(type){
9769a747e4fSDavid du Colombier default:
9779a747e4fSDavid du Colombier break;
9789a747e4fSDavid du Colombier case 0x15:
9799a747e4fSDavid du Colombier tvers1(cb, &cis, type);
9809a747e4fSDavid du Colombier break;
9819a747e4fSDavid du Colombier case 0x1A:
9829a747e4fSDavid du Colombier tcfig(cb, &cis, type);
9839a747e4fSDavid du Colombier break;
9849a747e4fSDavid du Colombier case 0x1B:
9859a747e4fSDavid du Colombier tentry(cb, &cis, type);
9869a747e4fSDavid du Colombier break;
9879a747e4fSDavid du Colombier }
9889a747e4fSDavid du Colombier
9899a747e4fSDavid du Colombier if(link == 0xFF)
9909a747e4fSDavid du Colombier break;
9919a747e4fSDavid du Colombier cis.cispos = this + (2+link);
9929a747e4fSDavid du Colombier }
9939a747e4fSDavid du Colombier isaunmap(m);
9949a747e4fSDavid du Colombier }
9959a747e4fSDavid du Colombier
9969a747e4fSDavid du Colombier /*
9979a747e4fSDavid du Colombier * look for a card whose version contains 'idstr'
9989a747e4fSDavid du Colombier */
9999a747e4fSDavid du Colombier static int
pccard_pcmspecial(char * idstr,ISAConf * isa)10009a747e4fSDavid du Colombier pccard_pcmspecial(char *idstr, ISAConf *isa)
10019a747e4fSDavid du Colombier {
10029a747e4fSDavid du Colombier int i, irq;
10039a747e4fSDavid du Colombier PCMconftab *ct, *et;
10049a747e4fSDavid du Colombier Pcminfo *pi;
10059a747e4fSDavid du Colombier Cardbus *cb;
10069a747e4fSDavid du Colombier uchar x, we, *p;
10079a747e4fSDavid du Colombier
10089a747e4fSDavid du Colombier cb = nil;
10099a747e4fSDavid du Colombier for (i = 0; i != nslots; i++) {
10109a747e4fSDavid du Colombier cb = &cbslots[i];
10119a747e4fSDavid du Colombier
10123ff48bf5SDavid du Colombier lock(cb);
10139a747e4fSDavid du Colombier if (cb->state == SlotConfigured &&
10149a747e4fSDavid du Colombier cb->type == PC16 &&
10159a747e4fSDavid du Colombier !cb->special &&
10169a747e4fSDavid du Colombier strstr(cb->linfo.verstr, idstr))
10179a747e4fSDavid du Colombier break;
10183ff48bf5SDavid du Colombier unlock(cb);
10199a747e4fSDavid du Colombier }
10209a747e4fSDavid du Colombier
10219a747e4fSDavid du Colombier if (i == nslots) {
102241dd6b47SDavid du Colombier if(0 && DEBUG)
102341dd6b47SDavid du Colombier print("#Y: %s not found\n", idstr);
10249a747e4fSDavid du Colombier return -1;
10259a747e4fSDavid du Colombier }
10269a747e4fSDavid du Colombier
10279a747e4fSDavid du Colombier pi = &cb->linfo;
10289a747e4fSDavid du Colombier
10299a747e4fSDavid du Colombier /*
10309a747e4fSDavid du Colombier * configure the PCMslot for IO. We assume very heavily that we can read
10319a747e4fSDavid du Colombier * configuration info from the CIS. If not, we won't set up correctly.
10329a747e4fSDavid du Colombier */
10339a747e4fSDavid du Colombier irq = isa->irq;
10349a747e4fSDavid du Colombier if(irq == 2)
10359a747e4fSDavid du Colombier irq = 9;
10369a747e4fSDavid du Colombier
10379a747e4fSDavid du Colombier et = &pi->ctab[pi->nctab];
10389a747e4fSDavid du Colombier ct = nil;
10399a747e4fSDavid du Colombier for(i = 0; i < isa->nopt; i++){
10409a747e4fSDavid du Colombier int index;
10419a747e4fSDavid du Colombier char *cp;
10429a747e4fSDavid du Colombier
10439a747e4fSDavid du Colombier if(strncmp(isa->opt[i], "index=", 6))
10449a747e4fSDavid du Colombier continue;
10459a747e4fSDavid du Colombier index = strtol(&isa->opt[i][6], &cp, 0);
10469a747e4fSDavid du Colombier if(cp == &isa->opt[i][6] || index >= pi->nctab) {
10473ff48bf5SDavid du Colombier unlock(cb);
10489a747e4fSDavid du Colombier print("#Y%d: Cannot find index %d in conf table\n",
10499a747e4fSDavid du Colombier (int)(cb - cbslots), index);
10509a747e4fSDavid du Colombier return -1;
10519a747e4fSDavid du Colombier }
10529a747e4fSDavid du Colombier ct = &pi->ctab[index];
10539a747e4fSDavid du Colombier }
10549a747e4fSDavid du Colombier
10559a747e4fSDavid du Colombier if(ct == nil){
10569a747e4fSDavid du Colombier PCMconftab *t;
10579a747e4fSDavid du Colombier
10589a747e4fSDavid du Colombier /* assume default is right */
10599a747e4fSDavid du Colombier if(pi->defctab)
10609a747e4fSDavid du Colombier ct = pi->defctab;
10619a747e4fSDavid du Colombier else
10629a747e4fSDavid du Colombier ct = pi->ctab;
10639a747e4fSDavid du Colombier
10649a747e4fSDavid du Colombier /* try for best match */
10659a747e4fSDavid du Colombier if(ct->nio == 0
10669a747e4fSDavid du Colombier || ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
10679a747e4fSDavid du Colombier for(t = pi->ctab; t < et; t++)
10689a747e4fSDavid du Colombier if(t->nio
10699a747e4fSDavid du Colombier && t->io[0].start == isa->port
10709a747e4fSDavid du Colombier && ((1<<irq) & t->irqs)){
10719a747e4fSDavid du Colombier ct = t;
10729a747e4fSDavid du Colombier break;
10739a747e4fSDavid du Colombier }
10749a747e4fSDavid du Colombier }
10759a747e4fSDavid du Colombier if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
10769a747e4fSDavid du Colombier for(t = pi->ctab; t < et; t++)
10779a747e4fSDavid du Colombier if(t->nio && ((1<<irq) & t->irqs)){
10789a747e4fSDavid du Colombier ct = t;
10799a747e4fSDavid du Colombier break;
10809a747e4fSDavid du Colombier }
10819a747e4fSDavid du Colombier }
10829a747e4fSDavid du Colombier if(ct->nio == 0){
10839a747e4fSDavid du Colombier for(t = pi->ctab; t < et; t++)
10849a747e4fSDavid du Colombier if(t->nio){
10859a747e4fSDavid du Colombier ct = t;
10869a747e4fSDavid du Colombier break;
10879a747e4fSDavid du Colombier }
10889a747e4fSDavid du Colombier }
10899a747e4fSDavid du Colombier }
10909a747e4fSDavid du Colombier
10919a747e4fSDavid du Colombier if(ct == et || ct->nio == 0) {
10923ff48bf5SDavid du Colombier unlock(cb);
10939a747e4fSDavid du Colombier print("#Y%d: No configuration?\n", (int)(cb - cbslots));
10949a747e4fSDavid du Colombier return -1;
10959a747e4fSDavid du Colombier }
10969a747e4fSDavid du Colombier if(isa->port == 0 && ct->io[0].start == 0) {
10973ff48bf5SDavid du Colombier unlock(cb);
10989a747e4fSDavid du Colombier print("#Y%d: No part or start address\n", (int)(cb - cbslots));
10999a747e4fSDavid du Colombier return -1;
11009a747e4fSDavid du Colombier }
11019a747e4fSDavid du Colombier
11029a747e4fSDavid du Colombier cb->special = 1; /* taken */
11039a747e4fSDavid du Colombier
11049a747e4fSDavid du Colombier /* route interrupts */
11059a747e4fSDavid du Colombier isa->irq = irq;
11069a747e4fSDavid du Colombier wrreg(cb, Rigc, irq | Fnotreset | Fiocard);
11079a747e4fSDavid du Colombier
11089a747e4fSDavid du Colombier /* set power and enable device */
11099a747e4fSDavid du Colombier x = vcode(ct->vpp1);
11109a747e4fSDavid du Colombier wrreg(cb, Rpc, x|Fautopower|Foutena|Fcardena);
11119a747e4fSDavid du Colombier
11129a747e4fSDavid du Colombier /* 16-bit data path */
11139a747e4fSDavid du Colombier if(ct->bit16)
11149a747e4fSDavid du Colombier x = Ftiming|Fiocs16|Fwidth16;
11159a747e4fSDavid du Colombier else
11169a747e4fSDavid du Colombier x = Ftiming;
11179a747e4fSDavid du Colombier if(ct->nio == 2 && ct->io[1].start)
11189a747e4fSDavid du Colombier x |= x<<4;
11199a747e4fSDavid du Colombier wrreg(cb, Rio, x);
11209a747e4fSDavid du Colombier
11219a747e4fSDavid du Colombier /*
11229a747e4fSDavid du Colombier * enable io port map 0
11239a747e4fSDavid du Colombier * the 'top' register value includes the last valid address
11249a747e4fSDavid du Colombier */
11259a747e4fSDavid du Colombier if(isa->port == 0)
11269a747e4fSDavid du Colombier isa->port = ct->io[0].start;
11279a747e4fSDavid du Colombier we = rdreg(cb, Rwe);
11289a747e4fSDavid du Colombier wrreg(cb, Riobtm0lo, isa->port);
11299a747e4fSDavid du Colombier wrreg(cb, Riobtm0hi, isa->port>>8);
11309a747e4fSDavid du Colombier i = isa->port+ct->io[0].len-1;
11319a747e4fSDavid du Colombier wrreg(cb, Riotop0lo, i);
11329a747e4fSDavid du Colombier wrreg(cb, Riotop0hi, i>>8);
11339a747e4fSDavid du Colombier we |= 1<<6;
11349a747e4fSDavid du Colombier if(ct->nio == 2 && ct->io[1].start){
11359a747e4fSDavid du Colombier wrreg(cb, Riobtm1lo, ct->io[1].start);
11369a747e4fSDavid du Colombier wrreg(cb, Riobtm1hi, ct->io[1].start>>8);
11379a747e4fSDavid du Colombier i = ct->io[1].start+ct->io[1].len-1;
11389a747e4fSDavid du Colombier wrreg(cb, Riotop1lo, i);
11399a747e4fSDavid du Colombier wrreg(cb, Riotop1hi, i>>8);
11409a747e4fSDavid du Colombier we |= 1<<7;
11419a747e4fSDavid du Colombier }
11429a747e4fSDavid du Colombier wrreg(cb, Rwe, we);
11439a747e4fSDavid du Colombier
11449a747e4fSDavid du Colombier /* only touch Rconfig if it is present */
11459a747e4fSDavid du Colombier if(pi->conf_present & (1<<Rconfig)){
11469a747e4fSDavid du Colombier PCMmap *m;
11479a747e4fSDavid du Colombier
11489a747e4fSDavid du Colombier /* Reset adapter */
11499a747e4fSDavid du Colombier m = isamap(cb, pi->conf_addr + Rconfig, 1, 1);
11509a747e4fSDavid du Colombier p = KADDR(m->isa + pi->conf_addr + Rconfig - m->ca);
11519a747e4fSDavid du Colombier
11529a747e4fSDavid du Colombier /* set configuration and interrupt type */
11539a747e4fSDavid du Colombier x = ct->index;
11549a747e4fSDavid du Colombier if(ct->irqtype & 0x20)
11559a747e4fSDavid du Colombier x |= Clevel;
11569a747e4fSDavid du Colombier *p = x;
11579a747e4fSDavid du Colombier delay(5);
11589a747e4fSDavid du Colombier
11599a747e4fSDavid du Colombier isaunmap(m);
11609a747e4fSDavid du Colombier }
11619a747e4fSDavid du Colombier
11629a747e4fSDavid du Colombier pi->port = isa->port;
11639a747e4fSDavid du Colombier pi->irq = isa->irq;
11643ff48bf5SDavid du Colombier unlock(cb);
11659a747e4fSDavid du Colombier
116664c7f6b6SDavid du Colombier print("#Y%ld: %s irq %d, port %lX\n", cb - cbslots, pi->verstr, isa->irq, isa->port);
11679a747e4fSDavid du Colombier return (int)(cb - cbslots);
11689a747e4fSDavid du Colombier }
11699a747e4fSDavid du Colombier
11709a747e4fSDavid du Colombier static void
pccard_pcmspecialclose(int slotno)11719a747e4fSDavid du Colombier pccard_pcmspecialclose(int slotno)
11729a747e4fSDavid du Colombier {
11739a747e4fSDavid du Colombier Cardbus *cb = &cbslots[slotno];
11749a747e4fSDavid du Colombier
11759a747e4fSDavid du Colombier wrreg(cb, Rwe, 0); /* no windows */
11769a747e4fSDavid du Colombier cb->special = 0;
11779a747e4fSDavid du Colombier }
11789a747e4fSDavid du Colombier
11799a747e4fSDavid du Colombier static Chan*
pccardattach(char * spec)11809a747e4fSDavid du Colombier pccardattach(char *spec)
11819a747e4fSDavid du Colombier {
11829a747e4fSDavid du Colombier if (!managerstarted) {
11839a747e4fSDavid du Colombier managerstarted = 1;
11849a747e4fSDavid du Colombier kproc("cardbus", processevents, nil);
11859a747e4fSDavid du Colombier }
11869a747e4fSDavid du Colombier return devattach('Y', spec);
11879a747e4fSDavid du Colombier }
11889a747e4fSDavid du Colombier
11899a747e4fSDavid du Colombier enum
11909a747e4fSDavid du Colombier {
11919a747e4fSDavid du Colombier Qdir,
11929a747e4fSDavid du Colombier Qctl,
11939a747e4fSDavid du Colombier
11949a747e4fSDavid du Colombier Nents = 1,
11959a747e4fSDavid du Colombier };
11969a747e4fSDavid du Colombier
11979a747e4fSDavid du Colombier #define SLOTNO(c) ((ulong)((c->qid.path>>8)&0xff))
11989a747e4fSDavid du Colombier #define TYPE(c) ((ulong)(c->qid.path&0xff))
11999a747e4fSDavid du Colombier #define QID(s,t) (((s)<<8)|(t))
12009a747e4fSDavid du Colombier
12019a747e4fSDavid du Colombier static int
pccardgen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)12029a747e4fSDavid du Colombier pccardgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
12039a747e4fSDavid du Colombier {
12049a747e4fSDavid du Colombier int slotno;
12059a747e4fSDavid du Colombier Qid qid;
12069a747e4fSDavid du Colombier long len;
12079a747e4fSDavid du Colombier int entry;
12089a747e4fSDavid du Colombier
12099a747e4fSDavid du Colombier if(i == DEVDOTDOT){
12109a747e4fSDavid du Colombier mkqid(&qid, Qdir, 0, QTDIR);
12119a747e4fSDavid du Colombier devdir(c, qid, "#Y", 0, eve, 0555, dp);
12129a747e4fSDavid du Colombier return 1;
12139a747e4fSDavid du Colombier }
12149a747e4fSDavid du Colombier
12159a747e4fSDavid du Colombier len = 0;
12169a747e4fSDavid du Colombier if(i >= Nents * nslots) return -1;
12179a747e4fSDavid du Colombier slotno = i / Nents;
12189a747e4fSDavid du Colombier entry = i % Nents;
12199a747e4fSDavid du Colombier if (entry == 0) {
12209a747e4fSDavid du Colombier qid.path = QID(slotno, Qctl);
12219a747e4fSDavid du Colombier snprint(up->genbuf, sizeof up->genbuf, "cb%dctl", slotno);
12229a747e4fSDavid du Colombier }
12239a747e4fSDavid du Colombier else {
12249a747e4fSDavid du Colombier /* Entries for memory regions. I'll implement them when
12259a747e4fSDavid du Colombier needed. (pb) */
12269a747e4fSDavid du Colombier }
12279a747e4fSDavid du Colombier qid.vers = 0;
12289a747e4fSDavid du Colombier qid.type = QTFILE;
12299a747e4fSDavid du Colombier devdir(c, qid, up->genbuf, len, eve, 0660, dp);
12309a747e4fSDavid du Colombier return 1;
12319a747e4fSDavid du Colombier }
12329a747e4fSDavid du Colombier
12339a747e4fSDavid du Colombier static Walkqid*
pccardwalk(Chan * c,Chan * nc,char ** name,int nname)12349a747e4fSDavid du Colombier pccardwalk(Chan *c, Chan *nc, char **name, int nname)
12359a747e4fSDavid du Colombier {
12369a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, 0, 0, pccardgen);
12379a747e4fSDavid du Colombier }
12389a747e4fSDavid du Colombier
12399a747e4fSDavid du Colombier static int
pccardstat(Chan * c,uchar * db,int n)12409a747e4fSDavid du Colombier pccardstat(Chan *c, uchar *db, int n)
12419a747e4fSDavid du Colombier {
12429a747e4fSDavid du Colombier return devstat(c, db, n, 0, 0, pccardgen);
12439a747e4fSDavid du Colombier }
12449a747e4fSDavid du Colombier
12459a747e4fSDavid du Colombier static void
increfp(Cardbus * cb)12469a747e4fSDavid du Colombier increfp(Cardbus *cb)
12479a747e4fSDavid du Colombier {
12483ff48bf5SDavid du Colombier lock(&cb->refslock);
12499a747e4fSDavid du Colombier cb->refs++;
12503ff48bf5SDavid du Colombier unlock(&cb->refslock);
12519a747e4fSDavid du Colombier }
12529a747e4fSDavid du Colombier
12539a747e4fSDavid du Colombier static void
decrefp(Cardbus * cb)12549a747e4fSDavid du Colombier decrefp(Cardbus *cb)
12559a747e4fSDavid du Colombier {
12563ff48bf5SDavid du Colombier lock(&cb->refslock);
12579a747e4fSDavid du Colombier cb->refs--;
12583ff48bf5SDavid du Colombier unlock(&cb->refslock);
12599a747e4fSDavid du Colombier }
12609a747e4fSDavid du Colombier
12619a747e4fSDavid du Colombier static Chan*
pccardopen(Chan * c,int omode)12629a747e4fSDavid du Colombier pccardopen(Chan *c, int omode)
12639a747e4fSDavid du Colombier {
12649a747e4fSDavid du Colombier if (c->qid.type & QTDIR){
12659a747e4fSDavid du Colombier if(omode != OREAD)
12669a747e4fSDavid du Colombier error(Eperm);
12679a747e4fSDavid du Colombier } else
12689a747e4fSDavid du Colombier increfp(&cbslots[SLOTNO(c)]);
12699a747e4fSDavid du Colombier c->mode = openmode(omode);
12709a747e4fSDavid du Colombier c->flag |= COPEN;
12719a747e4fSDavid du Colombier c->offset = 0;
12729a747e4fSDavid du Colombier return c;
12739a747e4fSDavid du Colombier }
12749a747e4fSDavid du Colombier
12759a747e4fSDavid du Colombier static void
pccardclose(Chan * c)12769a747e4fSDavid du Colombier pccardclose(Chan *c)
12779a747e4fSDavid du Colombier {
12789a747e4fSDavid du Colombier if(c->flag & COPEN)
12799a747e4fSDavid du Colombier if((c->qid.type & QTDIR) == 0)
12809a747e4fSDavid du Colombier decrefp(&cbslots[SLOTNO(c)]);
12819a747e4fSDavid du Colombier }
12829a747e4fSDavid du Colombier
12839a747e4fSDavid du Colombier static long
pccardread(Chan * c,void * a,long n,vlong offset)12849a747e4fSDavid du Colombier pccardread(Chan *c, void *a, long n, vlong offset)
12859a747e4fSDavid du Colombier {
12869a747e4fSDavid du Colombier Cardbus *cb;
12879a747e4fSDavid du Colombier char *buf, *p, *e;
1288d9306527SDavid du Colombier int i;
12899a747e4fSDavid du Colombier
12909a747e4fSDavid du Colombier switch(TYPE(c)){
12919a747e4fSDavid du Colombier case Qdir:
12929a747e4fSDavid du Colombier return devdirread(c, a, n, 0, 0, pccardgen);
12939a747e4fSDavid du Colombier
12949a747e4fSDavid du Colombier case Qctl:
12959a747e4fSDavid du Colombier buf = p = malloc(READSTR);
1296*aa72973aSDavid du Colombier if(p == nil)
1297*aa72973aSDavid du Colombier error(Enomem);
12989a747e4fSDavid du Colombier buf[0] = 0;
12999a747e4fSDavid du Colombier e = p + READSTR;
13009a747e4fSDavid du Colombier
13019a747e4fSDavid du Colombier cb = &cbslots[SLOTNO(c)];
13023ff48bf5SDavid du Colombier lock(cb);
13039a747e4fSDavid du Colombier p = seprint(p, e, "slot %ld: %s; ", cb - cbslots, states[cb->state]);
13049a747e4fSDavid du Colombier
13059a747e4fSDavid du Colombier switch (cb->type) {
13069a747e4fSDavid du Colombier case -1:
13079a747e4fSDavid du Colombier seprint(p, e, "\n");
13089a747e4fSDavid du Colombier break;
13099a747e4fSDavid du Colombier
13109a747e4fSDavid du Colombier case PC32:
13119a747e4fSDavid du Colombier if (cb->pci->bridge) {
13129a747e4fSDavid du Colombier Pcidev *pci = cb->pci->bridge;
13139a747e4fSDavid du Colombier int i;
13149a747e4fSDavid du Colombier
13159a747e4fSDavid du Colombier while (pci) {
13169a747e4fSDavid du Colombier p = seprint(p, e, "%.4uX %.4uX; irq %d\n",
13179a747e4fSDavid du Colombier pci->vid, pci->did, pci->intl);
13189a747e4fSDavid du Colombier for (i = 0; i != Nbars; i++)
13199a747e4fSDavid du Colombier if (pci->mem[i].size)
13209a747e4fSDavid du Colombier p = seprint(p, e,
13219a747e4fSDavid du Colombier "\tmem[%d] %.8ulX (%.8uX)\n",
13229a747e4fSDavid du Colombier i, pci->mem[i].bar,
13239a747e4fSDavid du Colombier pci->mem[i].size);
13249a747e4fSDavid du Colombier if (pci->rom.size)
13259a747e4fSDavid du Colombier p = seprint(p, e, "\tROM %.8ulX (%.8uX)\n",
13269a747e4fSDavid du Colombier pci->rom.bar, pci->rom.size);
13279a747e4fSDavid du Colombier pci = pci->list;
13289a747e4fSDavid du Colombier }
13299a747e4fSDavid du Colombier }
13309a747e4fSDavid du Colombier break;
13319a747e4fSDavid du Colombier
13329a747e4fSDavid du Colombier case PC16:
13339a747e4fSDavid du Colombier if (cb->state == SlotConfigured) {
13349a747e4fSDavid du Colombier Pcminfo *pi = &cb->linfo;
13359a747e4fSDavid du Colombier
13369a747e4fSDavid du Colombier p = seprint(p, e, "%s port %X; irq %d;\n",
13379a747e4fSDavid du Colombier pi->verstr, pi->port,
13389a747e4fSDavid du Colombier pi->irq);
1339d9306527SDavid du Colombier for (i = 0; i != pi->nctab; i++) {
13409a747e4fSDavid du Colombier PCMconftab *ct;
1341d9306527SDavid du Colombier int j;
13429a747e4fSDavid du Colombier
1343d9306527SDavid du Colombier ct = &pi->ctab[i];
13449a747e4fSDavid du Colombier p = seprint(p, e,
134568060204SDavid du Colombier "\tconfiguration[%d] irqs %.4uX; vpp %d, %d; %s\n",
134668060204SDavid du Colombier i, ct->irqs, ct->vpp1, ct->vpp2,
13479a747e4fSDavid du Colombier (ct == pi->defctab)? "(default);": "");
1348d9306527SDavid du Colombier for (j = 0; j != ct->nio; j++)
1349d9306527SDavid du Colombier if (ct->io[j].len > 0)
13509a747e4fSDavid du Colombier p = seprint(p, e, "\t\tio[%d] %.8ulX %uld\n",
135168060204SDavid du Colombier j, ct->io[j].start, ct->io[j].len);
13529a747e4fSDavid du Colombier }
13539a747e4fSDavid du Colombier }
13549a747e4fSDavid du Colombier break;
13559a747e4fSDavid du Colombier }
13563ff48bf5SDavid du Colombier unlock(cb);
13579a747e4fSDavid du Colombier
13589a747e4fSDavid du Colombier n = readstr(offset, a, n, buf);
13599a747e4fSDavid du Colombier free(buf);
13609a747e4fSDavid du Colombier return n;
13619a747e4fSDavid du Colombier }
13629a747e4fSDavid du Colombier return 0;
13639a747e4fSDavid du Colombier }
13649a747e4fSDavid du Colombier
13659a747e4fSDavid du Colombier static long
pccardwrite(Chan * c,void * v,long n,vlong)13669a747e4fSDavid du Colombier pccardwrite(Chan *c, void *v, long n, vlong)
13679a747e4fSDavid du Colombier {
13689a747e4fSDavid du Colombier Rune r;
13699a747e4fSDavid du Colombier ulong n0;
13709a747e4fSDavid du Colombier char *device;
13719a747e4fSDavid du Colombier Cmdbuf *cbf;
13729a747e4fSDavid du Colombier Cmdtab *ct;
13739a747e4fSDavid du Colombier Cardbus *cb;
13749a747e4fSDavid du Colombier
13759a747e4fSDavid du Colombier n0 = n;
13769a747e4fSDavid du Colombier switch(TYPE(c)){
13779a747e4fSDavid du Colombier case Qctl:
13789a747e4fSDavid du Colombier cb = &cbslots[SLOTNO(c)];
13799a747e4fSDavid du Colombier
13809a747e4fSDavid du Colombier cbf = parsecmd(v, n);
13819a747e4fSDavid du Colombier if(waserror()){
13829a747e4fSDavid du Colombier free(cbf);
13839a747e4fSDavid du Colombier nexterror();
13849a747e4fSDavid du Colombier }
13859a747e4fSDavid du Colombier ct = lookupcmd(cbf, pccardctlmsg, nelem(pccardctlmsg));
13869a747e4fSDavid du Colombier switch(ct->index){
13879a747e4fSDavid du Colombier case CMdown:
13889a747e4fSDavid du Colombier device = cbf->f[1];
13899a747e4fSDavid du Colombier device += chartorune(&r, device);
13909a747e4fSDavid du Colombier if ((n = devno(r, 1)) >= 0 && devtab[n]->config)
13919a747e4fSDavid du Colombier devtab[n]->config(0, device, nil);
13929a747e4fSDavid du Colombier qengine(cb, CardEjected);
13939a747e4fSDavid du Colombier break;
13949a747e4fSDavid du Colombier case CMpower:
13959a747e4fSDavid du Colombier if ((cb->regs[SocketState] & SS_CCD) == 0)
13969a747e4fSDavid du Colombier qengine(cb, CardDetected);
13979a747e4fSDavid du Colombier break;
13989a747e4fSDavid du Colombier }
13999a747e4fSDavid du Colombier poperror();
14009a747e4fSDavid du Colombier free(cbf);
14019a747e4fSDavid du Colombier break;
14029a747e4fSDavid du Colombier }
14039a747e4fSDavid du Colombier return n0 - n;
14049a747e4fSDavid du Colombier }
14059a747e4fSDavid du Colombier
14069a747e4fSDavid du Colombier Dev pccarddevtab = {
14079a747e4fSDavid du Colombier 'Y',
14089a747e4fSDavid du Colombier "cardbus",
14099a747e4fSDavid du Colombier
14109a747e4fSDavid du Colombier devreset,
14119a747e4fSDavid du Colombier devinit,
14129a747e4fSDavid du Colombier devshutdown,
14139a747e4fSDavid du Colombier pccardattach,
14149a747e4fSDavid du Colombier pccardwalk,
14159a747e4fSDavid du Colombier pccardstat,
14169a747e4fSDavid du Colombier pccardopen,
14179a747e4fSDavid du Colombier devcreate,
14189a747e4fSDavid du Colombier pccardclose,
14199a747e4fSDavid du Colombier pccardread,
14209a747e4fSDavid du Colombier devbread,
14219a747e4fSDavid du Colombier pccardwrite,
14229a747e4fSDavid du Colombier devbwrite,
14239a747e4fSDavid du Colombier devremove,
14249a747e4fSDavid du Colombier devwstat,
14259a747e4fSDavid du Colombier };
14269a747e4fSDavid du Colombier
14279a747e4fSDavid du Colombier static PCMmap *
isamap(Cardbus * cb,ulong offset,int len,int attr)14289a747e4fSDavid du Colombier isamap(Cardbus *cb, ulong offset, int len, int attr)
14299a747e4fSDavid du Colombier {
14309a747e4fSDavid du Colombier uchar we, bit;
14319a747e4fSDavid du Colombier PCMmap *m, *nm;
14329a747e4fSDavid du Colombier Pcminfo *pi;
14339a747e4fSDavid du Colombier int i;
14349a747e4fSDavid du Colombier ulong e;
14359a747e4fSDavid du Colombier
14369a747e4fSDavid du Colombier pi = &cb->linfo;
14379a747e4fSDavid du Colombier
14389a747e4fSDavid du Colombier /* convert offset to granularity */
14399a747e4fSDavid du Colombier if(len <= 0)
14409a747e4fSDavid du Colombier len = 1;
14419a747e4fSDavid du Colombier e = ROUND(offset+len, Mgran);
14429a747e4fSDavid du Colombier offset &= Mmask;
14439a747e4fSDavid du Colombier len = e - offset;
14449a747e4fSDavid du Colombier
14459a747e4fSDavid du Colombier /* look for a map that covers the right area */
14469a747e4fSDavid du Colombier we = rdreg(cb, Rwe);
14479a747e4fSDavid du Colombier bit = 1;
14489a747e4fSDavid du Colombier nm = 0;
14499a747e4fSDavid du Colombier for(m = pi->mmap; m < &pi->mmap[nelem(pi->mmap)]; m++){
14509a747e4fSDavid du Colombier if((we & bit))
14519a747e4fSDavid du Colombier if(m->attr == attr)
14529a747e4fSDavid du Colombier if(offset >= m->ca && e <= m->cea){
14539a747e4fSDavid du Colombier
14549a747e4fSDavid du Colombier m->ref++;
14559a747e4fSDavid du Colombier return m;
14569a747e4fSDavid du Colombier }
14579a747e4fSDavid du Colombier bit <<= 1;
14589a747e4fSDavid du Colombier if(nm == 0 && m->ref == 0)
14599a747e4fSDavid du Colombier nm = m;
14609a747e4fSDavid du Colombier }
14619a747e4fSDavid du Colombier m = nm;
14629a747e4fSDavid du Colombier if(m == 0)
14639a747e4fSDavid du Colombier return 0;
14649a747e4fSDavid du Colombier
14659a747e4fSDavid du Colombier /* if isa space isn't big enough, free it and get more */
14669a747e4fSDavid du Colombier if(m->len < len){
14679a747e4fSDavid du Colombier if(m->isa){
14689a747e4fSDavid du Colombier umbfree(m->isa, m->len);
14699a747e4fSDavid du Colombier m->len = 0;
14709a747e4fSDavid du Colombier }
14719a747e4fSDavid du Colombier m->isa = PADDR(umbmalloc(0, len, Mgran));
14729a747e4fSDavid du Colombier if(m->isa == 0){
14739a747e4fSDavid du Colombier print("isamap: out of isa space\n");
14749a747e4fSDavid du Colombier return 0;
14759a747e4fSDavid du Colombier }
14769a747e4fSDavid du Colombier m->len = len;
14779a747e4fSDavid du Colombier }
14789a747e4fSDavid du Colombier
14799a747e4fSDavid du Colombier /* set up new map */
14809a747e4fSDavid du Colombier m->ca = offset;
14819a747e4fSDavid du Colombier m->cea = m->ca + m->len;
14829a747e4fSDavid du Colombier m->attr = attr;
14839a747e4fSDavid du Colombier i = m - pi->mmap;
14849a747e4fSDavid du Colombier bit = 1<<i;
14859a747e4fSDavid du Colombier wrreg(cb, Rwe, we & ~bit); /* disable map before changing it */
14869a747e4fSDavid du Colombier wrreg(cb, MAP(i, Mbtmlo), m->isa>>Mshift);
14879a747e4fSDavid du Colombier wrreg(cb, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
14889a747e4fSDavid du Colombier wrreg(cb, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
14899a747e4fSDavid du Colombier wrreg(cb, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
14909a747e4fSDavid du Colombier offset -= m->isa;
14919a747e4fSDavid du Colombier offset &= (1<<25)-1;
14929a747e4fSDavid du Colombier offset >>= Mshift;
14939a747e4fSDavid du Colombier wrreg(cb, MAP(i, Mofflo), offset);
14949a747e4fSDavid du Colombier wrreg(cb, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
14959a747e4fSDavid du Colombier wrreg(cb, Rwe, we | bit); /* enable map */
14969a747e4fSDavid du Colombier m->ref = 1;
14979a747e4fSDavid du Colombier
14989a747e4fSDavid du Colombier return m;
14999a747e4fSDavid du Colombier }
15009a747e4fSDavid du Colombier
15019a747e4fSDavid du Colombier static void
isaunmap(PCMmap * m)15029a747e4fSDavid du Colombier isaunmap(PCMmap* m)
15039a747e4fSDavid du Colombier {
15049a747e4fSDavid du Colombier m->ref--;
15059a747e4fSDavid du Colombier }
15069a747e4fSDavid du Colombier
15079a747e4fSDavid du Colombier /*
15089a747e4fSDavid du Colombier * reading and writing card registers
15099a747e4fSDavid du Colombier */
15109a747e4fSDavid du Colombier static uchar
rdreg(Cardbus * cb,int index)15119a747e4fSDavid du Colombier rdreg(Cardbus *cb, int index)
15129a747e4fSDavid du Colombier {
15139a747e4fSDavid du Colombier outb(cb->lindex, cb->lbase + index);
15149a747e4fSDavid du Colombier return inb(cb->ldata);
15159a747e4fSDavid du Colombier }
15169a747e4fSDavid du Colombier
15179a747e4fSDavid du Colombier static void
wrreg(Cardbus * cb,int index,uchar val)15189a747e4fSDavid du Colombier wrreg(Cardbus *cb, int index, uchar val)
15199a747e4fSDavid du Colombier {
15209a747e4fSDavid du Colombier outb(cb->lindex, cb->lbase + index);
15219a747e4fSDavid du Colombier outb(cb->ldata, val);
15229a747e4fSDavid du Colombier }
15239a747e4fSDavid du Colombier
15249a747e4fSDavid du Colombier static int
readc(Cisdat * cis,uchar * x)15259a747e4fSDavid du Colombier readc(Cisdat *cis, uchar *x)
15269a747e4fSDavid du Colombier {
15279a747e4fSDavid du Colombier if(cis->cispos >= cis->cislen)
15289a747e4fSDavid du Colombier return 0;
15299a747e4fSDavid du Colombier *x = cis->cisbase[cis->cisskip*cis->cispos];
15309a747e4fSDavid du Colombier cis->cispos++;
15319a747e4fSDavid du Colombier return 1;
15329a747e4fSDavid du Colombier }
15339a747e4fSDavid du Colombier
15349a747e4fSDavid du Colombier static ulong
getlong(Cisdat * cis,int size)15359a747e4fSDavid du Colombier getlong(Cisdat *cis, int size)
15369a747e4fSDavid du Colombier {
15379a747e4fSDavid du Colombier uchar c;
15389a747e4fSDavid du Colombier int i;
15399a747e4fSDavid du Colombier ulong x;
15409a747e4fSDavid du Colombier
15419a747e4fSDavid du Colombier x = 0;
15429a747e4fSDavid du Colombier for(i = 0; i < size; i++){
15439a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
15449a747e4fSDavid du Colombier break;
15459a747e4fSDavid du Colombier x |= c<<(i*8);
15469a747e4fSDavid du Colombier }
15479a747e4fSDavid du Colombier return x;
15489a747e4fSDavid du Colombier }
15499a747e4fSDavid du Colombier
15509a747e4fSDavid du Colombier static void
tcfig(Cardbus * cb,Cisdat * cis,int)15519a747e4fSDavid du Colombier tcfig(Cardbus *cb, Cisdat *cis, int )
15529a747e4fSDavid du Colombier {
15539a747e4fSDavid du Colombier uchar size, rasize, rmsize;
15549a747e4fSDavid du Colombier uchar last;
15559a747e4fSDavid du Colombier Pcminfo *pi;
15569a747e4fSDavid du Colombier
15579a747e4fSDavid du Colombier if(readc(cis, &size) != 1)
15589a747e4fSDavid du Colombier return;
15599a747e4fSDavid du Colombier rasize = (size&0x3) + 1;
15609a747e4fSDavid du Colombier rmsize = ((size>>2)&0xf) + 1;
15619a747e4fSDavid du Colombier if(readc(cis, &last) != 1)
15629a747e4fSDavid du Colombier return;
15639a747e4fSDavid du Colombier
15649a747e4fSDavid du Colombier pi = &cb->linfo;
15659a747e4fSDavid du Colombier pi->conf_addr = getlong(cis, rasize);
15669a747e4fSDavid du Colombier pi->conf_present = getlong(cis, rmsize);
15679a747e4fSDavid du Colombier }
15689a747e4fSDavid du Colombier
15699a747e4fSDavid du Colombier static void
tvers1(Cardbus * cb,Cisdat * cis,int)15709a747e4fSDavid du Colombier tvers1(Cardbus *cb, Cisdat *cis, int )
15719a747e4fSDavid du Colombier {
15729a747e4fSDavid du Colombier uchar c, major, minor, last;
15739a747e4fSDavid du Colombier int i;
15749a747e4fSDavid du Colombier Pcminfo *pi;
15759a747e4fSDavid du Colombier
15769a747e4fSDavid du Colombier pi = &cb->linfo;
15779a747e4fSDavid du Colombier if(readc(cis, &major) != 1)
15789a747e4fSDavid du Colombier return;
15799a747e4fSDavid du Colombier if(readc(cis, &minor) != 1)
15809a747e4fSDavid du Colombier return;
15819a747e4fSDavid du Colombier last = 0;
15829a747e4fSDavid du Colombier for(i = 0; i < sizeof(pi->verstr) - 1; i++){
15839a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
15849a747e4fSDavid du Colombier return;
15859a747e4fSDavid du Colombier if(c == 0)
15869a747e4fSDavid du Colombier c = ';';
15879a747e4fSDavid du Colombier if(c == '\n')
15889a747e4fSDavid du Colombier c = ';';
15899a747e4fSDavid du Colombier if(c == 0xff)
15909a747e4fSDavid du Colombier break;
15919a747e4fSDavid du Colombier if(c == ';' && last == ';')
15929a747e4fSDavid du Colombier continue;
15939a747e4fSDavid du Colombier pi->verstr[i] = c;
15949a747e4fSDavid du Colombier last = c;
15959a747e4fSDavid du Colombier }
15969a747e4fSDavid du Colombier pi->verstr[i] = 0;
15979a747e4fSDavid du Colombier }
15989a747e4fSDavid du Colombier
15999a747e4fSDavid du Colombier static ulong
microvolt(Cisdat * cis)16009a747e4fSDavid du Colombier microvolt(Cisdat *cis)
16019a747e4fSDavid du Colombier {
16029a747e4fSDavid du Colombier uchar c;
16039a747e4fSDavid du Colombier ulong microvolts;
16049a747e4fSDavid du Colombier ulong exp;
16059a747e4fSDavid du Colombier
16069a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
16079a747e4fSDavid du Colombier return 0;
16089a747e4fSDavid du Colombier exp = exponent[c&0x7];
16099a747e4fSDavid du Colombier microvolts = vmant[(c>>3)&0xf]*exp;
16109a747e4fSDavid du Colombier while(c & 0x80){
16119a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
16129a747e4fSDavid du Colombier return 0;
16139a747e4fSDavid du Colombier switch(c){
16149a747e4fSDavid du Colombier case 0x7d:
16159a747e4fSDavid du Colombier break; /* high impedence when sleeping */
16169a747e4fSDavid du Colombier case 0x7e:
16179a747e4fSDavid du Colombier case 0x7f:
16189a747e4fSDavid du Colombier microvolts = 0; /* no connection */
16199a747e4fSDavid du Colombier break;
16209a747e4fSDavid du Colombier default:
16219a747e4fSDavid du Colombier exp /= 10;
16229a747e4fSDavid du Colombier microvolts += exp*(c&0x7f);
16239a747e4fSDavid du Colombier }
16249a747e4fSDavid du Colombier }
16259a747e4fSDavid du Colombier return microvolts;
16269a747e4fSDavid du Colombier }
16279a747e4fSDavid du Colombier
16289a747e4fSDavid du Colombier static ulong
nanoamps(Cisdat * cis)16299a747e4fSDavid du Colombier nanoamps(Cisdat *cis)
16309a747e4fSDavid du Colombier {
16319a747e4fSDavid du Colombier uchar c;
16329a747e4fSDavid du Colombier ulong nanoamps;
16339a747e4fSDavid du Colombier
16349a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
16359a747e4fSDavid du Colombier return 0;
16369a747e4fSDavid du Colombier nanoamps = exponent[c&0x7]*vmant[(c>>3)&0xf];
16379a747e4fSDavid du Colombier while(c & 0x80){
16389a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
16399a747e4fSDavid du Colombier return 0;
16409a747e4fSDavid du Colombier if(c == 0x7d || c == 0x7e || c == 0x7f)
16419a747e4fSDavid du Colombier nanoamps = 0;
16429a747e4fSDavid du Colombier }
16439a747e4fSDavid du Colombier return nanoamps;
16449a747e4fSDavid du Colombier }
16459a747e4fSDavid du Colombier
16469a747e4fSDavid du Colombier /*
16479a747e4fSDavid du Colombier * only nominal voltage (feature 1) is important for config,
16489a747e4fSDavid du Colombier * other features must read card to stay in sync.
16499a747e4fSDavid du Colombier */
16509a747e4fSDavid du Colombier static ulong
power(Cisdat * cis)16519a747e4fSDavid du Colombier power(Cisdat *cis)
16529a747e4fSDavid du Colombier {
16539a747e4fSDavid du Colombier uchar feature;
16549a747e4fSDavid du Colombier ulong mv;
16559a747e4fSDavid du Colombier
16569a747e4fSDavid du Colombier mv = 0;
16579a747e4fSDavid du Colombier if(readc(cis, &feature) != 1)
16589a747e4fSDavid du Colombier return 0;
16599a747e4fSDavid du Colombier if(feature & 1)
16609a747e4fSDavid du Colombier mv = microvolt(cis);
16619a747e4fSDavid du Colombier if(feature & 2)
16629a747e4fSDavid du Colombier microvolt(cis);
16639a747e4fSDavid du Colombier if(feature & 4)
16649a747e4fSDavid du Colombier microvolt(cis);
16659a747e4fSDavid du Colombier if(feature & 8)
16669a747e4fSDavid du Colombier nanoamps(cis);
16679a747e4fSDavid du Colombier if(feature & 0x10)
16689a747e4fSDavid du Colombier nanoamps(cis);
16699a747e4fSDavid du Colombier if(feature & 0x20)
16709a747e4fSDavid du Colombier nanoamps(cis);
16719a747e4fSDavid du Colombier if(feature & 0x40)
16729a747e4fSDavid du Colombier nanoamps(cis);
16739a747e4fSDavid du Colombier return mv/1000000;
16749a747e4fSDavid du Colombier }
16759a747e4fSDavid du Colombier
16769a747e4fSDavid du Colombier static ulong
ttiming(Cisdat * cis,int scale)16779a747e4fSDavid du Colombier ttiming(Cisdat *cis, int scale)
16789a747e4fSDavid du Colombier {
16799a747e4fSDavid du Colombier uchar unscaled;
16809a747e4fSDavid du Colombier ulong nanosecs;
16819a747e4fSDavid du Colombier
16829a747e4fSDavid du Colombier if(readc(cis, &unscaled) != 1)
16839a747e4fSDavid du Colombier return 0;
16849a747e4fSDavid du Colombier nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
16859a747e4fSDavid du Colombier nanosecs = nanosecs * exponent[scale];
16869a747e4fSDavid du Colombier return nanosecs;
16879a747e4fSDavid du Colombier }
16889a747e4fSDavid du Colombier
16899a747e4fSDavid du Colombier static void
timing(Cisdat * cis,PCMconftab * ct)16909a747e4fSDavid du Colombier timing(Cisdat *cis, PCMconftab *ct)
16919a747e4fSDavid du Colombier {
16929a747e4fSDavid du Colombier uchar c, i;
16939a747e4fSDavid du Colombier
16949a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
16959a747e4fSDavid du Colombier return;
16969a747e4fSDavid du Colombier i = c&0x3;
16979a747e4fSDavid du Colombier if(i != 3)
16989a747e4fSDavid du Colombier ct->maxwait = ttiming(cis, i); /* max wait */
16999a747e4fSDavid du Colombier i = (c>>2)&0x7;
17009a747e4fSDavid du Colombier if(i != 7)
17019a747e4fSDavid du Colombier ct->readywait = ttiming(cis, i); /* max ready/busy wait */
17029a747e4fSDavid du Colombier i = (c>>5)&0x7;
17039a747e4fSDavid du Colombier if(i != 7)
17049a747e4fSDavid du Colombier ct->otherwait = ttiming(cis, i); /* reserved wait */
17059a747e4fSDavid du Colombier }
17069a747e4fSDavid du Colombier
17079a747e4fSDavid du Colombier static void
iospaces(Cisdat * cis,PCMconftab * ct)17089a747e4fSDavid du Colombier iospaces(Cisdat *cis, PCMconftab *ct)
17099a747e4fSDavid du Colombier {
17109a747e4fSDavid du Colombier uchar c;
17119a747e4fSDavid du Colombier int i, nio;
17129a747e4fSDavid du Colombier
17139a747e4fSDavid du Colombier ct->nio = 0;
17149a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
17159a747e4fSDavid du Colombier return;
17169a747e4fSDavid du Colombier
17179a747e4fSDavid du Colombier ct->bit16 = ((c>>5)&3) >= 2;
17189a747e4fSDavid du Colombier if(!(c & 0x80)){
17199a747e4fSDavid du Colombier ct->io[0].start = 0;
17209a747e4fSDavid du Colombier ct->io[0].len = 1<<(c&0x1f);
17219a747e4fSDavid du Colombier ct->nio = 1;
17229a747e4fSDavid du Colombier return;
17239a747e4fSDavid du Colombier }
17249a747e4fSDavid du Colombier
17259a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
17269a747e4fSDavid du Colombier return;
17279a747e4fSDavid du Colombier
17289a747e4fSDavid du Colombier /*
17299a747e4fSDavid du Colombier * For each of the range descriptions read the
17309a747e4fSDavid du Colombier * start address and the length (value is length-1).
17319a747e4fSDavid du Colombier */
17329a747e4fSDavid du Colombier nio = (c&0xf)+1;
17339a747e4fSDavid du Colombier for(i = 0; i < nio; i++){
17349a747e4fSDavid du Colombier ct->io[i].start = getlong(cis, (c>>4)&0x3);
17359a747e4fSDavid du Colombier ct->io[i].len = getlong(cis, (c>>6)&0x3)+1;
17369a747e4fSDavid du Colombier }
17379a747e4fSDavid du Colombier ct->nio = nio;
17389a747e4fSDavid du Colombier }
17399a747e4fSDavid du Colombier
17409a747e4fSDavid du Colombier static void
irq(Cisdat * cis,PCMconftab * ct)17419a747e4fSDavid du Colombier irq(Cisdat *cis, PCMconftab *ct)
17429a747e4fSDavid du Colombier {
17439a747e4fSDavid du Colombier uchar c;
17449a747e4fSDavid du Colombier
17459a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
17469a747e4fSDavid du Colombier return;
17479a747e4fSDavid du Colombier ct->irqtype = c & 0xe0;
17489a747e4fSDavid du Colombier if(c & 0x10)
17499a747e4fSDavid du Colombier ct->irqs = getlong(cis, 2);
17509a747e4fSDavid du Colombier else
17519a747e4fSDavid du Colombier ct->irqs = 1<<(c&0xf);
17529a747e4fSDavid du Colombier ct->irqs &= 0xDEB8; /* levels available to card */
17539a747e4fSDavid du Colombier }
17549a747e4fSDavid du Colombier
17559a747e4fSDavid du Colombier static void
memspace(Cisdat * cis,int asize,int lsize,int host)17569a747e4fSDavid du Colombier memspace(Cisdat *cis, int asize, int lsize, int host)
17579a747e4fSDavid du Colombier {
17589a747e4fSDavid du Colombier ulong haddress, address, len;
17599a747e4fSDavid du Colombier
17609a747e4fSDavid du Colombier len = getlong(cis, lsize)*256;
17619a747e4fSDavid du Colombier address = getlong(cis, asize)*256;
17629a747e4fSDavid du Colombier USED(len, address);
17639a747e4fSDavid du Colombier if(host){
17649a747e4fSDavid du Colombier haddress = getlong(cis, asize)*256;
17659a747e4fSDavid du Colombier USED(haddress);
17669a747e4fSDavid du Colombier }
17679a747e4fSDavid du Colombier }
17689a747e4fSDavid du Colombier
17699a747e4fSDavid du Colombier static void
tentry(Cardbus * cb,Cisdat * cis,int)17709a747e4fSDavid du Colombier tentry(Cardbus *cb, Cisdat *cis, int )
17719a747e4fSDavid du Colombier {
17729a747e4fSDavid du Colombier uchar c, i, feature;
17739a747e4fSDavid du Colombier PCMconftab *ct;
17749a747e4fSDavid du Colombier Pcminfo *pi;
17759a747e4fSDavid du Colombier
17769a747e4fSDavid du Colombier pi = &cb->linfo;
17779a747e4fSDavid du Colombier if(pi->nctab >= nelem(pi->ctab))
17789a747e4fSDavid du Colombier return;
17799a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
17809a747e4fSDavid du Colombier return;
17819a747e4fSDavid du Colombier ct = &pi->ctab[pi->nctab++];
17829a747e4fSDavid du Colombier
17839a747e4fSDavid du Colombier /* copy from last default config */
17849a747e4fSDavid du Colombier if(pi->defctab)
17859a747e4fSDavid du Colombier *ct = *pi->defctab;
17869a747e4fSDavid du Colombier
17879a747e4fSDavid du Colombier ct->index = c & 0x3f;
17889a747e4fSDavid du Colombier
17899a747e4fSDavid du Colombier /* is this the new default? */
17909a747e4fSDavid du Colombier if(c & 0x40)
17919a747e4fSDavid du Colombier pi->defctab = ct;
17929a747e4fSDavid du Colombier
17939a747e4fSDavid du Colombier /* memory wait specified? */
17949a747e4fSDavid du Colombier if(c & 0x80){
17959a747e4fSDavid du Colombier if(readc(cis, &i) != 1)
17969a747e4fSDavid du Colombier return;
17979a747e4fSDavid du Colombier if(i&0x80)
17989a747e4fSDavid du Colombier ct->memwait = 1;
17999a747e4fSDavid du Colombier }
18009a747e4fSDavid du Colombier
18019a747e4fSDavid du Colombier if(readc(cis, &feature) != 1)
18029a747e4fSDavid du Colombier return;
18039a747e4fSDavid du Colombier switch(feature&0x3){
18049a747e4fSDavid du Colombier case 1:
18059a747e4fSDavid du Colombier ct->vpp1 = ct->vpp2 = power(cis);
18069a747e4fSDavid du Colombier break;
18079a747e4fSDavid du Colombier case 2:
18089a747e4fSDavid du Colombier power(cis);
18099a747e4fSDavid du Colombier ct->vpp1 = ct->vpp2 = power(cis);
18109a747e4fSDavid du Colombier break;
18119a747e4fSDavid du Colombier case 3:
18129a747e4fSDavid du Colombier power(cis);
18139a747e4fSDavid du Colombier ct->vpp1 = power(cis);
18149a747e4fSDavid du Colombier ct->vpp2 = power(cis);
18159a747e4fSDavid du Colombier break;
18169a747e4fSDavid du Colombier default:
18179a747e4fSDavid du Colombier break;
18189a747e4fSDavid du Colombier }
18199a747e4fSDavid du Colombier if(feature&0x4)
18209a747e4fSDavid du Colombier timing(cis, ct);
18219a747e4fSDavid du Colombier if(feature&0x8)
18229a747e4fSDavid du Colombier iospaces(cis, ct);
18239a747e4fSDavid du Colombier if(feature&0x10)
18249a747e4fSDavid du Colombier irq(cis, ct);
18259a747e4fSDavid du Colombier switch((feature>>5)&0x3){
18269a747e4fSDavid du Colombier case 1:
18279a747e4fSDavid du Colombier memspace(cis, 0, 2, 0);
18289a747e4fSDavid du Colombier break;
18299a747e4fSDavid du Colombier case 2:
18309a747e4fSDavid du Colombier memspace(cis, 2, 2, 0);
18319a747e4fSDavid du Colombier break;
18329a747e4fSDavid du Colombier case 3:
18339a747e4fSDavid du Colombier if(readc(cis, &c) != 1)
18349a747e4fSDavid du Colombier return;
18359a747e4fSDavid du Colombier for(i = 0; i <= (c&0x7); i++)
18369a747e4fSDavid du Colombier memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
18379a747e4fSDavid du Colombier break;
18389a747e4fSDavid du Colombier }
18399a747e4fSDavid du Colombier }
18409a747e4fSDavid du Colombier
18419a747e4fSDavid du Colombier static void
i82365probe(Cardbus * cb,int lindex,int ldata)18429a747e4fSDavid du Colombier i82365probe(Cardbus *cb, int lindex, int ldata)
18439a747e4fSDavid du Colombier {
18449a747e4fSDavid du Colombier uchar c, id;
18459a747e4fSDavid du Colombier int dev = 0; /* According to the Ricoh spec 00->3F _and_ 80->BF seem
18469a747e4fSDavid du Colombier to be the same socket A (ditto for B). */
18479a747e4fSDavid du Colombier
18489a747e4fSDavid du Colombier outb(lindex, Rid + (dev<<7));
18499a747e4fSDavid du Colombier id = inb(ldata);
18509a747e4fSDavid du Colombier if((id & 0xf0) != 0x80)
18519a747e4fSDavid du Colombier return; /* not a memory & I/O card */
18529a747e4fSDavid du Colombier if((id & 0x0f) == 0x00)
18539a747e4fSDavid du Colombier return; /* no revision number, not possible */
18549a747e4fSDavid du Colombier
18559a747e4fSDavid du Colombier cb->lindex = lindex;
18569a747e4fSDavid du Colombier cb->ldata = ldata;
18579a747e4fSDavid du Colombier cb->ltype = Ti82365;
18589a747e4fSDavid du Colombier cb->lbase = (int)(cb - cbslots) * 0x40;
18599a747e4fSDavid du Colombier
18609a747e4fSDavid du Colombier switch(id){
18619a747e4fSDavid du Colombier case 0x82:
18629a747e4fSDavid du Colombier case 0x83:
18639a747e4fSDavid du Colombier case 0x84:
18649a747e4fSDavid du Colombier /* could be a cirrus */
18659a747e4fSDavid du Colombier outb(cb->lindex, Rchipinfo + (dev<<7));
18669a747e4fSDavid du Colombier outb(cb->ldata, 0);
18679a747e4fSDavid du Colombier c = inb(cb->ldata);
18689a747e4fSDavid du Colombier if((c & 0xc0) != 0xc0)
18699a747e4fSDavid du Colombier break;
18709a747e4fSDavid du Colombier c = inb(cb->ldata);
18719a747e4fSDavid du Colombier if((c & 0xc0) != 0x00)
18729a747e4fSDavid du Colombier break;
18739a747e4fSDavid du Colombier if(c & 0x20){
18749a747e4fSDavid du Colombier cb->ltype = Tpd6720;
18759a747e4fSDavid du Colombier } else {
18769a747e4fSDavid du Colombier cb->ltype = Tpd6710;
18779a747e4fSDavid du Colombier }
18782c77d828SDavid du Colombier
18792c77d828SDavid du Colombier /* low power mode */
18802c77d828SDavid du Colombier outb(cb->lindex, Rmisc2 + (dev<<7));
18812c77d828SDavid du Colombier c = inb(cb->ldata);
18822c77d828SDavid du Colombier outb(cb->ldata, c & ~Flowpow);
18832c77d828SDavid du Colombier break;
18849a747e4fSDavid du Colombier break;
18859a747e4fSDavid du Colombier }
18869a747e4fSDavid du Colombier
18879a747e4fSDavid du Colombier /* if it's not a Cirrus, it could be a Vadem... */
18889a747e4fSDavid du Colombier if(cb->ltype == Ti82365){
18899a747e4fSDavid du Colombier /* unlock the Vadem extended regs */
18909a747e4fSDavid du Colombier outb(cb->lindex, 0x0E + (dev<<7));
18919a747e4fSDavid du Colombier outb(cb->lindex, 0x37 + (dev<<7));
18929a747e4fSDavid du Colombier
18939a747e4fSDavid du Colombier /* make the id register show the Vadem id */
18949a747e4fSDavid du Colombier outb(cb->lindex, 0x3A + (dev<<7));
18959a747e4fSDavid du Colombier c = inb(cb->ldata);
18969a747e4fSDavid du Colombier outb(cb->ldata, c|0xC0);
18979a747e4fSDavid du Colombier outb(cb->lindex, Rid + (dev<<7));
18989a747e4fSDavid du Colombier c = inb(cb->ldata);
18999a747e4fSDavid du Colombier if(c & 0x08)
19009a747e4fSDavid du Colombier cb->ltype = Tvg46x;
19019a747e4fSDavid du Colombier
19029a747e4fSDavid du Colombier /* go back to Intel compatible id */
19039a747e4fSDavid du Colombier outb(cb->lindex, 0x3A + (dev<<7));
19049a747e4fSDavid du Colombier c = inb(cb->ldata);
19059a747e4fSDavid du Colombier outb(cb->ldata, c & ~0xC0);
19069a747e4fSDavid du Colombier }
19079a747e4fSDavid du Colombier }
19089a747e4fSDavid du Colombier
19099a747e4fSDavid du Colombier static int
vcode(int volt)19109a747e4fSDavid du Colombier vcode(int volt)
19119a747e4fSDavid du Colombier {
19129a747e4fSDavid du Colombier switch(volt){
19139a747e4fSDavid du Colombier case 5:
19149a747e4fSDavid du Colombier return 1;
19159a747e4fSDavid du Colombier case 12:
19169a747e4fSDavid du Colombier return 2;
19179a747e4fSDavid du Colombier default:
19189a747e4fSDavid du Colombier return 0;
19199a747e4fSDavid du Colombier }
19209a747e4fSDavid du Colombier }
1921