xref: /plan9/sys/src/9/pc/devpccard.c (revision aa72973a2891ccbd3fb042462446761159389e19)
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