Charles.Forsyth20060303644188019 years agoHistory
1949 lines · 39.3 KB · C
RawDownload
/*      cardbus and pcmcia (grmph) support.*/#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "io.h" #define MAP(x,o)	(Rmap + (x)*0x8 + o) enum {	TI_vid = 0x104c,	TI_1131_did = 0xAC15,	TI_1250_did = 0xAC16,	TI_1450_did = 0xAC1B,	TI_1251A_did = 0xAC1D,	TI_1420_did = 0xAC51, 	Ricoh_vid = 0x1180,	Ricoh_475_did = 0x0475,	Ricoh_476_did = 0x0476,	Ricoh_478_did = 0x0478, 	Nslots = 4,		/* Maximum number of CardBus slots to use */ 	K = 1024,	M = K * K, 	LegacyAddr = 0x3e0,	NUMEVENTS = 10, 	TI1131xSC = 0x80,		// system control		TI122X_SC_INTRTIE	= 1 << 29,	TI12xxIM = 0x8c,		// 	TI1131xCC = 0x91,		// card control		TI113X_CC_RIENB = 1 << 7,		TI113X_CC_ZVENABLE = 1 << 6,		TI113X_CC_PCI_IRQ_ENA = 1 << 5,		TI113X_CC_PCI_IREQ = 1 << 4,		TI113X_CC_PCI_CSC = 1 << 3,		TI113X_CC_SPKROUTEN = 1 << 1,		TI113X_CC_IFG = 1 << 0,	TI1131xDC = 0x92,		// device control}; typedef struct Variant Variant;struct Variant {	ushort	vid;	ushort	did;	char		*name;}; static Variant variant[] = {{	Ricoh_vid,	Ricoh_475_did,	"Ricoh 475 PCI/Cardbus bridge",	},{	Ricoh_vid,	Ricoh_476_did,	"Ricoh 476 PCI/Cardbus bridge",	},{	Ricoh_vid,	Ricoh_478_did,	"Ricoh 478 PCI/Cardbus bridge",	},{	TI_vid,		TI_1131_did,	"TI PCI-1131 Cardbus Controller", },{	TI_vid,		TI_1250_did,	"TI PCI-1250 Cardbus Controller", },{	TI_vid,		TI_1450_did,	"TI PCI-1450 Cardbus Controller", },{	TI_vid,		TI_1251A_did,	"TI PCI-1251A Cardbus Controller", },{	TI_vid,		TI_1420_did,	"TI PCI-1420 Cardbus Controller", },}; /* Cardbus registers */enum {	SocketEvent = 0,		SE_CCD = 3 << 1,		SE_POWER = 1 << 3,	SocketMask = 1,	SocketState = 2,		SS_CCD = 3 << 1,		SS_POWER = 1 << 3,		SS_PC16 = 1 << 4,		SS_CBC = 1 << 5,		SS_NOTCARD = 1 << 7,		SS_BADVCC = 1 << 9,		SS_5V = 1 << 10,		SS_3V = 1 << 11,	SocketForce = 3,	SocketControl = 4,		SC_5V = 0x22,		SC_3V = 0x33,}; enum {	PciPCR_IO = 1 << 0,	PciPCR_MEM = 1 << 1,	PciPCR_Master = 1 << 2, 	PciPMC = 0xa4, 	Nbars = 6,	Ncmd = 10,	CBIRQ = 9, 	PC16,	PC32,}; enum {	Ti82365,	Tpd6710,	Tpd6720,	Tvg46x,}; static char *chipname[] = {[Ti82365]		"Intel 82365SL",[Tpd6710]	"Cirrus Logic PD6710",[Tpd6720]	"Cirrus Logic PD6720",[Tvg46x]		"Vadem VG-46x",}; /* *  Intel 82365SL PCIC controller for the PCMCIA or *  Cirrus Logic PD6710/PD6720 which is mostly register compatible */enum{	/*	 *  registers indices	 */	Rid=		0x0,		/* identification and revision */	Ris=		0x1,		/* interface status */	Rpc=	 	0x2,		/* power control */	 Foutena=	 (1<<7),	/*  output enable */	 Fautopower=	 (1<<5),	/*  automatic power switching */	 Fcardena=	 (1<<4),	/*  PC card enable */	Rigc= 		0x3,		/* interrupt and general control */	 Fiocard=	 (1<<5),	/*  I/O card (vs memory) */	 Fnotreset=	 (1<<6),	/*  reset if not set */		 FSMIena=	 (1<<4),	/*  enable change interrupt on SMI */ 	Rcsc= 		0x4,		/* card status change */	Rcscic= 	0x5,		/* card status change interrupt config */	 Fchangeena=	 (1<<3),	/*  card changed */	 Fbwarnena=	 (1<<1),	/*  card battery warning */	 Fbdeadena=	 (1<<0),	/*  card battery dead */	Rwe= 		0x6,		/* address window enable */	 Fmem16=	 (1<<5),	/*  use A23-A12 to decode address */	Rio= 		0x7,		/* I/O control */	 Fwidth16=	 (1<<0),	/*  16 bit data width */	 Fiocs16=	 (1<<1),	/*  IOCS16 determines data width */	 Fzerows=	 (1<<2),	/*  zero wait state */	 Ftiming=	 (1<<3),	/*  timing register to use */	Riobtm0lo=	0x8,		/* I/O address 0 start low byte */	Riobtm0hi=	0x9,		/* I/O address 0 start high byte */	Riotop0lo=	0xa,		/* I/O address 0 stop low byte */	Riotop0hi=	0xb,		/* I/O address 0 stop high byte */	Riobtm1lo=	0xc,		/* I/O address 1 start low byte */	Riobtm1hi=	0xd,		/* I/O address 1 start high byte */	Riotop1lo=	0xe,		/* I/O address 1 stop low byte */	Riotop1hi=	0xf,		/* I/O address 1 stop high byte */	Rmap=		0x10,		/* map 0 */ 	/*	 *  CL-PD67xx extension registers	 */	Rmisc1=		0x16,		/* misc control 1 */	 F5Vdetect=	 (1<<0),	 Fvcc3V=	 (1<<1),	 Fpmint=	 (1<<2),	 Fpsirq=	 (1<<3),	 Fspeaker=	 (1<<4),	 Finpack=	 (1<<7),	Rfifo=		0x17,		/* fifo control */	 Fflush=	 (1<<7),	/*  flush fifo */	Rmisc2=		0x1E,		/* misc control 2 */	 Flowpow=	 (1<<1),	/*  low power mode */	Rchipinfo=	0x1F,		/* chip information */	Ratactl=	0x26,		/* ATA control */ 	/*	 *  offsets into the system memory address maps	 */	Mbtmlo=		0x0,		/* System mem addr mapping start low byte */	Mbtmhi=		0x1,		/* System mem addr mapping start high byte */	 F16bit=	 (1<<7),	/*  16-bit wide data path */	Mtoplo=		0x2,		/* System mem addr mapping stop low byte */	Mtophi=		0x3,		/* System mem addr mapping stop high byte */	 Ftimer1=	 (1<<6),	/*  timer set 1 */	Mofflo=		0x4,		/* Card memory offset address low byte */	Moffhi=		0x5,		/* Card memory offset address high byte */	 Fregactive=	 (1<<6),	/*  attribute memory */ 	/*	 *  configuration registers - they start at an offset in attribute	 *  memory found in the CIS.	 */	Rconfig=	0,	 Creset=	 (1<<7),	/*  reset device */	 Clevel=	 (1<<6),	/*  level sensitive interrupt line */}; /* *  read and crack the card information structure enough to set *  important parameters like power *//* cis memory walking */typedef struct Cisdat Cisdat;struct Cisdat {	uchar		*cisbase;	int			cispos;	int			cisskip;	int			cislen;}; typedef struct Pcminfo Pcminfo;struct Pcminfo {	char			verstr[512];		/* Version string */	PCMmap		mmap[4];		/* maps, last is always for the kernel */	ulong		conf_addr;		/* Config address */	uchar		conf_present;	/* Config register present */	int			nctab;			/* In use configuration tables */	PCMconftab	ctab[8];		/* Configuration tables */	PCMconftab	*defctab;		/* Default conftab */ 	int			port;			/* Actual port usage */	int			irq;			/* Actual IRQ usage */}; typedef struct Cardbus Cardbus;struct Cardbus {	Lock;	Variant		*variant;		/* Which CardBus chipset */	Pcidev		*pci;			/* The bridge itself */	ulong		*regs;			/* Cardbus registers */	int			ltype;			/* Legacy type */	int			lindex;		/* Legacy port index address */	int			ldata;			/* Legacy port data address */	int			lbase;			/* Base register for this socket */ 	int			state;			/* Current state of card */	int			type;			/* Type of card */	Pcminfo		linfo;			/* PCMCIA slot info */ 	int			special;		/* card is allocated to a driver */ 	int			refs;			/* Number of refs to slot */	Lock		refslock;		/* inc/dev ref lock */}; static int managerstarted; enum {	Mshift=	12,	Mgran=	(1<<Mshift),	/* granularity of maps */	Mmask=	~(Mgran-1),	/* mask for address bits important to the chip */}; static Cardbus cbslots[Nslots];static int nslots; static ulong exponent[8] = { 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; static ulong vmant[16] = {	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,}; static ulong mantissa[16] = { 	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; static char Enocard[] = "No card in slot"; enum{	CMdown,	CMpower,}; static Cmdtab pccardctlmsg[] ={	CMdown,		"down",	2,	CMpower,	"power",	1,}; static void cbint(Ureg *, void *);static int powerup(Cardbus *);static void configure(Cardbus *);static void managecard(Cardbus *);static void cardmanager(void *);static void eject(Cardbus *);static void interrupt(Ureg *, void *);static void powerdown(Cardbus *cb);static void unconfigure(Cardbus *cb); static void i82365probe(Cardbus *cb, int lindex, int ldata);static void i82365configure(Cardbus *cb);static PCMmap *isamap(Cardbus *cb, ulong offset, int len, int attr);static void isaunmap(PCMmap* m);static uchar rdreg(Cardbus *cb, int index);static void wrreg(Cardbus *cb, int index, uchar val);static int readc(Cisdat *cis, uchar *x);static void tvers1(Cardbus *cb, Cisdat *cis, int );static void tcfig(Cardbus *cb, Cisdat *cis, int );static void tentry(Cardbus *cb, Cisdat *cis, int );static int vcode(int volt);static int pccard_pcmspecial(char *idstr, ISAConf *isa);static void pccard_pcmspecialclose(int slotno); enum {	CardDetected,	CardPowered,	CardEjected,	CardConfigured,}; static char *messages[] = {[CardDetected]		"CardDetected",[CardPowered]		"CardPowered",[CardEjected]		"CardEjected",[CardConfigured]	"CardConfigured",}; enum {	SlotEmpty,	SlotFull,	SlotPowered,	SlotConfigured,}; static char *states[] = {[SlotEmpty]		"SlotEmpty",[SlotFull]			"SlotFull",[SlotPowered]		"SlotPowered",[SlotConfigured]	"SlotConfigured",}; static voidengine(Cardbus *cb, int message){	//print("engine(%d): %s(%s)\n", 	//	 (int)(cb - cbslots), states[cb->state], messages[message]);	switch (cb->state) {	case SlotEmpty: 		switch (message) {		case CardDetected:			cb->state = SlotFull;			powerup(cb);			break;		case CardEjected:			break;		default:			//print("#Y%d: Invalid message %s in SlotEmpty state\n",			//	(int)(cb - cbslots), messages[message]);			break;		}		break; 	case SlotFull: 		switch (message) {		case CardPowered:			cb->state = SlotPowered;			configure(cb);			break;		case CardEjected:			cb->state = SlotEmpty;			powerdown(cb);			break;		default:			//print("#Y%d: Invalid message %s in SlotFull state\n",			//	(int)(cb - cbslots), messages[message]);			break;		}		break; 	case SlotPowered: 		switch (message) {		case CardConfigured:			cb->state = SlotConfigured;			break;		case CardEjected:			cb->state = SlotEmpty;			unconfigure(cb);			powerdown(cb);			break;		default:			//print("#Y%d: Invalid message %s in SlotPowered state\n",			//	(int)(cb - cbslots), messages[message]);			break;		}		break; 	case SlotConfigured: 		switch (message) {		case CardEjected:			cb->state = SlotEmpty;			unconfigure(cb);			powerdown(cb);			break;		default:			//print("#Y%d: Invalid message %s in SlotConfigured state\n",			//	(int)(cb - cbslots), messages[message]);			break;		}		break;	}} static voidqengine(Cardbus *cb, int message){	lock(cb);	engine(cb, message);	unlock(cb);} typedef struct Events Events;struct Events {	Cardbus	*cb;	int	message;}; static Lock levents;static Events events[NUMEVENTS];static Rendez revents;static int nevents; static voidiengine(Cardbus *cb, int message){	if (nevents >= NUMEVENTS) {		print("#Y: Too many events queued, discarding request\n");		return;	}	ilock(&levents);	events[nevents].cb = cb;	events[nevents].message = message;	nevents++;	iunlock(&levents);	wakeup(&revents);} static inteventoccured(void){	return nevents > 0;} static voidprocessevents(void *){	while (1) {		int message;		Cardbus *cb; 		sleep(&revents, (int (*)(void *))eventoccured, nil); 		cb = nil;		message = 0;		ilock(&levents);		if (nevents > 0) {			cb = events[0].cb;			message = events[0].message;			nevents--;			if (nevents > 0)				memmove(events, &events[1], nevents * sizeof(Events));		}		iunlock(&levents); 		if (cb)			qengine(cb, message);	}} static voidcbinterrupt(Ureg *, void *){	int i; 	for (i = 0; i != nslots; i++) {		Cardbus *cb = &cbslots[i];		ulong event, state; 		event= cb->regs[SocketEvent];		state = cb->regs[SocketState];		rdreg(cb, Rcsc);	/* Ack the interrupt */ 		//print("interrupt: slot %d, event %.8lX, state %.8lX, (%s)\n", 		//	(int)(cb - cbslots), event, state, states[cb->state]); 		if (event & SE_CCD) {			cb->regs[SocketEvent] |= SE_CCD;	/* Ack interrupt */			if (state & SE_CCD) {				if (cb->state != SlotEmpty) {					print("#Y: take cardejected interrupt\n");					iengine(cb, CardEjected);				}			}			else				iengine(cb, CardDetected);

Lines 1–500 of 1949.