1929 lines · 38.8 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /*     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 DEBUG	0 #pragma	varargck	type	"T"	int #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, 	O2_vid = 0x1217,	O2_OZ711M3_did = 0x7134, 	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", },{	O2_vid,		O2_OZ711M3_did,	"O2Micro OZ711M3 MemoryCardBus", },}; /* 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,}; /* *  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 int powerup(Cardbus *);static void configure(Cardbus *);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){	if(DEBUG)		print("engine(%ld): %s(%s)\n", 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:			if(DEBUG)				print("#Y%ld: Invalid message %s in SlotEmpty state\n",					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:			if(DEBUG)				print("#Y%ld: Invalid message %s in SlotFull state\n",					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%ld: Invalid message %s in SlotPowered state\n",				cb - cbslots, messages[message]);			break;		}		break; 	case SlotConfigured: 		switch (message) {		case CardEjected:			cb->state = SlotEmpty;			unconfigure(cb);			powerdown(cb);			break;		default:			if(DEBUG)				print("#Y%ld: Invalid message %s in SlotConfigured state\n",					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];		if(!(event & (SE_POWER|SE_CCD)))			continue;		state = cb->regs[SocketState];		rdreg(cb, Rcsc);	/* Ack the interrupt */ 		if(DEBUG)			print("#Y%ld: interrupt: event %.8lX, state %.8lX, (%s)\n",

Lines 1–500 of 1929.